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); _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->setBaseRotation(x, y, 0);
_engine->_renderer->getBaseRotationPosition(0, 0, zPos + 1000); _engine->_renderer->getBaseRotationPosition(0, 0, zPos + 1000);
_engine->_renderer->getBaseRotationPosition(_engine->_renderer->destPos.x, _engine->_renderer->destPos.y, _engine->_renderer->destPos.z); _engine->_renderer->getBaseRotationPosition(_engine->_renderer->destPos.x, _engine->_renderer->destPos.y, _engine->_renderer->destPos.z);
_engine->_interface->resetClip(); _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) { void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
@ -296,8 +296,8 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
AnimTimerDataStruct animTimerData; AnimTimerDataStruct animTimerData;
AnimData animData; AnimData animData;
animData.loadFromHQR(Resources::HQR_RESS_FILE, data->getAnimation()); animData.loadFromHQR(Resources::HQR_RESS_FILE, data->getAnimation());
uint8 *modelPtr = nullptr; BodyData bodyData;
HQR::getAllocEntry(&modelPtr, Resources::HQR_RESS_FILE, data->getModel()); bodyData.loadFromHQR(Resources::HQR_RESS_FILE, data->getModel());
uint frameNumber = 0; uint frameNumber = 0;
int32 frameTime = _engine->lbaTime; int32 frameTime = _engine->lbaTime;
int16 trajAnimFrameIdx = 0; int16 trajAnimFrameIdx = 0;
@ -329,7 +329,7 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
_engine->_movements->setActorAngleSafe(ANGLE_0, -ANGLE_90, 500, &move); _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++; frameNumber++;
if (frameNumber >= animData.getNumKeyframes()) { if (frameNumber >= animData.getNumKeyframes()) {
frameNumber = animData.getLoopFrame(); frameNumber = animData.getLoopFrame();
@ -340,7 +340,7 @@ void Holomap::drawHolomapTrajectory(int32 trajectoryIndex) {
_engine->_renderer->setLightVector(-60, 128, 0); _engine->_renderer->setLightVector(-60, 128, 0);
const Common::Rect rect(0, 200, 199, 479); const Common::Rect rect(0, 200, 199, 479);
_engine->_interface->drawFilledRect(rect, COLOR_BLACK); _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->copyBlockPhys(rect);
_engine->_renderer->setCameraPosition(400, 240, 128, 1024, 1024); _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->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->_text->initSceneTextBank();
_engine->_input->enableKeyMap(mainKeyMapId); _engine->_input->enableKeyMap(mainKeyMapId);
free(modelPtr);
} }
int32 Holomap::getNextHolomapLocation(int32 currentLocation, int32 dir) const { 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) { for (int i = 0; i < n; ++i) {
const DrawListStruct &drawList = _engine->_redraw->drawList[i]; const DrawListStruct &drawList = _engine->_redraw->drawList[i];
const uint16 flags = drawList.type; const uint16 flags = drawList.type;
const uint8 *bodyPtr = nullptr; const BodyData *bodyData = nullptr;
if (flags == 1u) { if (flags == 1u) {
bodyPtr = _engine->_resources->holomapArrowPtr; bodyData = &_engine->_resources->holomapArrowPtr;
} else if (flags == 2u) { } else if (flags == 2u) {
bodyPtr = _engine->_resources->holomapTwinsenModelPtr; bodyData = &_engine->_resources->holomapTwinsenModelPtr;
} else if (flags == 3u) { } 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 angleX = _locations[drawList.actorIdx].angle.x;
int32 angleY = _locations[drawList.actorIdx].angle.y; 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 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 prepareHolomapSurface();
void prepareHolomapProjectedPositions(); void prepareHolomapProjectedPositions();

View file

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

View file

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

View file

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

View file

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

View file

@ -42,6 +42,8 @@ struct BodyVertex {
struct BodyBone { struct BodyBone {
uint16 parent; uint16 parent;
uint16 vertex; uint16 vertex;
int16 firstVertex;
int16 numVertices;
int32 numOfShades; int32 numOfShades;
BoneFrame initalBoneState; BoneFrame initalBoneState;
@ -61,20 +63,22 @@ struct BodyPolygon {
Common::Array<uint16> indices; Common::Array<uint16> indices;
Common::Array<uint16> intensities; Common::Array<uint16> intensities;
int8 renderType = 0; int8 renderType = 0;
uint16 color = 0; int16 color = 0;
}; };
struct BodyLine { struct BodyLine {
uint16 unk1; uint8 color;
uint16 color; uint8 unk1;
uint16 unk2;
uint16 vertex1; uint16 vertex1;
uint16 vertex2; uint16 vertex2;
}; };
struct BodySphere { struct BodySphere {
uint8 unk1;
uint8 color;
uint16 unk2;
uint16 radius; uint16 radius;
uint16 color;
uint16 size;
uint16 vertex; uint16 vertex;
}; };
@ -158,8 +162,8 @@ public:
return _shades; return _shades;
} }
const BodyShade* getShade(int16 shadeIdx) const { const BodyShade &getShade(int16 shadeIdx) const {
return &_shades[shadeIdx]; return _shades[shadeIdx];
} }
const Common::Array<BodyLine> &getLines() const { const Common::Array<BodyLine> &getLines() const {
@ -170,8 +174,8 @@ public:
return _bones; return _bones;
} }
const BodyBone* getBone(int16 boneIdx) const { const BodyBone &getBone(int16 boneIdx) const {
return &_bones[boneIdx]; return _bones[boneIdx];
} }
bool loadFromStream(Common::SeekableReadStream &stream) override; 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); ActorStruct *actor = _engine->_scene->getActor(actorIdx);
if (actor->previousAnimIdx >= 0) { if (actor->previousAnimIdx >= 0) {
const AnimData &animData = _engine->_resources->animData[actor->previousAnimIdx]; 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 x = actor->pos.x - _engine->_grid->camera.x;
const int32 y = actor->pos.y - _engine->_grid->camera.y; const int32 y = actor->pos.y - _engine->_grid->camera.y;
const int32 z = actor->pos.z - _engine->_grid->camera.z; 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; return;
} }
@ -623,7 +623,7 @@ void Redraw::renderOverlays() {
_engine->_interface->drawFilledRect(rect, COLOR_BLACK); _engine->_interface->drawFilledRect(rect, COLOR_BLACK);
_engine->_interface->setClip(rect); _engine->_interface->setClip(rect);
const uint8* bodyPtr = _engine->_resources->inventoryTable[item]; const BodyData &bodyPtr = _engine->_resources->inventoryTable[item];
_overlayRotation += 1; // overlayRotation += 8; _overlayRotation += 1; // overlayRotation += 8;
_engine->_renderer->renderInventoryItem(40, 40, bodyPtr, _overlayRotation, 16000); _engine->_renderer->renderInventoryItem(40, 40, bodyPtr, _overlayRotation, 16000);
_engine->_menu->drawBox(rect); _engine->_menu->drawBox(rect);

View file

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

View file

@ -34,26 +34,16 @@
namespace TwinE { namespace TwinE {
Resources::~Resources() { Resources::~Resources() {
for (size_t i = 0; i < ARRAYSIZE(inventoryTable); ++i) {
free(inventoryTable[i]);
}
for (size_t i = 0; i < ARRAYSIZE(spriteTable); ++i) { for (size_t i = 0; i < ARRAYSIZE(spriteTable); ++i) {
free(spriteTable[i]); free(spriteTable[i]);
} }
for (size_t i = 0; i < ARRAYSIZE(samplesTable); ++i) { for (size_t i = 0; i < ARRAYSIZE(samplesTable); ++i) {
free(samplesTable[i]); free(samplesTable[i]);
} }
for (size_t i = 0; i < ARRAYSIZE(bodyTable); ++i) {
free(bodyTable[i]);
}
free(fontPtr); free(fontPtr);
free(spriteShadowPtr); free(spriteShadowPtr);
free(holomapSurfacePtr); free(holomapSurfacePtr);
free(holomapImagePtr); free(holomapImagePtr);
free(holomapTwinsenModelPtr);
free(holomapPointModelPtr);
free(holomapTwinsenArrowPtr);
free(holomapArrowPtr);
free(_engine->_screens->mainPalette); free(_engine->_screens->mainPalette);
} }
@ -142,7 +132,7 @@ void Resources::preloadInventoryItems() {
} }
debug("preload %i inventory items", numEntries); debug("preload %i inventory items", numEntries);
for (int32 i = 0; i < numEntries; i++) { 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"); error("Failed to load holomap image");
} }
holomapTwinsenModelSize = HQR::getAllocEntry(&holomapTwinsenModelPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINMDL); if (!holomapTwinsenModelPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINMDL)) {
if (holomapTwinsenModelSize == 0) {
error("Failed to load holomap twinsen model"); error("Failed to load holomap twinsen model");
} }
holomapPointModelSize = HQR::getAllocEntry(&holomapPointModelPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTMDL); if (!holomapPointModelPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOPOINTMDL)) {
if (holomapPointModelSize == 0) {
error("Failed to load holomap point model"); error("Failed to load holomap point model");
} }
holomapArrowSize = HQR::getAllocEntry(&holomapArrowPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWMDL); if (!holomapArrowPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOARROWMDL)) {
if (holomapArrowSize == 0) {
error("Failed to load holomap arrow model"); error("Failed to load holomap arrow model");
} }
holomapTwinsenArrowSize = HQR::getAllocEntry(&holomapTwinsenArrowPtr, Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINARROWMDL); if (!holomapTwinsenArrowPtr.loadFromHQR(Resources::HQR_RESS_FILE, RESSHQR_HOLOTWINARROWMDL)) {
if (holomapTwinsenArrowSize == 0) {
error("Failed to load holomap twinsen arrow model"); 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; const Common::Array<int32>& getFlaMovieInfo(const Common::String &name) const;
/** Table with all loaded samples */ /** Table with all loaded samples */
uint8 *inventoryTable[NUM_INVENTORY_ITEMS] {nullptr}; BodyData inventoryTable[NUM_INVENTORY_ITEMS];
/** Table with all loaded samples sizes */
uint32 inventorySizeTable[NUM_INVENTORY_ITEMS] {0};
/** Table with all loaded sprites */ /** Table with all loaded sprites */
uint8 *spriteTable[NUM_SPRITES] {nullptr}; uint8 *spriteTable[NUM_SPRITES] {nullptr};
@ -173,8 +171,6 @@ public:
AnimData animData[NUM_ANIMS]; AnimData animData[NUM_ANIMS];
/** Actors 3D body table - size of NUM_BODIES */ /** Actors 3D body table - size of NUM_BODIES */
uint8 *bodyTable[NUM_BODIES]{nullptr};
int32 bodyTableSize[NUM_BODIES]{0};
BodyData bodyData[NUM_BODIES]; BodyData bodyData[NUM_BODIES];
/** Table with all loaded samples */ /** Table with all loaded samples */
@ -194,14 +190,11 @@ public:
uint8 *holomapSurfacePtr = nullptr; uint8 *holomapSurfacePtr = nullptr;
uint32 holomapImageSize = 0; uint32 holomapImageSize = 0;
uint8 *holomapImagePtr = nullptr; uint8 *holomapImagePtr = nullptr;
uint32 holomapPointModelSize = 0;
uint8 *holomapPointModelPtr = nullptr; BodyData holomapPointModelPtr;
uint32 holomapTwinsenModelSize = 0; BodyData holomapTwinsenModelPtr;
uint8 *holomapTwinsenModelPtr = nullptr; BodyData holomapTwinsenArrowPtr;
uint32 holomapTwinsenArrowSize = 0; BodyData holomapArrowPtr;
uint8 *holomapTwinsenArrowPtr = nullptr;
uint32 holomapArrowSize = 0;
uint8 *holomapArrowPtr = nullptr;
/** Initialize resource pointers */ /** Initialize resource pointers */
void initResources(); void initResources();

View file

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

View file

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

View file

@ -45,8 +45,8 @@ private:
*/ */
bool verifyAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, AnimTimerDataStruct *animTimerDataPtr); bool verifyAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, AnimTimerDataStruct *animTimerDataPtr);
void copyKeyFrameToState(const KeyFrame *keyframe, uint8 *bodyPtr, int32 numBones) const; void copyKeyFrameToState(const KeyFrame *keyframe, BodyData &bodyData, int32 numBones) const;
void copyStateToKeyFrame(KeyFrame *keyframe, const uint8 *bodyPtr) const; void copyStateToKeyFrame(KeyFrame *keyframe, const BodyData &bodyData) const;
int animKeyframeBufIdx = 0; int animKeyframeBufIdx = 0;
KeyFrame animKeyframeBuf[32]; KeyFrame animKeyframeBuf[32];
@ -75,19 +75,19 @@ public:
* Set animation keyframe * Set animation keyframe
* @param keyframIdx Animation keyframe index * @param keyframIdx Animation keyframe index
* @param animData Animation data * @param animData Animation data
* @param bodyPtr Body model poitner * @param bodyData Body model data
* @param animTimerDataPtr Animation time 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 * Set new body animation
* @param keyframeIdx Animation key frame index * @param keyframeIdx Animation key frame index
* @param animData Animation data * @param animData Animation data
* @param bodyPtr Body model poitner * @param bodyData Body model data
* @param animTimerDataPtr Animation time 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) * 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 * 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 * @param animTimerDataPtr Animation time data
*/ */
void stockAnimation(const uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr); void stockAnimation(const BodyData &bodyData, AnimTimerDataStruct *animTimerDataPtr);
/** /**
* Initialize animation * Initialize animation

View file

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