~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/CAnimatedMeshMD3.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
4
 
 
5
#include "IrrCompileConfig.h"
 
6
#ifdef _IRR_COMPILE_WITH_MD3_LOADER_
 
7
 
 
8
#include "CAnimatedMeshMD3.h"
 
9
#include "os.h"
 
10
 
 
11
namespace irr
 
12
{
 
13
namespace scene
 
14
{
 
15
 
 
16
 
 
17
#if defined(_MSC_VER) ||  defined(__BORLANDC__) || defined (__BCPLUSPLUS__) 
 
18
#       pragma pack( push, packing )
 
19
#       pragma pack( 1 )
 
20
#       define PACK_STRUCT
 
21
#elif defined( __GNUC__ )
 
22
#       define PACK_STRUCT      __attribute__((packed))
 
23
#else
 
24
#       error compiler not supported
 
25
#endif
 
26
 
 
27
 
 
28
//! General properties of a single animation frame.
 
29
struct SMD3Frame
 
30
{
 
31
        f32  mins[3];           // bounding box per frame
 
32
        f32  maxs[3];
 
33
        f32  position[3];       // position of bounding box
 
34
        f32  radius;            // radius of bounding sphere
 
35
        c8   creator[16];       // name of frame
 
36
};
 
37
 
 
38
 
 
39
//! An attachment point for another MD3 model.
 
40
struct SMD3Tag
 
41
{
 
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
 
45
};
 
46
 
 
47
//!Shader
 
48
struct SMD3Shader
 
49
{
 
50
        c8 name[64];            // name of shader
 
51
        s32 shaderIndex;
 
52
};
 
53
 
 
54
 
 
55
 
 
56
// Default alignment
 
57
#if defined(_MSC_VER) ||  defined(__BORLANDC__) || defined (__BCPLUSPLUS__) 
 
58
#       pragma pack( pop, packing )
 
59
#endif
 
60
 
 
61
#undef PACK_STRUCT
 
62
 
 
63
 
 
64
//! Constructor
 
65
CAnimatedMeshMD3::CAnimatedMeshMD3()
 
66
:Mesh(0), IPolShift(0), LoopMode(0), Scaling(1.f)//, FramesPerSecond(25.f)
 
67
{
 
68
#ifdef _DEBUG
 
69
        setDebugName("CAnimatedMeshMD3");
 
70
#endif
 
71
 
 
72
        Mesh = new SMD3Mesh();
 
73
 
 
74
        setInterpolationShift(0, 0);
 
75
}
 
76
 
 
77
 
 
78
//! Destructor
 
79
CAnimatedMeshMD3::~CAnimatedMeshMD3()
 
80
{
 
81
        if (Mesh)
 
82
                Mesh->drop();
 
83
}
 
84
 
 
85
 
 
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
 
88
{
 
89
        return Mesh->MD3Header.numFrames << IPolShift;
 
90
}
 
91
 
 
92
 
 
93
//! Rendering Hint
 
94
void CAnimatedMeshMD3::setInterpolationShift ( u32 shift, u32 loopMode )
 
95
{
 
96
        IPolShift = shift;
 
97
        LoopMode = loopMode;
 
98
}
 
99
 
 
100
 
 
101
//! set the hardware mapping hint, for driver
 
102
void CAnimatedMeshMD3::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
 
103
                E_BUFFER_TYPE buffer)
 
104
{
 
105
        MeshIPol.setHardwareMappingHint(newMappingHint, buffer);
 
106
}
 
107
 
 
108
 
 
109
//! flags the meshbuffer as changed, reloads hardware buffers
 
110
void CAnimatedMeshMD3::setDirty(E_BUFFER_TYPE buffer)
 
111
{
 
112
        MeshIPol.setDirty(buffer);
 
113
}
 
114
 
 
115
 
 
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)
 
118
{
 
119
        if ( 0 == Mesh )
 
120
                return 0;
 
121
 
 
122
        getMesh(frame, detailLevel, startFrameLoop, endFrameLoop);
 
123
        return &TagListIPol;
 
124
}
 
