1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "twine/parser/body.h"
24 #include "twine/renderer/renderer.h"
25 #include "common/memstream.h"
26
27 namespace TwinE {
28
reset()29 void BodyData::reset() {
30 _vertices.clear();
31 _bones.clear();
32 _shades.clear();
33 _polygons.clear();
34 _spheres.clear();
35 _lines.clear();
36 }
37
loadVertices(Common::SeekableReadStream & stream)38 void BodyData::loadVertices(Common::SeekableReadStream &stream) {
39 const uint16 numVertices = stream.readUint16LE();
40 if (stream.eos())
41 return;
42
43 _vertices.reserve(numVertices);
44 for (uint16 i = 0U; i < numVertices; ++i) {
45 const int16 x = stream.readSint16LE();
46 const int16 y = stream.readSint16LE();
47 const int16 z = stream.readSint16LE();
48 const uint16 bone = 0;
49 _vertices.push_back({x, y, z, bone});
50 }
51 }
52
loadBones(Common::SeekableReadStream & stream)53 void BodyData::loadBones(Common::SeekableReadStream &stream) {
54 const uint16 numBones = stream.readUint16LE();
55 if (stream.eos())
56 return;
57
58 _bones.reserve(numBones);
59 for (uint16 i = 0; i < numBones; ++i) {
60 const int16 firstPoint = stream.readSint16LE() / 6;
61 const int16 numPoints = stream.readSint16LE();
62 const int16 basePoint = stream.readSint16LE() / 6;
63 const int16 baseElementOffset = stream.readSint16LE();
64 BoneFrame boneframe;
65 boneframe.type = stream.readSint16LE();
66 boneframe.x = stream.readSint16LE();
67 boneframe.y = stream.readSint16LE();
68 boneframe.z = stream.readSint16LE();
69 /*int16 unk1 =*/ stream.readSint16LE();
70 const int16 numOfShades = stream.readSint16LE();
71 /*int16 unk2 =*/ stream.readSint16LE();
72 /*int32 field_18 =*/ stream.readSint32LE();
73 /*int32 y =*/ stream.readSint32LE();
74 /*int32 field_20 =*/ stream.readSint32LE();
75 /*int32 field_24 =*/ stream.readSint32LE();
76
77 BodyBone bone;
78 bone.parent = baseElementOffset == -1 ? 0xffff : baseElementOffset / 38;
79 bone.vertex = basePoint;
80 bone.firstVertex = firstPoint;
81 bone.numVertices = numPoints;
82 bone.initalBoneState = boneframe;
83 bone.numOfShades = numOfShades;
84
85 // assign the bone index to the vertices
86 for (int j = 0; j < numPoints; ++j) {
87 _vertices[firstPoint + j].bone = i;
88 }
89
90 _bones.push_back(bone);
91 _boneStates[i] = bone.initalBoneState;
92 }
93 }
94
loadShades(Common::SeekableReadStream & stream)95 void BodyData::loadShades(Common::SeekableReadStream &stream) {
96 const uint16 numShades = stream.readUint16LE();
97 if (stream.eos())
98 return;
99
100 _shades.reserve(numShades);
101 for (uint16 i = 0; i < numShades; ++i) {
102 BodyShade shape;
103 shape.col1 = stream.readSint16LE();
104 shape.col2 = stream.readSint16LE();
105 shape.col3 = stream.readSint16LE();
106 shape.unk4 = stream.readUint16LE();
107 _shades.push_back(shape);
108 }
109 }
110
loadPolygons(Common::SeekableReadStream & stream)111 void BodyData::loadPolygons(Common::SeekableReadStream &stream) {
112 const uint16 numPolygons = stream.readUint16LE();
113 if (stream.eos())
114 return;
115
116 _polygons.reserve(numPolygons);
117 for (uint16 i = 0; i < numPolygons; ++i) {
118 BodyPolygon poly;
119 poly.renderType = stream.readByte();
120 const uint8 numVertices = stream.readByte();
121
122 poly.color = stream.readSint16LE();
123 int16 intensity = -1;
124 if (poly.renderType == POLYGONTYPE_GOURAUD || poly.renderType == POLYGONTYPE_DITHER) {
125 intensity = stream.readSint16LE();
126 }
127
128 poly.indices.reserve(numVertices);
129 poly.intensities.reserve(numVertices);
130 for (int k = 0; k < numVertices; ++k) {
131 if (poly.renderType >= POLYGONTYPE_UNKNOWN) {
132 intensity = stream.readSint16LE();
133 }
134 const uint16 vertexIndex = stream.readUint16LE() / 6;
135 poly.indices.push_back(vertexIndex);
136 poly.intensities.push_back(intensity);
137 }
138
139 _polygons.push_back(poly);
140 }
141 }
142
loadLines(Common::SeekableReadStream & stream)143 void BodyData::loadLines(Common::SeekableReadStream &stream) {
144 const uint16 numLines = stream.readUint16LE();
145 if (stream.eos())
146 return;
147
148 _lines.reserve(numLines);
149 for (uint16 i = 0; i < numLines; ++i) {
150 BodyLine line;
151 stream.skip(1);
152 line.color = stream.readByte();
153 stream.skip(2);
154 line.vertex1 = stream.readUint16LE() / 6;
155 line.vertex2 = stream.readUint16LE() / 6;
156 _lines.push_back(line);
157 }
158 }
159
loadSpheres(Common::SeekableReadStream & stream)160 void BodyData::loadSpheres(Common::SeekableReadStream &stream) {
161 const uint16 numSpheres = stream.readUint16LE();
162 if (stream.eos())
163 return;
164
165 _spheres.reserve(numSpheres);
166 for (uint16 i = 0; i < numSpheres; ++i) {
167 BodySphere sphere;
168 sphere.fillType = stream.readByte();
169 sphere.color = stream.readUint16LE();
170 stream.readByte();
171 sphere.radius = stream.readUint16LE();
172 sphere.vertex = stream.readUint16LE() / 6;
173 _spheres.push_back(sphere);
174 }
175 }
176
loadFromStream(Common::SeekableReadStream & stream,bool lba1)177 bool BodyData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
178 reset();
179 if (lba1) {
180 const uint16 flags = stream.readUint16LE();
181 animated = (flags & 2) != 0;
182 bbox.mins.x = stream.readSint16LE();
183 bbox.maxs.x = stream.readSint16LE();
184 bbox.mins.y = stream.readSint16LE();
185 bbox.maxs.y = stream.readSint16LE();
186 bbox.mins.z = stream.readSint16LE();
187 bbox.maxs.z = stream.readSint16LE();
188
189 stream.seek(0x1A);
190 loadVertices(stream);
191 loadBones(stream);
192 loadShades(stream);
193 loadPolygons(stream);
194 loadLines(stream);
195 loadSpheres(stream);
196 } else {
197 const uint32 flags = stream.readUint32LE();
198 animated = (flags & 2) != 0;
199 stream.skip(4);
200 bbox.mins.x = stream.readSint32LE();
201 bbox.maxs.x = stream.readSint32LE();
202 bbox.mins.y = stream.readSint32LE();
203 bbox.maxs.y = stream.readSint32LE();
204 bbox.mins.z = stream.readSint32LE();
205 bbox.maxs.z = stream.readSint32LE();
206 stream.seek(0x20);
207 #if 0
208 const uint32 bonesSize = stream.readUint32LE();
209 const uint32 bonesOffset = stream.readUint32LE();
210 const uint32 verticesSize = stream.readUint32LE();
211 const uint32 verticesOffset = stream.readUint32LE();
212 const uint32 normalsSize = stream.readUint32LE();
213 const uint32 normalsOffset = stream.readUint32LE();
214 const uint32 unk1Size = stream.readUint32LE();
215 const uint32 unk1Offset = stream.readUint32LE();
216 const uint32 polygonsSize = stream.readUint32LE();
217 const uint32 polygonsOffset = stream.readUint32LE();
218 const uint32 linesSize = stream.readUint32LE();
219 const uint32 linesOffset = stream.readUint32LE();
220 const uint32 spheresSize = stream.readUint32LE();
221 const uint32 spheresOffset = stream.readUint32LE();
222 const uint32 uvGroupsSize = stream.readUint32LE();
223 const uint32 uvGroupsOffset = stream.readUint32LE();
224 #endif
225 }
226
227 return !stream.err();
228 }
229
230 } // namespace TwinE
231