scummvm/engines/twine/holomap.cpp

625 lines
23 KiB
C++
Raw Normal View History

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "twine/holomap.h"
2020-12-22 17:16:27 +01:00
#include "common/debug.h"
#include "common/memstream.h"
#include "common/stream.h"
#include "common/types.h"
#include "twine/audio/sound.h"
#include "twine/menu/interface.h"
#include "twine/parser/anim.h"
#include "twine/parser/holomap.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/renderer.h"
#include "twine/renderer/screens.h"
2021-01-11 20:21:49 +01:00
#include "twine/resources/hqr.h"
#include "twine/resources/resources.h"
#include "twine/scene/animations.h"
#include "twine/scene/collision.h"
2021-01-11 20:21:49 +01:00
#include "twine/scene/gamestate.h"
#include "twine/scene/movements.h"
#include "twine/scene/scene.h"
#include "twine/shared.h"
#include "twine/text.h"
#include "twine/twine.h"
namespace TwinE {
#define HOLOMAP_ARROW (1 << 0)
#define HOLOMAP_VISITED (1 << 1)
#define HOLOMAP_UNK3 (1 << 2)
#define HOLOMAP_UNK4 (1 << 3)
#define HOLOMAP_UNK5 (1 << 4)
#define HOLOMAP_UNK6 (1 << 5)
#define HOLOMAP_UNK7 (1 << 6)
#define HOLOMAP_CAN_FOCUS (1 << 7)
#define HOLOMAP_RESET (HOLOMAP_VISITED | HOLOMAP_UNK3 | HOLOMAP_UNK4 | HOLOMAP_UNK5 | HOLOMAP_UNK6 | HOLOMAP_UNK7)
#define HOLOMAP_ACTIVE (HOLOMAP_CAN_FOCUS | HOLOMAP_ARROW)
Holomap::Holomap(TwinEEngine *engine) : _engine(engine) {}
bool Holomap::loadLocations() {
uint8 *locationsPtr = nullptr;
const int32 locationsSize = HQR::getAllocEntry(&locationsPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWINFO);
if (locationsSize == 0) {
warning("Could not find holomap locations at index %i in %s", RESSHQR_HOLOARROWINFO, Resources::HQR_RESS_FILE);
return false;
}
Common::MemoryReadStream stream(locationsPtr, locationsSize, DisposeAfterUse::YES);
_numLocations = locationsSize / 8;
if (_numLocations > NUM_LOCATIONS) {
warning("Amount of locations (%i) exceeds the maximum of %i", _numLocations, NUM_LOCATIONS);
return false;
}
_engine->_text->initTextBank(TextBankId::Inventory_Intro_and_Holomap);
for (int32 i = 0; i < _numLocations; i++) {
2021-03-17 00:12:48 +01:00
_locations[i].angle.x = ClampAngle(stream.readSint16LE());
_locations[i].angle.y = ClampAngle(stream.readSint16LE());
_locations[i].angle.z = ClampAngle(stream.readSint16LE());
_locations[i].textIndex = (TextId)stream.readUint16LE();
if (_engine->_text->getMenuText(_locations[i].textIndex, _locations[i].name, sizeof(_locations[i].name))) {
debug(2, "Scene %i: %s", i, _locations[i].name);
continue;
}
debug(2, "Could not get location text for index %i", i);
}
return true;
}
void Holomap::setHolomapPosition(int32 locationIdx) {
assert(locationIdx >= 0 && locationIdx <= ARRAYSIZE(_engine->_gameState->holomapFlags));
_engine->_gameState->holomapFlags[locationIdx] = HOLOMAP_ACTIVE;
if (_engine->_gameState->hasItem(InventoryItems::kiHolomap)) {
_engine->_redraw->addOverlay(OverlayType::koInventoryItem, InventoryItems::kiHolomap, 0, 0, 0, OverlayPosType::koNormal, 3);
}
2020-10-14 14:20:38 +02:00
}
void Holomap::clearHolomapPosition(int32 locationIdx) {
assert(locationIdx >= 0 && locationIdx <= ARRAYSIZE(_engine->_gameState->holomapFlags));
_engine->_gameState->holomapFlags[locationIdx] &= HOLOMAP_RESET;
_engine->_gameState->holomapFlags[locationIdx] |= HOLOMAP_UNK7;
}
void Holomap::loadHolomapGFX() {
_engine->_screens->loadCustomPalette(RESSHQR_HOLOPAL);
int32 j = 576;
for (int32 i = 0; i < 96; i += 3, j += 3) {
2021-07-31 15:37:40 +02:00
_paletteHolomap[i + 0] = _engine->_screens->_palette[j + 0];
_paletteHolomap[i + 1] = _engine->_screens->_palette[j + 1];
_paletteHolomap[i + 2] = _engine->_screens->_palette[j + 2];
}
j = 576;
for (int32 i = 96; i < 189; i += 3, j += 3) {
2021-07-31 15:37:40 +02:00
_paletteHolomap[i + 0] = _engine->_screens->_palette[j + 0];
_paletteHolomap[i + 1] = _engine->_screens->_palette[j + 1];
_paletteHolomap[i + 2] = _engine->_screens->_palette[j + 2];
}
2021-02-09 11:45:59 +01:00
prepareHolomapProjectedPositions();
prepareHolomapSurface();
2021-03-19 15:30:22 +01:00
_holomapPaletteIndex = 0;
}
2021-01-24 15:16:37 +01:00
static int sortHolomapSurfaceCoordsByDepth(const void *a1, const void *a2) {
return (int)*(const int16 *)a1 - (int)*(const int16 *)a2;
2021-01-24 15:16:37 +01:00
}
// verified with disassembly
void Holomap::prepareHolomapSurface() {
Common::MemoryReadStream stream(_engine->_resources->holomapSurfacePtr, _engine->_resources->holomapSurfaceSize);
2021-01-24 15:16:37 +01:00
int holomapSurfaceArrayIdx = 0;
2021-02-09 11:45:59 +01:00
_engine->_renderer->setBaseRotation(0, 0, 0);
2021-03-01 19:54:06 +01:00
for (int angle = -ANGLE_90; angle <= ANGLE_90; angle += ANGLE_11_25) {
2021-02-09 11:45:59 +01:00
int rotation = 0;
2021-03-01 19:54:06 +01:00
for (int i = 0; i <= ANGLE_11_25; ++i, rotation += ANGLE_11_25) {
2021-02-09 11:45:59 +01:00
const int32 rotX = stream.readByte();
2021-03-17 00:17:51 +01:00
const IVec3& rotVec = _engine->_renderer->getHolomapRotation(rotX, angle, rotation);
_holomapSurface[holomapSurfaceArrayIdx].x = rotVec.x;
_holomapSurface[holomapSurfaceArrayIdx].y = rotVec.y;
_holomapSurface[holomapSurfaceArrayIdx].z = rotVec.z;
2021-02-09 11:45:59 +01:00
++holomapSurfaceArrayIdx;
}
}
2021-03-01 19:54:06 +01:00
assert(stream.eos());
2021-02-09 11:45:59 +01:00
}
// verified with disassembly
2021-02-09 11:45:59 +01:00
void Holomap::prepareHolomapProjectedPositions() {
2021-01-24 15:16:37 +01:00
int projectedIndex = 0;
for (int32 angle = -ANGLE_90; angle <= ANGLE_90; angle += ANGLE_11_25) {
2021-01-24 15:16:37 +01:00
int rotation = 0;
2021-03-01 19:54:06 +01:00
for (int32 i = 0; i < ANGLE_11_25; ++i) {
2021-01-24 15:31:54 +01:00
_projectedSurfacePositions[projectedIndex].unk1 = _engine->_screens->crossDot(0, 0xffff, ANGLE_360 - 1, rotation);
2021-01-24 15:16:37 +01:00
if (angle == ANGLE_90) {
_projectedSurfacePositions[projectedIndex].unk2 = -1;
2021-01-24 15:16:37 +01:00
} else {
_projectedSurfacePositions[projectedIndex].unk2 = ((angle + ANGLE_90) * ANGLE_90) / 2;
2021-01-24 15:16:37 +01:00
}
2021-02-06 13:23:56 +01:00
rotation += ANGLE_11_25;
2021-01-24 15:16:37 +01:00
++projectedIndex;
}
_projectedSurfacePositions[projectedIndex].unk1 = -1;
2021-01-24 15:16:37 +01:00
if (angle == ANGLE_90) {
_projectedSurfacePositions[projectedIndex].unk2 = -1;
2021-01-24 15:16:37 +01:00
} else {
_projectedSurfacePositions[projectedIndex].unk2 = ((angle + ANGLE_90) * ANGLE_90) / 2;
2021-01-24 15:16:37 +01:00
}
++projectedIndex;
}
2021-02-09 11:45:59 +01:00
}
2021-03-07 13:00:23 +01:00
// verified with disassembly
2021-02-09 11:45:59 +01:00
void Holomap::prepareHolomapPolygons() {
int holomapSortArrayIdx = 0;
int holomapSurfaceArrayIdx = 0;
_projectedSurfaceIndex = 0;
2021-02-09 11:45:59 +01:00
for (int32 angle = -ANGLE_90; angle <= ANGLE_90; angle += ANGLE_11_25) {
int rotation = 0;
for (int32 stepWidth = 0; stepWidth < ANGLE_11_25; ++stepWidth) {
2021-03-17 00:17:51 +01:00
IVec3* vec = &_holomapSurface[holomapSurfaceArrayIdx++];
2021-02-09 11:45:59 +01:00
_engine->_renderer->getBaseRotationPosition(vec->x, vec->y, vec->z);
if (angle != ANGLE_90) {
2021-02-26 10:23:21 +01:00
_holomapSort[holomapSortArrayIdx].z = _engine->_renderer->destPos.z;
_holomapSort[holomapSortArrayIdx].projectedPosIdx = _projectedSurfaceIndex;
2021-02-09 11:45:59 +01:00
++holomapSortArrayIdx;
}
_engine->_renderer->projectXYPositionOnScreen(_engine->_renderer->destPos);
2021-02-26 10:18:07 +01:00
_projectedSurfacePositions[_projectedSurfaceIndex].x = _engine->_renderer->projPos.x;
_projectedSurfacePositions[_projectedSurfaceIndex].y = _engine->_renderer->projPos.y;
2021-02-09 11:45:59 +01:00
rotation += ANGLE_11_25;
++_projectedSurfaceIndex;
2021-02-09 11:45:59 +01:00
}
2021-03-17 00:17:51 +01:00
IVec3* vec = &_holomapSurface[holomapSurfaceArrayIdx++];
2021-02-09 11:45:59 +01:00
_engine->_renderer->getBaseRotationPosition(vec->x, vec->y, vec->z);
_engine->_renderer->projectXYPositionOnScreen(_engine->_renderer->destPos);
2021-02-26 10:18:07 +01:00
_projectedSurfacePositions[_projectedSurfaceIndex].x = _engine->_renderer->projPos.x;
_projectedSurfacePositions[_projectedSurfaceIndex].y = _engine->_renderer->projPos.y;
2021-02-09 11:45:59 +01:00
rotation += ANGLE_11_25;
++_projectedSurfaceIndex;
2021-02-09 11:45:59 +01:00
}
assert(holomapSortArrayIdx == ARRAYSIZE(_holomapSort));
assert(holomapSurfaceArrayIdx == ARRAYSIZE(_holomapSurface));
assert(_projectedSurfaceIndex == ARRAYSIZE(_projectedSurfacePositions));
qsort(_holomapSort, ARRAYSIZE(_holomapSort), sizeof(HolomapSort), sortHolomapSurfaceCoordsByDepth);
}
2021-02-13 14:35:13 +01:00
bool Holomap::isTriangleVisible(const Vertex *vertices) const {
2021-02-28 16:09:23 +01:00
const int32 iVar2 = ((int32)vertices[1].x - (int32)vertices[0].x) *
((int32)vertices[0].y - (int32)vertices[2].y);
const int32 iVar1 = ((int32)vertices[1].y - (int32)vertices[0].y) *
((int32)vertices[0].x - (int32)vertices[2].x);
return iVar2 - iVar1 != 0 && iVar1 <= iVar2;
2021-02-12 22:16:33 +01:00
}
2021-01-24 15:16:37 +01:00
void Holomap::renderHolomapSurfacePolygons() {
2021-02-09 11:45:59 +01:00
prepareHolomapPolygons();
for (int32 i = 0; i < ARRAYSIZE(_holomapSort); ++i) {
assert(_holomapSort[i].projectedPosIdx + 34 < _projectedSurfaceIndex);
2021-02-12 22:16:33 +01:00
const HolomapProjectedPos &pos1 = _projectedSurfacePositions[_holomapSort[i].projectedPosIdx + 0];
const HolomapProjectedPos &pos2 = _projectedSurfacePositions[_holomapSort[i].projectedPosIdx + 33];
const HolomapProjectedPos &pos3 = _projectedSurfacePositions[_holomapSort[i].projectedPosIdx + 1];
Vertex vertexCoordinates[3];
vertexCoordinates[0].x = pos1.x;
vertexCoordinates[0].y = pos1.y;
vertexCoordinates[1].x = pos2.x;
vertexCoordinates[1].y = pos2.y;
vertexCoordinates[2].x = pos3.x;
vertexCoordinates[2].y = pos3.y;
2021-02-28 16:09:23 +01:00
if (isTriangleVisible(vertexCoordinates)) {
Vertex vertexAngles[3];
vertexAngles[0].x = pos1.unk1;
vertexAngles[0].y = pos1.unk2;
vertexAngles[1].x = pos2.unk1;
vertexAngles[1].y = pos2.unk2;
vertexAngles[2].x = pos3.unk1;
vertexAngles[2].y = pos3.unk2;
_engine->_renderer->renderHolomapVertices(vertexCoordinates, vertexAngles);
2021-01-24 15:16:37 +01:00
}
2021-02-12 22:16:33 +01:00
const HolomapProjectedPos &pos4 = _projectedSurfacePositions[_holomapSort[i].projectedPosIdx + 33];
const HolomapProjectedPos &pos5 = _projectedSurfacePositions[_holomapSort[i].projectedPosIdx + 34];
const HolomapProjectedPos &pos6 = _projectedSurfacePositions[_holomapSort[i].projectedPosIdx + 1];
vertexCoordinates[0].x = pos4.x;
vertexCoordinates[0].y = pos4.y;
vertexCoordinates[1].x = pos5.x;
vertexCoordinates[1].y = pos5.y;
vertexCoordinates[2].x = pos6.x;
vertexCoordinates[2].y = pos6.y;
2021-02-28 16:09:23 +01:00
if (isTriangleVisible(vertexCoordinates)) {
Vertex vertexAngles[3];
vertexAngles[0].x = pos4.unk1;
vertexAngles[0].y = pos4.unk2;
vertexAngles[1].x = pos5.unk1;
vertexAngles[1].y = pos5.unk2;
vertexAngles[2].x = pos6.unk1;
vertexAngles[2].y = pos6.unk2;
_engine->_renderer->renderHolomapVertices(vertexCoordinates, vertexAngles);
2021-01-24 15:16:37 +01:00
}
}
2021-01-24 09:54:13 +01:00
}
2020-12-22 17:16:27 +01:00
void Holomap::drawHolomapText(int32 centerx, int32 top, const char *title) {
const int32 size = _engine->_text->getTextSize(title);
const int32 x = centerx - size / 2;
const int32 y = top;
_engine->_text->setFontColor(COLOR_WHITE);
2020-12-22 17:16:27 +01:00
_engine->_text->drawText(x, y, title);
}
2021-03-27 08:57:54 +01:00
void Holomap::renderHolomapModel(const BodyData &bodyData, int32 x, int32 y, int32 zPos) {
2021-01-24 16:19:39 +01:00
_engine->_renderer->setBaseRotation(x, y, 0);
2021-01-24 09:54:13 +01:00
_engine->_renderer->getBaseRotationPosition(0, 0, zPos + 1000);
2021-02-26 10:23:21 +01:00
_engine->_renderer->getBaseRotationPosition(_engine->_renderer->destPos.x, _engine->_renderer->destPos.y, _engine->_renderer->destPos.z);
2021-01-24 09:54:13 +01:00
_engine->_interface->resetClip();
Common::Rect dummy;
_engine->_renderer->renderIsoModel(_engine->_renderer->destPos.x, _engine->_renderer->destPos.y, _engine->_renderer->destPos.z, x, y, ANGLE_0, bodyData, dummy);
2021-01-24 09:54:13 +01:00
}
void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
debug("Draw trajectory index %i", trajectoryIndex);
2021-01-24 16:19:39 +01:00
const Trajectory *data = _engine->_resources->getTrajectory(trajectoryIndex);
if (data == nullptr) {
warning("Failed to load trajectory data for index %i", trajectoryIndex);
return;
}
_engine->exitSceneryView();
2021-01-24 16:19:39 +01:00
_engine->_interface->resetClip();
_engine->_screens->clearScreen();
2021-07-31 15:37:40 +02:00
_engine->setPalette(_engine->_screens->_paletteRGBA);
2021-01-24 16:19:39 +01:00
loadHolomapGFX();
2021-01-11 20:21:49 +01:00
ScopedEngineFreeze timeFreeze(_engine);
_engine->_renderer->setCameraPosition(400, 240, 128, 1024, 1024);
_engine->_renderer->setCameraAngle(0, 0, 0, data->pos.x, data->pos.y, data->pos.z, 5300);
2021-01-24 15:16:37 +01:00
renderHolomapSurfacePolygons();
2021-01-24 09:54:13 +01:00
const Location &loc = _locations[data->locationIdx];
2021-03-17 00:12:48 +01:00
renderHolomapModel(_engine->_resources->holomapPointModelPtr, loc.angle.x, loc.angle.y, 0);
2021-01-24 09:54:13 +01:00
2021-01-11 20:21:49 +01:00
ActorMoveStruct move;
AnimTimerDataStruct animTimerData;
AnimData animData;
animData.loadFromHQR(Resources::HQR_RESS_FILE, data->getAnimation());
2021-03-27 08:57:54 +01:00
BodyData bodyData;
bodyData.loadFromHQR(Resources::HQR_RESS_FILE, data->getModel());
2021-03-08 19:59:59 +01:00
uint frameNumber = 0;
int32 frameTime = _engine->lbaTime;
int16 trajAnimFrameIdx = 0;
2021-01-24 16:19:39 +01:00
int32 local18 = 0;
bool fadeInPalette = true;
_engine->_input->enableKeyMap(holomapKeyMapId);
2021-01-11 20:21:49 +01:00
for (;;) {
FrameMarker frame(_engine);
2021-01-11 20:21:49 +01:00
_engine->readKeys();
if (_engine->shouldQuit() || _engine->_input->toggleAbortAction()) {
break;
}
2021-01-24 16:19:39 +01:00
if (!fadeInPalette && local18 < _engine->lbaTime) {
//const Common::Rect rect(170, 50, 470, 330);
//_engine->_interface->setClip(rect);
2021-03-19 15:30:22 +01:00
_engine->setPalette(192, 32, &_paletteHolomap[3 * _holomapPaletteIndex++]);
//_engine->copyBlockPhys(rect);
//_engine->_interface->resetClip();
2021-03-19 15:30:22 +01:00
if (_holomapPaletteIndex == 32) {
_holomapPaletteIndex = 0;
2021-01-11 20:21:49 +01:00
}
2021-01-24 16:19:39 +01:00
local18 = _engine->lbaTime + 3;
2021-01-11 20:21:49 +01:00
}
2021-01-11 20:21:49 +01:00
const int16 newAngle = move.getRealAngle(_engine->lbaTime);
if (move.numOfStep == 0) {
2021-01-24 16:19:39 +01:00
_engine->_movements->setActorAngleSafe(ANGLE_0, -ANGLE_90, 500, &move);
2021-01-11 20:21:49 +01:00
}
2021-03-27 08:57:54 +01:00
if (_engine->_animations->setModelAnimation(frameNumber, animData, bodyData, &animTimerData)) {
frameNumber++;
2021-03-08 19:59:59 +01:00
if (frameNumber >= animData.getNumKeyframes()) {
frameNumber = animData.getLoopFrame();
2021-01-11 20:21:49 +01:00
}
}
_engine->_renderer->setCameraPosition(100, 400, 128, 900, 900);
2021-01-24 16:19:39 +01:00
_engine->_renderer->setCameraAngle(0, 0, 0, 60, 128, 0, 30000);
2021-02-09 21:38:01 +01:00
_engine->_renderer->setLightVector(-60, 128, 0);
2021-01-24 16:19:39 +01:00
const Common::Rect rect(0, 200, 199, 479);
2021-01-30 14:35:12 +01:00
_engine->_interface->drawFilledRect(rect, COLOR_BLACK);
Common::Rect dummy;
_engine->_renderer->renderIsoModel(0, 0, 0, ANGLE_0, newAngle, ANGLE_0, bodyData, dummy);
2021-01-24 16:19:39 +01:00
_engine->copyBlockPhys(rect);
2021-01-11 20:21:49 +01:00
_engine->_renderer->setCameraPosition(400, 240, 128, 1024, 1024);
_engine->_renderer->setCameraAngle(0, 0, 0, data->pos.x, data->pos.y, data->pos.z, 5300);
_engine->_renderer->setLightVector(data->pos.x, data->pos.y, 0);
if (frameTime + 40 <= _engine->lbaTime) {
frameTime = _engine->lbaTime;
2021-01-24 16:19:39 +01:00
int32 modelX;
int32 modelY;
if (trajAnimFrameIdx < data->numAnimFrames) {
modelX = data->positions[trajAnimFrameIdx].x;
modelY = data->positions[trajAnimFrameIdx].y;
2021-01-24 09:54:13 +01:00
} else {
if (data->numAnimFrames < trajAnimFrameIdx) {
2021-01-24 09:54:13 +01:00
break;
}
modelX = _locations[data->trajLocationIdx].angle.x;
modelY = _locations[data->trajLocationIdx].angle.y;
2021-01-11 20:21:49 +01:00
}
2021-01-24 16:19:39 +01:00
renderHolomapModel(_engine->_resources->holomapPointModelPtr, modelX, modelY, 0);
2021-02-28 20:58:49 +01:00
++trajAnimFrameIdx;
2021-01-11 20:21:49 +01:00
}
2021-01-24 16:19:39 +01:00
if (fadeInPalette) {
fadeInPalette = false;
2021-02-28 20:58:49 +01:00
// TODO: this does a flip - which puts stuff onto the screen that shouldn't be there
//_engine->_screens->fadeToPal(_engine->_screens->paletteRGBA);
2021-01-11 20:21:49 +01:00
}
}
2021-02-28 20:58:49 +01:00
_engine->_screens->clearScreen();
2021-07-31 15:37:40 +02:00
_engine->setPalette(_engine->_screens->_paletteRGBA);
_engine->_gameState->initEngineProjections();
_engine->_interface->loadClip();
_engine->_text->initSceneTextBank();
_engine->_input->enableKeyMap(mainKeyMapId);
}
int32 Holomap::getNextHolomapLocation(int32 currentLocation, int32 dir) const {
2021-01-31 18:14:44 +01:00
const int32 idx = currentLocation;
int32 i = currentLocation + dir;
if (i < 0) {
i = NUM_LOCATIONS - 1;
} else {
i %= NUM_LOCATIONS;
}
for (; i != idx; i = (i + dir) % NUM_LOCATIONS) {
if (_engine->_gameState->holomapFlags[i] & HOLOMAP_ACTIVE) {
return i;
}
}
return -1;
2020-12-22 17:16:27 +01:00
}
2021-01-13 00:09:57 +01:00
void Holomap::renderLocations(int xRot, int yRot, int zRot, bool lower) {
int n = 0;
DrawListStruct drawListArray[NUM_LOCATIONS];
2021-01-13 00:09:57 +01:00
for (int locationIdx = 0; locationIdx < NUM_LOCATIONS; ++locationIdx) {
if ((_engine->_gameState->holomapFlags[locationIdx] & HOLOMAP_CAN_FOCUS) || locationIdx == _engine->_scene->currentSceneIdx) {
2021-01-13 00:09:57 +01:00
const Location &loc = _locations[locationIdx];
2021-03-17 00:12:48 +01:00
_engine->_renderer->setBaseRotation(loc.angle.x, loc.angle.y, 0);
_engine->_renderer->getBaseRotationPosition(0, 0, loc.angle.z + 1000);
2021-02-26 10:23:21 +01:00
int32 xpos1 = _engine->_renderer->destPos.x;
int32 ypos1 = _engine->_renderer->destPos.y;
int32 zpos1 = _engine->_renderer->destPos.z;
2021-01-17 00:04:44 +01:00
_engine->_renderer->getBaseRotationPosition(0, 0, 1500);
2021-02-26 10:23:21 +01:00
int32 xpos2 = _engine->_renderer->destPos.x;
int32 ypos2 = _engine->_renderer->destPos.y;
int32 zpos2 = _engine->_renderer->destPos.z;
_engine->_renderer->setBaseRotation(xRot, yRot, zRot, true);
int32 zpos1_copy = zpos1;
2021-02-26 10:12:16 +01:00
_engine->_renderer->baseRotPos.x = 0;
_engine->_renderer->baseRotPos.y = 0;
_engine->_renderer->baseRotPos.z = 9500;
_engine->_renderer->getBaseRotationPosition(xpos1, ypos1, zpos1);
2021-02-26 10:23:21 +01:00
int32 zpos1_copy2 = _engine->_renderer->destPos.z;
_engine->_renderer->getBaseRotationPosition(xpos2, ypos2, zpos2);
2021-01-13 00:09:57 +01:00
if (lower) {
if (zpos1_copy2 > _engine->_renderer->destPos.z) {
2021-01-13 00:09:57 +01:00
continue;
}
} else {
if (_engine->_renderer->destPos.z > zpos1_copy2) {
2021-01-13 00:09:57 +01:00
continue;
}
}
uint8 flags = _engine->_gameState->holomapFlags[locationIdx] & HOLOMAP_ARROW;
2021-03-12 19:29:53 +01:00
if (locationIdx == _engine->_scene->currentSceneIdx) {
flags |= 2u; // model type
}
DrawListStruct &drawList = drawListArray[n];
drawList.posValue = zpos1_copy2;
2021-01-17 00:04:44 +01:00
drawList.actorIdx = locationIdx;
drawList.type = flags;
drawList.x = xpos1;
drawList.y = ypos1;
drawList.z = zpos1_copy;
2021-01-13 00:09:57 +01:00
++n;
}
}
_engine->_redraw->sortDrawingList(drawListArray, n);
for (int i = 0; i < n; ++i) {
const DrawListStruct &drawList = drawListArray[i];
const uint16 flags = drawList.type;
2021-03-27 08:57:54 +01:00
const BodyData *bodyData = nullptr;
2021-01-24 15:16:37 +01:00
if (flags == 1u) {
2021-03-27 08:57:54 +01:00
bodyData = &_engine->_resources->holomapArrowPtr;
2021-01-17 00:04:44 +01:00
} else if (flags == 2u) {
2021-03-27 08:57:54 +01:00
bodyData = &_engine->_resources->holomapTwinsenModelPtr;
2021-01-24 15:16:37 +01:00
} else if (flags == 3u) {
2021-03-27 08:57:54 +01:00
bodyData = &_engine->_resources->holomapTwinsenArrowPtr;
2021-01-13 00:09:57 +01:00
}
2021-03-27 08:57:54 +01:00
if (bodyData != nullptr) {
2021-03-17 00:12:48 +01:00
int32 angleX = _locations[drawList.actorIdx].angle.x;
int32 angleY = _locations[drawList.actorIdx].angle.y;
Common::Rect dummy;
_engine->_renderer->renderIsoModel(drawList.x, drawList.y, drawList.z, angleX, angleY, ANGLE_0, *bodyData, dummy);
2021-01-13 00:09:57 +01:00
}
}
}
void Holomap::processHolomap() {
2020-11-02 23:09:27 +01:00
ScopedEngineFreeze freeze(_engine);
2020-10-23 10:52:33 +02:00
const int32 alphaLightTmp = _engine->_scene->alphaLight;
const int32 betaLightTmp = _engine->_scene->betaLight;
_engine->exitSceneryView();
2021-07-31 15:37:40 +02:00
_engine->_screens->fadeToBlack(_engine->_screens->_paletteRGBA);
_engine->_sound->stopSamples();
2020-12-22 17:16:27 +01:00
_engine->_interface->saveClip();
_engine->_interface->resetClip();
_engine->_screens->clearScreen();
2021-07-31 15:37:40 +02:00
_engine->setPalette(_engine->_screens->_paletteRGBA);
loadHolomapGFX();
2020-11-01 22:35:29 +01:00
_engine->_text->initTextBank(TextBankId::Inventory_Intro_and_Holomap);
2021-01-26 00:29:24 +01:00
_engine->_text->setFontCrossColor(COLOR_9);
2021-02-09 21:38:01 +01:00
_engine->_renderer->setCameraPosition(_engine->width() / 2, 190, 128, 1024, 1024);
int32 currentLocation = _engine->_scene->currentSceneIdx;
_engine->_text->drawHolomapLocation(_locations[currentLocation].textIndex);
2020-12-22 17:16:27 +01:00
2021-01-17 00:04:44 +01:00
int32 time = _engine->lbaTime;
2021-03-17 00:12:48 +01:00
int32 xRot = ClampAngle(_locations[currentLocation].angle.x);
int32 yRot = ClampAngle(_locations[currentLocation].angle.y);
bool rotate = false;
bool redraw = true;
int local18 = 0;
bool fadeInPalette = true;
_engine->_input->enableKeyMap(holomapKeyMapId);
2020-12-22 14:44:56 +01:00
for (;;) {
FrameMarker frame(_engine);
2020-12-22 14:44:56 +01:00
_engine->_input->readKeys();
if (_engine->shouldQuit() || _engine->_input->toggleAbortAction()) {
break;
}
if (_engine->_input->toggleActionIfActive(TwinEActionType::HolomapPrev)) {
const int32 nextLocation = getNextHolomapLocation(currentLocation, -1);
if (nextLocation != -1) {
currentLocation = nextLocation;
_engine->_text->drawHolomapLocation(_locations[currentLocation].textIndex);
2021-01-17 00:04:44 +01:00
time = _engine->lbaTime;
rotate = true;
}
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::HolomapNext)) {
const int32 nextLocation = getNextHolomapLocation(currentLocation, 1);
if (nextLocation != -1) {
currentLocation = nextLocation;
_engine->_text->drawHolomapLocation(_locations[currentLocation].textIndex);
2021-01-17 00:04:44 +01:00
time = _engine->lbaTime;
rotate = true;
}
2020-12-22 14:44:56 +01:00
}
2021-01-17 00:04:44 +01:00
if (_engine->_input->isActionActive(TwinEActionType::HolomapLeft)) {
2021-02-06 13:23:56 +01:00
xRot += ANGLE_1;
rotate = true;
2021-01-17 00:04:44 +01:00
time = _engine->lbaTime;
} else if (_engine->_input->isActionActive(TwinEActionType::HolomapRight)) {
xRot -= 8;
rotate = true;
2021-01-17 00:04:44 +01:00
time = _engine->lbaTime;
}
2021-01-17 00:04:44 +01:00
if (_engine->_input->isActionActive(TwinEActionType::HolomapUp)) {
yRot += 8;
rotate = true;
2021-01-17 00:04:44 +01:00
time = _engine->lbaTime;
} else if (_engine->_input->isActionActive(TwinEActionType::HolomapDown)) {
yRot -= 8;
rotate = true;
2021-01-17 00:04:44 +01:00
time = _engine->lbaTime;
}
2021-01-17 00:04:44 +01:00
if (rotate) {
2021-01-17 00:04:44 +01:00
const int32 dt = _engine->lbaTime - time;
2021-03-17 00:12:48 +01:00
xRot = _engine->_collision->getAverageValue(ClampAngle(xRot), _locations[currentLocation].angle.x, 75, dt);
yRot = _engine->_collision->getAverageValue(ClampAngle(yRot), _locations[currentLocation].angle.y, 75, dt);
redraw = true;
2020-12-22 14:44:56 +01:00
}
if (!fadeInPalette && local18 < _engine->lbaTime) {
//const Common::Rect rect(170, 50, 470, 330);
//_engine->_interface->setClip(rect);
2021-03-19 15:30:22 +01:00
_engine->setPalette(192, 32, &_paletteHolomap[3 * _holomapPaletteIndex++]);
//_engine->copyBlockPhys(rect);
//_engine->_interface->resetClip();
2021-03-19 15:30:22 +01:00
if (_holomapPaletteIndex == 32) {
_holomapPaletteIndex = 0;
}
local18 = _engine->lbaTime + 3;
redraw = true;
}
if (redraw) {
redraw = false;
2021-01-13 00:09:57 +01:00
const Common::Rect rect(170, 0, 470, 330);
2021-01-30 14:35:12 +01:00
_engine->_interface->drawFilledRect(rect, COLOR_BLACK);
_engine->_renderer->setBaseRotation(xRot, yRot, 0, true);
2021-01-13 00:09:57 +01:00
_engine->_renderer->setLightVector(xRot, yRot, 0);
2021-01-26 00:09:24 +01:00
renderLocations(xRot, yRot, 0, false);
_engine->_renderer->setBaseRotation(xRot, yRot, 0, true);
2021-02-26 10:12:16 +01:00
_engine->_renderer->baseRotPos.x = 0;
_engine->_renderer->baseRotPos.y = 0;
_engine->_renderer->baseRotPos.z = 9500;
2021-01-24 15:16:37 +01:00
renderHolomapSurfacePolygons();
2021-01-26 00:09:24 +01:00
renderLocations(xRot, yRot, 0, true);
2021-02-28 16:09:23 +01:00
drawHolomapText(_engine->width() / 2, 25, "HoloMap");
2021-01-13 00:09:57 +01:00
if (rotate) {
_engine->_menu->drawBox(300, 170, 340, 210);
}
2021-02-09 21:38:01 +01:00
_engine->copyBlockPhys(rect);
2021-01-13 00:09:57 +01:00
}
2021-03-17 00:12:48 +01:00
if (rotate && xRot == _locations[currentLocation].angle.x && yRot == _locations[currentLocation].angle.y) {
2021-01-13 00:09:57 +01:00
rotate = false;
}
2020-12-22 14:44:56 +01:00
2021-01-17 00:04:44 +01:00
++_engine->lbaTime;
2021-01-13 00:09:57 +01:00
// TODO: text afterwards on top (not before as it is currently implemented)?
// pos 0x140,0x19?
//_engine->restoreFrontBuffer();
if (fadeInPalette) {
fadeInPalette = false;
2021-02-28 20:58:49 +01:00
// TODO: this does a flip - which puts stuff onto the screen that shouldn't be there
//_engine->_screens->fadeToPal(_engine->_screens->paletteRGBA);
}
2020-12-22 14:44:56 +01:00
}
2021-02-28 20:58:49 +01:00
_engine->_screens->clearScreen();
_engine->_text->drawTextBoxBackground = true;
2021-07-31 15:37:40 +02:00
_engine->setPalette(_engine->_screens->_paletteRGBA);
_engine->_scene->alphaLight = alphaLightTmp;
_engine->_scene->betaLight = betaLightTmp;
_engine->_gameState->initEngineProjections();
2020-12-22 17:16:27 +01:00
_engine->_interface->loadClip();
_engine->_input->enableKeyMap(mainKeyMapId);
_engine->_text->initSceneTextBank();
2020-10-14 14:20:38 +02:00
}
} // namespace TwinE