125
 
 
126
 
 
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)
 
129
{
 
130
        if ( 0 == Mesh )
 
131
                return 0;
 
132
 
 
133
        //! check if we have the mesh in our private cache
 
134
        SCacheInfo candidate ( frame, startFrameLoop, endFrameLoop );
 
135
        if ( candidate == Current )
 
136
                return &MeshIPol;
 
137
 
 
138
        startFrameLoop = core::s32_max ( 0, startFrameLoop >> IPolShift );
 
139
        endFrameLoop = core::if_c_a_else_b ( endFrameLoop < 0, Mesh->MD3Header.numFrames - 1, endFrameLoop >> IPolShift );
 
140
 
 
141
        const u32 mask = 1 << IPolShift;
 
142
 
 
143
        s32 frameA;
 
144
        s32 frameB;
 
145
        f32 iPol;
 
146
 
 
147
        if ( LoopMode )
 
148
        {
 
149
                // correct frame to "pixel center"
 
150
                frame -= mask >> 1;
 
151
 
 
152
                // interpolation
 
153
                iPol = f32(frame & ( mask - 1 )) * core::reciprocal ( f32(mask) );
 
154
 
 
155
                // wrap anim
 
156
                frame >>= IPolShift;
 
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 );
 
159
        }
 
160
        else
 
161
        {
 
162
                // correct frame to "pixel center"
 
163
                frame -= mask >> 1;
 
164
 
 
165
                iPol = f32(frame & ( mask - 1 )) * core::reciprocal ( f32(mask) );
 
166
 
 
167
                // clamp anim
 
168
                frame >>= IPolShift;
 
169
                frameA = core::s32_clamp ( frame, startFrameLoop, endFrameLoop );
 
170
                frameB = core::s32_min ( frameA + 1, endFrameLoop );
 
171
        }
 
172
 
 
173
        // build current vertex
 
174
        for (u32 i = 0; i!= Mesh->Buffer.size (); ++i)
 
175
        {
 
176
                buildVertexArray(frameA, frameB, iPol,
 
177
                                        Mesh->Buffer[i],
 
178
                                        (SMeshBufferLightMap*) MeshIPol.getMeshBuffer(i));
 
179
        }
 
180
        MeshIPol.recalculateBoundingBox();
 
181
 
 
182
        // build current tags
 
183
        buildTagArray( frameA, frameB, iPol );
 
184
 
 
185
        Current = candidate;
 
186
        return &MeshIPol;
 
187
}
 
188
 
 
189
 
 
190
//! create a Irrlicht MeshBuffer for a MD3 MeshBuffer
 
191
IMeshBuffer * CAnimatedMeshMD3::createMeshBuffer(const SMD3MeshBuffer* source,
 
192
                                                         io::IFileSystem* fs, video::IVideoDriver * driver)
 
193
{
 
194
        SMeshBufferLightMap * dest = new SMeshBufferLightMap();
 
195
        dest->Vertices.set_used( source->MeshHeader.numVertices );
 
196
        dest->Indices.set_used( source->Indices.size () );
 
197
 
 
198
        u32 i;
 
199
 
 
200
        // fill in static face info
 
201
        for ( i = 0; i < source->Indices.size(); i += 3 )
 
202
        {
 
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];
 
206
        }
 
207
 
 
208
        // fill in static vertex info
 
209
        for ( i = 0; i!= (u32)source->MeshHeader.numVertices; ++i )
 
210
        {
 
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;
 
215
                v.TCoords2.X = 0.f;
 
216
                v.TCoords2.Y = 0.f;
 
217
        }
 
218
 
 
219
        // load static texture
 
220
        u32 pos = 0;
 
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;
 
226
 
 
227
        return dest;
 
228
}
 
229
 
 
230
 
 
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
 
235
                                        )
 
