1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #include "IrrCompileConfig.h"
6 #ifdef _IRR_COMPILE_WITH_MD2_LOADER_
7 
8 #include "CAnimatedMeshMD2.h"
9 #include "SColor.h"
10 #include "irrMath.h"
11 
12 namespace irr
13 {
14 namespace scene
15 {
16 
17 const s32 MD2_FRAME_SHIFT	= 2;
18 const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / (1 << MD2_FRAME_SHIFT);
19 
20 const s32 Q2_VERTEX_NORMAL_TABLE_SIZE = 162;
21 
22 static const f32 Q2_VERTEX_NORMAL_TABLE[Q2_VERTEX_NORMAL_TABLE_SIZE][3] = {
23 	{-0.525731f, 0.000000f, 0.850651f},
24 	{-0.442863f, 0.238856f, 0.864188f},
25 	{-0.295242f, 0.000000f, 0.955423f},
26 	{-0.309017f, 0.500000f, 0.809017f},
27 	{-0.162460f, 0.262866f, 0.951056f},
28 	{0.000000f, 0.000000f, 1.000000f},
29 	{0.000000f, 0.850651f, 0.525731f},
30 	{-0.147621f, 0.716567f, 0.681718f},
31 	{0.147621f, 0.716567f, 0.681718f},
32 	{0.000000f, 0.525731f, 0.850651f},
33 	{0.309017f, 0.500000f, 0.809017f},
34 	{0.525731f, 0.000000f, 0.850651f},
35 	{0.295242f, 0.000000f, 0.955423f},
36 	{0.442863f, 0.238856f, 0.864188f},
37 	{0.162460f, 0.262866f, 0.951056f},
38 	{-0.681718f, 0.147621f, 0.716567f},
39 	{-0.809017f, 0.309017f, 0.500000f},
40 	{-0.587785f, 0.425325f, 0.688191f},
41 	{-0.850651f, 0.525731f, 0.000000f},
42 	{-0.864188f, 0.442863f, 0.238856f},
43 	{-0.716567f, 0.681718f, 0.147621f},
44 	{-0.688191f, 0.587785f, 0.425325f},
45 	{-0.500000f, 0.809017f, 0.309017f},
46 	{-0.238856f, 0.864188f, 0.442863f},
47 	{-0.425325f, 0.688191f, 0.587785f},
48 	{-0.716567f, 0.681718f, -0.147621f},
49 	{-0.500000f, 0.809017f, -0.309017f},
50 	{-0.525731f, 0.850651f, 0.000000f},
51 	{0.000000f, 0.850651f, -0.525731f},
52 	{-0.238856f, 0.864188f, -0.442863f},
53 	{0.000000f, 0.955423f, -0.295242f},
54 	{-0.262866f, 0.951056f, -0.162460f},
55 	{0.000000f, 1.000000f, 0.000000f},
56 	{0.000000f, 0.955423f, 0.295242f},
57 	{-0.262866f, 0.951056f, 0.162460f},
58 	{0.238856f, 0.864188f, 0.442863f},
59 	{0.262866f, 0.951056f, 0.162460f},
60 	{0.500000f, 0.809017f, 0.309017f},
61 	{0.238856f, 0.864188f, -0.442863f},
62 	{0.262866f, 0.951056f, -0.162460f},
63 	{0.500000f, 0.809017f, -0.309017f},
64 	{0.850651f, 0.525731f, 0.000000f},
65 	{0.716567f, 0.681718f, 0.147621f},
66 	{0.716567f, 0.681718f, -0.147621f},
67 	{0.525731f, 0.850651f, 0.000000f},
68 	{0.425325f, 0.688191f, 0.587785f},
69 	{0.864188f, 0.442863f, 0.238856f},
70 	{0.688191f, 0.587785f, 0.425325f},
71 	{0.809017f, 0.309017f, 0.500000f},
72 	{0.681718f, 0.147621f, 0.716567f},
73 	{0.587785f, 0.425325f, 0.688191f},
74 	{0.955423f, 0.295242f, 0.000000f},
75 	{1.000000f, 0.000000f, 0.000000f},
76 	{0.951056f, 0.162460f, 0.262866f},
77 	{0.850651f, -0.525731f, 0.000000f},
78 	{0.955423f, -0.295242f, 0.000000f},
79 	{0.864188f, -0.442863f, 0.238856f},
80 	{0.951056f, -0.162460f, 0.262866f},
81 	{0.809017f, -0.309017f, 0.500000f},
82 	{0.681718f, -0.147621f, 0.716567f},
83 	{0.850651f, 0.000000f, 0.525731f},
84 	{0.864188f, 0.442863f, -0.238856f},
85 	{0.809017f, 0.309017f, -0.500000f},
86 	{0.951056f, 0.162460f, -0.262866f},
87 	{0.525731f, 0.000000f, -0.850651f},
88 	{0.681718f, 0.147621f, -0.716567f},
89 	{0.681718f, -0.147621f, -0.716567f},
90 	{0.850651f, 0.000000f, -0.525731f},
91 	{0.809017f, -0.309017f, -0.500000f},
92 	{0.864188f, -0.442863f, -0.238856f},
93 	{0.951056f, -0.162460f, -0.262866f},
94 	{0.147621f, 0.716567f, -0.681718f},
95 	{0.309017f, 0.500000f, -0.809017f},
96 	{0.425325f, 0.688191f, -0.587785f},
97 	{0.442863f, 0.238856f, -0.864188f},
98 	{0.587785f, 0.425325f, -0.688191f},
99 	{0.688191f, 0.587785f, -0.425325f},
100 	{-0.147621f, 0.716567f, -0.681718f},
101 	{-0.309017f, 0.500000f, -0.809017f},
102 	{0.000000f, 0.525731f, -0.850651f},
103 	{-0.525731f, 0.000000f, -0.850651f},
104 	{-0.442863f, 0.238856f, -0.864188f},
105 	{-0.295242f, 0.000000f, -0.955423f},
106 	{-0.162460f, 0.262866f, -0.951056f},
107 	{0.000000f, 0.000000f, -1.000000f},
108 	{0.295242f, 0.000000f, -0.955423f},
109 	{0.162460f, 0.262866f, -0.951056f},
110 	{-0.442863f, -0.238856f, -0.864188f},
111 	{-0.309017f, -0.500000f, -0.809017f},
112 	{-0.162460f, -0.262866f, -0.951056f},
113 	{0.000000f, -0.850651f, -0.525731f},
114 	{-0.147621f, -0.716567f, -0.681718f},
115 	{0.147621f, -0.716567f, -0.681718f},
116 	{0.000000f, -0.525731f, -0.850651f},
117 	{0.309017f, -0.500000f, -0.809017f},
118 	{0.442863f, -0.238856f, -0.864188f},
119 	{0.162460f, -0.262866f, -0.951056f},
120 	{0.238856f, -0.864188f, -0.442863f},
121 	{0.500000f, -0.809017f, -0.309017f},
122 	{0.425325f, -0.688191f, -0.587785f},
123 	{0.716567f, -0.681718f, -0.147621f},
124 	{0.688191f, -0.587785f, -0.425325f},
125 	{0.587785f, -0.425325f, -0.688191f},
126 	{0.000000f, -0.955423f, -0.295242f},
127 	{0.000000f, -1.000000f, 0.000000f},
128 	{0.262866f, -0.951056f, -0.162460f},
129 	{0.000000f, -0.850651f, 0.525731f},
130 	{0.000000f, -0.955423f, 0.295242f},
131 	{0.238856f, -0.864188f, 0.442863f},
132 	{0.262866f, -0.951056f, 0.162460f},
133 	{0.500000f, -0.809017f, 0.309017f},
134 	{0.716567f, -0.681718f, 0.147621f},
135 	{0.525731f, -0.850651f, 0.000000f},
136 	{-0.238856f, -0.864188f, -0.442863f},
137 	{-0.500000f, -0.809017f, -0.309017f},
138 	{-0.262866f, -0.951056f, -0.162460f},
139 	{-0.850651f, -0.525731f, 0.000000f},
140 	{-0.716567f, -0.681718f, -0.147621f},
141 	{-0.716567f, -0.681718f, 0.147621f},
142 	{-0.525731f, -0.850651f, 0.000000f},
143 	{-0.500000f, -0.809017f, 0.309017f},
144 	{-0.238856f, -0.864188f, 0.442863f},
145 	{-0.262866f, -0.951056f, 0.162460f},
146 	{-0.864188f, -0.442863f, 0.238856f},
147 	{-0.809017f, -0.309017f, 0.500000f},
148 	{-0.688191f, -0.587785f, 0.425325f},
149 	{-0.681718f, -0.147621f, 0.716567f},
150 	{-0.442863f, -0.238856f, 0.864188f},
151 	{-0.587785f, -0.425325f, 0.688191f},
152 	{-0.309017f, -0.500000f, 0.809017f},
153 	{-0.147621f, -0.716567f, 0.681718f},
154 	{-0.425325f, -0.688191f, 0.587785f},
155 	{-0.162460f, -0.262866f, 0.951056f},
156 	{0.442863f, -0.238856f, 0.864188f},
157 	{0.162460f, -0.262866f, 0.951056f},
158 	{0.309017f, -0.500000f, 0.809017f},
159 	{0.147621f, -0.716567f, 0.681718f},
160 	{0.000000f, -0.525731f, 0.850651f},
161 	{0.425325f, -0.688191f, 0.587785f},
162 	{0.587785f, -0.425325f, 0.688191f},
163 	{0.688191f, -0.587785f, 0.425325f},
164 	{-0.955423f, 0.295242f, 0.000000f},
165 	{-0.951056f, 0.162460f, 0.262866f},
166 	{-1.000000f, 0.000000f, 0.000000f},
167 	{-0.850651f, 0.000000f, 0.525731f},
168 	{-0.955423f, -0.295242f, 0.000000f},
169 	{-0.951056f, -0.162460f, 0.262866f},
170 	{-0.864188f, 0.442863f, -0.238856f},
171 	{-0.951056f, 0.162460f, -0.262866f},
172 	{-0.809017f, 0.309017f, -0.500000f},
173 	{-0.864188f, -0.442863f, -0.238856f},
174 	{-0.951056f, -0.162460f, -0.262866f},
175 	{-0.809017f, -0.309017f, -0.500000f},
176 	{-0.681718f, 0.147621f, -0.716567f},
177 	{-0.681718f, -0.147621f, -0.716567f},
178 	{-0.850651f, 0.000000f, -0.525731f},
179 	{-0.688191f, 0.587785f, -0.425325f},
180 	{-0.587785f, 0.425325f, -0.688191f},
181 	{-0.425325f, 0.688191f, -0.587785f},
182 	{-0.425325f, -0.688191f, -0.587785f},
183 	{-0.587785f, -0.425325f, -0.688191f},
184 	{-0.688191f, -0.587785f, -0.425325f},
185 	};
186 
187 struct SMD2AnimationType
188 {
189 	s32 begin;
190 	s32 end;
191 	s32 fps;
192 };
193 
194 static const SMD2AnimationType MD2AnimationTypeList[21] =
195 {
196 	{  0,  39,  9}, // STAND
197 	{ 40,  45, 10}, // RUN
198 	{ 46,  53, 10}, // ATTACK
199 	{ 54,  57,  7}, // PAIN_A
200 	{ 58,  61,  7}, // PAIN_B
201 	{ 62,  65,  7}, // PAIN_C
202 	{ 66,  71,  7}, // JUMP
203 	{ 72,  83,  7}, // FLIP
204 	{ 84,  94,  7}, // SALUTE
205 	{ 95, 111, 10}, // FALLBACK
206 	{112, 122,  7}, // WAVE
207 	{123, 134,  6}, // POINT
208 	{135, 153, 10}, // CROUCH_STAND
209 	{154, 159,  7}, // CROUCH_WALK
210 	{160, 168, 10}, // CROUCH_ATTACK
211 	{169, 172,  7}, // CROUCH_PAIN
212 	{173, 177,  5}, // CROUCH_DEATH
213 	{178, 183,  7}, // DEATH_FALLBACK
214 	{184, 189,  7}, // DEATH_FALLFORWARD
215 	{190, 197,  7}, // DEATH_FALLBACKSLOW
216 	{198, 198,  5}, // BOOM
217 };
218 
219 
220 //! constructor
CAnimatedMeshMD2()221 CAnimatedMeshMD2::CAnimatedMeshMD2()
222 	: InterpolationBuffer(0), FrameList(0), FrameCount(0), FramesPerSecond((f32)(MD2AnimationTypeList[0].fps << MD2_FRAME_SHIFT))
223 {
224 	#ifdef _DEBUG
225 	IAnimatedMesh::setDebugName("CAnimatedMeshMD2 IAnimatedMesh");
226 	IMesh::setDebugName("CAnimatedMeshMD2 IMesh");
227 	#endif
228 	InterpolationBuffer = new SMeshBuffer;
229 }
230 
231 
232 //! destructor
~CAnimatedMeshMD2()233 CAnimatedMeshMD2::~CAnimatedMeshMD2()
234 {
235 	delete [] FrameList;
236 	if (InterpolationBuffer)
237 		InterpolationBuffer->drop();
238 }
239 
240 
241 //! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
getFrameCount() const242 u32 CAnimatedMeshMD2::getFrameCount() const
243 {
244 	return FrameCount<<MD2_FRAME_SHIFT;
245 }
246 
247 
248 //! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
getMesh(s32 frame,s32 detailLevel,s32 startFrameLoop,s32 endFrameLoop)249 IMesh* CAnimatedMeshMD2::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
250 {
251 	if ((u32)frame > getFrameCount())
252 		frame = (frame % getFrameCount());
253 
254 	if (startFrameLoop == -1 && endFrameLoop == -1)
255 	{
256 		startFrameLoop = 0;
257 		endFrameLoop = getFrameCount();
258 	}
259 
260 	updateInterpolationBuffer(frame, startFrameLoop, endFrameLoop);
261 	return this;
262 }
263 
264 
265 //! returns amount of mesh buffers. MD2 meshes only have one buffer
getMeshBufferCount() const266 u32 CAnimatedMeshMD2::getMeshBufferCount() const
267 {
268 	return 1;
269 }
270 
271 
272 //! returns pointer to a mesh buffer
getMeshBuffer(u32 nr) const273 IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(u32 nr) const
274 {
275 	if (nr == 0)
276 		return InterpolationBuffer;
277 	else
278 		return 0;
279 }
280 
281 
282 //! Returns pointer to a mesh buffer which fits a material
getMeshBuffer(const video::SMaterial & material) const283 IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(const video::SMaterial &material) const
284 {
285 	if (InterpolationBuffer->Material == material)
286 		return InterpolationBuffer;
287 	else
288 		return 0;
289 }
290 
291 
292 // updates the interpolation buffer
updateInterpolationBuffer(s32 frame,s32 startFrameLoop,s32 endFrameLoop)293 void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, s32 endFrameLoop)
294 {
295 	u32 firstFrame, secondFrame;
296 	f32 div;
297 
298 	// TA: resolve missing ipol in loop between end-start
299 
300 	if (endFrameLoop - startFrameLoop == 0)
301 	{
302 		firstFrame = frame>>MD2_FRAME_SHIFT;
303 		secondFrame = frame>>MD2_FRAME_SHIFT;
304 		div = 1.0f;
305 	}
306 	else
307 	{
308 		// key frames
309 		u32 s = startFrameLoop >> MD2_FRAME_SHIFT;
310 		u32 e = endFrameLoop >> MD2_FRAME_SHIFT;
311 
312 		firstFrame = frame >> MD2_FRAME_SHIFT;
313 		secondFrame = core::if_c_a_else_b(firstFrame + 1 > e, s, firstFrame + 1);
314 
315 		firstFrame = core::s32_min(FrameCount - 1, firstFrame);
316 		secondFrame = core::s32_min(FrameCount - 1, secondFrame);
317 
318 		//div = (frame % (1<<MD2_FRAME_SHIFT)) / (f32)(1<<MD2_FRAME_SHIFT);
319 		frame &= (1<<MD2_FRAME_SHIFT) - 1;
320 		div = frame * MD2_FRAME_SHIFT_RECIPROCAL;
321 	}
322 
323 	video::S3DVertex* target = static_cast<video::S3DVertex*>(InterpolationBuffer->getVertices());
324 	SMD2Vert* first = FrameList[firstFrame].pointer();
325 	SMD2Vert* second = FrameList[secondFrame].pointer();
326 
327 	// interpolate both frames
328 	const u32 count = FrameList[firstFrame].size();
329 	for (u32 i=0; i<count; ++i)
330 	{
331 		const core::vector3df one = core::vector3df(f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X,
332 				f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y,
333 				f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z);
334 		const core::vector3df two = core::vector3df(f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X,
335 				f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y,
336 				f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z);
337 		target->Pos = two.getInterpolated(one, div);
338 		const core::vector3df n1(
339 				Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][0],
340 				Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][2],
341 				Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][1]);
342 		const core::vector3df n2(
343 				Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][0],
344 				Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][2],
345 				Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][1]);
346 		target->Normal = n2.getInterpolated(n1, div);
347 		++target;
348 		++first;
349 		++second;
350 	}
351 
352 	//update bounding box
353 	InterpolationBuffer->setBoundingBox(BoxList[secondFrame].getInterpolated(BoxList[firstFrame], div));
354 	InterpolationBuffer->setDirty();
355 }
356 
357 
358 //! sets a flag of all contained materials to a new value
setMaterialFlag(video::E_MATERIAL_FLAG flag,bool newvalue)359 void CAnimatedMeshMD2::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
360 {
361 	InterpolationBuffer->Material.setFlag(flag, newvalue);
362 }
363 
364 
365 //! set the hardware mapping hint, for driver
setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,E_BUFFER_TYPE buffer)366 void CAnimatedMeshMD2::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
367 		E_BUFFER_TYPE buffer)
368 {
369 	InterpolationBuffer->setHardwareMappingHint(newMappingHint, buffer);
370 }
371 
372 
373 //! flags the meshbuffer as changed, reloads hardware buffers
setDirty(E_BUFFER_TYPE buffer)374 void CAnimatedMeshMD2::setDirty(E_BUFFER_TYPE buffer)
375 {
376 	InterpolationBuffer->setDirty(buffer);
377 }
378 
379 
380 //! returns an axis aligned bounding box
getBoundingBox() const381 const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const
382 {
383 	return InterpolationBuffer->BoundingBox;
384 }
385 
386 
387 //! set user axis aligned bounding box
setBoundingBox(const core::aabbox3df & box)388 void CAnimatedMeshMD2::setBoundingBox(const core::aabbox3df& box)
389 {
390 	InterpolationBuffer->BoundingBox = box;
391 }
392 
393 
394 //! Returns the type of the animated mesh.
getMeshType() const395 E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const
396 {
397 	return EAMT_MD2;
398 }
399 
400 
401 //! Returns frame loop data for a special MD2 animation type.
getFrameLoop(EMD2_ANIMATION_TYPE l,s32 & outBegin,s32 & outEnd,s32 & outFPS) const402 void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
403 				s32& outBegin, s32& outEnd, s32& outFPS) const
404 {
405 	if (l < 0 || l >= EMAT_COUNT)
406 		return;
407 
408 	outBegin = MD2AnimationTypeList[l].begin << MD2_FRAME_SHIFT;
409 	outEnd = MD2AnimationTypeList[l].end << MD2_FRAME_SHIFT;
410 
411 	// correct to anim between last->first frame
412 	outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
413 	outFPS = MD2AnimationTypeList[l].fps << MD2_FRAME_SHIFT;
414 }
415 
416 
417 //! Returns frame loop data for a special MD2 animation type.
getFrameLoop(const c8 * name,s32 & outBegin,s32 & outEnd,s32 & outFPS) const418 bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
419 	s32& outBegin, s32&outEnd, s32& outFPS) const
420 {
421 	for (u32 i=0; i < AnimationData.size(); ++i)
422 	{
423 		if (AnimationData[i].name == name)
424 		{
425 			outBegin = AnimationData[i].begin << MD2_FRAME_SHIFT;
426 			outEnd = AnimationData[i].end << MD2_FRAME_SHIFT;
427 			outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
428 			outFPS = AnimationData[i].fps << MD2_FRAME_SHIFT;
429 			return true;
430 		}
431 	}
432 
433 	return false;
434 }
435 
436 
437 //! Returns amount of md2 animations in this file.
getAnimationCount() const438 s32 CAnimatedMeshMD2::getAnimationCount() const
439 {
440 	return AnimationData.size();
441 }
442 
443 
444 //! Returns name of md2 animation.
getAnimationName(s32 nr) const445 const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const
446 {
447 	if ((u32)nr >= AnimationData.size())
448 		return 0;
449 
450 	return AnimationData[nr].name.c_str();
451 }
452 
453 
454 } // end namespace scene
455 } // end namespace irr
456 
457 #endif // _IRR_COMPILE_WITH_MD2_LOADER_
458