[Scummvm-git-logs] scummvm master -> 1af583e6bd2c5244022c784f83e81ffc1972f0ee

mgerhardy martin.gerhardy at gmail.com
Sat Mar 27 12:35:47 UTC 2021


This automated email contains information about 19 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
d8f8de5601 TWINE: renamed struct to I16Vec3
e637781769 TWINE: moved I16Vec3 into shared header
5fcaf25b48 TWINE: changed function return type of getVerticesBaseData
d137e3c52a TWINE: use BodyShade for getShadesBaseData
0c8305f53b TWINE: reduced visibility
a3acbceae9 TWINE: renamed method
22f040bab5 TWINE: removed cast
19d71f081b TWINE: use size of structs
cf587e5d80 TWINE: reduced visibility
cdc6281bd0 TWINE: extracted to methods
33371ae454 TWINE: use BodyData for rendering
b081f3e711 TWINE: doxygen
8c76c1fac7 TWINE: use EntityData
7cfb6f00d5 TWINE: updated actor bbox code and minor cleanup
fca24a4eb7 TWINE: use I16Vec3 in animation code
e0ba8d1d74 TWINE: use IVec3 and minor cleanup
750128b2cb TWINE: minor cleanup
b6b9cd5fbd TWINE: use IVec3 for bounding box checks
1af583e6bd TWINE: optimized renderPolygons by not looping twice over all the vertices


Commit: d8f8de5601f2a0fc9e27484b0902425878e94c73
    https://github.com/scummvm/scummvm/commit/d8f8de5601f2a0fc9e27484b0902425878e94c73
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: renamed struct to I16Vec3

Changed paths:
    engines/twine/renderer/renderer.cpp
    engines/twine/renderer/renderer.h


diff --git a/engines/twine/renderer/renderer.cpp b/engines/twine/renderer/renderer.cpp
index c7dd869e67..9327ce4ccb 100644
--- a/engines/twine/renderer/renderer.cpp
+++ b/engines/twine/renderer/renderer.cpp
@@ -313,7 +313,7 @@ void Renderer::applyRotation(IMatrix3x3 *targetMatrix, const IMatrix3x3 *current
 	}
 }
 