236
{
 
237
        const u32 frameOffsetA = frameA * source->MeshHeader.numVertices;
 
238
        const u32 frameOffsetB = frameB * source->MeshHeader.numVertices;
 
239
        const f32 scale = ( 1.f/ 64.f );
 
240
 
 
241
        for (s32 i = 0; i != source->MeshHeader.numVertices; ++i)
 
242
        {
 
243
                video::S3DVertex2TCoords &v = dest->Vertices [ i ];
 
244
 
 
245
                const SMD3Vertex &vA = source->Vertices [ frameOffsetA + i ];
 
246
                const SMD3Vertex &vB = source->Vertices [ frameOffsetB + i ];
 
247
 
 
248
                // position
 
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] ) );
 
252
 
 
253
                // normal
 
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] ));
 
256
 
 
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 );
 
260
        }
 
261
 
 
262
        dest->recalculateBoundingBox ();
 
263
}
 
264
 
 
265
 
 
266
//! build final mesh's tag from frames frameA and frameB with linear interpolation.
 
267
void CAnimatedMeshMD3::buildTagArray ( u32 frameA, u32 frameB, f32 interpolate )
 
268
{
 
269
        const u32 frameOffsetA = frameA * Mesh->MD3Header.numTags;
 
270
        const u32 frameOffsetB = frameB * Mesh->MD3Header.numTags;
 
271
 
 
272
        for ( s32 i = 0; i != Mesh->MD3Header.numTags; ++i )
 
273
        {
 
274
                SMD3QuaternionTag &d = TagListIPol [ i ];
 
275
 
 
276
                const SMD3QuaternionTag &qA = Mesh->TagList[ frameOffsetA + i];
 
277
                const SMD3QuaternionTag &qB = Mesh->TagList[ frameOffsetB + i];
 
278
 
 
279
                // rotation
 
280
                d.rotation.slerp( qA.rotation, qB.rotation, interpolate );
 
281
 
 
282
                // position
 
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 );
 
286
        }
 
287
}
 
288
 
 
289
 
 
290
/*!
 
291
        loads a model
 
292
*/
 
293
bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file,
 
294
                                                 io::IFileSystem* fs, video::IVideoDriver * driver)
 
