1
// Copyright (C) 2002-2011 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
5
#include "IrrCompileConfig.h"
6
#ifdef _IRR_COMPILE_WITH_MD3_LOADER_
8
#include "CAnimatedMeshMD3.h"
17
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
18
# pragma pack( push, packing )
21
#elif defined( __GNUC__ )
22
# define PACK_STRUCT __attribute__((packed))
24
# error compiler not supported
28
//! General properties of a single animation frame.
31
f32 mins[3]; // bounding box per frame
33
f32 position[3]; // position of bounding box
34
f32 radius; // radius of bounding sphere
35
c8 creator[16]; // name of frame
39
//! An attachment point for another MD3 model.
42
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.
43
f32 position[3]; //relative position of tag
44
f32 rotationMatrix[9]; //3x3 rotation direction of tag
50
c8 name[64]; // name of shader
57
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
58
# pragma pack( pop, packing )
65
CAnimatedMeshMD3::CAnimatedMeshMD3()
66
:Mesh(0), IPolShift(0), LoopMode(0), Scaling(1.f)//, FramesPerSecond(25.f)
69
setDebugName("CAnimatedMeshMD3");
72
Mesh = new SMD3Mesh();
74
setInterpolationShift(0, 0);
79
CAnimatedMeshMD3::~CAnimatedMeshMD3()
86
//! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
87
u32 CAnimatedMeshMD3::getFrameCount() const
89
return Mesh->MD3Header.numFrames << IPolShift;
94
void CAnimatedMeshMD3::setInterpolationShift ( u32 shift, u32 loopMode )
101
//! set the hardware mapping hint, for driver
102
void CAnimatedMeshMD3::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
103
E_BUFFER_TYPE buffer)
105
MeshIPol.setHardwareMappingHint(newMappingHint, buffer);
109
//! flags the meshbuffer as changed, reloads hardware buffers
110
void CAnimatedMeshMD3::setDirty(E_BUFFER_TYPE buffer)
112
MeshIPol.setDirty(buffer);
116
//! Returns the animated tag list based on a detail level. 0 is the lowest, 255 the highest detail.
117
SMD3QuaternionTagList *CAnimatedMeshMD3::getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
122
getMesh(frame, detailLevel, startFrameLoop, endFrameLoop);
127
//! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail.
128
IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
133
//! check if we have the mesh in our private cache
134
SCacheInfo candidate ( frame, startFrameLoop, endFrameLoop );
135
if ( candidate == Current )
138
startFrameLoop = core::s32_max ( 0, startFrameLoop >> IPolShift );
139
endFrameLoop = core::if_c_a_else_b ( endFrameLoop < 0, Mesh->MD3Header.numFrames - 1, endFrameLoop >> IPolShift );
141
const u32 mask = 1 << IPolShift;
149
// correct frame to "pixel center"
153
iPol = f32(frame & ( mask - 1 )) * core::reciprocal ( f32(mask) );
157
frameA = core::if_c_a_else_b ( frame < startFrameLoop, endFrameLoop, frame );
158
frameB = core::if_c_a_else_b ( frameA + 1 > endFrameLoop, startFrameLoop, frameA + 1 );
162
// correct frame to "pixel center"
165
iPol = f32(frame & ( mask - 1 )) * core::reciprocal ( f32(mask) );
169
frameA = core::s32_clamp ( frame, startFrameLoop, endFrameLoop );
170
frameB = core::s32_min ( frameA + 1, endFrameLoop );
173
// build current vertex
174
for (u32 i = 0; i!= Mesh->Buffer.size (); ++i)
176
buildVertexArray(frameA, frameB, iPol,
178
(SMeshBufferLightMap*) MeshIPol.getMeshBuffer(i));
180
MeshIPol.recalculateBoundingBox();
182
// build current tags
183
buildTagArray( frameA, frameB, iPol );
190
//! create a Irrlicht MeshBuffer for a MD3 MeshBuffer
191
IMeshBuffer * CAnimatedMeshMD3::createMeshBuffer(const SMD3MeshBuffer* source,
192
io::IFileSystem* fs, video::IVideoDriver * driver)
194
SMeshBufferLightMap * dest = new SMeshBufferLightMap();
195
dest->Vertices.set_used( source->MeshHeader.numVertices );
196
dest->Indices.set_used( source->Indices.size () );
200
// fill in static face info
201
for ( i = 0; i < source->Indices.size(); i += 3 )
203
dest->Indices[i + 0] = (u16) source->Indices[i + 0];
204
dest->Indices[i + 1] = (u16) source->Indices[i + 1];
205
dest->Indices[i + 2] = (u16) source->Indices[i + 2];
208
// fill in static vertex info
209
for ( i = 0; i!= (u32)source->MeshHeader.numVertices; ++i )
211
video::S3DVertex2TCoords &v = dest->Vertices[i];
212
v.Color = 0xFFFFFFFF;
213
v.TCoords.X = source->Tex[i].u;
214
v.TCoords.Y = source->Tex[i].v;
219
// load static texture
221
quake3::tTexArray textureArray;
222
quake3::getTextures( textureArray, source->Shader, pos, fs, driver );
223
dest->Material.MaterialType = video::EMT_SOLID;
224
dest->Material.setTexture ( 0, textureArray[0] );
225
dest->Material.Lighting = false;
231
//! build final mesh's vertices from frames frameA and frameB with linear interpolation.
232
void CAnimatedMeshMD3::buildVertexArray ( u32 frameA, u32 frameB, f32 interpolate,
233
const SMD3MeshBuffer * source,
234
SMeshBufferLightMap * dest
237
const u32 frameOffsetA = frameA * source->MeshHeader.numVertices;
238
const u32 frameOffsetB = frameB * source->MeshHeader.numVertices;
239
const f32 scale = ( 1.f/ 64.f );
241
for (s32 i = 0; i != source->MeshHeader.numVertices; ++i)
243
video::S3DVertex2TCoords &v = dest->Vertices [ i ];
245
const SMD3Vertex &vA = source->Vertices [ frameOffsetA + i ];
246
const SMD3Vertex &vB = source->Vertices [ frameOffsetB + i ];
249
v.Pos.X = scale * ( vA.position[0] + interpolate * ( vB.position[0] - vA.position[0] ) );
250
v.Pos.Y = scale * ( vA.position[2] + interpolate * ( vB.position[2] - vA.position[2] ) );
251
v.Pos.Z = scale * ( vA.position[1] + interpolate * ( vB.position[1] - vA.position[1] ) );
254
const core::vector3df nA( quake3::getMD3Normal ( vA.normal[0], vA.normal[1] ));
255
const core::vector3df nB( quake3::getMD3Normal ( vB.normal[0], vB.normal[1] ));
257
v.Normal.X = nA.X + interpolate * ( nB.X - nA.X );
258
v.Normal.Y = nA.Z + interpolate * ( nB.Z - nA.Z );
259
v.Normal.Z = nA.Y + interpolate * ( nB.Y - nA.Y );
262
dest->recalculateBoundingBox ();
266
//! build final mesh's tag from frames frameA and frameB with linear interpolation.
267
void CAnimatedMeshMD3::buildTagArray ( u32 frameA, u32 frameB, f32 interpolate )
269
const u32 frameOffsetA = frameA * Mesh->MD3Header.numTags;
270
const u32 frameOffsetB = frameB * Mesh->MD3Header.numTags;
272
for ( s32 i = 0; i != Mesh->MD3Header.numTags; ++i )
274
SMD3QuaternionTag &d = TagListIPol [ i ];
276
const SMD3QuaternionTag &qA = Mesh->TagList[ frameOffsetA + i];
277
const SMD3QuaternionTag &qB = Mesh->TagList[ frameOffsetB + i];
280
d.rotation.slerp( qA.rotation, qB.rotation, interpolate );
283
d.position.X = qA.position.X + interpolate * ( qB.position.X - qA.position.X );
284
d.position.Y = qA.position.Y + interpolate * ( qB.position.Y - qA.position.Y );
285
d.position.Z = qA.position.Z + interpolate * ( qB.position.Z - qA.position.Z );
293
bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file,
294
io::IFileSystem* fs, video::IVideoDriver * driver)
301
file->read( &Mesh->MD3Header, sizeof(SMD3Header) );
303
if ( strncmp("IDP3", Mesh->MD3Header.headerID, 4) )
305
os::Printer::log("MD3 Loader: invalid header");
311
Mesh->Name = file->getFileName();
315
//! Frame Data ( ignore )
317
SMD3Frame frameImport;
318
file->seek ( Mesh->MD3Header.frameStart );
319
for (i = 0; i != Mesh->MD3Header.numFrames; ++i )
321
file->read(&frameImport, sizeof(frameImport) );
326
const u32 totalTags = Mesh->MD3Header.numTags * Mesh->MD3Header.numFrames;
330
file->seek( Mesh->MD3Header.tagStart );
331
Mesh->TagList.set_used ( totalTags );
332
for (i = 0; i != totalTags; ++i )
334
file->read(&import, sizeof(import) );
336
SMD3QuaternionTag &exp = Mesh->TagList[i];
339
exp.Name = import.Name;
342
exp.position.X = import.position[0];
343
exp.position.Y = import.position[2];
344
exp.position.Z = import.position[1];
346
//! construct quaternion from a RH 3x3 Matrix
347
exp.rotation.set (import.rotationMatrix[7],
349
-import.rotationMatrix[6],
350
1 + import.rotationMatrix[8]);
351
exp.rotation.normalize ();
355
u32 offset = Mesh->MD3Header.tagEnd;
357
for (i = 0; i != (u32)Mesh->MD3Header.numMeshes; ++i )
359
//! construct a new mesh buffer
360
SMD3MeshBuffer * buf = new SMD3MeshBuffer ();
362
// !read mesh header info
363
SMD3MeshHeader &meshHeader = buf->MeshHeader;
366
file->seek( offset );
367
file->read( &meshHeader, sizeof(SMD3MeshHeader) );
370
buf->Vertices.set_used ( meshHeader.numVertices * Mesh->MD3Header.numFrames );
371
buf->Indices.set_used ( meshHeader.numTriangles * 3 );
372
buf->Tex.set_used ( meshHeader.numVertices );
374
//! read skins (shaders). should be 1 per meshbuffer
376
file->seek( offset + buf->MeshHeader.offset_shaders );
377
for ( s32 g = 0; g != buf->MeshHeader.numShader; ++g )
379
file->read( &skin, sizeof(skin) );
382
cutFilenameExtension ( name, skin.name );
383
name.replace ( '\\', '/' );
387
//! read texture coordinates
388
file->seek( offset + buf->MeshHeader.offset_st);
389
file->read( buf->Tex.pointer(), buf->MeshHeader.numVertices * sizeof(SMD3TexCoord) );
392
file->seek(offset + meshHeader.vertexStart);
393
file->read( buf->Vertices.pointer(), Mesh->MD3Header.numFrames * meshHeader.numVertices * sizeof(SMD3Vertex) );
396
file->seek( offset + meshHeader.offset_triangles );
397
file->read( buf->Indices.pointer(), meshHeader.numTriangles * sizeof(SMD3Face) );
400
Mesh->Buffer.push_back ( buf );
402
offset += meshHeader.offset_end;
405
// Init Mesh Interpolation
406
for ( i = 0; i != Mesh->Buffer.size (); ++i )
408
IMeshBuffer * buffer = createMeshBuffer ( Mesh->Buffer[i], fs, driver );
409
MeshIPol.addMeshBuffer ( buffer );
412
MeshIPol.recalculateBoundingBox ();
414
// Init Tag Interpolation
415
for (i = 0; i != (u32)Mesh->MD3Header.numTags; ++i )
417
TagListIPol.push_back ( Mesh->TagList[i] );
424
SMD3Mesh * CAnimatedMeshMD3::getOriginalMesh ()
430
//! Returns an axis aligned bounding box
431
const core::aabbox3d<f32>& CAnimatedMeshMD3::getBoundingBox() const
433
return MeshIPol.BoundingBox;
437
//! Returns the type of the animated mesh.
438
E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const
444
} // end namespace scene
445
} // end namespace irr
447
#endif // _IRR_COMPILE_WITH_MD3_LOADER_