TWINE: use BodyData for rendering

This commit is contained in:
Martin Gerhardy 2021-03-27 08:57:54 +01:00
parent cdc6281bd0
commit 33371ae454
16 changed files with 232 additions and 393 deletions

View file

@ -259,12 +259,12 @@ void Holomap::drawHolomapText(int32 centerx, int32 top, const char *title) {
_engine->_text->drawText(x, y, title);
}
void Holomap::renderHolomapModel(const uint8 *bodyPtr, int32 x, int32 y, int32 zPos) {
void Holomap::renderHolomapModel(const BodyData &bodyData, int32 x, int32 y, int32 zPos) {
_engine->_renderer->setBaseRotation(x, y, 0);
_engine->_renderer->getBaseRotationPosition(0, 0, zPos + 1000);
_engine->_renderer->getBaseRotationPosition(_engine->_renderer->destPos.x, _engine->_renderer->destPos.y, _engine->_renderer->destPos.z);
_engine->_interface->resetClip();
_engine->_renderer->renderIsoModel(_engine->_renderer->destPos.x, _engine->_renderer->destPos.y, _engine->_renderer->destPos.z, x, y, 0, bodyPtr);
_engine->_renderer->renderIsoModel(_engine->_renderer->destPos.x, _engine->_renderer->destPos.y, _engine->_renderer->destPos.z, x, y, 0, bodyData);
}
void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
@ -296,8 +296,8 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
AnimTimerDataStruct animTimerData;
AnimData animData;
animData.loadFromHQR(Resources::HQR_RESS_FILE, data->getAnimation());
uint8 *modelPtr = nullptr;
HQR::getAllocEntry(&modelPtr, Resources::HQR_RESS_FILE, data->getModel());
BodyData bodyData;
bodyData.loadFromHQR(Resources::HQR_RESS_FILE, data->getModel());
uint frameNumber = 0;
int32 frameTime = _engine->lbaTime;
int16 trajAnimFrameIdx = 0;
@ -329,7 +329,7 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
_engine->_movements->setActorAngleSafe(ANGLE_0, -ANGLE_90, 500, &move);
}
if (_engine->_animations->setModelAnimation(frameNumber, animData, modelPtr, &animTimerData)) {
if (_engine->_animations->setModelAnimation(frameNumber, animData, bodyData, &animTimerData)) {
frameNumber++;
if (frameNumber >= animData.getNumKeyframes()) {
frameNumber = animData.getLoopFrame();
@ -340,7 +340,7 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
_engine->_renderer->setLightVector(-60, 128, 0);
const Common::Rect rect(0, 200, 199, 479);
_engine->_interface->drawFilledRect(rect, COLOR_BLACK);
_engine->_renderer->renderIsoModel(0, 0, 0, 0, newAngle, 0, modelPtr);
_engine->_renderer->renderIsoModel(0, 0, 0, 0, newAngle, 0, bodyData);
_engine->copyBlockPhys(rect);
_engine->_renderer->setCameraPosition(400, 240, 128, 1024, 1024);
_engine->_renderer->setCameraAngle(0, 0, 0, data->pos.x, data->pos.y, data->pos.z, 5300);
@ -377,7 +377,6 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
_engine->_text->initSceneTextBank();
_engine->_input->enableKeyMap(mainKeyMapId);
free(modelPtr);
}
int32 Holomap::getNextHolomapLocation(int32 currentLocation, int32 dir) const {
@ -445,18 +444,18 @@ void Holomap::renderLocations(int xRot, int yRot, int zRot, bool lower) {
for (int i = 0; i < n; ++i) {
const DrawListStruct &drawList = _engine->_redraw->drawList[i];
const uint16 flags = drawList.type;
const uint8 *bodyPtr = nullptr;
const BodyData *bodyData = nullptr;
if (flags == 1u) {
bodyPtr = _engine->_resources->holomapArrowPtr;
bodyData = &_engine->_resources->holomapArrowPtr;
} else if (flags == 2u) {
bodyPtr = _engine->_resources->holomapTwinsenModelPtr;
bodyData = &_engine->_resources->holomapTwinsenModelPtr;
} else if (flags == 3u) {
bodyPtr = _engine->_resources->holomapTwinsenArrowPtr;
bodyData = &_engine->_resources->holomapTwinsenArrowPtr;
}
if (bodyPtr != nullptr) {
if (bodyData != nullptr) {
int32 angleX = _locations[drawList.actorIdx].angle.x;
int32 angleY = _locations[drawList.actorIdx].angle.y;
_engine->_renderer->renderIsoModel(drawList.x, drawList.y, drawList.z, angleX, angleY, 0, bodyPtr);
_engine->_renderer->renderIsoModel(drawList.x, drawList.y, drawList.z, angleX, angleY, 0, *bodyData);
}
}
}

View file

@ -79,7 +79,7 @@ private:
void renderLocations(int xRot, int yRot, int zRot, bool lower);
void renderHolomapModel(const uint8 *bodyPtr, int32 x, int32 y, int32 zPos);
void renderHolomapModel(const BodyData &bodyData, int32 x, int32 y, int32 zPos);
void prepareHolomapSurface();
void prepareHolomapProjectedPositions();

View file

@ -918,7 +918,7 @@ void Menu::drawBehaviour(int32 left, int32 top, HeroBehaviourType behaviour, int
uint currentAnimState = behaviourAnimState[(byte)behaviour];
if (_engine->_animations->setModelAnimation(currentAnimState, currentAnimData, behaviourEntity, &behaviourAnimData[(byte)behaviour])) {
if (_engine->_animations->setModelAnimation(currentAnimState, currentAnimData, *behaviourEntity, &behaviourAnimData[(byte)behaviour])) {
currentAnimState++; // keyframe
if (currentAnimState >= currentAnimData.getNumKeyframes()) {
currentAnimState = currentAnimData.getLoopFrame();
@ -963,7 +963,7 @@ void Menu::drawBehaviour(int32 left, int32 top, HeroBehaviourType behaviour, int
_engine->_interface->drawFilledRect(boxRect, COLOR_BLACK);
}
_engine->_renderer->renderBehaviourModel(boxRect, -600, angle, behaviourEntity);
_engine->_renderer->renderBehaviourModel(boxRect, -600, angle, *behaviourEntity);
if (dirtyRect.isEmpty()) {
dirtyRect = boxRect;
@ -976,7 +976,7 @@ void Menu::drawBehaviour(int32 left, int32 top, HeroBehaviourType behaviour, int
void Menu::prepareAndDrawBehaviour(int32 left, int32 top, int32 angle, HeroBehaviourType behaviour, Common::Rect &dirtyRect) {
const int animIdx = _engine->_actor->heroAnimIdx[(byte)behaviour];
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[(byte)behaviour], _engine->_resources->animData[animIdx], behaviourEntity, &behaviourAnimData[(byte)behaviour]);
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[(byte)behaviour], _engine->_resources->animData[animIdx], *behaviourEntity, &behaviourAnimData[(byte)behaviour]);
drawBehaviour(left, top, behaviour, angle, false, dirtyRect);
}
@ -1011,7 +1011,7 @@ void Menu::processBehaviourMenu() {
_engine->_actor->setBehaviour(HeroBehaviourType::kNormal);
}
behaviourEntity = _engine->_resources->bodyTable[_engine->_scene->sceneHero->entity];
behaviourEntity = &_engine->_resources->bodyData[_engine->_scene->sceneHero->entity];
_engine->_actor->heroAnimIdx[(byte)HeroBehaviourType::kNormal] = _engine->_actor->heroAnimIdxNORMAL;
_engine->_actor->heroAnimIdx[(byte)HeroBehaviourType::kAthletic] = _engine->_actor->heroAnimIdxATHLETIC;
@ -1034,7 +1034,7 @@ void Menu::processBehaviourMenu() {
HeroBehaviourType tmpHeroBehaviour = _engine->_actor->heroBehaviour;
const int animIdx = _engine->_actor->heroAnimIdx[(byte)_engine->_actor->heroBehaviour];
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[(byte)_engine->_actor->heroBehaviour], _engine->_resources->animData[animIdx], behaviourEntity, &behaviourAnimData[(byte)_engine->_actor->heroBehaviour]);
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[(byte)_engine->_actor->heroBehaviour], _engine->_resources->animData[animIdx], *behaviourEntity, &behaviourAnimData[(byte)_engine->_actor->heroBehaviour]);
int32 tmpTime = _engine->lbaTime;
@ -1080,7 +1080,7 @@ void Menu::processBehaviourMenu() {
tmpHeroBehaviour = _engine->_actor->heroBehaviour;
_engine->_movements->setActorAngleSafe(_engine->_scene->sceneHero->angle, _engine->_scene->sceneHero->angle - ANGLE_90, ANGLE_17, &moveMenu);
const int tmpAnimIdx = _engine->_actor->heroAnimIdx[(byte)_engine->_actor->heroBehaviour];
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[(byte)_engine->_actor->heroBehaviour], _engine->_resources->animData[tmpAnimIdx], behaviourEntity, &behaviourAnimData[(byte)_engine->_actor->heroBehaviour]);
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[(byte)_engine->_actor->heroBehaviour], _engine->_resources->animData[tmpAnimIdx], *behaviourEntity, &behaviourAnimData[(byte)_engine->_actor->heroBehaviour]);
}
drawBehaviour(left, top, _engine->_actor->heroBehaviour, -1, true, dirtyRect);

View file

@ -137,7 +137,7 @@ class Menu {
private:
TwinEEngine *_engine;
/** Hero behaviour menu entity */
uint8 *behaviourEntity = nullptr;
BodyData *behaviourEntity = nullptr;
/** Behaviour menu anim state */
uint behaviourAnimState[4]; // winTab
/** Behaviour menu anim data pointer */

View file

@ -31,6 +31,11 @@
namespace TwinE {
struct BoneFrame {
/**
* 0 = allow global rotate
* 1 = disallow global rotate
* 2 = disallow global rotate and hide
*/
uint16 type = 0;
int16 x = 0;
int16 y = 0;

View file

@ -64,6 +64,8 @@ void BodyData::loadBones(Common::SeekableReadStream &stream) {
BodyBone bone;
bone.parent = baseElementOffset == -1 ? 0xffff : baseElementOffset / 38;
bone.vertex = basePoint;
bone.firstVertex = firstPoint;
bone.numVertices = numPoints;
bone.initalBoneState = boneframe;
bone.numOfShades = numOfShades;
@ -73,6 +75,7 @@ void BodyData::loadBones(Common::SeekableReadStream &stream) {
}
_bones.push_back(bone);
_boneStates[i] = bone.initalBoneState;
}
}
@ -96,18 +99,18 @@ void BodyData::loadPolygons(Common::SeekableReadStream &stream) {
_polygons.reserve(numPolygons);
for (uint16 i = 0; i < numPolygons; ++i) {
BodyPolygon poly;
poly.renderType = stream.readSByte();
const int8 numVertex = stream.readSByte();
poly.renderType = stream.readByte();
const uint8 numVertices = stream.readByte();
poly.color = stream.readUint16LE();
poly.color = stream.readSint16LE();
int16 intensity = -1;
if (poly.renderType == POLYGONTYPE_GOURAUD || poly.renderType == POLYGONTYPE_DITHER) {
intensity = stream.readSint16LE();
}
poly.indices.reserve(numVertex);
poly.intensities.reserve(numVertex);
for (int k = 0; k < numVertex; ++k) {
poly.indices.reserve(numVertices);
poly.intensities.reserve(numVertices);
for (int k = 0; k < numVertices; ++k) {
if (poly.renderType >= POLYGONTYPE_UNKNOWN) {
intensity = stream.readSint16LE();
}
@ -126,8 +129,9 @@ void BodyData::loadLines(Common::SeekableReadStream &stream) {
_lines.reserve(numLines);
for (uint16 i = 0; i < numLines; ++i) {
BodyLine line;
line.unk1 = stream.readUint16LE();
line.color = stream.readUint16LE();
line.color = stream.readByte();
line.unk1 = stream.readByte();
line.unk2 = stream.readUint16LE();
line.vertex1 = stream.readUint16LE() / 6;
line.vertex2 = stream.readUint16LE() / 6;
_lines.push_back(line);
@ -140,9 +144,10 @@ void BodyData::loadSpheres(Common::SeekableReadStream &stream) {
_spheres.reserve(numSpheres);
for (uint16 i = 0; i < numSpheres; ++i) {
BodySphere sphere;
sphere.unk1 = stream.readByte();
sphere.color = stream.readByte();
sphere.unk2 = stream.readUint16LE();
sphere.radius = stream.readUint16LE();
sphere.color = stream.readUint16LE();
sphere.size = stream.readUint16LE();
sphere.vertex = stream.readUint16LE() / 6;
_spheres.push_back(sphere);
}

View file

@ -42,6 +42,8 @@ struct BodyVertex {
struct BodyBone {
uint16 parent;
uint16 vertex;
int16 firstVertex;
int16 numVertices;
int32 numOfShades;
BoneFrame initalBoneState;
@ -61,20 +63,22 @@ struct BodyPolygon {
Common::Array<uint16> indices;
Common::Array<uint16> intensities;
int8 renderType = 0;
uint16 color = 0;
int16 color = 0;
};
struct BodyLine {
uint16 unk1;
uint16 color;
uint8 color;
uint8 unk1;
uint16 unk2;
uint16 vertex1;
uint16 vertex2;
};
struct BodySphere {
uint8 unk1;
uint8 color;
uint16 unk2;
uint16 radius;
uint16 color;
uint16 size;
uint16 vertex;
};
@ -158,8 +162,8 @@ public:
return _shades;
}
const BodyShade* getShade(int16 shadeIdx) const {
return &_shades[shadeIdx];
const BodyShade &getShade(int16 shadeIdx) const {
return _shades[shadeIdx];
}
const Common::Array<BodyLine> &getLines() const {
@ -170,8 +174,8 @@ public:
return _bones;
}
const BodyBone* getBone(int16 boneIdx) const {
return &_bones[boneIdx];
const BodyBone &getBone(int16 boneIdx) const {
return _bones[boneIdx];
}
bool loadFromStream(Common::SeekableReadStream &stream) override;

View file

@ -343,13 +343,13 @@ void Redraw::processDrawListActors(const DrawListStruct &drawCmd, bool bgRedraw)
ActorStruct *actor = _engine->_scene->getActor(actorIdx);
if (actor->previousAnimIdx >= 0) {
const AnimData &animData = _engine->_resources->animData[actor->previousAnimIdx];
_engine->_animations->setModelAnimation(actor->animPosition, animData, _engine->_resources->bodyTable[actor->entity], &actor->animTimerData);
_engine->_animations->setModelAnimation(actor->animPosition, animData, _engine->_resources->bodyData[actor->entity], &actor->animTimerData);
}
const int32 x = actor->pos.x - _engine->_grid->camera.x;
const int32 y = actor->pos.y - _engine->_grid->camera.y;
const int32 z = actor->pos.z - _engine->_grid->camera.z;
if (!_engine->_renderer->renderIsoModel(x, y, z, ANGLE_0, actor->angle, ANGLE_0, _engine->_resources->bodyTable[actor->entity])) {
if (!_engine->_renderer->renderIsoModel(x, y, z, ANGLE_0, actor->angle, ANGLE_0, _engine->_resources->bodyData[actor->entity])) {
return;
}
@ -623,7 +623,7 @@ void Redraw::renderOverlays() {
_engine->_interface->drawFilledRect(rect, COLOR_BLACK);
_engine->_interface->setClip(rect);
const uint8* bodyPtr = _engine->_resources->inventoryTable[item];
const BodyData &bodyPtr = _engine->_resources->inventoryTable[item];
_overlayRotation += 1; // overlayRotation += 8;
_engine->_renderer->renderInventoryItem(40, 40, bodyPtr, _overlayRotation, 16000);
_engine->_menu->drawBox(rect);

View file

@ -27,6 +27,7 @@
#include "common/util.h"
#include "twine/menu/interface.h"
#include "twine/menu/menu.h"
#include "twine/parser/body.h"
#include "twine/renderer/redraw.h"
#include "twine/renderer/shadeangletab.h"
#include "twine/resources/resources.h"
@ -313,26 +314,24 @@ void Renderer::applyRotation(IMatrix3x3 *targetMatrix, const IMatrix3x3 *current
}
}
void Renderer::applyPointsRotation(const I16Vec3 *pointsPtr, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *rotationMatrix) {
int32 numOfPoints2 = numPoints;
do {
const int32 tmpX = pointsPtr->x;
const int32 tmpY = pointsPtr->y;
const int32 tmpZ = pointsPtr->z;
void Renderer::applyPointsRotation(const Common::Array<BodyVertex> &vertices, int32 firstPoint, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *rotationMatrix) {
for (int32 i = 0; i < numPoints; ++i) {
const BodyVertex &vertex = vertices[i + firstPoint];
const int32 tmpX = vertex.x;
const int32 tmpY = vertex.y;
const int32 tmpZ = vertex.z;
destPoints->x = ((rotationMatrix->row1[0] * tmpX + rotationMatrix->row1[1] * tmpY + rotationMatrix->row1[2] * tmpZ) / SCENE_SIZE_HALF) + destPos.x;
destPoints->y = ((rotationMatrix->row2[0] * tmpX + rotationMatrix->row2[1] * tmpY + rotationMatrix->row2[2] * tmpZ) / SCENE_SIZE_HALF) + destPos.y;
destPoints->z = ((rotationMatrix->row3[0] * tmpX + rotationMatrix->row3[1] * tmpY + rotationMatrix->row3[2] * tmpZ) / SCENE_SIZE_HALF) + destPos.z;
destPoints++;
pointsPtr++;
} while (--numOfPoints2);
}
}
void Renderer::processRotatedElement(IMatrix3x3 *targetMatrix, const I16Vec3 *pointsPtr, int32 rotZ, int32 rotY, int32 rotX, const BonesBaseData *boneData, ModelData *modelData) {
int32 firstPoint = boneData->firstPoint / sizeof(I16Vec3);
int32 numOfPoints2 = boneData->numOfPoints;
void Renderer::processRotatedElement(IMatrix3x3 *targetMatrix, const Common::Array<BodyVertex> &vertices, int32 rotX, int32 rotY, int32 rotZ, const BodyBone &bone, ModelData *modelData) {
const int32 firstPoint = bone.firstVertex;
const int32 numOfPoints = bone.numVertices;
IVec3 renderAngle;
renderAngle.x = rotX;
@ -341,15 +340,15 @@ void Renderer::processRotatedElement(IMatrix3x3 *targetMatrix, const I16Vec3 *po
const IMatrix3x3 *currentMatrix;
// if its the first point
if (boneData->baseElement == -1) {
if (bone.isRoot()) {
currentMatrix = &_baseMatrix;
destPos.x = 0;
destPos.y = 0;
destPos.z = 0;
} else {
const int32 pointIdx = boneData->basePoint / sizeof(I16Vec3);
const int32 matrixIndex = boneData->baseElement / sizeof(BonesBaseData);
const int32 pointIdx = bone.vertex;
const int32 matrixIndex = bone.parent;
assert(matrixIndex >= 0 && matrixIndex < ARRAYSIZE(_matricesTable));
currentMatrix = &_matricesTable[matrixIndex];
@ -360,54 +359,52 @@ void Renderer::processRotatedElement(IMatrix3x3 *targetMatrix, const I16Vec3 *po
applyRotation(targetMatrix, currentMatrix, renderAngle);
if (!numOfPoints2) {
if (!numOfPoints) {
warning("RENDER WARNING: No points in this model!");
}
applyPointsRotation(&pointsPtr[firstPoint], numOfPoints2, &modelData->computedPoints[firstPoint], targetMatrix);
applyPointsRotation(vertices, firstPoint, numOfPoints, &modelData->computedPoints[firstPoint], targetMatrix);
}
void Renderer::applyPointsTranslation(const I16Vec3 *pointsPtr, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *translationMatrix, const IVec3 &angleVec) {
int32 numOfPoints2 = numPoints;
do {
const int32 tmpX = pointsPtr->x + angleVec.z;
const int32 tmpY = pointsPtr->y + angleVec.y;
const int32 tmpZ = pointsPtr->z + angleVec.x;
void Renderer::applyPointsTranslation(const Common::Array<BodyVertex> &vertices, int32 firstPoint, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *translationMatrix, const IVec3 &angleVec) {
for (int32 i = 0; i < numPoints; ++i) {
const BodyVertex &vertex = vertices[i + firstPoint];
const int32 tmpX = vertex.x + angleVec.z;
const int32 tmpY = vertex.y + angleVec.y;
const int32 tmpZ = vertex.z + angleVec.x;
destPoints->x = ((translationMatrix->row1[0] * tmpX + translationMatrix->row1[1] * tmpY + translationMatrix->row1[2] * tmpZ) / SCENE_SIZE_HALF) + destPos.x;
destPoints->y = ((translationMatrix->row2[0] * tmpX + translationMatrix->row2[1] * tmpY + translationMatrix->row2[2] * tmpZ) / SCENE_SIZE_HALF) + destPos.y;
destPoints->z = ((translationMatrix->row3[0] * tmpX + translationMatrix->row3[1] * tmpY + translationMatrix->row3[2] * tmpZ) / SCENE_SIZE_HALF) + destPos.z;
destPoints++;
pointsPtr++;
} while (--numOfPoints2);
}
}
void Renderer::processTranslatedElement(IMatrix3x3 *targetMatrix, const I16Vec3 *pointsPtr, int32 rotX, int32 rotY, int32 rotZ, const BonesBaseData *boneData, ModelData *modelData) {
void Renderer::processTranslatedElement(IMatrix3x3 *targetMatrix, const Common::Array<BodyVertex> &vertices, int32 rotX, int32 rotY, int32 rotZ, const BodyBone &bone, ModelData *modelData) {
IVec3 renderAngle;
renderAngle.x = rotX;
renderAngle.y = rotY;
renderAngle.z = rotZ;
if (boneData->baseElement == -1) { // base point
if (bone.isRoot()) { // base point
destPos.x = 0;
destPos.y = 0;
destPos.z = 0;
*targetMatrix = _baseMatrix;
} else { // dependent
const int32 pointsIdx = boneData->basePoint / sizeof(I16Vec3);
const int32 pointsIdx = bone.vertex;
destPos.x = modelData->computedPoints[pointsIdx].x;
destPos.y = modelData->computedPoints[pointsIdx].y;
destPos.z = modelData->computedPoints[pointsIdx].z;
const int32 matrixIndex = boneData->baseElement / sizeof(BonesBaseData);
const int32 matrixIndex = bone.parent;
assert(matrixIndex >= 0 && matrixIndex < ARRAYSIZE(_matricesTable));
*targetMatrix = _matricesTable[matrixIndex];
}
applyPointsTranslation(&pointsPtr[boneData->firstPoint / sizeof(I16Vec3)], boneData->numOfPoints, &modelData->computedPoints[boneData->firstPoint / sizeof(I16Vec3)], targetMatrix, renderAngle);
applyPointsTranslation(vertices, bone.firstVertex, bone.numVertices, &modelData->computedPoints[bone.firstVertex], targetMatrix, renderAngle);
}
void Renderer::setLightVector(int32 angleX, int32 angleY, int32 angleZ) {
@ -1080,22 +1077,14 @@ void Renderer::circleFill(int32 x, int32 y, int32 radius, uint8 color) {
}
}
uint8 *Renderer::prepareSpheres(Common::MemoryReadStream &stream, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData) {
int16 numSpheres = stream.readSint16LE();
if (numSpheres <= 0) {
return renderBufferPtr;
}
numOfPrimitives += numSpheres;
do {
CmdRenderSphere *sphere = (CmdRenderSphere *)renderBufferPtr;
stream.skip(1);
sphere->colorIndex = stream.readByte();
stream.skip(2);
sphere->radius = stream.readUint16LE();
const int16 centerOffset = stream.readUint16LE();
const int16 centerIndex = centerOffset / 6;
sphere->x = modelData->flattenPoints[centerIndex].x;
sphere->y = modelData->flattenPoints[centerIndex].y;
uint8 *Renderer::prepareSpheres(const Common::Array<BodySphere> &spheres, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData) {
for (const BodySphere &sphere : spheres) {
CmdRenderSphere *cmd = (CmdRenderSphere *)renderBufferPtr;
cmd->colorIndex = sphere.color;
cmd->radius = sphere.radius;
const int16 centerIndex = sphere.vertex;
cmd->x = modelData->flattenPoints[centerIndex].x;
cmd->y = modelData->flattenPoints[centerIndex].y;
(*renderCmds)->depth = modelData->flattenPoints[centerIndex].z;
(*renderCmds)->renderType = RENDERTYPE_DRAWSPHERE;
@ -1103,51 +1092,38 @@ uint8 *Renderer::prepareSpheres(Common::MemoryReadStream &stream, int32 &numOfPr
(*renderCmds)++;
renderBufferPtr += sizeof(CmdRenderSphere);
} while (--numSpheres);
}
numOfPrimitives += spheres.size();
return renderBufferPtr;
}
uint8 *Renderer::prepareLines(Common::MemoryReadStream &stream, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData) {
int16 numLines = stream.readSint16LE();
if (numLines <= 0) {
return renderBufferPtr;
}
numOfPrimitives += numLines;
do {
CmdRenderLine *lineCoordinatesPtr = (CmdRenderLine *)renderBufferPtr;
lineCoordinatesPtr->colorIndex = stream.readByte();
stream.skip(3);
const int32 point1Index = stream.readSint16LE() / 6;
const int32 point2Index = stream.readSint16LE() / 6;
lineCoordinatesPtr->x1 = modelData->flattenPoints[point1Index].x;
lineCoordinatesPtr->y1 = modelData->flattenPoints[point1Index].y;
lineCoordinatesPtr->x2 = modelData->flattenPoints[point2Index].x;
lineCoordinatesPtr->y2 = modelData->flattenPoints[point2Index].y;
uint8 *Renderer::prepareLines(const Common::Array<BodyLine> &lines, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData) {
for (const BodyLine &line : lines) {
CmdRenderLine *cmd = (CmdRenderLine *)renderBufferPtr;
cmd->colorIndex = line.color;
const int32 point1Index = line.vertex1;
const int32 point2Index = line.vertex2;
cmd->x1 = modelData->flattenPoints[point1Index].x;
cmd->y1 = modelData->flattenPoints[point1Index].y;
cmd->x2 = modelData->flattenPoints[point2Index].x;
cmd->y2 = modelData->flattenPoints[point2Index].y;
(*renderCmds)->depth = MAX(modelData->flattenPoints[point1Index].z, modelData->flattenPoints[point2Index].z);
(*renderCmds)->renderType = RENDERTYPE_DRAWLINE;
(*renderCmds)->dataPtr = renderBufferPtr;
(*renderCmds)++;
renderBufferPtr += sizeof(CmdRenderLine);
} while (--numLines);
}
numOfPrimitives += lines.size();
return renderBufferPtr;
}
uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData) {
int16 numPolygons = stream.readSint16LE();
if (numPolygons <= 0) {
return renderBufferPtr;
}
int16 primitiveCounter = numPolygons; // the number of primitives = the number of polygons
do { // loop that load all the polygons
const uint8 renderType = stream.readByte();
const uint8 numVertices = stream.readByte();
uint8 *Renderer::preparePolygons(const Common::Array<BodyPolygon> &polygons, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData) {
for (const BodyPolygon &polygon : polygons) {
const uint8 renderType = polygon.renderType;
const uint8 numVertices = polygon.indices.size();
assert(numVertices <= 16);
const int16 colorIndex = stream.readSint16LE();
const int16 colorIndex = polygon.color;
int16 bestDepth = -32000;
@ -1160,19 +1136,16 @@ uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfP
renderBufferPtr += destinationPolygon->numVertices * sizeof(Vertex);
Vertex *vertex = vertices;
int16 counter = destinationPolygon->numVertices;
// TODO: RECHECK coordinates axis
if (renderType >= 9) {
destinationPolygon->renderType = renderType - 2;
destinationPolygon->colorIndex = colorIndex;
if (renderType >= POLYGONTYPE_UNKNOWN) {
destinationPolygon->renderType = polygon.renderType - 2;
destinationPolygon->colorIndex = polygon.color;
do {
const int16 shadeEntry = stream.readSint16LE();
for (int16 idx = 0; idx < numVertices; ++idx) {
const int16 shadeEntry = polygon.intensities[idx];
const int16 shadeValue = colorIndex + modelData->shadeTable[shadeEntry];
const int16 vertexOffset = stream.readSint16LE();
const int16 vertexIndex = vertexOffset / 6;
const int16 vertexIndex = polygon.indices[idx];
const I16Vec3 *point = &modelData->flattenPoints[vertexIndex];
vertex->colorIndex = shadeValue;
@ -1180,12 +1153,12 @@ uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfP
vertex->y = point->y;
bestDepth = MAX(bestDepth, point->z);
++vertex;
} while (--counter > 0);
}
} else {
if (renderType >= POLYGONTYPE_GOURAUD) {
// only 1 shade value is used
destinationPolygon->renderType = renderType - POLYGONTYPE_GOURAUD;
const int16 shadeEntry = stream.readSint16LE();
const int16 shadeEntry = polygon.intensities[0];
const int16 shadeValue = colorIndex + modelData->shadeTable[shadeEntry];
destinationPolygon->colorIndex = shadeValue;
} else {
@ -1194,9 +1167,8 @@ uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfP
destinationPolygon->colorIndex = colorIndex;
}
do {
const int16 vertexOffset = stream.readSint16LE();
const int16 vertexIndex = vertexOffset / 6;
for (int16 idx = 0; idx < numVertices; ++idx) {
const int16 vertexIndex = polygon.indices[idx];
const I16Vec3 *point = &modelData->flattenPoints[vertexIndex];
vertex->colorIndex = destinationPolygon->colorIndex;
@ -1204,7 +1176,7 @@ uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfP
vertex->y = point->y;
bestDepth = MAX(bestDepth, point->z);
++vertex;
} while (--counter > 0);
}
}
numOfPrimitives++;
@ -1213,7 +1185,7 @@ uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfP
(*renderCmds)->renderType = RENDERTYPE_DRAWPOLYGON;
(*renderCmds)->dataPtr = (uint8 *)destinationPolygon;
(*renderCmds)++;
} while (--primitiveCounter);
}
return renderBufferPtr;
}
@ -1223,14 +1195,11 @@ const Renderer::RenderCommand *Renderer::depthSortRenderCommands(int32 numOfPrim
return _renderCmds;
}
bool Renderer::renderModelElements(int32 numOfPrimitives, const uint8 *polygonPtr, RenderCommand **renderCmds, ModelData *modelData) {
// TODO: proper size
Common::MemoryReadStream stream(polygonPtr, 100000);
bool Renderer::renderModelElements(int32 numOfPrimitives, const BodyData &bodyData, RenderCommand **renderCmds, ModelData *modelData) {
uint8 *renderBufferPtr = _renderCoordinatesBuffer;
renderBufferPtr = preparePolygons(stream, numOfPrimitives, renderCmds, renderBufferPtr, modelData);
renderBufferPtr = prepareLines(stream, numOfPrimitives, renderCmds, renderBufferPtr, modelData);
renderBufferPtr = prepareSpheres(stream, numOfPrimitives, renderCmds, renderBufferPtr, modelData);
renderBufferPtr = preparePolygons(bodyData.getPolygons(), numOfPrimitives, renderCmds, renderBufferPtr, modelData);
renderBufferPtr = prepareLines(bodyData.getLines(), numOfPrimitives, renderCmds, renderBufferPtr, modelData);
renderBufferPtr = prepareSpheres(bodyData.getSpheres(), numOfPrimitives, renderCmds, renderBufferPtr, modelData);
if (numOfPrimitives == 0) {
_engine->_redraw->renderRect.right = -1;
@ -1305,32 +1274,32 @@ bool Renderer::renderModelElements(int32 numOfPrimitives, const uint8 *polygonPt
return true;
}
bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, RenderCommand *renderCmds, const IVec3 &angleVec, const IVec3 &renderPos) {
const int32 numVertices = Model::getNumVertices(bodyPtr);
const int32 numBones = Model::getNumBones(bodyPtr);
bool Renderer::renderAnimatedModel(ModelData *modelData, const BodyData &bodyData, RenderCommand *renderCmds, const IVec3 &angleVec, const IVec3 &renderPos) {
const int32 numVertices = bodyData.getNumVertices();
const int32 numBones = bodyData.getNumBones();
const I16Vec3 *pointsPtr = Model::getVerticesBaseData(bodyPtr);
const Common::Array<BodyVertex> &vertices = bodyData.getVertices();
IMatrix3x3 *modelMatrix = &_matricesTable[0];
const BonesBaseData *boneData = Model::getBonesBaseData(bodyPtr, 0);
processRotatedElement(modelMatrix, pointsPtr, angleVec.x, angleVec.y, angleVec.z, boneData, modelData);
const BodyBone &firstBone = bodyData.getBone(0);
processRotatedElement(modelMatrix, vertices, angleVec.x, angleVec.y, angleVec.z, firstBone, modelData);
int32 numOfPrimitives = 0;
if (numBones - 1 != 0) {
numOfPrimitives = numBones - 1;
modelMatrix = &_matricesTable[1];
int boneIdx = 1;
do {
boneData = Model::getBonesBaseData(bodyPtr, boneIdx);
int16 boneType = boneData->flag;
modelMatrix = &_matricesTable[boneIdx];
if (boneType == 0) {
processRotatedElement(modelMatrix, pointsPtr, boneData->rotateX, boneData->rotateY, boneData->rotateZ, boneData, modelData);
} else if (boneType == 1) {
processTranslatedElement(modelMatrix, pointsPtr, boneData->rotateX, boneData->rotateY, boneData->rotateZ, boneData, modelData);
do {
const BodyBone &bone = bodyData.getBone(boneIdx);
const BoneFrame *boneData = bodyData.getBoneState(boneIdx);
if (boneData->type == 0) {
processRotatedElement(modelMatrix, vertices, boneData->x, boneData->y, boneData->z, bone, modelData);
} else if (boneData->type == 1) {
processTranslatedElement(modelMatrix, vertices, boneData->x, boneData->y, boneData->z, bone, modelData);
}
++modelMatrix;
@ -1432,7 +1401,7 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
} while (--numOfPrimitives);
}
int32 numOfShades = Model::getNumShades(bodyPtr);
int32 numOfShades = bodyData.getShades().size();
if (numOfShades) { // process normal data
uint16 *currentShadeDestination = (uint16 *)modelData->shadeTable;
@ -1443,7 +1412,7 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
int shadeIndex = 0;
int boneIdx = 0;
do { // for each element
numOfShades = Model::getNumShadesBone(bodyPtr, boneIdx);
numOfShades = bodyData.getBone(boneIdx).numOfShades;
if (numOfShades) {
int32 numShades = numOfShades;
@ -1451,11 +1420,11 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
_shadeMatrix = *lightMatrix * _lightPos;
do { // for each normal
const BodyShade *shadePtr = Model::getBodyShadesData(bodyPtr, shadeIndex);
const BodyShade &shadePtr = bodyData.getShade(shadeIndex);
const int16 col1 = shadePtr->col1;
const int16 col2 = shadePtr->col2;
const int16 col3 = shadePtr->col3;
const int16 col1 = shadePtr.col1;
const int16 col2 = shadePtr.col2;
const int16 col3 = shadePtr.col3;
int32 color = 0;
color += _shadeMatrix.row1[0] * col1 + _shadeMatrix.row1[1] * col2 + _shadeMatrix.row1[2] * col3;
@ -1466,7 +1435,7 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
if (color > 0) {
color >>= 14;
color /= shadePtr->unk4;
color /= shadePtr.unk4;
shade = (uint16)color;
}
@ -1481,10 +1450,10 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
} while (--numOfPrimitives);
}
return renderModelElements(numOfPrimitives, Model::getPolygonData(bodyPtr), &renderCmds, modelData);
return renderModelElements(numOfPrimitives, bodyData, &renderCmds, modelData);
}
bool Renderer::renderIsoModel(int32 x, int32 y, int32 z, int32 angleX, int32 angleY, int32 angleZ, const uint8 *bodyPtr) {
bool Renderer::renderIsoModel(int32 x, int32 y, int32 z, int32 angleX, int32 angleY, int32 angleZ, const BodyData &bodyData) {
IVec3 renderAngle;
renderAngle.x = angleX;
renderAngle.y = angleY;
@ -1507,18 +1476,18 @@ bool Renderer::renderIsoModel(int32 x, int32 y, int32 z, int32 angleX, int32 ang
renderPos = destPos - baseRotPos; // RECHECK y
}
if (!Model::isAnimated(bodyPtr)) {
if (!bodyData.isAnimated()) {
error("Unsupported unanimated model render!");
}
// restart at the beginning of the renderTable
return renderAnimatedModel(&_modelData, bodyPtr, _renderCmds, renderAngle, renderPos);
return renderAnimatedModel(&_modelData, bodyData, _renderCmds, renderAngle, renderPos);
}
void Renderer::renderBehaviourModel(const Common::Rect &rect, int32 y, int32 angle, const uint8 *bodyPtr) {
renderBehaviourModel(rect.left, rect.top, rect.right, rect.bottom, y, angle, bodyPtr);
void Renderer::renderBehaviourModel(const Common::Rect &rect, int32 y, int32 angle, const BodyData &bodyData) {
renderBehaviourModel(rect.left, rect.top, rect.right, rect.bottom, y, angle, bodyData);
}
void Renderer::renderBehaviourModel(int32 boxLeft, int32 boxTop, int32 boxRight, int32 boxBottom, int32 y, int32 angle, const uint8 *bodyPtr) {
void Renderer::renderBehaviourModel(int32 boxLeft, int32 boxTop, int32 boxRight, int32 boxBottom, int32 y, int32 angle, const BodyData &bodyData) {
const int32 ypos = (boxBottom + boxTop) / 2;
const int32 xpos = (boxRight + boxLeft) / 2;
@ -1531,17 +1500,17 @@ void Renderer::renderBehaviourModel(int32 boxLeft, int32 boxTop, int32 boxRight,
if (move.numOfStep == 0) {
_engine->_movements->setActorAngleSafe(newAngle, newAngle - ANGLE_90, ANGLE_17, &move);
}
renderIsoModel(0, y, 0, ANGLE_0, newAngle, ANGLE_0, bodyPtr);
renderIsoModel(0, y, 0, ANGLE_0, newAngle, ANGLE_0, bodyData);
} else {
renderIsoModel(0, y, 0, ANGLE_0, angle, ANGLE_0, bodyPtr);
renderIsoModel(0, y, 0, ANGLE_0, angle, ANGLE_0, bodyData);
}
}
void Renderer::renderInventoryItem(int32 x, int32 y, const uint8 *bodyPtr, int32 angle, int32 param) {
void Renderer::renderInventoryItem(int32 x, int32 y, const BodyData &bodyData, int32 angle, int32 param) {
setCameraPosition(x, y, 128, 200, 200);
setCameraAngle(0, 0, 0, 60, 0, 0, param);
renderIsoModel(0, 0, 0, ANGLE_0, angle, ANGLE_0, bodyPtr);
renderIsoModel(0, 0, 0, ANGLE_0, angle, ANGLE_0, bodyData);
}
void Renderer::computeHolomapPolygon(int32 top, int32 x1, int32 bottom, int32 x2, int16 *polygonTabPtr) {

View file

@ -83,122 +83,6 @@ inline IMatrix3x3 operator*(const IMatrix3x3 &matrix, const IVec3 &vec) {
return out;
}
#include "common/pack-start.h"
struct BonesBaseData {
int16 firstPoint = 0; // data1
int16 numOfPoints = 0; // data2
int16 basePoint = 0; // data3
int16 baseElement = 0; // param
int16 flag = 0;
int16 rotateZ = 0;
int16 rotateY = 0;
int16 rotateX = 0;
int16 unk1 = 0; // field_10
int16 numOfShades = 0;
int16 unk2 = 0;
int32 field_18 = 0;
int32 y = 0;
int32 field_20 = 0;
int32 field_24 = 0;
};
#include "common/pack-end.h"
static_assert(sizeof(BonesBaseData) == 38, "Unexpected elementEntry size");
class Model {
private:
static uint8 *getBonesData(uint8 *bodyPtr) {
uint8 *verticesBase = getData(bodyPtr);
const int16 numVertices = READ_LE_INT16(verticesBase);
return verticesBase + 2 + numVertices * sizeof(I16Vec3);
}
static const uint8 *getBonesData(const uint8 *bodyPtr) {
const uint8 *verticesBase = getData(bodyPtr);
const int16 numVertices = READ_LE_INT16(verticesBase);
return verticesBase + 2 + numVertices * sizeof(I16Vec3);
}
static uint8 *getData(uint8 *bodyPtr) {
return bodyPtr + 0x1A;
}
static const uint8 *getData(const uint8 *bodyPtr) {
return bodyPtr + 0x1A;
}
static BonesBaseData *getBonesBaseData(uint8 *bodyPtr, int boneIdx = 0) {
assert(boneIdx <= getNumBones(bodyPtr));
return (BonesBaseData *)(getBonesData(bodyPtr) + 2 + (boneIdx * sizeof(BonesBaseData)));
}
static const uint8 *getShadesData(const uint8 *bodyPtr) {
const int16 numBones = getNumBones(bodyPtr);
return (const uint8 *)getBonesBaseData(bodyPtr, numBones);
}
public:
static inline bool isAnimated(const uint8 *bodyPtr) {
const int16 bodyHeader = READ_LE_INT16(bodyPtr);
return (bodyHeader & 2) != 0;
}
static const I16Vec3 *getVerticesBaseData(const uint8 *bodyPtr) {
return (const I16Vec3*)(getData(bodyPtr) + 2);
}
static const BoneFrame *getBonesStateData(const uint8 *bodyPtr, int boneIdx) {
assert(boneIdx <= getNumBones(bodyPtr));
return (const BoneFrame*)((const uint8*)getBonesBaseData(bodyPtr) + 8 + (boneIdx * sizeof(BonesBaseData)));
}
static BoneFrame *getBonesStateData(uint8 *bodyPtr, int boneIdx) {
assert(boneIdx <= getNumBones(bodyPtr));
return (BoneFrame*)((uint8*)getBonesBaseData(bodyPtr) + 8 + (boneIdx * sizeof(BonesBaseData)));
}
static const BonesBaseData *getBonesBaseData(const uint8 *bodyPtr, int boneIdx = 0) {
assert(boneIdx <= getNumBones(bodyPtr));
return (const BonesBaseData *)(getBonesData(bodyPtr) + 2 + (boneIdx * sizeof(BonesBaseData)));
}
static int16 getNumBones(const uint8 *bodyPtr) {
const uint8 *bonesBase = getBonesData(bodyPtr);
return READ_LE_INT16(bonesBase);
}
static int16 getNumVertices(const uint8 *bodyPtr) {
const uint8 *verticesBase = getData(bodyPtr);
return READ_LE_INT16(verticesBase);
}
static const BodyShade *getBodyShadesData(const uint8 *bodyPtr, int16 shadeIdx = 0) {
assert(shadeIdx <= getNumShades(bodyPtr));
return (const BodyShade*)(getShadesData(bodyPtr) + 2 + (shadeIdx * sizeof(BodyShade)));
}
static int16 getNumShades(const uint8 *bodyPtr) {
const uint8 *shadesBase = getShadesData(bodyPtr);
return READ_LE_INT16(shadesBase);
}
static int16 getNumShadesBone(const uint8 *bodyPtr, int boneIdx) {
return getBonesBaseData(bodyPtr, boneIdx)->numOfShades;
}
static const uint8 *getPolygonData(const uint8 *bodyPtr) {
const uint8 *shades = (const uint8*)getBodyShadesData(bodyPtr);
const int16 numShades = getNumShades(bodyPtr);
if (numShades <= 0) {
return shades;
}
const int16 bones = getNumBones(bodyPtr);
for (int16 boneIdx = 0; boneIdx < bones; ++boneIdx) {
int16 numOfShades = getNumShadesBone(bodyPtr, boneIdx);
shades += numOfShades * 8;
}
return shades;
}
};
class Renderer {
private:
TwinEEngine *_engine;
@ -254,15 +138,15 @@ private:
ModelData _modelData;
bool renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, RenderCommand *renderCmds, const IVec3 &angleVec, const IVec3 &renderPos);
bool renderAnimatedModel(ModelData *modelData, const BodyData &bodyData, RenderCommand *renderCmds, const IVec3 &angleVec, const IVec3 &renderPos);
void circleFill(int32 x, int32 y, int32 radius, uint8 color);
bool renderModelElements(int32 numOfPrimitives, const uint8 *polygonPtr, RenderCommand **renderCmds, ModelData *modelData);
bool renderModelElements(int32 numOfPrimitives, const BodyData &bodyData, RenderCommand **renderCmds, ModelData *modelData);
void getCameraAnglePositions(int32 x, int32 y, int32 z);
void applyRotation(IMatrix3x3 *targetMatrix, const IMatrix3x3 *currentMatrix, const IVec3 &angleVec);
void applyPointsRotation(const I16Vec3 *pointsPtr, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *rotationMatrix);
void processRotatedElement(IMatrix3x3 *targetMatrix, const I16Vec3 *pointsPtr, int32 rotZ, int32 rotY, int32 rotX, const BonesBaseData *boneData, ModelData *modelData);
void applyPointsTranslation(const I16Vec3 *pointsPtr, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *translationMatrix, const IVec3 &angleVec);
void processTranslatedElement(IMatrix3x3 *targetMatrix, const I16Vec3 *pointsPtr, int32 rotX, int32 rotY, int32 rotZ, const BonesBaseData *boneData, ModelData *modelData);
void applyPointsRotation(const Common::Array<BodyVertex>& vertices, int32 firstPoint, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *rotationMatrix);
void processRotatedElement(IMatrix3x3 *targetMatrix, const Common::Array<BodyVertex>& vertices, int32 rotX, int32 rotY, int32 rotZ, const BodyBone &bone, ModelData *modelData);
void applyPointsTranslation(const Common::Array<BodyVertex>& vertices, int32 firstPoint, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *translationMatrix, const IVec3 &angleVec);
void processTranslatedElement(IMatrix3x3 *targetMatrix, const Common::Array<BodyVertex>& vertices, int32 rotX, int32 rotY, int32 rotZ, const BodyBone &bone, ModelData *modelData);
void translateGroup(int32 x, int32 y, int32 z);
IVec3 _baseTransPos;
@ -312,9 +196,9 @@ private:
void computePolygons(int16 polyRenderType, const Vertex *vertices, int32 numVertices);
const RenderCommand *depthSortRenderCommands(int32 numOfPrimitives);
uint8 *preparePolygons(Common::MemoryReadStream &stream, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData);
uint8 *prepareSpheres(Common::MemoryReadStream &stream, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData);
uint8 *prepareLines(Common::MemoryReadStream &stream, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData);
uint8 *preparePolygons(const Common::Array<BodyPolygon>& polygons, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData);
uint8 *prepareSpheres(const Common::Array<BodySphere>& spheres, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData);
uint8 *prepareLines(const Common::Array<BodyLine>& lines, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData);
void baseMatrixTranspose();
@ -355,18 +239,18 @@ public:
void setBaseRotation(int32 x, int32 y, int32 z, bool transpose = false);
void setOrthoProjection(int32 x, int32 y, int32 z);
bool renderIsoModel(int32 x, int32 y, int32 z, int32 angleX, int32 angleY, int32 angleZ, const uint8 *bodyPtr);
bool renderIsoModel(int32 x, int32 y, int32 z, int32 angleX, int32 angleY, int32 angleZ, const BodyData &bodyData);
/**
* @param angle A value of @c -1 means that the model is automatically rotated
*/
void renderBehaviourModel(int32 boxLeft, int32 boxTop, int32 boxRight, int32 boxBottom, int32 y, int32 angle, const uint8 *bodyPtr);
void renderBehaviourModel(int32 boxLeft, int32 boxTop, int32 boxRight, int32 boxBottom, int32 y, int32 angle, const BodyData &bodyData);
/**
* @param angle A value of @c -1 means that the model is automatically rotated
*/
void renderBehaviourModel(const Common::Rect &rect, int32 y, int32 angle, const uint8 *bodyPtr);
void renderBehaviourModel(const Common::Rect &rect, int32 y, int32 angle, const BodyData &bodyData);
void renderInventoryItem(int32 x, int32 y, const uint8 *bodyPtr, int32 angle, int32 param);
void renderInventoryItem(int32 x, int32 y, const BodyData &bodyData, int32 angle, int32 param);
void renderHolomapVertices(const Vertex vertexCoordinates[3], const Vertex vertexAngles[3]);
};

View file

@ -34,26 +34,16 @@
namespace TwinE {
Resources::~Resources() {
for (size_t i = 0; i < ARRAYSIZE(inventoryTable); ++i) {
free(inventoryTable[i]);
}
for (size_t i = 0; i < ARRAYSIZE(spriteTable); ++i) {
free(spriteTable[i]);
}
for (size_t i = 0; i < ARRAYSIZE(samplesTable); ++i) {
free(samplesTable[i]);
}
for (size_t i = 0; i < ARRAYSIZE(bodyTable); ++i) {
free(bodyTable[i]);
}
free(fontPtr);
free(spriteShadowPtr);
free(holomapSurfacePtr);
free(holomapImagePtr);
free(holomapTwinsenModelPtr);
free(holomapPointModelPtr);
free(holomapTwinsenArrowPtr);
free(holomapArrowPtr);
free(_engine->_screens->mainPalette);
}
@ -142,7 +132,7 @@ void Resources::preloadInventoryItems() {
}
debug("preload %i inventory items", numEntries);
for (int32 i = 0; i < numEntries; i++) {
inventorySizeTable[i] = HQR::getAllocEntry(&inventoryTable[i], Resources::HQR_INVOBJ_FILE, i);
inventoryTable[i].loadFromHQR(Resources::HQR_INVOBJ_FILE, i);
}
}
@ -179,23 +169,19 @@ void Resources::initResources() {
error("Failed to load holomap image");
}
holomapTwinsenModelSize = HQR::getAllocEntry(&holomapTwinsenModelPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINMDL);
if (holomapTwinsenModelSize == 0) {
if (!holomapTwinsenModelPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINMDL)) {
error("Failed to load holomap twinsen model");
}
holomapPointModelSize = HQR::getAllocEntry(&holomapPointModelPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTMDL);
if (holomapPointModelSize == 0) {
if (!holomapPointModelPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTMDL)) {
error("Failed to load holomap point model");
}
holomapArrowSize = HQR::getAllocEntry(&holomapArrowPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWMDL);
if (holomapArrowSize == 0) {
if (!holomapArrowPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWMDL)) {
error("Failed to load holomap arrow model");
}
holomapTwinsenArrowSize = HQR::getAllocEntry(&holomapTwinsenArrowPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINARROWMDL);
if (holomapTwinsenArrowSize == 0) {
if (!holomapTwinsenArrowPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINARROWMDL)) {
error("Failed to load holomap twinsen arrow model");
}

View file

@ -160,9 +160,7 @@ public:
const Common::Array<int32>& getFlaMovieInfo(const Common::String &name) const;
/** Table with all loaded samples */
uint8 *inventoryTable[NUM_INVENTORY_ITEMS] {nullptr};
/** Table with all loaded samples sizes */
uint32 inventorySizeTable[NUM_INVENTORY_ITEMS] {0};
BodyData inventoryTable[NUM_INVENTORY_ITEMS];
/** Table with all loaded sprites */
uint8 *spriteTable[NUM_SPRITES] {nullptr};
@ -173,8 +171,6 @@ public:
AnimData animData[NUM_ANIMS];
/** Actors 3D body table - size of NUM_BODIES */
uint8 *bodyTable[NUM_BODIES]{nullptr};
int32 bodyTableSize[NUM_BODIES]{0};
BodyData bodyData[NUM_BODIES];
/** Table with all loaded samples */
@ -194,14 +190,11 @@ public:
uint8 *holomapSurfacePtr = nullptr;
uint32 holomapImageSize = 0;
uint8 *holomapImagePtr = nullptr;
uint32 holomapPointModelSize = 0;
uint8 *holomapPointModelPtr = nullptr;
uint32 holomapTwinsenModelSize = 0;
uint8 *holomapTwinsenModelPtr = nullptr;
uint32 holomapTwinsenArrowSize = 0;
uint8 *holomapTwinsenArrowPtr = nullptr;
uint32 holomapArrowSize = 0;
uint8 *holomapArrowPtr = nullptr;
BodyData holomapPointModelPtr;
BodyData holomapTwinsenModelPtr;
BodyData holomapTwinsenArrowPtr;
BodyData holomapArrowPtr;
/** Initialize resource pointers */
void initResources();

View file

@ -188,11 +188,7 @@ int32 Actor::initBody(BodyType bodyIdx, int32 actorIdx, ActorBoundingBox &actorB
if (!(bodyIndex & 0x8000)) {
index = _currentPositionInBodyPtrTab;
_currentPositionInBodyPtrTab++;
_engine->_resources->bodyTableSize[index] = HQR::getAllocEntry(&_engine->_resources->bodyTable[index], Resources::HQR_BODY_FILE, bodyIndex & 0xFFFF);
if (_engine->_resources->bodyTableSize[index] == 0) {
error("HQR ERROR: Loading body entity for actor %i: %i", actorIdx, (int)bodyIdx);
}
if (!_engine->_resources->bodyData[index].loadFromBuffer(_engine->_resources->bodyTable[index], _engine->_resources->bodyTableSize[index])) {
if (!_engine->_resources->bodyData[index].loadFromHQR(Resources::HQR_BODY_FILE, bodyIndex & 0xFFFF)) {
error("HQR ERROR: Parsing body entity for actor %i: %i", actorIdx, (int)bodyIdx);
}
stream.seek(stream.pos() - sizeof(uint16));

View file

@ -101,8 +101,8 @@ int16 Animations::applyAnimStepTranslation(int32 deltaTime, int32 keyFrameLength
return computedPos;
}
bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData, uint8 *const bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
if (!Model::isAnimated(bodyPtr)) {
bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData, BodyData &bodyData, AnimTimerDataStruct *animTimerDataPtr) {
if (!bodyData.isAnimated()) {
return false;
}
const KeyFrame *keyFrame = animData.getKeyframe(keyframeIdx);
@ -114,7 +114,7 @@ bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData,
processRotationByAnim = keyFrame->boneframes[0].type;
processLastRotationAngle = ToAngle(keyFrame->boneframes[0].y);
const int16 numBones = Model::getNumBones(bodyPtr);
const int16 numBones = bodyData.getNumBones();
int32 numOfBonesInAnim = animData.getNumBoneframes();
if (numOfBonesInAnim > numBones) {
@ -130,7 +130,7 @@ bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData,
}
const int32 deltaTime = _engine->lbaTime - remainingFrameTime;
if (deltaTime >= keyFrameLength) {
copyKeyFrameToState(keyFrame, bodyPtr, numOfBonesInAnim);
copyKeyFrameToState(keyFrame, bodyData, numOfBonesInAnim);
animTimerDataPtr->ptr = keyFrame;
animTimerDataPtr->time = _engine->lbaTime;
return true;
@ -145,19 +145,19 @@ bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData,
int16 boneIdx = 1;
int16 tmpNumOfPoints = MIN<int16>(lastKeyFramePtr->boneframes.size() - 1, numOfBonesInAnim - 1);
do {
BoneFrame *boneState = Model::getBonesStateData(bodyPtr, boneIdx);
BoneFrame *boneState = bodyData.getBoneState(boneIdx);
const BoneFrame &boneFrame = keyFrame->boneframes[boneIdx];
const BoneFrame &lastBoneFrame = lastKeyFramePtr->boneframes[boneIdx];
boneState->type = boneFrame.type;
switch (boneFrame.type) {
case 0: // allow global rotate
case 0:
boneState->x = applyAnimStepRotation(deltaTime, keyFrameLength, boneFrame.x, lastBoneFrame.x);
boneState->y = applyAnimStepRotation(deltaTime, keyFrameLength, boneFrame.y, lastBoneFrame.y);
boneState->z = applyAnimStepRotation(deltaTime, keyFrameLength, boneFrame.z, lastBoneFrame.z);
break;
case 1: // disallow global rotate
case 2: // disallow global rotate + hide
case 1:
case 2:
boneState->x = applyAnimStepTranslation(deltaTime, keyFrameLength, boneFrame.x, lastBoneFrame.x);
boneState->y = applyAnimStepTranslation(deltaTime, keyFrameLength, boneFrame.y, lastBoneFrame.y);
boneState->z = applyAnimStepTranslation(deltaTime, keyFrameLength, boneFrame.z, lastBoneFrame.z);
@ -172,8 +172,8 @@ bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData,
return false;
}
void Animations::setAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, uint8 *const bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
if (!Model::isAnimated(bodyPtr)) {
void Animations::setAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, BodyData &bodyData, AnimTimerDataStruct *animTimerDataPtr) {
if (!bodyData.isAnimated()) {
return;
}
@ -194,18 +194,18 @@ void Animations::setAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData,
animTimerDataPtr->ptr = animData.getKeyframe(keyframeIdx);
animTimerDataPtr->time = _engine->lbaTime;
const int16 numBones = Model::getNumBones(bodyPtr);
const int16 numBones = bodyData.getNumBones();
int16 numOfBonesInAnim = animData.getNumBoneframes();
if (numOfBonesInAnim > numBones) {
numOfBonesInAnim = numBones;
}
copyKeyFrameToState(keyFrame, bodyPtr, numOfBonesInAnim);
copyKeyFrameToState(keyFrame, bodyData, numOfBonesInAnim);
}
void Animations::stockAnimation(const uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
if (!Model::isAnimated(bodyPtr)) {
void Animations::stockAnimation(const BodyData &bodyData, AnimTimerDataStruct *animTimerDataPtr) {
if (!bodyData.isAnimated()) {
return;
}
@ -215,22 +215,22 @@ void Animations::stockAnimation(const uint8 *bodyPtr, AnimTimerDataStruct *animT
animTimerDataPtr->time = _engine->lbaTime;
KeyFrame *keyframe = &animKeyframeBuf[animKeyframeBufIdx++];
animTimerDataPtr->ptr = keyframe;
copyStateToKeyFrame(keyframe, bodyPtr);
copyStateToKeyFrame(keyframe, bodyData);
}
void Animations::copyStateToKeyFrame(KeyFrame *keyframe, const uint8 *bodyPtr) const {
const int32 numBones = Model::getNumBones(bodyPtr);
void Animations::copyStateToKeyFrame(KeyFrame *keyframe, const BodyData &bodyData) const {
const int32 numBones = bodyData.getNumBones();
keyframe->boneframes.clear();
keyframe->boneframes.reserve(numBones);
for (int32 i = 0; i < numBones; ++i) {
const BoneFrame *boneState = Model::getBonesStateData(bodyPtr, i);
const BoneFrame *boneState = bodyData.getBoneState(i);
keyframe->boneframes.push_back(*boneState);
}
}
void Animations::copyKeyFrameToState(const KeyFrame *keyframe, uint8 *bodyPtr, int32 numBones) const {
void Animations::copyKeyFrameToState(const KeyFrame *keyframe, BodyData &bodyData, int32 numBones) const {
for (int32 i = 0; i < numBones; ++i) {
BoneFrame *boneState = Model::getBonesStateData(bodyPtr, i);
BoneFrame *boneState = bodyData.getBoneState(i);
*boneState = keyframe->boneframes[i];
}
}
@ -436,10 +436,10 @@ bool Animations::initAnim(AnimationTypes newAnim, AnimType animType, AnimationTy
if (actor->previousAnimIdx == -1) {
// if no previous animation
setAnimAtKeyframe(0, _engine->_resources->animData[animIndex], _engine->_resources->bodyTable[actor->entity], &actor->animTimerData);
setAnimAtKeyframe(0, _engine->_resources->animData[animIndex], _engine->_resources->bodyData[actor->entity], &actor->animTimerData);
} else {
// interpolation between animations
stockAnimation(_engine->_resources->bodyTable[actor->entity], &actor->animTimerData);
stockAnimation(_engine->_resources->bodyData[actor->entity], &actor->animTimerData);
}
actor->previousAnimIdx = animIndex;
@ -568,7 +568,7 @@ void Animations::processActorAnimations(int32 actorIdx) { // DoAnim
const AnimData &animData = _engine->_resources->animData[actor->previousAnimIdx];
bool keyFramePassed = false;
if (Model::isAnimated(_engine->_resources->bodyTable[actor->entity])) {
if (_engine->_resources->bodyData[actor->entity].isAnimated()) {
keyFramePassed = verifyAnimAtKeyframe(actor->animPosition, animData, &actor->animTimerData);
}

View file

@ -45,8 +45,8 @@ private:
*/
bool verifyAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, AnimTimerDataStruct *animTimerDataPtr);
void copyKeyFrameToState(const KeyFrame *keyframe, uint8 *bodyPtr, int32 numBones) const;
void copyStateToKeyFrame(KeyFrame *keyframe, const uint8 *bodyPtr) const;
void copyKeyFrameToState(const KeyFrame *keyframe, BodyData &bodyData, int32 numBones) const;
void copyStateToKeyFrame(KeyFrame *keyframe, const BodyData &bodyData) const;
int animKeyframeBufIdx = 0;
KeyFrame animKeyframeBuf[32];
@ -75,19 +75,19 @@ public:
* Set animation keyframe
* @param keyframIdx Animation keyframe index
* @param animData Animation data
* @param bodyPtr Body model poitner
* @param bodyData Body model data
* @param animTimerDataPtr Animation time data
*/
void setAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, uint8 *const bodyPtr, AnimTimerDataStruct *animTimerDataPtr);
void setAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, BodyData &bodyData, AnimTimerDataStruct *animTimerDataPtr);
/**
* Set new body animation
* @param keyframeIdx Animation key frame index
* @param animData Animation data
* @param bodyPtr Body model poitner
* @param bodyData Body model data
* @param animTimerDataPtr Animation time data
*/
bool setModelAnimation(int32 keyframeIdx, const AnimData &animData, uint8 *const bodyPtr, AnimTimerDataStruct *animTimerDataPtr);
bool setModelAnimation(int32 keyframeIdx, const AnimData &animData, BodyData &bodyData, AnimTimerDataStruct *animTimerDataPtr);
/**
* Get entity anim index (This is taken from File3D entities)
@ -98,10 +98,10 @@ public:
/**
* Stock animation - copy the next keyFrame from a different buffer
* @param bodyPtr Body model poitner
* @param bodyData Body model data
* @param animTimerDataPtr Animation time data
*/
void stockAnimation(const uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr);
void stockAnimation(const BodyData &bodyData, AnimTimerDataStruct *animTimerDataPtr);
/**
* Initialize animation

View file

@ -321,11 +321,11 @@ void GameState::processFoundItem(int32 item) {
const int32 itemCameraY = _engine->_grid->newCamera.y * BRICK_HEIGHT;
const int32 itemCameraZ = _engine->_grid->newCamera.z * BRICK_SIZE;
uint8 *bodyPtr = _engine->_resources->bodyTable[_engine->_scene->sceneHero->entity];
BodyData &bodyData = _engine->_resources->bodyData[_engine->_scene->sceneHero->entity];
const int32 bodyX = _engine->_scene->sceneHero->pos.x - itemCameraX;
const int32 bodyY = _engine->_scene->sceneHero->pos.y - itemCameraY;
const int32 bodyZ = _engine->_scene->sceneHero->pos.z - itemCameraZ;
_engine->_renderer->renderIsoModel(bodyX, bodyY, bodyZ, ANGLE_0, ANGLE_45, ANGLE_0, bodyPtr);
_engine->_renderer->renderIsoModel(bodyX, bodyY, bodyZ, ANGLE_0, ANGLE_45, ANGLE_0, bodyData);
_engine->_interface->setClip(_engine->_redraw->renderRect);
const int32 itemX = (_engine->_scene->sceneHero->pos.x + BRICK_HEIGHT) / BRICK_SIZE;
@ -365,7 +365,7 @@ void GameState::processFoundItem(int32 item) {
AnimTimerDataStruct tmpAnimTimer = _engine->_scene->sceneHero->animTimerData;
_engine->_animations->stockAnimation(bodyPtr, &_engine->_scene->sceneHero->animTimerData);
_engine->_animations->stockAnimation(bodyData, &_engine->_scene->sceneHero->animTimerData);
uint currentAnimState = 0;
@ -391,14 +391,14 @@ void GameState::processFoundItem(int32 item) {
_engine->_interface->resetClip();
initEngineProjections();
if (_engine->_animations->setModelAnimation(currentAnimState, currentAnimData, bodyPtr, &_engine->_scene->sceneHero->animTimerData)) {
if (_engine->_animations->setModelAnimation(currentAnimState, currentAnimData, bodyData, &_engine->_scene->sceneHero->animTimerData)) {
currentAnimState++; // keyframe
if (currentAnimState >= currentAnimData.getNumKeyframes()) {
currentAnimState = currentAnimData.getLoopFrame();
}
}
_engine->_renderer->renderIsoModel(bodyX, bodyY, bodyZ, ANGLE_0, ANGLE_45, ANGLE_0, bodyPtr);
_engine->_renderer->renderIsoModel(bodyX, bodyY, bodyZ, ANGLE_0, ANGLE_45, ANGLE_0, bodyData);
_engine->_interface->setClip(_engine->_redraw->renderRect);
_engine->_grid->drawOverModelActor(itemX, itemY, itemZ);
_engine->_redraw->addRedrawArea(_engine->_redraw->renderRect);
@ -495,8 +495,8 @@ void GameState::processGameoverAnimation() {
_engine->setPalette(_engine->_screens->paletteRGBA);
_engine->flip();
_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
uint8 *gameOverPtr = nullptr;
if (HQR::getAllocEntry(&gameOverPtr, Resources::HQR_RESS_FILE, RESSHQR_GAMEOVERMDL) == 0) {
BodyData gameOverPtr;
if (!gameOverPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_GAMEOVERMDL)) {
return;
}
@ -512,7 +512,6 @@ void GameState::processGameoverAnimation() {
ScopedFPS scopedFps(66);
_engine->readKeys();
if (_engine->shouldQuit()) {
free(gameOverPtr);
return;
}
@ -536,7 +535,6 @@ void GameState::processGameoverAnimation() {
_engine->delaySkip(2000);
_engine->_interface->resetClip();
free(gameOverPtr);
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
_engine->flip();
initEngineProjections();