aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CAnimatedMeshMD3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CAnimatedMeshMD3.cpp')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CAnimatedMeshMD3.cpp468
1 files changed, 468 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CAnimatedMeshMD3.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CAnimatedMeshMD3.cpp
new file mode 100644
index 0000000..0d3a091
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CAnimatedMeshMD3.cpp
@@ -0,0 +1,468 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt / Fabio Concas / Thomas Alten
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_MD3_LOADER_
7
8#include "CAnimatedMeshMD3.h"
9#include "os.h"
10
11namespace irr
12{
13namespace scene
14{
15
16
17// byte-align structures
18#include "irrpack.h"
19
20//! General properties of a single animation frame.
21struct SMD3Frame
22{
23 f32 mins[3]; // bounding box per frame
24 f32 maxs[3];
25 f32 position[3]; // position of bounding box
26 f32 radius; // radius of bounding sphere
27 c8 creator[16]; // name of frame
28} PACK_STRUCT;
29
30
31//! An attachment point for another MD3 model.
32struct SMD3Tag
33{
34 c8 Name[64]; //name of 'tag' as it's usually called in the md3 files try to see it as a sub-mesh/seperate mesh-part.
35 f32 position[3]; //relative position of tag
36 f32 rotationMatrix[9]; //3x3 rotation direction of tag
37} PACK_STRUCT;
38
39//!Shader
40struct SMD3Shader
41{
42 c8 name[64]; // name of shader
43 s32 shaderIndex;
44} PACK_STRUCT;
45
46// Default alignment
47#include "irrunpack.h"
48
49
50//! Constructor
51CAnimatedMeshMD3::CAnimatedMeshMD3()
52:Mesh(0), IPolShift(0), LoopMode(0), Scaling(1.f)//, FramesPerSecond(25.f)
53{
54#ifdef _DEBUG
55 setDebugName("CAnimatedMeshMD3");
56#endif
57
58 Mesh = new SMD3Mesh();
59 MeshIPol = new SMesh();
60 setInterpolationShift(0, 0);
61}
62
63
64//! Destructor
65CAnimatedMeshMD3::~CAnimatedMeshMD3()
66{
67 if (Mesh)
68 Mesh->drop();
69 if (MeshIPol)
70 MeshIPol->drop();
71}
72
73
74//! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
75u32 CAnimatedMeshMD3::getFrameCount() const
76{
77 return Mesh->MD3Header.numFrames << IPolShift;
78}
79
80
81//! Rendering Hint
82void CAnimatedMeshMD3::setInterpolationShift(u32 shift, u32 loopMode)
83{
84 IPolShift = shift;
85 LoopMode = loopMode;
86}
87
88
89//! returns amount of mesh buffers.
90u32 CAnimatedMeshMD3::getMeshBufferCount() const
91{
92 return MeshIPol->getMeshBufferCount();
93}
94
95
96//! returns pointer to a mesh buffer
97IMeshBuffer* CAnimatedMeshMD3::getMeshBuffer(u32 nr) const
98{
99 return MeshIPol->getMeshBuffer(nr);
100}
101
102
103//! Returns pointer to a mesh buffer which fits a material
104IMeshBuffer* CAnimatedMeshMD3::getMeshBuffer(const video::SMaterial &material) const
105{
106 return MeshIPol->getMeshBuffer(material);
107}
108
109
110void CAnimatedMeshMD3::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
111{
112 MeshIPol->setMaterialFlag(flag, newvalue);
113}
114
115
116//! set the hardware mapping hint, for driver
117void CAnimatedMeshMD3::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
118 E_BUFFER_TYPE buffer)
119{
120 MeshIPol->setHardwareMappingHint(newMappingHint, buffer);
121}
122
123
124//! flags the meshbuffer as changed, reloads hardware buffers
125void CAnimatedMeshMD3::setDirty(E_BUFFER_TYPE buffer)
126{
127 MeshIPol->setDirty(buffer);
128}
129
130
131//! set user axis aligned bounding box
132void CAnimatedMeshMD3::setBoundingBox(const core::aabbox3df& box)
133{
134 MeshIPol->setBoundingBox(box);
135}
136
137
138//! Returns the animated tag list based on a detail level. 0 is the lowest, 255 the highest detail.
139SMD3QuaternionTagList *CAnimatedMeshMD3::getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
140{
141 if (0 == Mesh)
142 return 0;
143
144 getMesh(frame, detailLevel, startFrameLoop, endFrameLoop);
145 return &TagListIPol;
146}
147
148
149//! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail.
150IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
151{
152 if (0 == Mesh)
153 return 0;
154
155 //! check if we have the mesh in our private cache
156 SCacheInfo candidate(frame, startFrameLoop, endFrameLoop);
157 if (candidate == Current)
158 return MeshIPol;
159
160 startFrameLoop = core::s32_max(0, startFrameLoop >> IPolShift);
161 endFrameLoop = core::if_c_a_else_b(endFrameLoop < 0, Mesh->MD3Header.numFrames - 1, endFrameLoop >> IPolShift);
162
163 const u32 mask = 1 << IPolShift;
164
165 s32 frameA;
166 s32 frameB;
167 f32 iPol;
168
169 if (LoopMode)
170 {
171 // correct frame to "pixel center"
172 frame -= mask >> 1;
173
174 // interpolation
175 iPol = f32(frame & (mask - 1)) * core::reciprocal(f32(mask));
176
177 // wrap anim
178 frame >>= IPolShift;
179 frameA = core::if_c_a_else_b(frame < startFrameLoop, endFrameLoop, frame);
180 frameB = core::if_c_a_else_b(frameA + 1 > endFrameLoop, startFrameLoop, frameA + 1);
181 }
182 else
183 {
184 // correct frame to "pixel center"
185 frame -= mask >> 1;
186
187 iPol = f32(frame & (mask - 1)) * core::reciprocal(f32(mask));
188
189 // clamp anim
190 frame >>= IPolShift;
191 frameA = core::s32_clamp(frame, startFrameLoop, endFrameLoop);
192 frameB = core::s32_min(frameA + 1, endFrameLoop);
193 }
194
195 // build current vertex
196 for (u32 i = 0; i!= Mesh->Buffer.size(); ++i)
197 {
198 buildVertexArray(frameA, frameB, iPol,
199 Mesh->Buffer[i],
200 (SMeshBufferLightMap*) MeshIPol->getMeshBuffer(i));
201 }
202 MeshIPol->recalculateBoundingBox();
203
204 // build current tags
205 buildTagArray(frameA, frameB, iPol);
206
207 Current = candidate;
208 return MeshIPol;
209}
210
211
212//! create a Irrlicht MeshBuffer for a MD3 MeshBuffer
213IMeshBuffer * CAnimatedMeshMD3::createMeshBuffer(const SMD3MeshBuffer* source,
214 io::IFileSystem* fs, video::IVideoDriver * driver)
215{
216 SMeshBufferLightMap * dest = new SMeshBufferLightMap();
217 dest->Vertices.set_used(source->MeshHeader.numVertices);
218 dest->Indices.set_used(source->Indices.size());
219
220 u32 i;
221
222 // fill in static face info
223 for (i = 0; i < source->Indices.size(); i += 3)
224 {
225 dest->Indices[i + 0] = (u16) source->Indices[i + 0];
226 dest->Indices[i + 1] = (u16) source->Indices[i + 1];
227 dest->Indices[i + 2] = (u16) source->Indices[i + 2];
228 }
229
230 // fill in static vertex info
231 for (i = 0; i!= (u32)source->MeshHeader.numVertices; ++i)
232 {
233 video::S3DVertex2TCoords &v = dest->Vertices[i];
234 v.Color = 0xFFFFFFFF;
235 v.TCoords.X = source->Tex[i].u;
236 v.TCoords.Y = source->Tex[i].v;
237 v.TCoords2.X = 0.f;
238 v.TCoords2.Y = 0.f;
239 }
240
241 // load static texture
242 u32 pos = 0;
243 quake3::tTexArray textureArray;
244 quake3::getTextures(textureArray, source->Shader, pos, fs, driver);
245 dest->Material.MaterialType = video::EMT_SOLID;
246 dest->Material.setTexture(0, textureArray[0]);
247 dest->Material.Lighting = false;
248
249 return dest;
250}
251
252
253//! build final mesh's vertices from frames frameA and frameB with linear interpolation.
254void CAnimatedMeshMD3::buildVertexArray(u32 frameA, u32 frameB, f32 interpolate,
255 const SMD3MeshBuffer* source,
256 SMeshBufferLightMap* dest)
257{
258 const u32 frameOffsetA = frameA * source->MeshHeader.numVertices;
259 const u32 frameOffsetB = frameB * source->MeshHeader.numVertices;
260 const f32 scale = (1.f/ 64.f);
261
262 for (s32 i = 0; i != source->MeshHeader.numVertices; ++i)
263 {
264 video::S3DVertex2TCoords &v = dest->Vertices [ i ];
265
266 const SMD3Vertex &vA = source->Vertices [ frameOffsetA + i ];
267 const SMD3Vertex &vB = source->Vertices [ frameOffsetB + i ];
268
269 // position
270 v.Pos.X = scale * (vA.position[0] + interpolate * (vB.position[0] - vA.position[0]));
271 v.Pos.Y = scale * (vA.position[2] + interpolate * (vB.position[2] - vA.position[2]));
272 v.Pos.Z = scale * (vA.position[1] + interpolate * (vB.position[1] - vA.position[1]));
273
274 // normal
275 const core::vector3df nA(quake3::getMD3Normal(vA.normal[0], vA.normal[1]));
276 const core::vector3df nB(quake3::getMD3Normal(vB.normal[0], vB.normal[1]));
277
278 v.Normal.X = nA.X + interpolate * (nB.X - nA.X);
279 v.Normal.Y = nA.Z + interpolate * (nB.Z - nA.Z);
280 v.Normal.Z = nA.Y + interpolate * (nB.Y - nA.Y);
281 }
282
283 dest->recalculateBoundingBox();
284}
285
286
287//! build final mesh's tag from frames frameA and frameB with linear interpolation.
288void CAnimatedMeshMD3::buildTagArray(u32 frameA, u32 frameB, f32 interpolate)
289{
290 const u32 frameOffsetA = frameA * Mesh->MD3Header.numTags;
291 const u32 frameOffsetB = frameB * Mesh->MD3Header.numTags;
292
293 for (s32 i = 0; i != Mesh->MD3Header.numTags; ++i)
294 {
295 SMD3QuaternionTag &d = TagListIPol [ i ];
296
297 const SMD3QuaternionTag &qA = Mesh->TagList[ frameOffsetA + i];
298 const SMD3QuaternionTag &qB = Mesh->TagList[ frameOffsetB + i];
299
300 // rotation
301 d.rotation.slerp(qA.rotation, qB.rotation, interpolate);
302
303 // position
304 d.position.X = qA.position.X + interpolate * (qB.position.X - qA.position.X);
305 d.position.Y = qA.position.Y + interpolate * (qB.position.Y - qA.position.Y);
306 d.position.Z = qA.position.Z + interpolate * (qB.position.Z - qA.position.Z);
307 }
308}
309
310
311/*!
312 loads a model
313*/
314bool CAnimatedMeshMD3::loadModelFile(u32 modelIndex, io::IReadFile* file,
315 io::IFileSystem* fs, video::IVideoDriver* driver)
316{
317 if (!file)
318 return false;
319
320 //! Check MD3Header
321 {
322 file->read(&Mesh->MD3Header, sizeof(SMD3Header));
323
324 if (strncmp("IDP3", Mesh->MD3Header.headerID, 4))
325 {
326 os::Printer::log("MD3 Loader: invalid header");
327 return false;
328 }
329 }
330
331 //! store model name
332 Mesh->Name = file->getFileName();
333
334 u32 i;
335
336 //! Frame Data (ignore)
337#if 0
338 SMD3Frame frameImport;
339 file->seek(Mesh->MD3Header.frameStart);
340 for (i = 0; i != Mesh->MD3Header.numFrames; ++i)
341 {
342 file->read(&frameImport, sizeof(frameImport));
343 }
344#endif
345
346 //! Tag Data
347 const u32 totalTags = Mesh->MD3Header.numTags * Mesh->MD3Header.numFrames;
348
349 SMD3Tag import;
350
351 file->seek(Mesh->MD3Header.tagStart);
352 Mesh->TagList.set_used(totalTags);
353 for (i = 0; i != totalTags; ++i)
354 {
355 file->read(&import, sizeof(import));
356
357 SMD3QuaternionTag &exp = Mesh->TagList[i];
358
359 //! tag name
360 exp.Name = import.Name;
361
362 //! position
363 exp.position.X = import.position[0];
364 exp.position.Y = import.position[2];
365 exp.position.Z = import.position[1];
366
367 //! construct quaternion from a RH 3x3 Matrix
368 exp.rotation.set(import.rotationMatrix[7],
369 0.f,
370 -import.rotationMatrix[6],
371 1 + import.rotationMatrix[8]);
372 exp.rotation.normalize();
373 }
374
375 //! Meshes
376 u32 offset = Mesh->MD3Header.tagEnd;
377
378 for (i = 0; i != (u32)Mesh->MD3Header.numMeshes; ++i)
379 {
380 //! construct a new mesh buffer
381 SMD3MeshBuffer * buf = new SMD3MeshBuffer();
382
383 // !read mesh header info
384 SMD3MeshHeader &meshHeader = buf->MeshHeader;
385
386 //! read mesh info
387 file->seek(offset);
388 file->read(&meshHeader, sizeof(SMD3MeshHeader));
389
390 //! prepare memory
391 buf->Vertices.set_used(meshHeader.numVertices * Mesh->MD3Header.numFrames);
392 buf->Indices.set_used(meshHeader.numTriangles * 3);
393 buf->Tex.set_used(meshHeader.numVertices);
394
395 //! read skins (shaders). should be 1 per meshbuffer
396 SMD3Shader skin;
397 file->seek(offset + buf->MeshHeader.offset_shaders);
398 for (s32 g = 0; g != buf->MeshHeader.numShader; ++g)
399 {
400 file->read(&skin, sizeof(skin));
401
402 io::path name;
403 cutFilenameExtension(name, skin.name);
404 name.replace('\\', '/');
405 buf->Shader = name;
406 }
407
408 //! read texture coordinates
409 file->seek(offset + buf->MeshHeader.offset_st);
410 file->read(buf->Tex.pointer(), buf->MeshHeader.numVertices * sizeof(SMD3TexCoord));
411
412 //! read vertices
413 file->seek(offset + meshHeader.vertexStart);
414 file->read(buf->Vertices.pointer(), Mesh->MD3Header.numFrames * meshHeader.numVertices * sizeof(SMD3Vertex));
415
416 //! read indices
417 file->seek(offset + meshHeader.offset_triangles);
418 file->read(buf->Indices.pointer(), meshHeader.numTriangles * sizeof(SMD3Face));
419
420 //! store meshBuffer
421 Mesh->Buffer.push_back(buf);
422
423 offset += meshHeader.offset_end;
424 }
425
426 // Init Mesh Interpolation
427 for (i = 0; i != Mesh->Buffer.size(); ++i)
428 {
429 IMeshBuffer * buffer = createMeshBuffer(Mesh->Buffer[i], fs, driver);
430 MeshIPol->addMeshBuffer(buffer);
431 buffer->drop();
432 }
433 MeshIPol->recalculateBoundingBox();
434
435 // Init Tag Interpolation
436 for (i = 0; i != (u32)Mesh->MD3Header.numTags; ++i)
437 {
438 TagListIPol.push_back(Mesh->TagList[i]);
439 }
440
441 return true;
442}
443
444
445SMD3Mesh * CAnimatedMeshMD3::getOriginalMesh()
446{
447 return Mesh;
448}
449
450
451//! Returns an axis aligned bounding box
452const core::aabbox3d<f32>& CAnimatedMeshMD3::getBoundingBox() const
453{
454 return MeshIPol->BoundingBox;
455}
456
457
458//! Returns the type of the animated mesh.
459E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const
460{
461 return EAMT_MD3;
462}
463
464
465} // end namespace scene
466} // end namespace irr
467
468#endif // _IRR_COMPILE_WITH_MD3_LOADER_