-void Renderer::applyPointsRotation(const pointTab *pointsPtr, int32 numPoints, pointTab *destPoints, const IMatrix3x3 *rotationMatrix) {
+void Renderer::applyPointsRotation(const I16Vec3 *pointsPtr, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *rotationMatrix) {
 	int32 numOfPoints2 = numPoints;
 
 	do {
@@ -330,8 +330,8 @@ void Renderer::applyPointsRotation(const pointTab *pointsPtr, int32 numPoints, p
 	} while (--numOfPoints2);
 }
 
-void Renderer::processRotatedElement(IMatrix3x3 *targetMatrix, const pointTab *pointsPtr, int32 rotZ, int32 rotY, int32 rotX, const BonesBaseData *boneData, ModelData *modelData) {
-	int32 firstPoint = boneData->firstPoint / sizeof(pointTab);
+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;
 
 	IVec3 renderAngle;
@@ -348,7 +348,7 @@ void Renderer::processRotatedElement(IMatrix3x3 *targetMatrix, const pointTab *p
 		destPos.y = 0;
 		destPos.z = 0;
 	} else {
-		const int32 pointIdx = boneData->basePoint / sizeof(pointTab);
+		const int32 pointIdx = boneData->basePoint / sizeof(I16Vec3);
 		const int32 matrixIndex = boneData->baseElement / sizeof(BonesBaseData);
 		assert(matrixIndex >= 0 && matrixIndex < ARRAYSIZE(_matricesTable));
 		currentMatrix = &_matricesTable[matrixIndex];
@@ -367,7 +367,7 @@ void Renderer::processRotatedElement(IMatrix3x3 *targetMatrix, const pointTab *p
 	applyPointsRotation(&pointsPtr[firstPoint], numOfPoints2, &modelData->computedPoints[firstPoint], targetMatrix);
 }
 
-void Renderer::applyPointsTranslation(const pointTab *pointsPtr, int32 numPoints, pointTab *destPoints, const IMatrix3x3 *translationMatrix, const IVec3 &angleVec) {
+void Renderer::applyPointsTranslation(const I16Vec3 *pointsPtr, int32 numPoints, I16Vec3 *destPoints, const IMatrix3x3 *translationMatrix, const IVec3 &angleVec) {
 	int32 numOfPoints2 = numPoints;
 
 	do {
@@ -384,7 +384,7 @@ void Renderer::applyPointsTranslation(const pointTab *pointsPtr, int32 numPoints
 	} while (--numOfPoints2);
 }
 
-void Renderer::processTranslatedElement(IMatrix3x3 *targetMatrix, const pointTab *pointsPtr, int32 rotX, int32 rotY, int32 rotZ, const BonesBaseData *boneData, ModelData *modelData) {
+void Renderer::processTranslatedElement(IMatrix3x3 *targetMatrix, const I16Vec3 *pointsPtr, int32 rotX, int32 rotY, int32 rotZ, const BonesBaseData *boneData, ModelData *modelData) {
 	IVec3 renderAngle;
 	renderAngle.x = rotX;
 	renderAngle.y = rotY;
@@ -397,7 +397,7 @@ void Renderer::processTranslatedElement(IMatrix3x3 *targetMatrix, const pointTab
 
 		*targetMatrix = _baseMatrix;
 	} else { // dependent
-		const int32 pointsIdx = boneData->basePoint / sizeof(pointTab);
+		const int32 pointsIdx = boneData->basePoint / sizeof(I16Vec3);
 		destPos.x = modelData->computedPoints[pointsIdx].x;
 		destPos.y = modelData->computedPoints[pointsIdx].y;
 		destPos.z = modelData->computedPoints[pointsIdx].z;
@@ -407,7 +407,7 @@ void Renderer::processTranslatedElement(IMatrix3x3 *targetMatrix, const pointTab
 		*targetMatrix = _matricesTable[matrixIndex];
 	}
 
-	applyPointsTranslation(&pointsPtr[boneData->firstPoint / sizeof(pointTab)], boneData->numOfPoints, &modelData->computedPoints[boneData->firstPoint / sizeof(pointTab)], targetMatrix, renderAngle);
+	applyPointsTranslation(&pointsPtr[boneData->firstPoint / sizeof(I16Vec3)], boneData->numOfPoints, &modelData->computedPoints[boneData->firstPoint / sizeof(I16Vec3)], targetMatrix, renderAngle);
 }
 
 void Renderer::setLightVector(int32 angleX, int32 angleY, int32 angleZ) {
@@ -1173,7 +1173,7 @@ uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfP
 
 				const int16 vertexOffset = stream.readSint16LE();
 				const int16 vertexIndex = vertexOffset / 6;
-				const pointTab *point = &modelData->flattenPoints[vertexIndex];
+				const I16Vec3 *point = &modelData->flattenPoints[vertexIndex];
 
 				vertex->colorIndex = shadeValue;
 				vertex->x = point->x;
@@ -1197,7 +1197,7 @@ uint8 *Renderer::preparePolygons(Common::MemoryReadStream &stream, int32 &numOfP
 			do {
 				const int16 vertexOffset = stream.readSint16LE();
 				const int16 vertexIndex = vertexOffset / 6;
-				const pointTab *point = &modelData->flattenPoints[vertexIndex];
+				const I16Vec3 *point = &modelData->flattenPoints[vertexIndex];
 
 				vertex->colorIndex = destinationPolygon->colorIndex;
 				vertex->x = point->x;
@@ -1309,7 +1309,7 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
 	const int32 numVertices = Model::getNumVertices(bodyPtr);
 	const int32 numBones = Model::getNumBones(bodyPtr);
 
-	const pointTab *pointsPtr = (const pointTab *)Model::getVerticesBaseData(bodyPtr);
+	const I16Vec3 *pointsPtr = (const I16Vec3 *)Model::getVerticesBaseData(bodyPtr);
 
 	IMatrix3x3 *modelMatrix = &_matricesTable[0];
 
@@ -1340,8 +1340,8 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
 
 	numOfPrimitives = numVertices;
 
-	const pointTab *pointPtr = &modelData->computedPoints[0];
-	pointTab *pointPtrDest = &modelData->flattenPoints[0];
+	const I16Vec3 *pointPtr = &modelData->computedPoints[0];
+	I16Vec3 *pointPtrDest = &modelData->flattenPoints[0];
 
 	if (_isUsingOrthoProjection) { // use standard projection
 		do {
diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index aa48065d68..23a175b70d 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -242,13 +242,13 @@ private:
 	};
 
 #include "common/pack-start.h"
-	struct pointTab {
+	struct I16Vec3 {
 		int16 x = 0;
 		int16 y = 0;
 		int16 z = 0;
 	};
 #include "common/pack-end.h"
-	static_assert(sizeof(pointTab) == 6, "Unexpected pointTab size");
+	static_assert(sizeof(I16Vec3) == 6, "Unexpected pointTab size");
 
 	struct polyVertexHeader {
 		int16 shadeEntry = 0;
@@ -256,8 +256,8 @@ private:
 	};
 
 	struct ModelData {
-		pointTab computedPoints[800];
-		pointTab flattenPoints[800];
+		I16Vec3 computedPoints[800];
+		I16Vec3 flattenPoints[800];
 		int16 shadeTable[500]{0};
 	};
 
@@ -268,10 +268,10 @@ private:
 	bool renderModelElements(int32 numOfPrimitives, const uint8 *polygonPtr, 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 pointTab *pointsPtr, int32 numPoints, pointTab *destPoints, const IMatrix3x3 *rotationMatrix);
-	void processRotatedElement(IMatrix3x3 *targetMatrix, const pointTab *pointsPtr, int32 rotZ, int32 rotY, int32 rotX, const BonesBaseData *boneData, ModelData *modelData);
-	void applyPointsTranslation(const pointTab *pointsPtr, int32 numPoints, pointTab *destPoints, const IMatrix3x3 *translationMatrix, const IVec3 &angleVec);
-	void processTranslatedElement(IMatrix3x3 *targetMatrix, const pointTab *pointsPtr, int32 rotX, int32 rotY, int32 rotZ, const BonesBaseData *boneData, ModelData *modelData);
+	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 translateGroup(int32 x, int32 y, int32 z);
 
 	IVec3 _baseTransPos;


Commit: e6377817690b3a0db3c83b56d3a0baebb0b7e149
    https://github.com/scummvm/scummvm/commit/e6377817690b3a0db3c83b56d3a0baebb0b7e149
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: moved I16Vec3 into shared header

Changed paths:
    engines/twine/renderer/renderer.h
    engines/twine/shared.h


diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index 23a175b70d..cd4c9af0f7 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -241,15 +241,6 @@ private:
 		int16 radius = 0;
 	};
 
-#include "common/pack-start.h"
-	struct I16Vec3 {
-		int16 x = 0;
-		int16 y = 0;
-		int16 z = 0;
-	};
-#include "common/pack-end.h"
-	static_assert(sizeof(I16Vec3) == 6, "Unexpected pointTab size");
-
 	struct polyVertexHeader {
 		int16 shadeEntry = 0;
 		int16 dataOffset = 0;
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index c69597a01c..a512a20096 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -74,6 +74,15 @@
 
 namespace TwinE {
 
+#include "common/pack-start.h"
+struct I16Vec3 {
+	int16 x = 0;
+	int16 y = 0;
+	int16 z = 0;
+};
+#include "common/pack-end.h"
+static_assert(sizeof(I16Vec3) == 6, "Unexpected pointTab size");
+
 struct IVec3 {
 	constexpr IVec3() : x(0), y(0), z(0) {}
 	constexpr IVec3(int32 _x, int32 _y, int32 _z) : x(_x), y(_y), z(_z) {}


Commit: 5fcaf25b4823080ac9396e622c4b828c648474b8
    https://github.com/scummvm/scummvm/commit/5fcaf25b4823080ac9396e622c4b828c648474b8
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: changed function return type of getVerticesBaseData

Changed paths:
    engines/twine/renderer/renderer.cpp
    engines/twine/renderer/renderer.h


diff --git a/engines/twine/renderer/renderer.cpp b/engines/twine/renderer/renderer.cpp
index 9327ce4ccb..21ff1670bb 100644
--- a/engines/twine/renderer/renderer.cpp
+++ b/engines/twine/renderer/renderer.cpp
@@ -1309,7 +1309,7 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
 	const int32 numVertices = Model::getNumVertices(bodyPtr);
 	const int32 numBones = Model::getNumBones(bodyPtr);
 
-	const I16Vec3 *pointsPtr = (const I16Vec3 *)Model::getVerticesBaseData(bodyPtr);
+	const I16Vec3 *pointsPtr = Model::getVerticesBaseData(bodyPtr);
 
 	IMatrix3x3 *modelMatrix = &_matricesTable[0];
 
diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index cd4c9af0f7..def1ff7792 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -131,8 +131,8 @@ public:
 		return (bodyHeader & 2) != 0;
 	}
 
-	static const uint8 *getVerticesBaseData(const uint8 *bodyPtr) {
-		return getData(bodyPtr) + 2;
+	static const I16Vec3 *getVerticesBaseData(const uint8 *bodyPtr) {
+		return (const I16Vec3*)(getData(bodyPtr) + 2);
 	}
 
 	static const BoneFrame *getBonesStateData(const uint8 *bodyPtr, int boneIdx) {


Commit: d137e3c52ab6002f7b115e9428a93f256d20c776
    https://github.com/scummvm/scummvm/commit/d137e3c52ab6002f7b115e9428a93f256d20c776
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: use BodyShade for getShadesBaseData

Changed paths:
    engines/twine/parser/body.cpp
    engines/twine/parser/body.h
    engines/twine/renderer/renderer.cpp
    engines/twine/renderer/renderer.h


diff --git a/engines/twine/parser/body.cpp b/engines/twine/parser/body.cpp
index 1abf4c07eb..933eac1e9e 100644
--- a/engines/twine/parser/body.cpp
+++ b/engines/twine/parser/body.cpp
@@ -85,7 +85,7 @@ void BodyData::loadShades(Common::SeekableReadStream &stream) {
 		shape.col1 = stream.readSint16LE();
 		shape.col2 = stream.readSint16LE();
 		shape.col3 = stream.readSint16LE();
-		shape.unk4 = stream.readSint16LE();
+		shape.unk4 = stream.readUint16LE();
 		_shades.push_back(shape);
 	}
 }
diff --git a/engines/twine/parser/body.h b/engines/twine/parser/body.h
index 76abcada26..36b6575e89 100644
--- a/engines/twine/parser/body.h
+++ b/engines/twine/parser/body.h
@@ -54,7 +54,7 @@ struct BodyShade {
 	int16 col1;
 	int16 col2;
 	int16 col3;
-	int16 unk4;
+	uint16 unk4;
 };
 
 struct BodyPolygon {
diff --git a/engines/twine/renderer/renderer.cpp b/engines/twine/renderer/renderer.cpp
index 21ff1670bb..1129e8d64d 100644
--- a/engines/twine/renderer/renderer.cpp
+++ b/engines/twine/renderer/renderer.cpp
@@ -1451,12 +1451,11 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
 				_shadeMatrix = *lightMatrix * _lightPos;
 
 				do { // for each normal
-					const uint8 *shadePtr = Model::getShadesBaseData(bodyPtr, shadeIndex);
-					const int16 *colPtr = (const int16 *)shadePtr;
+					const BodyShade *shadePtr = Model::getShadesBaseData(bodyPtr, shadeIndex);
 
-					const int16 col1 = *((const int16 *)colPtr++);
-					const int16 col2 = *((const int16 *)colPtr++);
-					const int16 col3 = *((const int16 *)colPtr++);
+					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;
@@ -1467,8 +1466,7 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
 
 					if (color > 0) {
 						color >>= 14;
-						const uint8 *tmpShadePtr = (const uint8 *)shadePtr;
-						color /= *((const uint16 *)(tmpShadePtr + 6));
+						color /= shadePtr->unk4;
 						shade = (uint16)color;
 					}
 
diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index def1ff7792..60c0057348 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -165,9 +165,9 @@ public:
 		return READ_LE_INT16(verticesBase);
 	}
 
-	static const uint8 *getShadesBaseData(const uint8 *bodyPtr, int16 shadeIdx = 0) {
+	static const BodyShade *getShadesBaseData(const uint8 *bodyPtr, int16 shadeIdx = 0) {
 		assert(shadeIdx <= getNumShades(bodyPtr));
-		return getShadesData(bodyPtr) + 2 + (shadeIdx * 8);
+		return (const BodyShade*)(getShadesData(bodyPtr) + 2 + (shadeIdx * 8));
 	}
 
 	static const uint8 *getShadesData(const uint8 *bodyPtr) {
@@ -185,7 +185,7 @@ public:
 	}
 
 	static const uint8 *getPolygonData(const uint8 *bodyPtr) {
-		const uint8 *shades = getShadesBaseData(bodyPtr);
+		const uint8 *shades = (const uint8*)getShadesBaseData(bodyPtr);
 		const int16 numShades = getNumShades(bodyPtr);
 		if (numShades <= 0) {
 			return shades;


Commit: 0c8305f53b237e7c81ab3982d65f98c30cb3d778
    https://github.com/scummvm/scummvm/commit/0c8305f53b237e7c81ab3982d65f98c30cb3d778
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: reduced visibility

Changed paths:
    engines/twine/renderer/renderer.h


diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index 60c0057348..dcdc58aafb 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -125,6 +125,11 @@ private:
 	static const uint8 *getData(const uint8 *bodyPtr) {
 		return bodyPtr + 0x1A;
 	}
+
+	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);
@@ -170,11 +175,6 @@ public:
 		return (const BodyShade*)(getShadesData(bodyPtr) + 2 + (shadeIdx * 8));
 	}
 
-	static const uint8 *getShadesData(const uint8 *bodyPtr) {
-		const int16 numBones = getNumBones(bodyPtr);
-		return (const uint8 *)getBonesBaseData(bodyPtr, numBones);
-	}
-
 	static int16 getNumShades(const uint8 *bodyPtr) {
 		const uint8 *shadesBase = getShadesData(bodyPtr);
 		return READ_LE_INT16(shadesBase);


Commit: a3acbceae9b7d1611da2b1597e1723fa6c385be5
    https://github.com/scummvm/scummvm/commit/a3acbceae9b7d1611da2b1597e1723fa6c385be5
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: renamed method

Changed paths:
    engines/twine/renderer/renderer.cpp
    engines/twine/renderer/renderer.h


diff --git a/engines/twine/renderer/renderer.cpp b/engines/twine/renderer/renderer.cpp
index 1129e8d64d..732a45887a 100644
--- a/engines/twine/renderer/renderer.cpp
+++ b/engines/twine/renderer/renderer.cpp
@@ -1451,7 +1451,7 @@ bool Renderer::renderAnimatedModel(ModelData *modelData, const uint8 *bodyPtr, R
 				_shadeMatrix = *lightMatrix * _lightPos;
 
 				do { // for each normal
-					const BodyShade *shadePtr = Model::getShadesBaseData(bodyPtr, shadeIndex);
+					const BodyShade *shadePtr = Model::getBodyShadesData(bodyPtr, shadeIndex);
 
 					const int16 col1 = shadePtr->col1;
 					const int16 col2 = shadePtr->col2;
diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index dcdc58aafb..5646b210ca 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -170,7 +170,7 @@ public:
 		return READ_LE_INT16(verticesBase);
 	}
 
-	static const BodyShade *getShadesBaseData(const uint8 *bodyPtr, int16 shadeIdx = 0) {
+	static const BodyShade *getBodyShadesData(const uint8 *bodyPtr, int16 shadeIdx = 0) {
 		assert(shadeIdx <= getNumShades(bodyPtr));
 		return (const BodyShade*)(getShadesData(bodyPtr) + 2 + (shadeIdx * 8));
 	}
@@ -185,7 +185,7 @@ public:
 	}
 
 	static const uint8 *getPolygonData(const uint8 *bodyPtr) {
-		const uint8 *shades = (const uint8*)getShadesBaseData(bodyPtr);
+		const uint8 *shades = (const uint8*)getBodyShadesData(bodyPtr);
 		const int16 numShades = getNumShades(bodyPtr);
 		if (numShades <= 0) {
 			return shades;


Commit: 22f040bab583ea6d98bc4877aeec47812c71c569
    https://github.com/scummvm/scummvm/commit/22f040bab583ea6d98bc4877aeec47812c71c569
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: removed cast

Changed paths:
    engines/twine/scene/animations.cpp


diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 070d31a279..1f06ff8c18 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -149,22 +149,22 @@ bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData,
 	int16 boneIdx = 1;
 	int16 tmpNumOfPoints = MIN<int16>(lastKeyFramePtr->boneframes.size() - 1, numOfBonesInAnim - 1);
 	do {
-		BoneFrame *modelStateBoneFrame = (BoneFrame *)Model::getBonesStateData(bodyPtr, boneIdx);
+		BoneFrame *boneState = Model::getBonesStateData(bodyPtr, boneIdx);
 		const BoneFrame &boneFrame = keyFrame->boneframes[boneIdx];
 		const BoneFrame &lastBoneFrame = lastKeyFramePtr->boneframes[boneIdx];
 
-		modelStateBoneFrame->type = boneFrame.type;
+		boneState->type = boneFrame.type;
 		switch (boneFrame.type) {
 		case 0: // allow global rotate
-			modelStateBoneFrame->x = applyAnimStepRotation(deltaTime, keyFrameLength, boneFrame.x, lastBoneFrame.x);
-			modelStateBoneFrame->y = applyAnimStepRotation(deltaTime, keyFrameLength, boneFrame.y, lastBoneFrame.y);
-			modelStateBoneFrame->z = applyAnimStepRotation(deltaTime, keyFrameLength, boneFrame.z, lastBoneFrame.z);
+			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
-			modelStateBoneFrame->x = applyAnimStepTranslation(deltaTime, keyFrameLength, boneFrame.x, lastBoneFrame.x);
-			modelStateBoneFrame->y = applyAnimStepTranslation(deltaTime, keyFrameLength, boneFrame.y, lastBoneFrame.y);
-			modelStateBoneFrame->z = applyAnimStepTranslation(deltaTime, keyFrameLength, boneFrame.z, lastBoneFrame.z);
+			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);
 			break;
 		default:
 			error("Unsupported animation rotation mode %d", boneFrame.type);
@@ -230,7 +230,8 @@ void Animations::stockAnimation(const uint8 *bodyPtr, AnimTimerDataStruct *animT
 	keyframe->boneframes.reserve(numBones);
 
 	for (int32 i = 0; i < numBones; ++i) {
-		keyframe->boneframes.push_back(*Model::getBonesStateData(bodyPtr, i));
+		const BoneFrame *boneState = Model::getBonesStateData(bodyPtr, i);
+		keyframe->boneframes.push_back(*boneState);
 	}
 }
 


Commit: 19d71f081b1380f0c6b02ce5c9ca87a5f37d5f7b
    https://github.com/scummvm/scummvm/commit/19d71f081b1380f0c6b02ce5c9ca87a5f37d5f7b
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: use size of structs

Changed paths:
    engines/twine/renderer/renderer.h


diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index 5646b210ca..4d3ed9e472 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -109,13 +109,13 @@ private:
 	static uint8 *getBonesData(uint8 *bodyPtr) {
 		uint8 *verticesBase = getData(bodyPtr);
 		const int16 numVertices = READ_LE_INT16(verticesBase);
-		return verticesBase + 2 + numVertices * 6;
+		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 * 6;
+		return verticesBase + 2 + numVertices * sizeof(I16Vec3);
 	}
 
 	static uint8 *getData(uint8 *bodyPtr) {
@@ -172,7 +172,7 @@ public:
 
 	static const BodyShade *getBodyShadesData(const uint8 *bodyPtr, int16 shadeIdx = 0) {
 		assert(shadeIdx <= getNumShades(bodyPtr));
-		return (const BodyShade*)(getShadesData(bodyPtr) + 2 + (shadeIdx * 8));
+		return (const BodyShade*)(getShadesData(bodyPtr) + 2 + (shadeIdx * sizeof(BodyShade)));
 	}
 
 	static int16 getNumShades(const uint8 *bodyPtr) {


Commit: cf587e5d80c515e59c5cb8ff6b58ee61e26000d1
    https://github.com/scummvm/scummvm/commit/cf587e5d80c515e59c5cb8ff6b58ee61e26000d1
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: reduced visibility

Changed paths:
    engines/twine/renderer/renderer.h


diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index 4d3ed9e472..3d653697e5 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -126,6 +126,11 @@ private:
 		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);
@@ -150,11 +155,6 @@ public:
 		return (BoneFrame*)((uint8*)getBonesBaseData(bodyPtr) + 8 + (boneIdx * sizeof(BonesBaseData)));
 	}
 
-	static BonesBaseData *getBonesBaseData(uint8 *bodyPtr, int boneIdx = 0) {
-		assert(boneIdx <= getNumBones(bodyPtr));
-		return (BonesBaseData *)(getBonesData(bodyPtr) + 2 + (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)));


Commit: cdc6281bd0944b691976d38746f68a3c3fc03453
    https://github.com/scummvm/scummvm/commit/cdc6281bd0944b691976d38746f68a3c3fc03453
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: extracted to methods

Changed paths:
    engines/twine/scene/animations.cpp
    engines/twine/scene/animations.h


diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 1f06ff8c18..22aec815c4 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -130,11 +130,7 @@ bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData,
 	}
 	const int32 deltaTime = _engine->lbaTime - remainingFrameTime;
 	if (deltaTime >= keyFrameLength) {
-		for (int32 i = 0; i < numOfBonesInAnim; ++i) {
-			BoneFrame *boneState = Model::getBonesStateData(bodyPtr, i);
-			*boneState = keyFrame->boneframes[i];
-		}
-
+		copyKeyFrameToState(keyFrame, bodyPtr, numOfBonesInAnim);
 		animTimerDataPtr->ptr = keyFrame;
 		animTimerDataPtr->time = _engine->lbaTime;
 		return true;
@@ -205,12 +201,7 @@ void Animations::setAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData,
 		numOfBonesInAnim = numBones;
 	}
 
-	for (int32 i = 0; i < numOfBonesInAnim; ++i) {
-		BoneFrame *boneState = Model::getBonesStateData(bodyPtr, i);
-		*boneState = keyFrame->boneframes[i];
-	}
-
-	return;
+	copyKeyFrameToState(keyFrame, bodyPtr, numOfBonesInAnim);
 }
 
 void Animations::stockAnimation(const uint8 *bodyPtr, AnimTimerDataStruct *animTimerDataPtr) {
@@ -223,18 +214,27 @@ void Animations::stockAnimation(const uint8 *bodyPtr, AnimTimerDataStruct *animT
 	}
 	animTimerDataPtr->time = _engine->lbaTime;
 	KeyFrame *keyframe = &animKeyframeBuf[animKeyframeBufIdx++];
-	keyframe->boneframes.clear();
 	animTimerDataPtr->ptr = keyframe;
+	copyStateToKeyFrame(keyframe, bodyPtr);
+}
 
+void Animations::copyStateToKeyFrame(KeyFrame *keyframe, const uint8 *bodyPtr) const {
 	const int32 numBones = Model::getNumBones(bodyPtr);
+	keyframe->boneframes.clear();
 	keyframe->boneframes.reserve(numBones);
-
 	for (int32 i = 0; i < numBones; ++i) {
 		const BoneFrame *boneState = Model::getBonesStateData(bodyPtr, i);
 		keyframe->boneframes.push_back(*boneState);
 	}
 }
 
+void Animations::copyKeyFrameToState(const KeyFrame *keyframe, uint8 *bodyPtr, int32 numBones) const {
+	for (int32 i = 0; i < numBones; ++i) {
+		BoneFrame *boneState = Model::getBonesStateData(bodyPtr, i);
+		*boneState = keyframe->boneframes[i];
+	}
+}
+
 bool Animations::verifyAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData, AnimTimerDataStruct *animTimerDataPtr) {
 	const KeyFrame *keyFrame = animData.getKeyframe(keyframeIdx);
 	const int32 keyFrameLength = keyFrame->length;
diff --git a/engines/twine/scene/animations.h b/engines/twine/scene/animations.h
index 677e622b0b..b28e2fd761 100644
--- a/engines/twine/scene/animations.h
+++ b/engines/twine/scene/animations.h
@@ -45,6 +45,9 @@ 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;
+
 	int animKeyframeBufIdx = 0;
 	KeyFrame animKeyframeBuf[32];
 


Commit: 33371ae4544cfc5435618300e9ac37a3232cb102
    https://github.com/scummvm/scummvm/commit/33371ae4544cfc5435618300e9ac37a3232cb102
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: use BodyData for rendering

Changed paths:
    engines/twine/holomap.cpp
    engines/twine/holomap.h
    engines/twine/menu/menu.cpp
    engines/twine/menu/menu.h
    engines/twine/parser/anim.h
    engines/twine/parser/body.cpp
    engines/twine/parser/body.h
    engines/twine/renderer/redraw.cpp
    engines/twine/renderer/renderer.cpp
    engines/twine/renderer/renderer.h
    engines/twine/resources/resources.cpp
    engines/twine/resources/resources.h
    engines/twine/scene/actor.cpp
    engines/twine/scene/animations.cpp
    engines/twine/scene/animations.h
    engines/twine/scene/gamestate.cpp


diff --git a/engines/twine/holomap.cpp b/engines/twine/holomap.cpp
index 48616de5e4..f58d6985e9 100644
--- a/engines/twine/holomap.cpp
+++ b/engines/twine/holomap.cpp
@@ -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);
 		}
 	}
 }
diff --git a/engines/twine/holomap.h b/engines/twine/holomap.h
index 369204440c..1107e7638d 100644
--- a/engines/twine/holomap.h
+++ b/engines/twine/holomap.h
@@ -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();
diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index 7192c77ba9..8f1ac503a9 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -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);
diff --git a/engines/twine/menu/menu.h b/engines/twine/menu/menu.h
index c9edc85f72..b4315d76dc 100644
--- a/engines/twine/menu/menu.h
+++ b/engines/twine/menu/menu.h
@@ -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 */
diff --git a/engines/twine/parser/anim.h b/engines/twine/parser/anim.h
index c73f48ad83..d8c9f5f16d 100644
--- a/engines/twine/parser/anim.h
+++ b/engines/twine/parser/anim.h
@@ -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;
diff --git a/engines/twine/parser/body.cpp b/engines/twine/parser/body.cpp
index 933eac1e9e..ca3cc2258b 100644
--- a/engines/twine/parser/body.cpp
+++ b/engines/twine/parser/body.cpp
@@ -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);
 	}
diff --git a/engines/twine/parser/body.h b/engines/twine/parser/body.h
index 36b6575e89..a3f8cba601 100644
--- a/engines/twine/parser/body.h
+++ b/engines/twine/parser/body.h
@@ -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;
 };
 
@@ -134,44 +138,44 @@ public:
 		return _vertices.size();
 	}
 
-	BoneFrame* getBoneState(int16 boneIdx) {
+	BoneFrame *getBoneState(int16 boneIdx) {
 		return &_boneStates[boneIdx];
 	}
 
-	const BoneFrame* getBoneState(int16 boneIdx) const {
+	const BoneFrame *getBoneState(int16 boneIdx) const {
 		return &_boneStates[boneIdx];
 	}
 
-	const Common::Array<BodyPolygon>& getPolygons() const {
+	const Common::Array<BodyPolygon> &getPolygons() const {
 		return _polygons;
 	}
 
-	const Common::Array<BodyVertex>& getVertices() const {
+	const Common::Array<BodyVertex> &getVertices() const {
 		return _vertices;
 	}
 
-	const Common::Array<BodySphere>& getSpheres() const {
+	const Common::Array<BodySphere> &getSpheres() const {
 		return _spheres;
 	}
 
-	const Common::Array<BodyShade>& getShades() const {
+	const Common::Array<BodyShade> &getShades() const {
 		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 {
+	const Common::Array<BodyLine> &getLines() const {
 		return _lines;
 	}
 
-	const Common::Array<BodyBone>& getBones() const {
+	const Common::Array<BodyBone> &getBones() const {
 		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;
diff --git a/engines/twine/renderer/redraw.cpp b/engines/twine/renderer/redraw.cpp
index 1856bdd342..a210315b04 100644
--- a/engines/twine/renderer/redraw.cpp
+++ b/engines/twine/renderer/redraw.cpp
@@ -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);
diff --git a/engines/twine/renderer/renderer.cpp b/engines/twine/renderer/renderer.cpp
index 732a45887a..3fe8e6ca50 100644
--- a/engines/twine/renderer/renderer.cpp
+++ b/engines/twine/renderer/renderer.cpp
@@ -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;
@@ -1268,7 +1237,7 @@ bool Renderer::renderModelElements(int32 numOfPrimitives, const uint8 *polygonPt
 			int32 radius = sphere->radius;
 
 			//if (isUsingOrthoProjection) {
-				radius = (radius * 34) / 512;
+			radius = (radius * 34) / 512;
 			//} else {
 			//	radius = (radius * cameraScaleY) / (cameraDepthOffset + *(const int16 *)pointer); // TODO: this does not make sense.
 			//}
@@ -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;
+		modelMatrix = &_matricesTable[boneIdx];
+
 		do {
-			boneData = Model::getBonesBaseData(bodyPtr, boneIdx);
-			int16 boneType = boneData->flag;
+			const BodyBone &bone = bodyData.getBone(boneIdx);
+			const BoneFrame *boneData = bodyData.getBoneState(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);
+			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) {
diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index 3d653697e5..9948486cdc 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -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]);
 };
diff --git a/engines/twine/resources/resources.cpp b/engines/twine/resources/resources.cpp
index 2ff14cd1a4..3a6860389f 100644
--- a/engines/twine/resources/resources.cpp
+++ b/engines/twine/resources/resources.cpp
@@ -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");
 	}
 
diff --git a/engines/twine/resources/resources.h b/engines/twine/resources/resources.h
index 7e88964e44..5785e1fc2e 100644
--- a/engines/twine/resources/resources.h
+++ b/engines/twine/resources/resources.h
@@ -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();
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index b5dd57f227..c8fb42f8f2 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -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));
diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 22aec815c4..75aa2fbd60 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -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);
 			}
 
diff --git a/engines/twine/scene/animations.h b/engines/twine/scene/animations.h
index b28e2fd761..2abe2bcbe8 100644
--- a/engines/twine/scene/animations.h
+++ b/engines/twine/scene/animations.h
@@ -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
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index bc46587b87..38f0c9657c 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -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();


Commit: b081f3e71158084785b7f84339f7a489c847e6a0
    https://github.com/scummvm/scummvm/commit/b081f3e71158084785b7f84339f7a489c847e6a0
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: doxygen

Changed paths:
    engines/twine/parser/entity.h


diff --git a/engines/twine/parser/entity.h b/engines/twine/parser/entity.h
index 5cef8863e4..893ee68f0c 100644
--- a/engines/twine/parser/entity.h
+++ b/engines/twine/parser/entity.h
@@ -32,9 +32,9 @@
 namespace TwinE {
 
 struct EntityBody {
-	int index;		/**< index in file3d.hqr */
+	int index; /**< index in file3d.hqr */
 	ActorBoundingBox actorBoundingBox;
-	int bodyIndex;	/**< index in body.hqr */
+	int bodyIndex; /**< index in body.hqr */
 };
 
 struct EntityAnim {
@@ -64,6 +64,9 @@ struct EntityAnim {
 	Common::Array<Action> _actions;
 };
 
+/**
+ * @brief Associate 3d models from body hqr with animations from anim.hqr for the game characters
+ */
 class EntityData : public Parser {
 private:
 	Common::Array<EntityBody> _bodies;


Commit: 8c76c1fac7c9f97fe45a074035ee0ce9e3a31597
    https://github.com/scummvm/scummvm/commit/8c76c1fac7c9f97fe45a074035ee0ce9e3a31597
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:27+01:00

Commit Message:
TWINE: use EntityData

Changed paths:
    engines/twine/parser/entity.cpp
    engines/twine/resources/resources.cpp
    engines/twine/scene/actor.cpp
    engines/twine/scene/actor.h
    engines/twine/scene/animations.cpp
    engines/twine/scene/gamestate.cpp
    engines/twine/scene/scene.cpp


diff --git a/engines/twine/parser/entity.cpp b/engines/twine/parser/entity.cpp
index 518c815c52..778cbf986a 100644
--- a/engines/twine/parser/entity.cpp
+++ b/engines/twine/parser/entity.cpp
@@ -156,6 +156,8 @@ bool EntityData::loadAnim(Common::SeekableReadStream &stream) {
 }
 
 bool EntityData::loadFromStream(Common::SeekableReadStream &stream) {
+	_animations.clear();
+	_bodies.clear();
 	do {
 		const uint8 opcode = stream.readByte();
 		if (opcode == 1) {
diff --git a/engines/twine/resources/resources.cpp b/engines/twine/resources/resources.cpp
index 3a6860389f..bff15c20f2 100644
--- a/engines/twine/resources/resources.cpp
+++ b/engines/twine/resources/resources.cpp
@@ -195,6 +195,13 @@ void Resources::initResources() {
 	preloadSamples();
 	preloadInventoryItems();
 
+	const int32 bodyCount = HQR::numEntries(Resources::HQR_BODY_FILE);
+	for (int32 i = 0; i < bodyCount; ++i) {
+		if (!bodyData[i].loadFromHQR(Resources::HQR_BODY_FILE, i)) {
+			error("HQR ERROR: Parsing body entity for model %i failed", i);
+		}
+	}
+
 	loadFlaInfo();
 }
 
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index c8fb42f8f2..3fb58bde8e 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -43,15 +43,6 @@ namespace TwinE {
 Actor::Actor(TwinEEngine *engine) : _engine(engine) {
 }
 
-Actor::~Actor() {
-	_engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->entityDataPtr = nullptr;
-	free(_heroEntityNORMAL);
-	free(_heroEntityATHLETIC);
-	free(_heroEntityAGGRESSIVE);
-	free(_heroEntityDISCRETE);
-	free(_heroEntityPROTOPACK);
-}
-
 void Actor::restartHeroScene() {
 	ActorStruct *sceneHero = _engine->_scene->sceneHero;
 	sceneHero->controlMode = ControlMode::kManual;
@@ -77,28 +68,27 @@ void Actor::restartHeroScene() {
 	cropBottomScreen = 0;
 }
 
-int32 Actor::loadBehaviourEntity(ActorStruct *sceneHero, uint8 **ptr, int16 &bodyAnimIndex, int32 index) {
-	const int32 size = HQR::getAllocEntry(ptr, Resources::HQR_FILE3D_FILE, index);
-	if (size == 0) {
+void Actor::loadBehaviourEntity(ActorStruct *actor, EntityData &entityData, int16 &bodyAnimIndex, int32 index) {
+	if (!entityData.loadFromHQR(Resources::HQR_FILE3D_FILE, index)) {
 		error("Failed to load actor 3d data for index: %i", index);
 	}
-	sceneHero->entityDataPtr = *ptr;
-	sceneHero->entityDataSize = size;
-	bodyAnimIndex = _engine->_animations->getBodyAnimIndex(AnimationTypes::kStanding);
+
+	actor->entityData = &entityData;
+	bodyAnimIndex = entityData.getAnimIndex(AnimationTypes::kStanding);
 	if (bodyAnimIndex == -1) {
 		error("Could not find animation data for 3d data with index %i", index);
 	}
-	return size;
 }
 
 void Actor::loadHeroEntities() {
 	ActorStruct *sceneHero = _engine->_scene->sceneHero;
-	_heroEntityATHLETICSize = loadBehaviourEntity(sceneHero, &_heroEntityATHLETIC, heroAnimIdxATHLETIC, FILE3DHQR_HEROATHLETIC);
-	_heroEntityAGGRESSIVESize = loadBehaviourEntity(sceneHero, &_heroEntityAGGRESSIVE, heroAnimIdxAGGRESSIVE, FILE3DHQR_HEROAGGRESSIVE);
-	_heroEntityDISCRETESize = loadBehaviourEntity(sceneHero, &_heroEntityDISCRETE, heroAnimIdxDISCRETE, FILE3DHQR_HERODISCRETE);
-	_heroEntityPROTOPACKSize = loadBehaviourEntity(sceneHero, &_heroEntityPROTOPACK, heroAnimIdxPROTOPACK, FILE3DHQR_HEROPROTOPACK);
-	_heroEntityNORMALSize = loadBehaviourEntity(sceneHero, &_heroEntityNORMAL, heroAnimIdxNORMAL, FILE3DHQR_HERONORMAL);
+	loadBehaviourEntity(sceneHero, _heroEntityATHLETIC, heroAnimIdxATHLETIC, FILE3DHQR_HEROATHLETIC);
+	loadBehaviourEntity(sceneHero, _heroEntityAGGRESSIVE, heroAnimIdxAGGRESSIVE, FILE3DHQR_HEROAGGRESSIVE);
+	loadBehaviourEntity(sceneHero, _heroEntityDISCRETE, heroAnimIdxDISCRETE, FILE3DHQR_HERODISCRETE);
+	loadBehaviourEntity(sceneHero, _heroEntityPROTOPACK, heroAnimIdxPROTOPACK, FILE3DHQR_HEROPROTOPACK);
+	loadBehaviourEntity(sceneHero, _heroEntityNORMAL, heroAnimIdxNORMAL, FILE3DHQR_HERONORMAL);
 
+	_engine->_animations->currentActorAnimExtraPtr = AnimationTypes::kStanding;
 	sceneHero->animExtraPtr = _engine->_animations->currentActorAnimExtraPtr;
 }
 
@@ -107,28 +97,23 @@ void Actor::setBehaviour(HeroBehaviourType behaviour) {
 	switch (behaviour) {
 	case HeroBehaviourType::kNormal:
 		heroBehaviour = behaviour;
-		sceneHero->entityDataPtr = _heroEntityNORMAL;
-		sceneHero->entityDataSize = _heroEntityNORMALSize;
+		sceneHero->entityData = &_heroEntityNORMAL;
 		break;
 	case HeroBehaviourType::kAthletic:
 		heroBehaviour = behaviour;
-		sceneHero->entityDataPtr = _heroEntityATHLETIC;
-		sceneHero->entityDataSize = _heroEntityATHLETICSize;
+		sceneHero->entityData = &_heroEntityATHLETIC;
 		break;
 	case HeroBehaviourType::kAggressive:
 		heroBehaviour = behaviour;
-		sceneHero->entityDataPtr = _heroEntityAGGRESSIVE;
-		sceneHero->entityDataSize = _heroEntityAGGRESSIVESize;
+		sceneHero->entityData = &_heroEntityAGGRESSIVE;
 		break;
 	case HeroBehaviourType::kDiscrete:
 		heroBehaviour = behaviour;
-		sceneHero->entityDataPtr = _heroEntityDISCRETE;
-		sceneHero->entityDataSize = _heroEntityDISCRETESize;
+		sceneHero->entityData = &_heroEntityDISCRETE;
 		break;
 	case HeroBehaviourType::kProtoPack:
 		heroBehaviour = behaviour;
-		sceneHero->entityDataPtr = _heroEntityPROTOPACK;
-		sceneHero->entityDataSize = _heroEntityPROTOPACKSize;
+		sceneHero->entityData = &_heroEntityPROTOPACK;
 		break;
 	};
 
@@ -163,61 +148,17 @@ int32 Actor::getTextIdForBehaviour() const {
 	return (int32)heroBehaviour;
 }
 
-// see Animations::getBodyAnimIndex
 int32 Actor::initBody(BodyType bodyIdx, int32 actorIdx, ActorBoundingBox &actorBoundingBox) {
 	if (bodyIdx == BodyType::btNone) {
 		return -1;
 	}
 	ActorStruct *actor = _engine->_scene->getActor(actorIdx);
-	Common::MemorySeekableReadWriteStream stream(actor->entityDataPtr, actor->entityDataSize);
-	do {
-		const uint8 type = stream.readByte();
-		if (type == 0xFF) {
-			return -1;
-		}
-
-		BodyType idx = (BodyType)stream.readByte();
-		const int32 pos = stream.pos();
-		const uint8 size = stream.readByte();
-		if (type == 1) { // 1 = body data - 3 is animdata
-			if (idx == bodyIdx) {
-				const int16 bodyIndex = stream.readUint16LE();
-
-				// TODO: move into resources class
-				int32 index;
-				if (!(bodyIndex & 0x8000)) {
-					index = _currentPositionInBodyPtrTab;
-					_currentPositionInBodyPtrTab++;
-					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));
-					stream.writeUint16LE(index + 0x8000);
-				} else {
-					index = bodyIndex & 0x7FFF;
-				}
-
-				actorBoundingBox.hasBoundingBox = stream.readByte();
-				if (!actorBoundingBox.hasBoundingBox) {
-					return index;
-				}
-
-				if (stream.readByte() != ActionType::ACTION_ZV) {
-					return index;
-				}
-
-				actorBoundingBox.bbox.mins.x = stream.readSint16LE();
-				actorBoundingBox.bbox.mins.y = stream.readSint16LE();
-				actorBoundingBox.bbox.mins.z = stream.readSint16LE();
-				actorBoundingBox.bbox.maxs.x = stream.readSint16LE();
-				actorBoundingBox.bbox.maxs.y = stream.readSint16LE();
-				actorBoundingBox.bbox.maxs.z = stream.readSint16LE();
-
-				return index;
-			}
-		}
-		stream.seek(pos + size);
-	} while (1);
+	const EntityBody* body = actor->entityData->getBody((int)bodyIdx);
+	if (body == nullptr) {
+		return -1;
+	}
+	actorBoundingBox = body->actorBoundingBox;
+	return body->bodyIndex;
 }
 
 void Actor::initModelActor(BodyType bodyIdx, int16 actorIdx) {
@@ -450,23 +391,16 @@ void Actor::processActorExtraBonus(int32 actorIdx) { // GiveExtraBonus
 	}
 }
 
-void Actor::clearBodyTable() {
-	_currentPositionInBodyPtrTab = 0;
-}
-
-ActorStruct::~ActorStruct() {
-	free(entityDataPtr);
-}
-
 void ActorStruct::loadModel(int32 modelIndex) {
 	entity = modelIndex;
 	if (!staticFlags.bIsSpriteActor) {
 		debug(1, "Init actor with model %i", modelIndex);
-		entityDataSize = HQR::getAllocEntry(&entityDataPtr, Resources::HQR_FILE3D_FILE, modelIndex);
+		if (!_entityData.loadFromHQR(Resources::HQR_FILE3D_FILE, modelIndex)) {
+			error("Failed to load entity data for index %i",  modelIndex);
+		}
+		entityData = &_entityData;
 	} else {
-		entityDataSize = 0;
-		free(entityDataPtr);
-		entityDataPtr = nullptr;
+		entityData = nullptr;
 	}
 }
 
diff --git a/engines/twine/scene/actor.h b/engines/twine/scene/actor.h
index 412eabda2a..ab0125dc52 100644
--- a/engines/twine/scene/actor.h
+++ b/engines/twine/scene/actor.h
@@ -159,9 +159,8 @@ private:
 	ShapeType _brickShape = ShapeType::kNone; // field_3
 	bool _brickCausesDamage = false;
 
+	EntityData _entityData;
 public:
-	~ActorStruct();
-
 	StaticFlagsStruct staticFlags;
 	DynamicFlagsStruct dynamicFlags;
 
@@ -180,8 +179,7 @@ public:
 	AnimationTypes animExtra = AnimationTypes::kStanding; //field_2
 	AnimationTypes animExtraPtr = AnimationTypes::kAnimNone;
 	int32 sprite = 0; // field_8
-	uint8 *entityDataPtr = nullptr;
-	int32 entityDataSize = 0;
+	EntityData *entityData = nullptr;
 
 	bool isAttackWeaponAnimationActive() const;
 	bool isAttackAnimationActive() const;
@@ -261,23 +259,15 @@ private:
 	TwinEEngine *_engine;
 
 	/** Hero 3D entity for normal behaviour */
-	uint8 *_heroEntityNORMAL = nullptr;
-	int32 _heroEntityNORMALSize = 0;
+	EntityData _heroEntityNORMAL;
 	/** Hero 3D entity for athletic behaviour */
-	uint8 *_heroEntityATHLETIC = nullptr;
-	int32 _heroEntityATHLETICSize = 0;
+	EntityData _heroEntityATHLETIC;
 	/** Hero 3D entity for aggressive behaviour */
-	uint8 *_heroEntityAGGRESSIVE = nullptr;
-	int32 _heroEntityAGGRESSIVESize = 0;
+	EntityData _heroEntityAGGRESSIVE;
 	/** Hero 3D entity for discrete behaviour */
-	uint8 *_heroEntityDISCRETE = nullptr;
-	int32 _heroEntityDISCRETESize = 0;
+	EntityData _heroEntityDISCRETE;
 	/** Hero 3D entity for protopack behaviour */
-	uint8 *_heroEntityPROTOPACK = nullptr;
-	int32 _heroEntityPROTOPACKSize = 0;
-
-	/** Current position in body table */
-	int32 _currentPositionInBodyPtrTab;
+	EntityData _heroEntityPROTOPACK;
 
 	void initSpriteActor(int32 actorIdx);
 
@@ -288,11 +278,10 @@ private:
 	 */
 	int32 initBody(BodyType bodyIdx, int32 actorIdx, ActorBoundingBox &actorBoundingBox);
 
-	int32 loadBehaviourEntity(ActorStruct *sceneHero, uint8 **ptr, int16 &bodyAnimIndex, int32 index);
+	void loadBehaviourEntity(ActorStruct *actor, EntityData &entityData, int16 &bodyAnimIndex, int32 index);
 
 public:
 	Actor(TwinEEngine *engine);
-	~Actor();
 
 	ActorStruct *processActorPtr = nullptr;
 
@@ -323,8 +312,6 @@ public:
 	/** Hero anim for behaviour menu */
 	int16 heroAnimIdx[4];
 
-	void clearBodyTable();
-
 	/** Restart hero variables while opening new scenes */
 	void restartHeroScene();
 
diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 75aa2fbd60..48cf51222e 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -56,10 +56,7 @@ Animations::Animations(TwinEEngine *engine) : _engine(engine) {
 
 int32 Animations::getBodyAnimIndex(AnimationTypes animIdx, int32 actorIdx) {
 	ActorStruct *actor = _engine->_scene->getActor(actorIdx);
-	// TODO: cache this
-	EntityData entityData;
-	entityData.loadFromBuffer(actor->entityDataPtr, actor->entityDataSize);
-	const int32 bodyAnimIndex = entityData.getAnimIndex(animIdx);
+	const int32 bodyAnimIndex = actor->entityData->getAnimIndex(animIdx);
 	if (bodyAnimIndex != -1) {
 		currentActorAnimExtraPtr = animIdx;
 	}
@@ -270,14 +267,11 @@ bool Animations::verifyAnimAtKeyframe(int32 keyframeIdx, const AnimData &animDat
 
 void Animations::processAnimActions(int32 actorIdx) {
 	ActorStruct *actor = _engine->_scene->getActor(actorIdx);
-	if (actor->entityDataPtr == nullptr || actor->animExtraPtr == AnimationTypes::kAnimNone) {
+	if (actor->entityData == nullptr || actor->animExtraPtr == AnimationTypes::kAnimNone) {
 		return;
 	}
 
-	// TODO: cache this
-	EntityData entityData;
-	entityData.loadFromBuffer(actor->entityDataPtr, actor->entityDataSize);
-	const Common::Array<EntityAnim::Action> *actions = entityData.getActions(actor->animExtraPtr);
+	const Common::Array<EntityAnim::Action> *actions = actor->entityData->getActions(actor->animExtraPtr);
 	if (actions == nullptr) {
 		return;
 	}
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 38f0c9657c..e5933e4630 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -82,8 +82,6 @@ void GameState::initGameStateVars() {
 	_engine->_scene->initSceneVars();
 
 	Common::fill(&holomapFlags[0], &holomapFlags[NUM_LOCATIONS], 0);
-
-	_engine->_actor->clearBodyTable();
 }
 
 void GameState::initHeroVars() {
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 9ae9f561ec..540ce7fc60 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -461,7 +461,6 @@ void Scene::resetScene() {
 		_engine->_redraw->overlayList[i].info0 = -1;
 	}
 
-	_engine->_actor->clearBodyTable();
 	_engine->_screens->useAlternatePalette = false;
 }
 


Commit: 7cfb6f00d5280f4f170b1731718572cfbe01cc22
    https://github.com/scummvm/scummvm/commit/7cfb6f00d5280f4f170b1731718572cfbe01cc22
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:28+01:00

Commit Message:
TWINE: updated actor bbox code and minor cleanup

Changed paths:
    engines/twine/scene/actor.cpp


diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index 3fb58bde8e..f88256d747 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -178,10 +178,7 @@ void Actor::initModelActor(BodyType bodyIdx, int16 actorIdx) {
 	if (entityIdx == -1) {
 		localActor->body = BodyType::btNone;
 		localActor->entity = -1;
-
-		BoundingBox &bbox = localActor->boudingBox;
-		bbox.mins = IVec3();
-		bbox.maxs = IVec3();
+		localActor->boudingBox = BoundingBox();
 		debug("Failed to initialize body %i for actor %i", (int)bodyIdx, actorIdx);
 		return;
 	}
@@ -194,22 +191,14 @@ void Actor::initModelActor(BodyType bodyIdx, int16 actorIdx) {
 	localActor->body = bodyIdx;
 
 	if (actorBoundingBox.hasBoundingBox) {
-		BoundingBox &bbox = localActor->boudingBox;
-		bbox.mins.x = actorBoundingBox.bbox.mins.x;
-		bbox.maxs.x = actorBoundingBox.bbox.maxs.x;
-		bbox.mins.y = actorBoundingBox.bbox.mins.y;
-		bbox.maxs.y = actorBoundingBox.bbox.maxs.y;
-		bbox.mins.z = actorBoundingBox.bbox.mins.z;
-		bbox.maxs.z = actorBoundingBox.bbox.maxs.z;
+		localActor->boudingBox = actorBoundingBox.bbox;
 	} else {
-		BoundingBox &bbox = localActor->boudingBox;
 		const BodyData &bd = _engine->_resources->bodyData[localActor->entity];
-		bbox.mins.y = bd.bbox.mins.y;
-		bbox.maxs.y = bd.bbox.maxs.y;
+		localActor->boudingBox = bd.bbox;
 
 		int32 result = 0;
-		const int32 distX = bd.bbox.maxs.x - bd.bbox.mins.x;
-		const int32 distZ = bd.bbox.maxs.z - bd.bbox.mins.z;
+		const int32 distX = localActor->boudingBox.maxs.x - localActor->boudingBox.mins.x;
+		const int32 distZ = localActor->boudingBox.maxs.z - localActor->boudingBox.mins.z;
 		if (localActor->staticFlags.bUseMiniZv) {
 			// take smaller for bound
 			result = MIN(distX, distZ);
@@ -223,10 +212,10 @@ void Actor::initModelActor(BodyType bodyIdx, int16 actorIdx) {
 			result >>= 2;
 		}
 
-		bbox.mins.x = -result;
-		bbox.maxs.x = result;
-		bbox.mins.z = -result;
-		bbox.maxs.z = result;
+		localActor->boudingBox.mins.x = -result;
+		localActor->boudingBox.maxs.x = result;
+		localActor->boudingBox.mins.z = -result;
+		localActor->boudingBox.maxs.z = result;
 	}
 }
 
@@ -274,13 +263,9 @@ void Actor::resetActor(int16 actorIdx) {
 	actor->actorIdx = actorIdx;
 	actor->body = BodyType::btNormal;
 	actor->anim = AnimationTypes::kStanding;
-	actor->pos.x = 0;
-	actor->pos.y = -1;
-	actor->pos.z = 0;
+	actor->pos = IVec3(0, -1, 0);
 
-	BoundingBox &bbox = actor->boudingBox;
-	bbox.mins = IVec3();
-	bbox.maxs = IVec3();
+	actor->boudingBox = BoundingBox();
 
 	actor->angle = 0;
 	actor->speed = 40;
@@ -304,9 +289,7 @@ void Actor::resetActor(int16 actorIdx) {
 	actor->armor = 1;
 	actor->hitBy = -1;
 	actor->lastRotationAngle = ANGLE_0;
-	actor->lastPos.x = 0;
-	actor->lastPos.y = 0;
-	actor->lastPos.z = 0;
+	actor->lastPos = IVec3();
 	actor->entity = -1;
 	actor->previousAnimIdx = -1;
 	actor->animType = AnimType::kAnimationTypeLoop;


Commit: fca24a4eb7ab056586c492f026d0f04b83e1f777
    https://github.com/scummvm/scummvm/commit/fca24a4eb7ab056586c492f026d0f04b83e1f777
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:28+01:00

Commit Message:
TWINE: use I16Vec3 in animation code

Changed paths:
    engines/twine/scene/animations.cpp
    engines/twine/scene/animations.h


diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 48cf51222e..3359a8c895 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -104,9 +104,9 @@ bool Animations::setModelAnimation(int32 keyframeIdx, const AnimData &animData,
 	}
 	const KeyFrame *keyFrame = animData.getKeyframe(keyframeIdx);
 
-	currentStepX = keyFrame->x;
-	currentStepY = keyFrame->y;
-	currentStepZ = keyFrame->z;
+	currentStep.x = keyFrame->x;
+	currentStep.y = keyFrame->y;
+	currentStep.z = keyFrame->z;
 
 	processRotationByAnim = keyFrame->boneframes[0].type;
 	processLastRotationAngle = ToAngle(keyFrame->boneframes[0].y);
@@ -181,9 +181,9 @@ void Animations::setAnimAtKeyframe(int32 keyframeIdx, const AnimData &animData,
 
 	const KeyFrame *keyFrame = animData.getKeyframe(keyframeIdx);
 
-	currentStepX = keyFrame->x;
-	currentStepY = keyFrame->y;
-	currentStepZ = keyFrame->z;
+	currentStep.x = keyFrame->x;
+	currentStep.y = keyFrame->y;
+	currentStep.z = keyFrame->z;
 
 	processRotationByAnim = keyFrame->boneframes[0].type;
 	processLastRotationAngle = ToAngle(keyFrame->boneframes[0].y);
@@ -243,9 +243,9 @@ bool Animations::verifyAnimAtKeyframe(int32 keyframeIdx, const AnimData &animDat
 
 	const int32 deltaTime = _engine->lbaTime - remainingFrameTime;
 
-	currentStepX = keyFrame->x;
-	currentStepY = keyFrame->y;
-	currentStepZ = keyFrame->z;
+	currentStep.x = keyFrame->x;
+	currentStep.y = keyFrame->y;
+	currentStep.z = keyFrame->z;
 
 	const BoneFrame &boneFrame = keyFrame->boneframes[0];
 	processRotationByAnim = boneFrame.type;
@@ -258,9 +258,9 @@ bool Animations::verifyAnimAtKeyframe(int32 keyframeIdx, const AnimData &animDat
 	}
 
 	processLastRotationAngle = (processLastRotationAngle * deltaTime) / keyFrameLength;
-	currentStepX = (currentStepX * deltaTime) / keyFrameLength;
-	currentStepY = (currentStepY * deltaTime) / keyFrameLength;
-	currentStepZ = (currentStepZ * deltaTime) / keyFrameLength;
+	currentStep.x = (currentStep.x * deltaTime) / keyFrameLength;
+	currentStep.y = (currentStep.y * deltaTime) / keyFrameLength;
+	currentStep.z = (currentStep.z * deltaTime) / keyFrameLength;
 
 	return false;
 }
@@ -575,18 +575,18 @@ void Animations::processActorAnimations(int32 actorIdx) { // DoAnim
 			actor->angle = ClampAngle(actor->angle + processLastRotationAngle - actor->lastRotationAngle);
 			actor->lastRotationAngle = processLastRotationAngle;
 
-			_engine->_movements->rotateActor(currentStepX, currentStepZ, actor->angle);
+			_engine->_movements->rotateActor(currentStep.x, currentStep.z, actor->angle);
 
-			currentStepX = _engine->_renderer->destPos.x;
-			currentStepZ = _engine->_renderer->destPos.z;
+			currentStep.x = _engine->_renderer->destPos.x;
+			currentStep.z = _engine->_renderer->destPos.z;
 
-			_engine->_movements->processActor.x = actor->pos.x + currentStepX - actor->lastPos.x;
-			_engine->_movements->processActor.y = actor->pos.y + currentStepY - actor->lastPos.y;
-			_engine->_movements->processActor.z = actor->pos.z + currentStepZ - actor->lastPos.z;
+			_engine->_movements->processActor.x = actor->pos.x + currentStep.x - actor->lastPos.x;
+			_engine->_movements->processActor.y = actor->pos.y + currentStep.y - actor->lastPos.y;
+			_engine->_movements->processActor.z = actor->pos.z + currentStep.z - actor->lastPos.z;
 
-			actor->lastPos.x = currentStepX;
-			actor->lastPos.y = currentStepY;
-			actor->lastPos.z = currentStepZ;
+			actor->lastPos.x = currentStep.x;
+			actor->lastPos.y = currentStep.y;
+			actor->lastPos.z = currentStep.z;
 
 			actor->dynamicFlags.bAnimEnded = 0;
 			actor->dynamicFlags.bAnimFrameReached = 0;
diff --git a/engines/twine/scene/animations.h b/engines/twine/scene/animations.h
index 2abe2bcbe8..0a87d4d603 100644
--- a/engines/twine/scene/animations.h
+++ b/engines/twine/scene/animations.h
@@ -56,12 +56,8 @@ private:
 	/** Last rotation angle */
 	int16 processLastRotationAngle = ANGLE_0; // processActorVar6
 
-	/** Current step X coornidate */
-	int16 currentStepX = 0;
-	/** Current step Y coornidate */
-	int16 currentStepY = 0;
-	/** Current step Z coornidate */
-	int16 currentStepZ = 0;
+	/** Current step coordinates */
+	I16Vec3 currentStep;
 
 public:
 	Animations(TwinEEngine *engine);


Commit: e0ba8d1d74ca0c3df4fd673bc8810f02d2176f75
    https://github.com/scummvm/scummvm/commit/e0ba8d1d74ca0c3df4fd673bc8810f02d2176f75
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:28+01:00

Commit Message:
TWINE: use IVec3 and minor cleanup

Changed paths:
    engines/twine/scene/animations.cpp
    engines/twine/scene/animations.h


diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index 3359a8c895..ae1bc9f54b 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -580,13 +580,9 @@ void Animations::processActorAnimations(int32 actorIdx) { // DoAnim
 			currentStep.x = _engine->_renderer->destPos.x;
 			currentStep.z = _engine->_renderer->destPos.z;
 
-			_engine->_movements->processActor.x = actor->pos.x + currentStep.x - actor->lastPos.x;
-			_engine->_movements->processActor.y = actor->pos.y + currentStep.y - actor->lastPos.y;
-			_engine->_movements->processActor.z = actor->pos.z + currentStep.z - actor->lastPos.z;
+			_engine->_movements->processActor = actor->pos + currentStep - actor->lastPos;
 
-			actor->lastPos.x = currentStep.x;
-			actor->lastPos.y = currentStep.y;
-			actor->lastPos.z = currentStep.z;
+			actor->lastPos = currentStep;
 
 			actor->dynamicFlags.bAnimEnded = 0;
 			actor->dynamicFlags.bAnimFrameReached = 0;
diff --git a/engines/twine/scene/animations.h b/engines/twine/scene/animations.h
index 0a87d4d603..3e98c9d4dc 100644
--- a/engines/twine/scene/animations.h
+++ b/engines/twine/scene/animations.h
@@ -57,7 +57,7 @@ private:
 	int16 processLastRotationAngle = ANGLE_0; // processActorVar6
 
 	/** Current step coordinates */
-	I16Vec3 currentStep;
+	IVec3 currentStep;
 
 public:
 	Animations(TwinEEngine *engine);


Commit: 750128b2cb971927c1b587786dc183d53f71e46e
    https://github.com/scummvm/scummvm/commit/750128b2cb971927c1b587786dc183d53f71e46e
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:28+01:00

Commit Message:
TWINE: minor cleanup

Changed paths:
    engines/twine/scene/animations.cpp


diff --git a/engines/twine/scene/animations.cpp b/engines/twine/scene/animations.cpp
index ae1bc9f54b..8f51703537 100644
--- a/engines/twine/scene/animations.cpp
+++ b/engines/twine/scene/animations.cpp
@@ -449,9 +449,7 @@ bool Animations::initAnim(AnimationTypes newAnim, AnimType animType, AnimationTy
 	processAnimActions(actorIdx);
 
 	actor->lastRotationAngle = ANGLE_0;
-	actor->lastPos.x = 0;
-	actor->lastPos.y = 0;
-	actor->lastPos.z = 0;
+	actor->lastPos = IVec3();
 
 	return true;
 }
@@ -600,7 +598,7 @@ void Animations::processActorAnimations(int32 actorIdx) { // DoAnim
 					if (actor->animType == AnimType::kAnimationTypeLoop) {
 						actor->animPosition = animData.getLoopFrame();
 					} else {
-						actor->anim = (AnimationTypes)actor->animExtra;
+						actor->anim = actor->animExtra;
 						actor->previousAnimIdx = getBodyAnimIndex(actor->anim, actorIdx);
 
 						if (actor->previousAnimIdx == -1) {


Commit: b6b9cd5fbda64dbdd6d67bee5fb49e8b78e8a1bd
    https://github.com/scummvm/scummvm/commit/b6b9cd5fbda64dbdd6d67bee5fb49e8b78e8a1bd
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:28+01:00

Commit Message:
TWINE: use IVec3 for bounding box checks

Changed paths:
    engines/twine/scene/collision.cpp
    engines/twine/scene/grid.h


diff --git a/engines/twine/scene/collision.cpp b/engines/twine/scene/collision.cpp
index 01932fd343..936774f3bb 100644
--- a/engines/twine/scene/collision.cpp
+++ b/engines/twine/scene/collision.cpp
@@ -44,51 +44,41 @@ bool Collision::standingOnActor(int32 actorIdx1, int32 actorIdx2) const {
 	const ActorStruct *actor1 = _engine->_scene->getActor(actorIdx1);
 	const ActorStruct *actor2 = _engine->_scene->getActor(actorIdx2);
 
-	// Current actor (actor 1)
-	const int32 x1Left = _engine->_movements->processActor.x + actor1->boudingBox.mins.x;
-	const int32 x1Right = _engine->_movements->processActor.x + actor1->boudingBox.maxs.x;
-	const int32 y1Left = _engine->_movements->processActor.y + actor1->boudingBox.mins.y;
-	const int32 y1Right = _engine->_movements->processActor.y + actor1->boudingBox.maxs.y;
-	const int32 z1Left = _engine->_movements->processActor.z + actor1->boudingBox.mins.z;
-	const int32 z1Right = _engine->_movements->processActor.z + actor1->boudingBox.maxs.z;
-
-	// Actor 2
-	const int32 x2Left = actor2->pos.x + actor2->boudingBox.mins.x;
-	const int32 x2Right = actor2->pos.x + actor2->boudingBox.maxs.x;
-	const int32 y2Left = actor2->pos.y + actor2->boudingBox.mins.y;
-	const int32 y2Right = actor2->pos.y + actor2->boudingBox.maxs.y;
-	const int32 z2Left = actor2->pos.z + actor2->boudingBox.mins.z;
-	const int32 z2Right = actor2->pos.z + actor2->boudingBox.maxs.z;
-
-	if (x1Left >= x2Right) {
-		return false; // not standing
+	const IVec3 &mins1 = _engine->_movements->processActor + actor1->boudingBox.mins;
+	const IVec3 &maxs1 = _engine->_movements->processActor + actor1->boudingBox.maxs;
+
+	const IVec3 &mins2 = actor2->pos + actor2->boudingBox.mins;
+	const IVec3 &maxs2 = actor2->pos + actor2->boudingBox.maxs;
+
+	if (mins1.x >= maxs2.x) {
+		return false;
 	}
 
-	if (x1Right <= x2Left) {
+	if (maxs1.x <= mins2.x) {
 		return false;
 	}
 
-	if (y1Left > (y2Right + 1)) {
+	if (mins1.y > (maxs2.y + 1)) {
 		return false;
 	}
 
-	if (y1Left <= (y2Right - 0x100)) {
+	if (mins1.y <= (maxs2.y - BRICK_HEIGHT)) {
 		return false;
 	}
 
-	if (y1Right <= y2Left) {
+	if (maxs1.y <= mins2.y) {
 		return false;
 	}
 
-	if (z1Left >= z2Right) {
+	if (mins1.z >= maxs2.z) {
 		return false;
 	}
 
-	if (z1Right <= z2Left) {
+	if (maxs1.z <= mins2.z) {
 		return false;
 	}
 
-	return true; // standing
+	return true;
 }
 
 int32 Collision::getAverageValue(int32 start, int32 end, int32 maxDelay, int32 delay) const {
@@ -202,12 +192,8 @@ void Collision::reajustActorPosition(ShapeType brickShape) {
 int32 Collision::checkCollisionWithActors(int32 actorIdx) {
 	ActorStruct *actor = _engine->_scene->getActor(actorIdx);
 
-	int32 xLeft = _engine->_movements->processActor.x + actor->boudingBox.mins.x;
-	int32 xRight = _engine->_movements->processActor.x + actor->boudingBox.maxs.x;
-	int32 yLeft = _engine->_movements->processActor.y + actor->boudingBox.mins.y;
-	int32 yRight = _engine->_movements->processActor.y + actor->boudingBox.maxs.y;
-	int32 zLeft = _engine->_movements->processActor.z + actor->boudingBox.mins.z;
-	int32 zRight = _engine->_movements->processActor.z + actor->boudingBox.maxs.z;
+	IVec3 mins = _engine->_movements->processActor + actor->boudingBox.mins;
+	IVec3 maxs = _engine->_movements->processActor + actor->boudingBox.maxs;
 
 	actor->collision = -1;
 
@@ -216,26 +202,22 @@ int32 Collision::checkCollisionWithActors(int32 actorIdx) {
 
 		// aviod current processed actor
 		if (a != actorIdx && actorTest->entity != -1 && !actor->staticFlags.bComputeLowCollision && actorTest->standOn != actorIdx) {
-			const int32 xLeftTest = actorTest->pos.x + actorTest->boudingBox.mins.x;
-			const int32 xRightTest = actorTest->pos.x + actorTest->boudingBox.maxs.x;
-			const int32 yLeftTest = actorTest->pos.y + actorTest->boudingBox.mins.y;
-			const int32 yRightTest = actorTest->pos.y + actorTest->boudingBox.maxs.y;
-			const int32 zLeftTest = actorTest->pos.z + actorTest->boudingBox.mins.z;
-			const int32 zRightTest = actorTest->pos.z + actorTest->boudingBox.maxs.z;
-
-			if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+			const IVec3 &minsTest = actorTest->pos + actorTest->boudingBox.mins;
+			const IVec3 &maxsTest = actorTest->pos + actorTest->boudingBox.maxs;
+
+			if (mins.x < maxsTest.x && maxs.x > minsTest.x && mins.y < maxsTest.y && maxs.y > minsTest.y && mins.z < maxsTest.z && maxs.z > minsTest.z) {
 				actor->collision = a; // mark as collision with actor a
 
 				if (actorTest->staticFlags.bIsCarrierActor) {
 					if (actor->dynamicFlags.bIsFalling) {
-						_engine->_movements->processActor.y = yRightTest - actor->boudingBox.mins.y + 1;
+						_engine->_movements->processActor.y = maxsTest.y - actor->boudingBox.mins.y + 1;
 						actor->standOn = a;
 					} else {
 						if (standingOnActor(actorIdx, a)) {
-							_engine->_movements->processActor.y = yRightTest - actor->boudingBox.mins.y + 1;
+							_engine->_movements->processActor.y = maxsTest.y - actor->boudingBox.mins.y + 1;
 							actor->standOn = a;
 						} else {
-							int32 newAngle = _engine->_movements->getAngleAndSetTargetActorDistance(_engine->_movements->processActor, actorTest->pos);
+							const int32 newAngle = _engine->_movements->getAngleAndSetTargetActorDistance(_engine->_movements->processActor, actorTest->pos);
 
 							if (actorTest->staticFlags.bCanBePushed && !actor->staticFlags.bCanBePushed) {
 								actorTest->lastPos.y = 0;
@@ -260,18 +242,18 @@ int32 Collision::checkCollisionWithActors(int32 actorIdx) {
 							}
 
 							if ((actorTest->boudingBox.maxs.x - actorTest->boudingBox.mins.x == actorTest->boudingBox.maxs.z - actorTest->boudingBox.mins.z) &&
-							    (actor->boudingBox.maxs.x - actor->boudingBox.mins.x == actor->boudingBox.maxs.z - actor->boudingBox.mins.z)) {
+								(actor->boudingBox.maxs.x - actor->boudingBox.mins.x == actor->boudingBox.maxs.z - actor->boudingBox.mins.z)) {
 								if (newAngle < ANGLE_135) {
-									_engine->_movements->processActor.x = xLeftTest - actor->boudingBox.maxs.x;
+									_engine->_movements->processActor.x = minsTest.x - actor->boudingBox.maxs.x;
 								}
 								if (newAngle >= ANGLE_135 && newAngle < ANGLE_225) {
-									_engine->_movements->processActor.z = zRightTest - actor->boudingBox.mins.z;
+									_engine->_movements->processActor.z = maxsTest.z - actor->boudingBox.mins.z;
 								}
 								if (newAngle >= ANGLE_225 && newAngle < ANGLE_315) {
-									_engine->_movements->processActor.x = xRightTest - actor->boudingBox.mins.x;
+									_engine->_movements->processActor.x = maxsTest.x - actor->boudingBox.mins.x;
 								}
 								if (newAngle >= ANGLE_315 || (newAngle < ANGLE_315 && newAngle < ANGLE_45)) {
-									_engine->_movements->processActor.z = zLeftTest - actor->boudingBox.maxs.z;
+									_engine->_movements->processActor.z = minsTest.z - actor->boudingBox.maxs.z;
 								}
 							} else {
 								if (!actor->dynamicFlags.bIsFalling) {
@@ -310,18 +292,18 @@ int32 Collision::checkCollisionWithActors(int32 actorIdx) {
 					}
 
 					if ((actorTest->boudingBox.maxs.x - actorTest->boudingBox.mins.x == actorTest->boudingBox.maxs.z - actorTest->boudingBox.mins.z) &&
-					    (actor->boudingBox.maxs.x - actor->boudingBox.mins.x == actor->boudingBox.maxs.z - actor->boudingBox.mins.z)) {
+						(actor->boudingBox.maxs.x - actor->boudingBox.mins.x == actor->boudingBox.maxs.z - actor->boudingBox.mins.z)) {
 						if (newAngle < ANGLE_135) {
-							_engine->_movements->processActor.x = xLeftTest - actor->boudingBox.maxs.x;
+							_engine->_movements->processActor.x = minsTest.x - actor->boudingBox.maxs.x;
 						}
 						if (newAngle >= ANGLE_135 && newAngle < ANGLE_225) {
-							_engine->_movements->processActor.z = zRightTest - actor->boudingBox.mins.z;
+							_engine->_movements->processActor.z = maxsTest.z - actor->boudingBox.mins.z;
 						}
 						if (newAngle >= ANGLE_225 && newAngle < ANGLE_315) {
-							_engine->_movements->processActor.x = xRightTest - actor->boudingBox.mins.x;
+							_engine->_movements->processActor.x = maxsTest.x - actor->boudingBox.mins.x;
 						}
 						if (newAngle >= ANGLE_315 || (newAngle < ANGLE_315 && newAngle < ANGLE_45)) {
-							_engine->_movements->processActor.z = zLeftTest - actor->boudingBox.maxs.z;
+							_engine->_movements->processActor.z = minsTest.z - actor->boudingBox.maxs.z;
 						}
 					} else {
 						if (!actor->dynamicFlags.bIsFalling) {
@@ -336,28 +318,22 @@ int32 Collision::checkCollisionWithActors(int32 actorIdx) {
 	if (actor->dynamicFlags.bIsHitting) {
 		_engine->_movements->rotateActor(0, 200, actor->angle);
 
-		xLeft = _engine->_renderer->destPos.x + _engine->_movements->processActor.x + actor->boudingBox.mins.x;
-		xRight = _engine->_renderer->destPos.x + _engine->_movements->processActor.x + actor->boudingBox.maxs.x;
-
-		yLeft = _engine->_movements->processActor.y + actor->boudingBox.mins.y;
-		yRight = _engine->_movements->processActor.y + actor->boudingBox.maxs.y;
+		mins.x = _engine->_renderer->destPos.x + _engine->_movements->processActor.x + actor->boudingBox.mins.x;
+		mins.y = _engine->_movements->processActor.y + actor->boudingBox.mins.y;
+		mins.z = _engine->_renderer->destPos.z + _engine->_movements->processActor.z + actor->boudingBox.mins.z;
 
-		zLeft = _engine->_renderer->destPos.z + _engine->_movements->processActor.z + actor->boudingBox.mins.z;
-		zRight = _engine->_renderer->destPos.z + _engine->_movements->processActor.z + actor->boudingBox.maxs.z;
+		maxs.x = _engine->_renderer->destPos.x + _engine->_movements->processActor.x + actor->boudingBox.maxs.x;
+		maxs.y = _engine->_movements->processActor.y + actor->boudingBox.maxs.y;
+		maxs.z = _engine->_renderer->destPos.z + _engine->_movements->processActor.z + actor->boudingBox.maxs.z;
 
 		for (int32 a = 0; a < _engine->_scene->sceneNumActors; a++) {
 			const ActorStruct *actorTest = _engine->_scene->getActor(a);
 
 			// aviod current processed actor
 			if (a != actorIdx && actorTest->entity != -1 && !actorTest->staticFlags.bIsHidden && actorTest->standOn != actorIdx) {
-				const int32 xLeftTest =  actorTest->pos.x + actorTest->boudingBox.mins.x;
-				const int32 xRightTest = actorTest->pos.x + actorTest->boudingBox.maxs.x;
-				const int32 yLeftTest =  actorTest->pos.y + actorTest->boudingBox.mins.y;
-				const int32 yRightTest = actorTest->pos.y + actorTest->boudingBox.maxs.y;
-				const int32 zLeftTest =  actorTest->pos.z + actorTest->boudingBox.mins.z;
-				const int32 zRightTest = actorTest->pos.z + actorTest->boudingBox.maxs.z;
-
-				if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+				const IVec3 minsTest = actorTest->pos + actorTest->boudingBox.mins;
+				const IVec3 maxsTest = actorTest->pos + actorTest->boudingBox.maxs;
+				if (mins.x < maxsTest.x && maxs.x > minsTest.x && mins.y < maxsTest.y && maxs.y > minsTest.y && mins.z < maxsTest.z && maxs.z > minsTest.z) {
 					_engine->_actor->hitActor(actorIdx, a, actor->strengthOfHit, actor->angle + ANGLE_180);
 					actor->dynamicFlags.bIsHitting = 0;
 				}
@@ -369,7 +345,7 @@ int32 Collision::checkCollisionWithActors(int32 actorIdx) {
 }
 
 void Collision::checkHeroCollisionWithBricks(int32 x, int32 y, int32 z, int32 damageMask) {
-	ShapeType brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActor.x, _engine->_movements->processActor.y, _engine->_movements->processActor.z);
+	ShapeType brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActor);
 
 	_engine->_movements->processActor.x += x;
 	_engine->_movements->processActor.y += y;
@@ -377,7 +353,7 @@ void Collision::checkHeroCollisionWithBricks(int32 x, int32 y, int32 z, int32 da
 
 	if (_engine->_movements->processActor.x >= 0 && _engine->_movements->processActor.z >= 0 && _engine->_movements->processActor.x <= 0x7E00 && _engine->_movements->processActor.z <= 0x7E00) {
 		reajustActorPosition(brickShape);
-		brickShape = _engine->_grid->getBrickShapeFull(_engine->_movements->processActor.x, _engine->_movements->processActor.y, _engine->_movements->processActor.z, _engine->_actor->processActorPtr->boudingBox.maxs.y);
+		brickShape = _engine->_grid->getBrickShapeFull(_engine->_movements->processActor, _engine->_actor->processActorPtr->boudingBox.maxs.y);
 
 		if (brickShape == ShapeType::kSolid) {
 			causeActorDamage |= damageMask;
@@ -399,7 +375,7 @@ void Collision::checkHeroCollisionWithBricks(int32 x, int32 y, int32 z, int32 da
 }
 
 void Collision::checkActorCollisionWithBricks(int32 x, int32 y, int32 z, int32 damageMask) {
-	ShapeType brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActor.x, _engine->_movements->processActor.y, _engine->_movements->processActor.z);
+	ShapeType brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActor);
 
 	_engine->_movements->processActor.x += x;
 	_engine->_movements->processActor.y += y;
@@ -407,7 +383,7 @@ void Collision::checkActorCollisionWithBricks(int32 x, int32 y, int32 z, int32 d
 
 	if (_engine->_movements->processActor.x >= 0 && _engine->_movements->processActor.z >= 0 && _engine->_movements->processActor.x <= 0x7E00 && _engine->_movements->processActor.z <= 0x7E00) {
 		reajustActorPosition(brickShape);
-		brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActor.x, _engine->_movements->processActor.y, _engine->_movements->processActor.z);
+		brickShape = _engine->_grid->getBrickShape(_engine->_movements->processActor);
 
 		if (brickShape == ShapeType::kSolid) {
 			causeActorDamage |= damageMask;
@@ -456,25 +432,17 @@ void Collision::stopFalling() { // ReceptionObj()
 
 int32 Collision::checkExtraCollisionWithActors(ExtraListStruct *extra, int32 actorIdx) {
 	const BoundingBox *bbox = _engine->_resources->spriteBoundingBox.bbox(extra->info0);
-	const int32 xLeft = bbox->mins.x + extra->pos.x;
-	const int32 xRight = bbox->maxs.x + extra->pos.x;
-	const int32 yLeft = bbox->mins.y + extra->pos.y;
-	const int32 yRight = bbox->maxs.y + extra->pos.y;
-	const int32 zLeft = bbox->mins.z + extra->pos.z;
-	const int32 zRight = bbox->maxs.z + extra->pos.z;
+	const IVec3 mins = bbox->mins + extra->pos;
+	const IVec3 maxs = bbox->maxs + extra->pos;
 
 	for (int32 a = 0; a < _engine->_scene->sceneNumActors; a++) {
 		const ActorStruct *actorTest = _engine->_scene->getActor(a);
 
 		if (a != actorIdx && actorTest->entity != -1) {
-			const int32 xLeftTest = actorTest->pos.x + actorTest->boudingBox.mins.x;
-			const int32 xRightTest = actorTest->pos.x + actorTest->boudingBox.maxs.x;
-			const int32 yLeftTest = actorTest->pos.y + actorTest->boudingBox.mins.y;
-			const int32 yRightTest = actorTest->pos.y + actorTest->boudingBox.maxs.y;
-			const int32 zLeftTest = actorTest->pos.z + actorTest->boudingBox.mins.z;
-			const int32 zRightTest = actorTest->pos.z + actorTest->boudingBox.maxs.z;
-
-			if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
+			const IVec3 minsTest = actorTest->pos + actorTest->boudingBox.mins;
+			const IVec3 maxsTest = actorTest->pos + actorTest->boudingBox.maxs;
+
+			if (mins.x < maxsTest.x && maxs.x > minsTest.x && mins.y < maxsTest.y && maxs.y > minsTest.y && mins.z < maxsTest.z && maxs.z > minsTest.z) {
 				if (extra->strengthOfHit != 0) {
 					_engine->_actor->hitActor(actorIdx, a, extra->strengthOfHit, -1);
 				}
@@ -514,29 +482,22 @@ bool Collision::checkExtraCollisionWithBricks(int32 x, int32 y, int32 z, int32 o
 int32 Collision::checkExtraCollisionWithExtra(ExtraListStruct *extra, int32 extraIdx) const {
 	int32 index = extra->info0;
 	const BoundingBox *bbox = _engine->_resources->spriteBoundingBox.bbox(index);
-	const int32 xLeft = bbox->mins.x + extra->pos.x;
-	const int32 xRight = bbox->maxs.x + extra->pos.x;
-	const int32 yLeft = bbox->mins.y + extra->pos.y;
-	const int32 yRight = bbox->maxs.y + extra->pos.y;
-	const int32 zLeft = bbox->mins.z + extra->pos.z;
-	const int32 zRight = bbox->maxs.z + extra->pos.z;
+	const IVec3 mins = bbox->mins + extra->pos;
+	const IVec3 maxs = bbox->maxs + extra->pos;
 
 	for (int32 i = 0; i < EXTRA_MAX_ENTRIES; i++) {
 		const ExtraListStruct *extraTest = &_engine->_extra->extraList[i];
 		if (i != extraIdx && extraTest->info0 != -1) {
 			// TODO: shouldn't this be extraTest->info0 as index?
 			const BoundingBox *testbbox = _engine->_resources->spriteBoundingBox.bbox(++index);
-			const int32 xLeftTest = testbbox->mins.x + extraTest->pos.x;
-			const int32 xRightTest = testbbox->maxs.x + extraTest->pos.x;
-			const int32 yLeftTest = testbbox->mins.y + extraTest->pos.y;
-			const int32 yRightTest = testbbox->maxs.y + extraTest->pos.y;
-			const int32 zLeftTest = testbbox->mins.z + extraTest->pos.z;
-			const int32 zRightTest = testbbox->maxs.z + extraTest->pos.z;
-
-			if (xLeft < xLeftTest) {
-				if (xLeft < xRightTest && xRight > xLeftTest && yLeft < yRightTest && yRight > yLeftTest && zLeft < zRightTest && zRight > zLeftTest) {
-					return i;
-				}
+			const IVec3 minsTest = testbbox->mins + extraTest->pos;
+			const IVec3 maxsTest = testbbox->maxs + extraTest->pos;
+
+			if (mins.x >= minsTest.x) {
+				continue;
+			}
+			if (mins.x < maxsTest.x && maxs.x > minsTest.x && mins.y < maxsTest.y && maxs.y > minsTest.y && mins.z < maxsTest.z && maxs.z > minsTest.z) {
+				return i;
 			}
 		}
 	}
diff --git a/engines/twine/scene/grid.h b/engines/twine/scene/grid.h
index 527d9052dd..09b6b22fc4 100644
--- a/engines/twine/scene/grid.h
+++ b/engines/twine/scene/grid.h
@@ -294,6 +294,18 @@ public:
 	ShapeType getBrickShapeFull(int32 x, int32 y, int32 z, int32 y2);
 
 	int32 getBrickSoundType(int32 x, int32 y, int32 z);
+
+	inline ShapeType getBrickShape(const IVec3 &pos) {
+		return getBrickShape(pos.x, pos.y, pos.z);
+	}
+
+	inline ShapeType getBrickShapeFull(const IVec3 &pos, int32 y2) {
+		return getBrickShapeFull(pos.x, pos.y, pos.z, y2);
+	}
+
+	inline int32 getBrickSoundType(const IVec3 &pos) {
+		return getBrickSoundType(pos.x, pos.y, pos.z);
+	}
 };
 
 } // namespace TwinE


Commit: 1af583e6bd2c5244022c784f83e81ffc1972f0ee
    https://github.com/scummvm/scummvm/commit/1af583e6bd2c5244022c784f83e81ffc1972f0ee
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-03-27T13:35:28+01:00

Commit Message:
TWINE: optimized renderPolygons by not looping twice over all the vertices

... to compute the bounding box

Changed paths:
    engines/twine/renderer/renderer.cpp
    engines/twine/renderer/renderer.h
    engines/twine/text.cpp


diff --git a/engines/twine/renderer/renderer.cpp b/engines/twine/renderer/renderer.cpp
index 3fe8e6ca50..551cd1b32c 100644
--- a/engines/twine/renderer/renderer.cpp
+++ b/engines/twine/renderer/renderer.cpp
@@ -424,27 +424,10 @@ void Renderer::setLightVector(int32 angleX, int32 angleY, int32 angleZ) {
 	_lightPos = destPos;
 }
 
-FORCEINLINE int16 clamp(int16 x, int16 a, int16 b) {
+static FORCEINLINE int16 clamp(int16 x, int16 a, int16 b) {
 	return x < a ? a : (x > b ? b : x);
 }
 
-void Renderer::computeBoundingBox(Vertex *vertices, int32 numVertices, int &vleft, int &vright, int &vtop, int &vbottom) const {
-	vleft = vtop = SCENE_SIZE_MAX;
-	vright = vbottom = SCENE_SIZE_MIN;
-	const int16 maxWidth = _engine->width() - 1;
-	const int16 maxHeight = _engine->height() - 1;
-
-	for (int32 i = 0; i < numVertices; i++) {
-		vertices[i].x = clamp(vertices[i].x, 0, maxWidth);
-		vleft = MIN<int>(vleft, vertices[i].x);
-		vright = MAX<int>(vright, vertices[i].x);
-
-		vertices[i].y = clamp(vertices[i].y, 0, maxHeight);
-		vtop = MIN<int>(vtop, vertices[i].y);
-		vbottom = MAX<int>(vbottom, vertices[i].y);
-	}
-}
-
 void Renderer::computePolygons(int16 polyRenderType, const Vertex *vertices, int32 numVertices) {
 	uint8 vertexParam1 = vertices[numVertices - 1].colorIndex;
 	int16 currentVertexX = vertices[numVertices - 1].x;
@@ -1013,15 +996,7 @@ void Renderer::renderPolygonsDither(uint8 *out, int vtop, int32 vsize) const {
 void Renderer::renderPolygonsMarble(uint8 *out, int vtop, int32 vsize, uint8 color) const {
 }
 
-void Renderer::renderPolygons(const CmdRenderPolygon &polygon, Vertex *vertices) {
-	int vleft = 0;
-	int vright = 0;
-	int vtop = 0;
-	int vbottom = 0;
-
-	if (polygon.numVertices > 0) {
-		computeBoundingBox(vertices, polygon.numVertices, vleft, vright, vtop, vbottom);
-	}
+void Renderer::renderPolygons(const CmdRenderPolygon &polygon, Vertex *vertices, int vtop, int vbottom) {
 	computePolygons(polygon.renderType, vertices, polygon.numVertices);
 
 	uint8 *out = (uint8 *)_engine->frontVideoBuffer.getBasePtr(0, vtop);
@@ -1119,6 +1094,9 @@ uint8 *Renderer::prepareLines(const Common::Array<BodyLine> &lines, int32 &numOf
 }
 
 uint8 *Renderer::preparePolygons(const Common::Array<BodyPolygon> &polygons, int32 &numOfPrimitives, RenderCommand **renderCmds, uint8 *renderBufferPtr, ModelData *modelData) {
+	const int16 maxHeight = _engine->height() - 1;
+	const int16 maxWidth = _engine->width() - 1;
+
 	for (const BodyPolygon &polygon : polygons) {
 		const uint8 renderType = polygon.renderType;
 		const uint8 numVertices = polygon.indices.size();
@@ -1129,6 +1107,8 @@ uint8 *Renderer::preparePolygons(const Common::Array<BodyPolygon> &polygons, int
 
 		CmdRenderPolygon *destinationPolygon = (CmdRenderPolygon *)renderBufferPtr;
 		destinationPolygon->numVertices = numVertices;
+		destinationPolygon->top = SCENE_SIZE_MAX;
+		destinationPolygon->bottom = SCENE_SIZE_MIN;
 
 		renderBufferPtr += sizeof(CmdRenderPolygon);
 
@@ -1149,8 +1129,10 @@ uint8 *Renderer::preparePolygons(const Common::Array<BodyPolygon> &polygons, int
 				const I16Vec3 *point = &modelData->flattenPoints[vertexIndex];
 
 				vertex->colorIndex = shadeValue;
-				vertex->x = point->x;
-				vertex->y = point->y;
+				vertex->x = clamp(point->x, 0, maxWidth);
+				vertex->y = clamp(point->y, 0, maxHeight);
+				destinationPolygon->top = MIN<int>(destinationPolygon->top, vertex->y);
+				destinationPolygon->bottom = MAX<int>(destinationPolygon->bottom, vertex->y);
 				bestDepth = MAX(bestDepth, point->z);
 				++vertex;
 			}
@@ -1172,8 +1154,10 @@ uint8 *Renderer::preparePolygons(const Common::Array<BodyPolygon> &polygons, int
 				const I16Vec3 *point = &modelData->flattenPoints[vertexIndex];
 
 				vertex->colorIndex = destinationPolygon->colorIndex;
-				vertex->x = point->x;
-				vertex->y = point->y;
+				vertex->x = clamp(point->x, 0, maxWidth);
+				vertex->y = clamp(point->y, 0, maxHeight);
+				destinationPolygon->top = MIN<int>(destinationPolygon->top, vertex->y);
+				destinationPolygon->bottom = MAX<int>(destinationPolygon->bottom, vertex->y);
 				bestDepth = MAX(bestDepth, point->z);
 				++vertex;
 			}
@@ -1229,7 +1213,7 @@ bool Renderer::renderModelElements(int32 numOfPrimitives, const BodyData &bodyDa
 		case RENDERTYPE_DRAWPOLYGON: {
 			const CmdRenderPolygon *header = (const CmdRenderPolygon *)pointer;
 			Vertex *vertices = (Vertex *)(pointer + sizeof(CmdRenderPolygon));
-			renderPolygons(*header, vertices);
+			renderPolygons(*header, vertices, header->top, header->bottom);
 			break;
 		}
 		case RENDERTYPE_DRAWSPHERE: {
diff --git a/engines/twine/renderer/renderer.h b/engines/twine/renderer/renderer.h
index 9948486cdc..903f6f60a7 100644
--- a/engines/twine/renderer/renderer.h
+++ b/engines/twine/renderer/renderer.h
@@ -58,6 +58,8 @@ struct CmdRenderPolygon {
 	uint8 renderType = 0;
 	uint8 numVertices = 0;
 	int16 colorIndex = 0;
+	int16 top = 0;
+	int16 bottom = 0;
 	// followed by Vertex array
 };
 
@@ -192,7 +194,6 @@ private:
 	void renderPolygonsDither(uint8 *out, int vtop, int32 vsize) const;
 	void renderPolygonsMarble(uint8 *out, int vtop, int32 vsize, uint8 color) const;
 
-	void computeBoundingBox(Vertex *vertices, int32 numVertices, int &vleft, int &vright, int &vtop, int &vbottom) const;
 	void computePolygons(int16 polyRenderType, const Vertex *vertices, int32 numVertices);
 
 	const RenderCommand *depthSortRenderCommands(int32 numOfPrimitives);
@@ -221,7 +222,7 @@ public:
 	void setLightVector(int32 angleX, int32 angleY, int32 angleZ);
 	void getBaseRotationPosition(int32 x, int32 y, int32 z);
 
-	void renderPolygons(const CmdRenderPolygon &polygon, Vertex *vertices);
+	void renderPolygons(const CmdRenderPolygon &polygon, Vertex *vertices, int vtop, int vbottom);
 
 	inline int32 projectPositionOnScreen(const IVec3& pos) {
 		return projectPositionOnScreen(pos.x, pos.y, pos.z);
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 9c5664c16e..6dde524a8d 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -489,7 +489,7 @@ void Text::renderContinueReadingTriangle() {
 	polygon.numVertices = ARRAYSIZE(vertices);
 	polygon.colorIndex = _dialTextStopColor;
 	polygon.renderType = POLYGONTYPE_FLAT;
-	_engine->_renderer->renderPolygons(polygon, vertices);
+	_engine->_renderer->renderPolygons(polygon, vertices, top, bottom);
 
 	_engine->copyBlockPhys(Common::Rect(left, top, right, bottom));
 }




More information about the Scummvm-git-logs mailing list