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