295
{
 
296
        if (!file)
 
297
                return false;
 
298
 
 
299
        //! Check MD3Header
 
300
        {
 
301
                file->read( &Mesh->MD3Header, sizeof(SMD3Header) );
 
302
 
 
303
                if ( strncmp("IDP3", Mesh->MD3Header.headerID, 4) )
 
304
                {
 
305
                        os::Printer::log("MD3 Loader: invalid header");
 
306
                        return false;
 
307
                }
 
308
        }
 
309
 
 
310
        //! store model name
 
311
        Mesh->Name = file->getFileName();
 
312
 
 
313
        u32 i;
 
314
 
 
315
        //! Frame Data ( ignore )
 
316
#if 0
 
317
        SMD3Frame frameImport;
 
318
        file->seek ( Mesh->MD3Header.frameStart );
 
319
        for (i = 0; i != Mesh->MD3Header.numFrames; ++i )
 
320
        {
 
321
                file->read(&frameImport, sizeof(frameImport) );
 
322
        }
 
323
#endif
 
324
 
 
325
        //! Tag Data
 
326
        const u32 totalTags = Mesh->MD3Header.numTags * Mesh->MD3Header.numFrames;
 
327
 
 
328
        SMD3Tag import;
 
329
 
 
330
        file->seek( Mesh->MD3Header.tagStart );
 
331
        Mesh->TagList.set_used ( totalTags );
 
332
        for (i = 0; i != totalTags; ++i )
 
333
        {
 
334
                file->read(&import, sizeof(import) );
 
335
 
 
336
                SMD3QuaternionTag &exp = Mesh->TagList[i];
 
337
 
 
338
                //! tag name
 
339
                exp.Name = import.Name;
 
340
 
 
341
                //! position
 
342
                exp.position.X = import.position[0];
 
343
                exp.position.Y = import.position[2];
 
344
                exp.position.Z = import.position[1];
 
345
 
 
346
                //! construct quaternion from a RH 3x3 Matrix
 
347
                exp.rotation.set (import.rotationMatrix[7],
 
348
                                        0.f,
 
349
                                        -import.rotationMatrix[6],
 
350
                                        1 + import.rotationMatrix[8]);
 
351
                exp.rotation.normalize ();
 
352
        }
 
353
 
 
354
        //! Meshes
 
355
        u32 offset = Mesh->MD3Header.tagEnd;
 
356
 
 
357
        for (i = 0; i != (u32)Mesh->MD3Header.numMeshes; ++i )
 
358
        {
 
359
                //! construct a new mesh buffer
 
360
                SMD3MeshBuffer * buf = new SMD3MeshBuffer ();
 
361
 
 
362
                // !read mesh header info
 
363
                SMD3MeshHeader &meshHeader = buf->MeshHeader;
 
364
 
 
365
                //! read mesh info
 
366
                file->seek( offset );
 
367
                file->read( &meshHeader, sizeof(SMD3MeshHeader) );
 
368
 
 
369
                //! prepare memory
 
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 );
 
373
 
 
374
                //! read skins (shaders). should be 1 per meshbuffer
 
375
                SMD3Shader skin;
 
376
                file->seek( offset + buf->MeshHeader.offset_shaders );
 
377
                for ( s32 g = 0; g != buf->MeshHeader.numShader; ++g )
 
378
                {
 
379
                        file->read( &skin, sizeof(skin) );
 
380
 
 
381
                        io::path name;
 
382
                        cutFilenameExtension ( name, skin.name );
 
383
                        name.replace ( '\\', '/' );
 
384
                        buf->Shader = name;
 
385
                }
 
386
 
 
387
                //! read texture coordinates
 
388
                file->seek( offset + buf->MeshHeader.offset_st);
 
389
                file->read( buf->Tex.pointer(), buf->MeshHeader.numVertices * sizeof(SMD3TexCoord) );
 
390
 
 
391
                //! read vertices
 
392
                file->seek(offset + meshHeader.vertexStart);
 
393
                file->read( buf->Vertices.pointer(), Mesh->MD3Header.numFrames * meshHeader.numVertices * sizeof(SMD3Vertex) );
 
394
 
 
395
                //! read indices
 
396
                file->seek( offset + meshHeader.offset_triangles );
 
397
                file->read( buf->Indices.pointer(), meshHeader.numTriangles * sizeof(SMD3Face) );
 
398
 
 
399
                //! store meshBuffer
 
400
                Mesh->Buffer.push_back ( buf );
 
401
 
 
402
                offset += meshHeader.offset_end;
 
403
        }
 
404
 
 
405
        // Init Mesh Interpolation
 
406
        for ( i = 0; i != Mesh->Buffer.size (); ++i )
 
407
        {
 
408
                IMeshBuffer * buffer = createMeshBuffer ( Mesh->Buffer[i], fs, driver );
 
409
                MeshIPol.addMeshBuffer ( buffer );
 
410
                buffer->drop ();
 
411
        }
 
412
        MeshIPol.recalculateBoundingBox ();
 
413
 
 
414
        // Init Tag Interpolation
 
415
        for (i = 0; i != (u32)Mesh->MD3Header.numTags; ++i )
 
416
        {
 
417
                TagListIPol.push_back ( Mesh->TagList[i] );
 
418
        }
 
419
 
 
420
        return true;
 
421
}
 
422
 
 
423
 
 
424
SMD3Mesh * CAnimatedMeshMD3::getOriginalMesh ()
 
425
{
 
426
        return Mesh;
 
427
}
 
428
 
 
429
 
 
430
//! Returns an axis aligned bounding box
 
431
const core::aabbox3d<f32>& CAnimatedMeshMD3::getBoundingBox() const
 
432
{
 
433
        return MeshIPol.BoundingBox;
 
434
}
 
435
 
 
436
 
 
437
//! Returns the type of the animated mesh.
 
438
E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const
 
439
{
 
440
        return EAMT_MD3;
 
441
}
 
442
 
 
443
 
 
444
} // end namespace scene
 
445
} // end namespace irr
 
446
 
 
447
#endif // _IRR_COMPILE_WITH_MD3_LOADER_