]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CAnimatedMeshHalfLife.cpp
Fix some more problems with OSX build file.
[irrlicht.git] / source / Irrlicht / CAnimatedMeshHalfLife.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Fabio Concas / Thomas Alten\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "IrrCompileConfig.h"\r
6 #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_\r
7 \r
8 #include "CAnimatedMeshHalfLife.h"\r
9 #include "os.h"\r
10 #include "CColorConverter.h"\r
11 #include "CImage.h"\r
12 #include "coreutil.h"\r
13 #include "SMeshBuffer.h"\r
14 #include "IVideoDriver.h"\r
15 #include "IFileSystem.h"\r
16 \r
17 namespace irr\r
18 {\r
19 namespace scene\r
20 {\r
21 \r
22         using namespace video;\r
23 \r
24         void AngleQuaternion(const core::vector3df& angles, vec4_hl quaternion)\r
25         {\r
26                 // FIXME: rescale the inputs to 1/2 angle\r
27                 double angle = angles.Z * 0.5;\r
28 \r
29                 const double sy = sin(angle);\r
30                 const double cy = cos(angle);\r
31                 angle = angles.Y * 0.5;\r
32                 const double sp = sin(angle);\r
33                 const double cp = cos(angle);\r
34                 angle = angles.X * 0.5;\r
35                 const double sr = sin(angle);\r
36                 const double cr = cos(angle);\r
37 \r
38                 quaternion[0] = (irr::f32)(sr*cp*cy-cr*sp*sy); // X\r
39                 quaternion[1] = (irr::f32)(cr*sp*cy+sr*cp*sy); // Y\r
40                 quaternion[2] = (irr::f32)(cr*cp*sy-sr*sp*cy); // Z\r
41                 quaternion[3] = (irr::f32)(cr*cp*cy+sr*sp*sy); // W\r
42         }\r
43 \r
44         void QuaternionMatrix( const vec4_hl quaternion, f32 (*matrix)[4] )\r
45         {\r
46                 matrix[0][0] = 1.f - 2.f * quaternion[1] * quaternion[1] - 2.f * quaternion[2] * quaternion[2];\r
47                 matrix[1][0] = 2.f * quaternion[0] * quaternion[1] + 2.f * quaternion[3] * quaternion[2];\r
48                 matrix[2][0] = 2.f * quaternion[0] * quaternion[2] - 2.f * quaternion[3] * quaternion[1];\r
49 \r
50                 matrix[0][1] = 2.f * quaternion[0] * quaternion[1] - 2.f * quaternion[3] * quaternion[2];\r
51                 matrix[1][1] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[2] * quaternion[2];\r
52                 matrix[2][1] = 2.f * quaternion[1] * quaternion[2] + 2.f * quaternion[3] * quaternion[0];\r
53 \r
54                 matrix[0][2] = 2.f * quaternion[0] * quaternion[2] + 2.f * quaternion[3] * quaternion[1];\r
55                 matrix[1][2] = 2.f * quaternion[1] * quaternion[2] - 2.f * quaternion[3] * quaternion[0];\r
56                 matrix[2][2] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[1] * quaternion[1];\r
57         }\r
58 \r
59         void QuaternionSlerp( const vec4_hl p, vec4_hl q, f32 t, vec4_hl qt )\r
60         {\r
61                 // decide if one of the quaternions is backwards\r
62                 f32 a = 0;\r
63                 f32 b = 0;\r
64                 for (s32 i = 0; i < 4; i++) {\r
65                         a += (p[i]-q[i])*(p[i]-q[i]);\r
66                         b += (p[i]+q[i])*(p[i]+q[i]);\r
67                 }\r
68                 if (a > b) {\r
69                         for (s32 i = 0; i < 4; i++) {\r
70                                 q[i] = -q[i];\r
71                         }\r
72                 }\r
73 \r
74                 double sclp, sclq;\r
75                 const double cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];\r
76 \r
77                 if ((1.f + cosom) > 0.00000001) {\r
78                         if ((1.f - cosom) > 0.00000001) {\r
79                                 const double omega = acos( cosom );\r
80                                 const double sinom = sin( omega );\r
81                                 sclp = sin( (1.f - t)*omega) / sinom;\r
82                                 sclq = sin( t*omega ) / sinom;\r
83                         }\r
84                         else {\r
85                                 sclp = 1.f - t;\r
86                                 sclq = t;\r
87                         }\r
88                         for (s32 i = 0; i < 4; i++) {\r
89                                 qt[i] = f32(sclp * p[i] + sclq * q[i]);\r
90                         }\r
91                 }\r
92                 else {\r
93                         qt[0] = -p[1];\r
94                         qt[1] = p[0];\r
95                         qt[2] = -p[3];\r
96                         qt[3] = p[2];\r
97                         sclp = sin( (1.f - t) * 0.5f * core::PI);\r
98                         sclq = sin( t * 0.5f * core::PI);\r
99                         for (s32 i = 0; i < 3; i++) {\r
100                                 qt[i] = f32(sclp * p[i] + sclq * qt[i]);\r
101                         }\r
102                 }\r
103         }\r
104 \r
105         void R_ConcatTransforms (const f32 in1[3][4], const f32 in2[3][4], f32 out[3][4])\r
106         {\r
107                 out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];\r
108                 out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];\r
109                 out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];\r
110                 out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3];\r
111                 out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];\r
112                 out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];\r
113                 out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];\r
114                 out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3];\r
115                 out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];\r
116                 out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];\r
117                 out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];\r
118                 out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3];\r
119         }\r
120 \r
121         #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])\r
122 \r
123         inline void VectorTransform(const vec3_hl in1, const f32 in2[3][4], core::vector3df& out)\r
124         {\r
125                 out.X = DotProduct(in1, in2[0]) + in2[0][3];\r
126                 out.Z = DotProduct(in1, in2[1]) + in2[1][3];\r
127                 out.Y = DotProduct(in1, in2[2]) + in2[2][3];\r
128         }\r
129 \r
130         static f32 BoneTransform[MAXSTUDIOBONES][3][4]; // bone transformation matrix\r
131 \r
132         void getBoneVector ( core::vector3df &out, u32 index )\r
133         {\r
134                 out.X = BoneTransform[index][0][3];\r
135                 out.Z = BoneTransform[index][1][3];\r
136                 out.Y = BoneTransform[index][2][3];\r
137         }\r
138 \r
139         void getBoneBox ( core::aabbox3df &box, u32 index, f32 size = 0.5f )\r
140         {\r
141                 box.MinEdge.X = BoneTransform[index][0][3] - size;\r
142                 box.MinEdge.Z = BoneTransform[index][1][3] - size;\r
143                 box.MinEdge.Y = BoneTransform[index][2][3] - size;\r
144 \r
145                 size *= 2.f;\r
146                 box.MaxEdge.X = box.MinEdge.X + size;\r
147                 box.MaxEdge.Y = box.MinEdge.Y + size;\r
148                 box.MaxEdge.Z = box.MinEdge.Z + size;\r
149         }\r
150 \r
151         void getTransformedBoneVector ( core::vector3df &out, u32 index, const vec3_hl in)\r
152         {\r
153                 out.X = DotProduct(in, BoneTransform[index][0]) + BoneTransform[index][0][3];\r
154                 out.Z = DotProduct(in, BoneTransform[index][1]) + BoneTransform[index][1][3];\r
155                 out.Y = DotProduct(in, BoneTransform[index][2]) + BoneTransform[index][2][3];\r
156 \r
157         }\r
158 \r
159 \r
160 //! Constructor\r
161 CHalflifeMDLMeshFileLoader::CHalflifeMDLMeshFileLoader(\r
162                 scene::ISceneManager* smgr) : SceneManager(smgr)\r
163 {\r
164 #ifdef _DEBUG\r
165         setDebugName("CHalflifeMDLMeshFileLoader");\r
166 #endif\r
167 }\r
168 \r
169 \r
170 //! returns true if the file maybe is able to be loaded by this class\r
171 //! based on the file extension (e.g. ".bsp")\r
172 bool CHalflifeMDLMeshFileLoader::isALoadableFileExtension(const io::path& filename) const\r
173 {\r
174         return core::hasFileExtension(filename, "mdl");\r
175 }\r
176 \r
177 \r
178 //! creates/loads an animated mesh from the file.\r
179 //! \return Pointer to the created mesh. Returns 0 if loading failed.\r
180 //! If you no longer need the mesh, you should call IAnimatedMesh::drop().\r
181 //! See IReferenceCounted::drop() for more information.\r
182 IAnimatedMesh* CHalflifeMDLMeshFileLoader::createMesh(io::IReadFile* file)\r
183 {\r
184         CAnimatedMeshHalfLife* msh = new CAnimatedMeshHalfLife();\r
185         if (msh)\r
186         {\r
187                 if (msh->loadModelFile(file, SceneManager))\r
188                         return msh;\r
189                 msh->drop();\r
190         }\r
191 \r
192         return 0;\r
193 }\r
194 \r
195 \r
196 //! Constructor\r
197 CAnimatedMeshHalfLife::CAnimatedMeshHalfLife()\r
198         : FrameCount(0), MeshIPol(0), SceneManager(0), Header(0), TextureHeader(0),\r
199         OwnTexModel(false), SequenceIndex(0), CurrentFrame(0), FramesPerSecond(25.f),\r
200         SkinGroupSelection(0)\r
201 #ifdef HL_TEXTURE_ATLAS\r
202 //      , TextureMaster(0)\r
203 #endif\r
204 {\r
205 #ifdef _DEBUG\r
206         setDebugName("CAnimatedMeshHalfLife");\r
207 #endif\r
208         initData();\r
209 }\r
210 \r
211 /*!\r
212         loads a complete model\r
213 */\r
214 bool CAnimatedMeshHalfLife::loadModelFile(io::IReadFile* file,\r
215                 ISceneManager* smgr)\r
216 {\r
217         if (!file)\r
218                 return false;\r
219 \r
220         SceneManager = smgr;\r
221 \r
222         if ( loadModel(file, file->getFileName()) )\r
223         {\r
224                 if ( postLoadModel ( file->getFileName() ) )\r
225                 {\r
226                         initModel ();\r
227                         //dumpModelInfo ( 1 );\r
228                         return true;\r
229                 }\r
230         }\r
231         return false;\r
232 }\r
233 \r
234 \r
235 //! Destructor\r
236 CAnimatedMeshHalfLife::~CAnimatedMeshHalfLife()\r
237 {\r
238         delete [] (u8*) Header;\r
239         if (OwnTexModel)\r
240                 delete [] (u8*) TextureHeader;\r
241 \r
242         for (u32 i = 0; i < 32; ++i)\r
243                 delete [] (u8*) AnimationHeader[i];\r
244 \r
245         if (MeshIPol)\r
246                 MeshIPol->drop();\r
247 }\r
248 \r
249 \r
250 //! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.\r
251 u32 CAnimatedMeshHalfLife::getFrameCount() const\r
252 {\r
253         return FrameCount;\r
254 }\r
255 \r
256 \r
257 //! set the hardware mapping hint, for driver\r
258 void CAnimatedMeshHalfLife::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,E_BUFFER_TYPE buffer)\r
259 {\r
260 }\r
261 \r
262 \r
263 //! flags the meshbuffer as changed, reloads hardware buffers\r
264 void CAnimatedMeshHalfLife::setDirty(E_BUFFER_TYPE buffer)\r
265 {\r
266 }\r
267 \r
268 \r
269 static core::vector3df TransformedVerts[MAXSTUDIOVERTS];        // transformed vertices\r
270 //static core::vector3df TransformedNormals[MAXSTUDIOVERTS];    // light surface normals\r
271 \r
272 \r
273 /*!\r
274 */\r
275 void CAnimatedMeshHalfLife::initModel()\r
276 {\r
277         // init Sequences to Animation\r
278         KeyFrameInterpolation ipol;\r
279         ipol.Name.reserve ( 64 );\r
280 \r
281         AnimList.clear();\r
282         FrameCount = 0;\r
283 \r
284         const SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex);\r
285         for (u32 i = 0; i < Header->numseq; i++)\r
286         {\r
287                 ipol.Name = seq[i].label;\r
288                 ipol.StartFrame = FrameCount;\r
289                 ipol.Frames = core::max_ ( 1, seq[i].numframes - 1 );\r
290                 ipol.EndFrame = ipol.StartFrame + ipol.Frames - 1;\r
291                 ipol.FramesPerSecond = seq[i].fps;\r
292                 ipol.AnimationType = seq[i].flags & STUDIO_LOOPING ? EAMT_LOOPING : EAMT_WAYPOINT;\r
293                 AnimList.push_back ( ipol );\r
294 \r
295                 FrameCount += ipol.Frames;\r
296         }\r
297 \r
298         // initBoneControllers\r
299 /*\r
300         SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex);\r
301         for ( i = 0; i < Header->numbonecontrollers; i++)\r
302         {\r
303                 printf ( "BoneController%d index:%d%s range:%f - %f\n",\r
304                         i,\r
305                         bonecontroller[i].index, bonecontroller[i].index == MOUTH_CONTROLLER ? " (Mouth)": "",\r
306                         bonecontroller[i].start,bonecontroller[i].end\r
307                         );\r
308         }\r
309 \r
310         // initSkins\r
311         for (i = 0; i < TextureHeader->numskinfamilies; i++)\r
312         {\r
313                 printf ( "Skin%d\n", i + 1);\r
314         }\r
315 */\r
316 \r
317         // initBodyparts\r
318         u32 meshBuffer = 0;\r
319         BodyList.clear();\r
320         const SHalflifeBody *body = (const SHalflifeBody *) ((u8*) Header + Header->bodypartindex);\r
321         for (u32 i=0; i < Header->numbodyparts; ++i)\r
322         {\r
323                 BodyPart part;\r
324                 part.name = body[i].name;\r
325                 part.defaultModel = core::max_ ( 0, (s32) body[i].base - 1 );\r
326 \r
327                 const SHalflifeModel * model = (SHalflifeModel *)((u8*) Header + body[i].modelindex);\r
328                 for ( u32 g = 0; g < body[i].nummodels; ++g)\r
329                 {\r
330                         SubModel sub;\r
331                         sub.name = model[g].name;\r
332                         sub.startBuffer = meshBuffer;\r
333                         sub.endBuffer = sub.startBuffer + model[g].nummesh;\r
334                         sub.state = g == part.defaultModel;\r
335                         part.model.push_back ( sub );\r
336                         meshBuffer += model[g].nummesh;\r
337                 }\r
338                 BodyList.push_back ( part );\r
339         }\r
340 \r
341         SequenceIndex = 0;\r
342         CurrentFrame = 0.f;\r
343 \r
344         SetController(0, 0.f);\r
345         SetController(1, 0.f);\r
346         SetController(2, 0.f);\r
347         SetController(3, 0.f);\r
348         SetController(MOUTH_CONTROLLER, 0.f);\r
349 \r
350         SetSkin (0);\r
351 \r
352         // init Meshbuffers\r
353         const SHalflifeTexture *tex = (SHalflifeTexture *) ((u8*) TextureHeader + TextureHeader->textureindex);\r
354         const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex);\r
355         if ((SkinGroupSelection != 0) && (SkinGroupSelection < TextureHeader->numskinfamilies))\r
356                 skinref += (SkinGroupSelection * TextureHeader->numskinref);\r
357 \r
358         core::vector2df tex_scale;\r
359         core::vector2di tex_trans ( 0, 0 );\r
360 \r
361 #ifdef HL_TEXTURE_ATLAS\r
362         TextureAtlas.getScale(tex_scale);\r
363 #endif\r
364 \r
365         for (u32 bodypart=0 ; bodypart < Header->numbodyparts ; ++bodypart)\r
366         {\r
367                 body = (const SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart;\r
368 \r
369                 for (u32 modelnr = 0; modelnr < body->nummodels; ++modelnr)\r
370                 {\r
371                         const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr;\r
372 #if 0\r
373                         const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex);\r
374                         const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex);\r
375 #endif\r
376                         for (u32 i = 0; i < model->nummesh; ++i)\r
377                         {\r
378                                 const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i;\r
379                                 const SHalflifeTexture *currentex = &tex[skinref[mesh->skinref]];\r
380 \r
381 #ifdef HL_TEXTURE_ATLAS\r
382                                 TextureAtlas.getTranslation ( currentex->name, tex_trans );\r
383 #else\r
384                                 tex_scale.X = 1.f/(f32)currentex->width;\r
385                                 tex_scale.Y = 1.f/(f32)currentex->height;\r
386 #endif\r
387 \r
388                                 SMeshBuffer * buffer = new SMeshBuffer();\r
389 \r
390                                 // count index vertex size      indexcount = mesh->numtris * 3\r
391                                 u32 indexCount = 0;\r
392                                 u32 vertexCount = 0;\r
393 \r
394                                 const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex);\r
395                                 s32 c;\r
396                                 while ( (c = *(tricmd++)) )\r
397                                 {\r
398                                         if (c < 0)\r
399                                                 c = -c;\r
400 \r
401                                         indexCount += ( c - 2 ) * 3;\r
402                                         vertexCount += c;\r
403                                         tricmd += ( 4 * c );\r
404                                 }\r
405 \r
406                                 // indices\r
407                                 buffer->Indices.set_used ( indexCount );\r
408                                 buffer->Vertices.set_used ( vertexCount );\r
409 \r
410                                 // fill in static indices and vertex\r
411                                 u16 *index = buffer->Indices.pointer();\r
412                                 video::S3DVertex * v = buffer->Vertices.pointer();\r
413 \r
414                                 // blow up gl_triangle_fan/gl_triangle_strip to indexed triangle list\r
415                                 E_PRIMITIVE_TYPE type;\r
416                                 vertexCount = 0;\r
417                                 indexCount = 0;\r
418                                 tricmd = (s16*)((u8*)Header + mesh->triindex);\r
419                                 while ( (c = *(tricmd++)) )\r
420                                 {\r
421                                         if (c < 0)\r
422                                         {\r
423                                                 // triangle fan\r
424                                                 c = -c;\r
425                                                 type = EPT_TRIANGLE_FAN;\r
426                                         }\r
427                                         else\r
428                                         {\r
429                                                 type = EPT_TRIANGLE_STRIP;\r
430                                         }\r
431 \r
432                                         for ( s32 g = 0; g < c; ++g, v += 1, tricmd += 4 )\r
433                                         {\r
434                                                 // fill vertex\r
435         #if 0\r
436                                                 const f32 *av = studioverts[tricmd[0]];\r
437                                                 v->Pos.X = av[0];\r
438                                                 v->Pos.Z = av[1];\r
439                                                 v->Pos.Y = av[2];\r
440 \r
441                                                 av = studionorms[tricmd[1]];\r
442                                                 v->Normal.X = av[0];\r
443                                                 v->Normal.Z = av[1];\r
444                                                 v->Normal.Y = av[2];\r
445 \r
446         #endif\r
447                                                 v->Normal.X = 0.f;\r
448                                                 v->Normal.Z = 0.f;\r
449                                                 v->Normal.Y = 1.f;\r
450 \r
451                                                 v->TCoords.X = (tex_trans.X + tricmd[2])*tex_scale.X;\r
452                                                 v->TCoords.Y = (tex_trans.Y + tricmd[3])*tex_scale.Y;\r
453 \r
454                                                 v->Color.color = 0xFFFFFFFF;\r
455 \r
456                                                 // fill index\r
457                                                 if ( g < c - 2 )\r
458                                                 {\r
459                                                         if ( type == EPT_TRIANGLE_FAN )\r
460                                                         {\r
461                                                                 index[indexCount+0] = vertexCount;\r
462                                                                 index[indexCount+1] = vertexCount+g+1;\r
463                                                                 index[indexCount+2] = vertexCount+g+2;\r
464                                                         }\r
465                                                         else\r
466                                                         {\r
467                                                                 if ( g & 1 )\r
468                                                                 {\r
469                                                                         index[indexCount+0] = vertexCount+g+1;\r
470                                                                         index[indexCount+1] = vertexCount+g+0;\r
471                                                                         index[indexCount+2] = vertexCount+g+2;\r
472                                                                 }\r
473                                                                 else\r
474                                                                 {\r
475                                                                         index[indexCount+0] = vertexCount+g+0;\r
476                                                                         index[indexCount+1] = vertexCount+g+1;\r
477                                                                         index[indexCount+2] = vertexCount+g+2;\r
478                                                                 }\r
479                                                         }\r
480 \r
481                                                         indexCount += 3;\r
482                                                 }\r
483                                         }\r
484 \r
485                                         vertexCount += c;\r
486                                 }\r
487 \r
488                                 // material\r
489                                 video::SMaterial &m = buffer->getMaterial();\r
490 \r
491                                 m.MaterialType = video::EMT_SOLID;\r
492                                 m.BackfaceCulling = true;\r
493 \r
494                                 if ( currentex->flags & STUDIO_NF_CHROME )\r
495                                 {\r
496                                         // don't know what to do with chrome here\r
497                                 }\r
498 \r
499 #ifdef HL_TEXTURE_ATLAS\r
500                                 io::path store = TextureBaseName + "atlas";\r
501 #else\r
502                                 io::path fname;\r
503                                 io::path ext;\r
504                                 core::splitFilename ( currentex->name, 0, &fname, &ext );\r
505                                 io::path store = TextureBaseName + fname;\r
506 #endif\r
507                                 m.TextureLayer[0].Texture = SceneManager->getVideoDriver()->getTexture ( store );\r
508                                 m.Lighting = false;\r
509 \r
510                                 MeshIPol->addMeshBuffer(buffer);\r
511                                 buffer->recalculateBoundingBox();\r
512                                 buffer->drop();\r
513                         } // mesh\r
514                         MeshIPol->recalculateBoundingBox();\r
515                 } // model\r
516         } // body part\r
517 }\r
518 \r
519 \r
520 /*!\r
521 */\r
522 void CAnimatedMeshHalfLife::buildVertices()\r
523 {\r
524 /*\r
525         const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex);\r
526         if (SkinGroupSelection != 0 && SkinGroupSelection < TextureHeader->numskinfamilies)\r
527                 skinref += (SkinGroupSelection * TextureHeader->numskinref);\r
528 */\r
529         u32 meshBufferNr = 0;\r
530         for ( u32 bodypart = 0 ; bodypart < Header->numbodyparts; ++bodypart)\r
531         {\r
532                 const SHalflifeBody *body = (SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart;\r
533 \r
534                 for ( u32 modelnr = 0; modelnr < body->nummodels; ++modelnr )\r
535                 {\r
536                         const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr;\r
537 \r
538                         const u8 *vertbone = ((u8*)Header + model->vertinfoindex);\r
539 \r
540                         const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex);\r
541 \r
542                         for (u32 i = 0; i < model->numverts; i++)\r
543                         {\r
544                                 VectorTransform ( studioverts[i],  BoneTransform[vertbone[i]], TransformedVerts[i]  );\r
545                         }\r
546         /*\r
547                         const u8 *normbone = ((u8*)Header + model->norminfoindex);\r
548                         const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex);\r
549                         for ( i = 0; i < model->numnorms; i++)\r
550                         {\r
551                                 VectorTransform ( studionorms[i],  BoneTransform[normbone[i]], TransformedNormals[i]  );\r
552                         }\r
553         */\r
554                         for (u32 i = 0; i < model->nummesh; i++)\r
555                         {\r
556                                 const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i;\r
557 \r
558                                 IMeshBuffer * buffer = MeshIPol->getMeshBuffer ( meshBufferNr++ );\r
559                                 video::S3DVertex* v = (video::S3DVertex* ) buffer->getVertices();\r
560 \r
561                                 const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex);\r
562                                 s32 c = 0;\r
563                                 while ( (c = *(tricmd++)) )\r
564                                 {\r
565                                         if (c < 0)\r
566                                                 c = -c;\r
567 \r
568                                         for (s32 g = 0; g < c; ++g, v += 1, tricmd += 4 )\r
569                                         {\r
570                                                 // fill vertex\r
571                                                 const core::vector3df& av = TransformedVerts[tricmd[0]];\r
572                                                 v->Pos = av;\r
573         /*\r
574                                                 const core::vector3df& an = TransformedNormals[tricmd[1]];\r
575                                                 v->Normal = an;\r
576                                                 //v->Normal.normalize();\r
577         */\r
578                                         }\r
579                                 } // tricmd\r
580                         } // nummesh\r
581                 } // model\r
582         } // bodypart\r
583 }\r
584 \r
585 \r
586 /*!\r
587         render Bones\r
588 */\r
589 void CAnimatedMeshHalfLife::renderModel(u32 param, IVideoDriver * driver, const core::matrix4 &absoluteTransformation)\r
590 {\r
591         const SHalflifeBone *bone = (SHalflifeBone *) ((u8 *) Header + Header->boneindex);\r
592 \r
593         const video::SColor blue(0xFF000080);\r
594         const video::SColor red(0xFF800000);\r
595         const video::SColor yellow(0xFF808000);\r
596         const video::SColor cyan(0xFF008080);\r
597 \r
598         core::aabbox3df box;\r
599 \r
600         for (u32 i = 0; i < Header->numbones; i++)\r
601         {\r
602                 if (bone[i].parent >= 0)\r
603                 {\r
604                         getBoneVector ( box.MinEdge, bone[i].parent );\r
605                         getBoneVector ( box.MaxEdge, i );\r
606                         driver->draw3DLine ( box.MinEdge, box.MaxEdge, blue );\r
607 \r
608                         // draw parent bone node\r
609                         if (bone[bone[i].parent].parent >=0 )\r
610                         {\r
611                                 getBoneBox ( box, bone[i].parent );\r
612                                 driver->draw3DBox ( box, blue );\r
613                         }\r
614                         getBoneBox ( box, i );\r
615                         driver->draw3DBox ( box, blue );\r
616                 }\r
617                 else\r
618                 {\r
619                         // draw parent bone node\r
620                         getBoneBox ( box, i, 1.f );\r
621                         driver->draw3DBox ( box , red );\r
622                 }\r
623         }\r
624 \r
625         // attachements\r
626         const SHalflifeAttachment *attach = (SHalflifeAttachment *) ((u8*) Header + Header->attachmentindex);\r
627         core::vector3df v[8];\r
628         for (u32 i = 0; i < Header->numattachments; i++)\r
629         {\r
630                 getTransformedBoneVector ( v[0],attach[i].bone,attach[i].org );\r
631                 getTransformedBoneVector ( v[1],attach[i].bone,attach[i].vectors[0] );\r
632                 getTransformedBoneVector ( v[2],attach[i].bone,attach[i].vectors[1] );\r
633                 getTransformedBoneVector ( v[3],attach[i].bone,attach[i].vectors[2] );\r
634                 driver->draw3DLine ( v[0], v[1], cyan );\r
635                 driver->draw3DLine ( v[0], v[2], cyan );\r
636                 driver->draw3DLine ( v[0], v[3], cyan );\r
637         }\r
638 \r
639         // hit boxes\r
640         SHalflifeBBox *hitbox = (SHalflifeBBox *) ((u8*) Header + Header->hitboxindex);\r
641         vec3_hl v2[8];\r
642         for (u32 i = 0; i < Header->numhitboxes; i++)\r
643         {\r
644                 f32 *bbmin = hitbox[i].bbmin;\r
645                 f32 *bbmax = hitbox[i].bbmax;\r
646 \r
647                 v2[0][0] = bbmin[0];\r
648                 v2[0][1] = bbmax[1];\r
649                 v2[0][2] = bbmin[2];\r
650 \r
651                 v2[1][0] = bbmin[0];\r
652                 v2[1][1] = bbmin[1];\r
653                 v2[1][2] = bbmin[2];\r
654 \r
655                 v2[2][0] = bbmax[0];\r
656                 v2[2][1] = bbmax[1];\r
657                 v2[2][2] = bbmin[2];\r
658 \r
659                 v2[3][0] = bbmax[0];\r
660                 v2[3][1] = bbmin[1];\r
661                 v2[3][2] = bbmin[2];\r
662 \r
663                 v2[4][0] = bbmax[0];\r
664                 v2[4][1] = bbmax[1];\r
665                 v2[4][2] = bbmax[2];\r
666 \r
667                 v2[5][0] = bbmax[0];\r
668                 v2[5][1] = bbmin[1];\r
669                 v2[5][2] = bbmax[2];\r
670 \r
671                 v2[6][0] = bbmin[0];\r
672                 v2[6][1] = bbmax[1];\r
673                 v2[6][2] = bbmax[2];\r
674 \r
675                 v2[7][0] = bbmin[0];\r
676                 v2[7][1] = bbmin[1];\r
677                 v2[7][2] = bbmax[2];\r
678 \r
679                 for ( u32 g = 0; g < 8; ++g )\r
680                         getTransformedBoneVector ( v[g],hitbox[i].bone,v2[g] );\r
681 \r
682                 driver->draw3DLine(v[0], v[1], yellow);\r
683                 driver->draw3DLine(v[1], v[3], yellow);\r
684                 driver->draw3DLine(v[3], v[2], yellow);\r
685                 driver->draw3DLine(v[2], v[0], yellow);\r
686 \r
687                 driver->draw3DLine(v[4], v[5], yellow);\r
688                 driver->draw3DLine(v[5], v[7], yellow);\r
689                 driver->draw3DLine(v[7], v[6], yellow);\r
690                 driver->draw3DLine(v[6], v[4], yellow);\r
691 \r
692                 driver->draw3DLine(v[0], v[6], yellow);\r
693                 driver->draw3DLine(v[1], v[7], yellow);\r
694                 driver->draw3DLine(v[3], v[5], yellow);\r
695                 driver->draw3DLine(v[2], v[4], yellow);\r
696         }\r
697 }\r
698 \r
699 \r
700 //! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail.\r
701 IMesh* CAnimatedMeshHalfLife::getMesh(s32 frameInt, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)\r
702 {\r
703         const f32 frame = frameInt + (detailLevel * 0.001f);\r
704         const u32 frameA = core::floor32 ( frame );\r
705 //      f32 blend = core::fract ( frame );\r
706 \r
707         SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex);\r
708 \r
709         // find SequenceIndex from summed list\r
710         u32 frameCount = 0;\r
711         for (u32 i = 0; i < Header->numseq; ++i)\r
712         {\r
713                 const u32 val = core::max_ ( 1, seq[i].numframes - 1 );\r
714                 if ( frameCount + val > frameA  )\r
715                 {\r
716                         SequenceIndex = i;\r
717                         CurrentFrame = frame - frameCount;\r
718                         break;\r
719                 }\r
720                 frameCount += val;\r
721         }\r
722 \r
723         seq += SequenceIndex;\r
724 \r
725         //SetBodyPart ( 1, 1 );\r
726         setUpBones ();\r
727         buildVertices();\r
728 \r
729         MeshIPol->BoundingBox.MinEdge.X = seq->bbmin[0];\r
730         MeshIPol->BoundingBox.MinEdge.Z = seq->bbmin[1];\r
731         MeshIPol->BoundingBox.MinEdge.Y = seq->bbmin[2];\r
732 \r
733         MeshIPol->BoundingBox.MaxEdge.X = seq->bbmax[0];\r
734         MeshIPol->BoundingBox.MaxEdge.Z = seq->bbmax[1];\r
735         MeshIPol->BoundingBox.MaxEdge.Y = seq->bbmax[2];\r
736 \r
737         return MeshIPol;\r
738 }\r
739 \r
740 \r
741 /*!\r
742 */\r
743 void CAnimatedMeshHalfLife::initData ()\r
744 {\r
745         Header = 0;\r
746         TextureHeader = 0;\r
747         OwnTexModel = false;\r
748 \r
749         for (u32 i = 0; i < 32; ++i )\r
750                 AnimationHeader[i] = 0;\r
751 \r
752         SequenceIndex = 0;\r
753         CurrentFrame = 0.f;\r
754 \r
755         for (u32 i = 0; i < 5; ++i )\r
756                 BoneController[i] = 0;\r
757 \r
758         for (u32 i = 0; i < 2; ++i )\r
759                 Blending[i] = 0;\r
760 \r
761         SkinGroupSelection = 0;\r
762 \r
763         AnimList.clear();\r
764         FrameCount = 0;\r
765 \r
766         if (!MeshIPol)\r
767                 MeshIPol = new SMesh();\r
768         MeshIPol->clear();\r
769 \r
770 #ifdef HL_TEXTURE_ATLAS\r
771         TextureAtlas.release();\r
772 #endif\r
773 }\r
774 \r
775 \r
776 /*!\r
777 */\r
778 void STextureAtlas::release()\r
779 {\r
780         for (u32 i = 0; i < atlas.size(); i++)\r
781         {\r
782                 if ( atlas[i].image )\r
783                 {\r
784                         atlas[i].image->drop();\r
785                         atlas[i].image = 0;\r
786                 }\r
787         }\r
788         Master = 0;\r
789 }\r
790 \r
791 \r
792 /*!\r
793 */\r
794 void STextureAtlas::addSource ( const c8 * name, video::IImage * image )\r
795 {\r
796         TextureAtlasEntry entry;\r
797         entry.name = name;\r
798         entry.image = image;\r
799         entry.width = image->getDimension().Width;\r
800         entry.height = image->getDimension().Height;\r
801         entry.pos.X = 0;\r
802         entry.pos.Y = 0;\r
803         atlas.push_back ( entry );\r
804 }\r
805 \r
806 \r
807 /*!\r
808 */\r
809 void STextureAtlas::getScale(core::vector2df& scale)\r
810 {\r
811         for (s32 i = static_cast<s32>(atlas.size()) - 1; i >= 0; --i)\r
812         {\r
813                 if ( atlas[i].name == "_merged_" )\r
814                 {\r
815                         scale.X = 1.f / atlas[i].width;\r
816                         scale.Y = 1.f / atlas[i].height;\r
817                         return;\r
818                 }\r
819         }\r
820         scale.X = 1.f;\r
821         scale.Y = 1.f;\r
822 }\r
823 \r
824 \r
825 /*!\r
826 */\r
827 void STextureAtlas::getTranslation(const c8* name, core::vector2di& pos)\r
828 {\r
829         for ( u32 i = 0; i < atlas.size(); ++i)\r
830         {\r
831                 if ( atlas[i].name == name )\r
832                 {\r
833                         pos = atlas[i].pos;\r
834                         return;\r
835                 }\r
836         }\r
837 }\r
838 \r
839 \r
840 /*!\r
841 */\r
842 void STextureAtlas::create(u32 border, E_TEXTURE_CLAMP texmode)\r
843 {\r
844         u32 w = 0;\r
845         u32 w2;\r
846         u32 h2;\r
847         u32 h;\r
848         u32 wsum;\r
849         u32 hsum = 0;\r
850         ECOLOR_FORMAT format = ECF_R8G8B8;\r
851 \r
852         const s32 frame = core::s32_max ( 0, (border - 1 ) / 2 );\r
853 \r
854         // sort for biggest coming first\r
855         atlas.sort();\r
856 \r
857         // split size\r
858         wsum = frame;\r
859         for (u32 i = 0; i < atlas.size(); i++)\r
860         {\r
861                 // make space\r
862                 w2 = atlas[i].width + border;\r
863 \r
864                 // align\r
865                 w2 = (w2 + 1) & ~1;\r
866                 wsum += w2;\r
867         }\r
868         u32 splitsize = 256;\r
869         if ( wsum > 512 )\r
870                 splitsize = 512;\r
871 \r
872         wsum = frame;\r
873         hsum = frame;\r
874         w = frame;\r
875         h = 0;\r
876         for (u32 i = 0; i < atlas.size(); i++)\r
877         {\r
878                 if ( atlas[i].image->getColorFormat() == ECF_A8R8G8B8 )\r
879                 {\r
880                         format = ECF_A8R8G8B8;\r
881                 }\r
882 \r
883                 // make space\r
884                 w2 = atlas[i].width + border;\r
885                 h2 = atlas[i].height + border;\r
886 \r
887                 // align\r
888                 w2 = (w2 + 1) & ~1;\r
889                 h2 = (h2 + 1) & ~1;\r
890 \r
891                 h = core::s32_max ( h, h2 );\r
892 \r
893                 if ( w + w2 >= splitsize )\r
894                 {\r
895                         hsum += h;\r
896                         wsum = core::s32_max ( wsum, w );\r
897                         h = h2;\r
898                         w = frame;\r
899                 }\r
900 \r
901                 atlas[i].pos.X = w;\r
902                 atlas[i].pos.Y = hsum;\r
903 \r
904                 w += w2;\r
905 \r
906         }\r
907         hsum += h;\r
908         wsum = core::s32_max ( wsum, w );\r
909 \r
910         // build image\r
911         const core::dimension2d<u32> dim = core::dimension2d<u32>( wsum, hsum ).getOptimalSize();\r
912         IImage* master = new CImage(format, dim);\r
913         master->fill(0);\r
914 \r
915         video::SColor col[2];\r
916 \r
917         static const u8 wrap[][4] =\r
918         {\r
919                 {1, 0}, // ETC_REPEAT\r
920                 {0, 1}, // ETC_CLAMP\r
921                 {0, 1}, // ETC_CLAMP_TO_EDGE\r
922                 {0, 1}  // ETC_MIRROR\r
923         };\r
924 \r
925         for (u32 i = 0; i < atlas.size(); i++)\r
926         {\r
927                 atlas[i].image->copyTo ( master, atlas[i].pos );\r
928 \r
929                 // clamp/wrap ( copy edges, filtering needs it )\r
930 \r
931                 for (s32 b = 0; b < frame; ++b )\r
932                 {\r
933                         for (s32 a = 0 - b; a <= (s32) atlas[i].width + b; ++a )\r
934                         {\r
935                                 col[0] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), 0 );\r
936                                 col[1] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), atlas[i].height - 1 );\r
937 \r
938                                 master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + ( b + 1 ) * -1, col[wrap[texmode][0]] );\r
939                                 master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + atlas[i].height - 1 + ( b + 1 ) * 1, col[wrap[texmode][1]] );\r
940                         }\r
941 \r
942                         for (s32 a = -1 - b; a <= (s32) atlas[i].height + b; ++a )\r
943                         {\r
944                                 col[0] = atlas[i].image->getPixel ( 0, core::s32_clamp ( a, 0, atlas[i].height - 1 ) );\r
945                                 col[1] = atlas[i].image->getPixel ( atlas[i].width - 1, core::s32_clamp ( a, 0, atlas[i].height - 1 ) );\r
946 \r
947                                 master->setPixel ( atlas[i].pos.X + ( b + 1 ) * -1, atlas[i].pos.Y + a, col[wrap[texmode][0]] );\r
948                                 master->setPixel ( atlas[i].pos.X + atlas[i].width + b, atlas[i].pos.Y + a, col[wrap[texmode][1]] );\r
949                         }\r
950                 }\r
951         }\r
952 \r
953         addSource ( "_merged_", master );\r
954         Master = master;\r
955 }\r
956 \r
957 \r
958 /*!\r
959 */\r
960 SHalflifeHeader* CAnimatedMeshHalfLife::loadModel(io::IReadFile* file, const io::path& filename)\r
961 {\r
962         bool closefile = false;\r
963 \r
964         // if secondary files are needed, open here and mark for closing\r
965         if ( 0 == file )\r
966         {\r
967                 file = SceneManager->getFileSystem()->createAndOpenFile(filename);\r
968                 closefile = true;\r
969         }\r
970 \r
971         if ( 0 == file )\r
972                 return 0;\r
973 \r
974         // read into memory\r
975         u8* pin = new u8[file->getSize()];\r
976         file->read(pin, file->getSize());\r
977 \r
978         SHalflifeHeader* header = (SHalflifeHeader*) pin;\r
979 \r
980         const bool idst = (0 == strncmp(header->id, "IDST", 4));\r
981         const bool idsq = (0 == strncmp(header->id, "IDSQ", 4));\r
982 \r
983         if ( (!idst && !idsq) || (idsq && !Header) )\r
984         {\r
985                 os::Printer::log("MDL Halflife Loader: Wrong file header", file->getFileName(), ELL_WARNING);\r
986                 if ( closefile )\r
987                 {\r
988                         file->drop();\r
989                         file = 0;\r
990                 }\r
991                 delete [] pin;\r
992                 return 0;\r
993         }\r
994 \r
995         // don't know the real header.. idsg might be different\r
996         if (header->textureindex && idst )\r
997         {\r
998                 io::path path;\r
999                 io::path fname;\r
1000                 io::path ext;\r
1001 \r
1002                 core::splitFilename(file->getFileName(), &path, &fname, &ext);\r
1003                 TextureBaseName = path + fname + "_";\r
1004 \r
1005                 const SHalflifeTexture *tex = (SHalflifeTexture *)(pin + header->textureindex);\r
1006                 u32 *palette = new u32[256];\r
1007                 for (u32 i = 0; i < header->numtextures; ++i)\r
1008                 {\r
1009                         const u8 *src = pin + tex[i].index;\r
1010 \r
1011                         // convert rgb to argb palette\r
1012                         {\r
1013                                 const u8 *pal = src + tex[i].width * tex[i].height;\r
1014                                 for( u32 g=0; g<256; ++g )\r
1015                                 {\r
1016                                         palette[g] = 0xFF000000 | pal[0] << 16 | pal[1] << 8 | pal[2];\r
1017                                         pal += 3;\r
1018                                 }\r
1019                         }\r
1020 \r
1021                         IImage* image = SceneManager->getVideoDriver()->createImage(ECF_R8G8B8, core::dimension2d<u32>(tex[i].width, tex[i].height));\r
1022 \r
1023                         CColorConverter::convert8BitTo24Bit(src, (u8*)image->getData(), tex[i].width, tex[i].height, (u8*) palette, 0, false);\r
1024 \r
1025 #ifdef HL_TEXTURE_ATLAS\r
1026                         TextureAtlas.addSource ( tex[i].name, image );\r
1027 #else\r
1028                         core::splitFilename ( tex[i].name, 0, &fname, &ext );\r
1029                         SceneManager->getVideoDriver()->addTexture ( TextureBaseName + fname, image );\r
1030                         image->drop();\r
1031 #endif\r
1032                 }\r
1033                 delete [] palette;\r
1034 \r
1035 #ifdef HL_TEXTURE_ATLAS\r
1036                 TextureAtlas.create ( 2 * 2 + 1, ETC_CLAMP );\r
1037                 SceneManager->getVideoDriver()->addTexture ( TextureBaseName + "atlas", TextureAtlas.Master );\r
1038                 TextureAtlas.release();\r
1039 #endif\r
1040         }\r
1041 \r
1042         if (!Header)\r
1043                 Header = header;\r
1044 \r
1045         if ( closefile )\r
1046         {\r
1047                 file->drop();\r
1048                 file = 0;\r
1049         }\r
1050 \r
1051         return header;\r
1052 }\r
1053 \r
1054 \r
1055 /*!\r
1056 */\r
1057 f32 CAnimatedMeshHalfLife::SetController( s32 controllerIndex, f32 value )\r
1058 {\r
1059         if (!Header)\r
1060                 return 0.f;\r
1061 \r
1062         SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex);\r
1063 \r
1064         // find first controller that matches the index\r
1065         u32 i;\r
1066         for (i = 0; i < Header->numbonecontrollers; i++, bonecontroller++)\r
1067         {\r
1068                 if (bonecontroller->index == controllerIndex)\r
1069                         break;\r
1070         }\r
1071         if (i >= Header->numbonecontrollers)\r
1072                 return value;\r
1073 \r
1074         // wrap 0..360 if it's a rotational controller\r
1075         if (bonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR))\r
1076         {\r
1077                 // ugly hack, invert value if end < start\r
1078                 if (bonecontroller->end < bonecontroller->start)\r
1079                         value = -value;\r
1080 \r
1081                 // does the controller not wrap?\r
1082                 if (bonecontroller->start + 359.f >= bonecontroller->end)\r
1083                 {\r
1084                         if (value > ((bonecontroller->start + bonecontroller->end) / 2.f) + 180.f)\r
1085                                 value = value - 360.f;\r
1086                         if (value < ((bonecontroller->start + bonecontroller->end) / 2.f) - 180.f)\r
1087                                 value = value + 360.f;\r
1088                 }\r
1089                 else\r
1090                 {\r
1091                         if (value > 360.f)\r
1092                                 value = value - (s32)(value / 360.f) * 360.f;\r
1093                         else if (value < 0.f)\r
1094                                 value = value + (s32)((value / -360.f) + 1) * 360.f;\r
1095                 }\r
1096         }\r
1097 \r
1098         const s32 range = controllerIndex == MOUTH_CONTROLLER ? 64 : 255;\r
1099 \r
1100         s32 setting = (s32) ( (f32) range * (value - bonecontroller->start) / (bonecontroller->end - bonecontroller->start));\r
1101 \r
1102         if (setting < 0) setting = 0;\r
1103         if (setting > range) setting = range;\r
1104 \r
1105         BoneController[controllerIndex] = setting;\r
1106 \r
1107         return setting * (1.f / (f32) range ) * (bonecontroller->end - bonecontroller->start) + bonecontroller->start;\r
1108 }\r
1109 \r
1110 \r
1111 /*!\r
1112 */\r
1113 u32 CAnimatedMeshHalfLife::SetSkin( u32 value )\r
1114 {\r
1115         if (value < Header->numskinfamilies)\r
1116                 SkinGroupSelection = value;\r
1117 \r
1118         return SkinGroupSelection;\r
1119 }\r
1120 \r
1121 \r
1122 /*!\r
1123 */\r
1124 bool CAnimatedMeshHalfLife::postLoadModel( const io::path &filename )\r
1125 {\r
1126         io::path path;\r
1127         io::path texname;\r
1128         io::path submodel;\r
1129 \r
1130         core::splitFilename ( filename ,&path, &texname, 0 );\r
1131 \r
1132         // preload textures\r
1133         // if no textures are stored in main file, use texfile\r
1134         if (Header->numtextures == 0)\r
1135         {\r
1136                 submodel = path + texname + "T.mdl";\r
1137                 TextureHeader = loadModel(0, submodel);\r
1138                 if (!TextureHeader)\r
1139                         return false;\r
1140                 OwnTexModel = true;\r
1141         }\r
1142         else\r
1143         {\r
1144                 TextureHeader = Header;\r
1145                 OwnTexModel = false;\r
1146         }\r
1147 \r
1148         // preload animations\r
1149         if (Header->numseqgroups > 1)\r
1150         {\r
1151                 c8 seq[8];\r
1152                 for (u32 i = 1; i < Header->numseqgroups; i++)\r
1153                 {\r
1154                         snprintf_irr( seq, 8, "%02u.mdl", i );\r
1155                         submodel = path + texname + seq;\r
1156 \r
1157                         AnimationHeader[i] = loadModel(0, submodel);\r
1158                         if (!AnimationHeader[i])\r
1159                                 return false;\r
1160                 }\r
1161         }\r
1162 \r
1163         return true;\r
1164 }\r
1165 \r
1166 \r
1167 /*!\r
1168 */\r
1169 void CAnimatedMeshHalfLife::dumpModelInfo(u32 level) const\r
1170 {\r
1171         const u8 *phdr = (const u8*) Header;\r
1172         const SHalflifeHeader * hdr = Header;\r
1173 \r
1174         if (level == 0)\r
1175         {\r
1176                 printf (\r
1177                         "Bones: %u\n"\r
1178                         "Bone Controllers: %u\n"\r
1179                         "Hit Boxes: %u\n"\r
1180                         "Sequences: %u\n"\r
1181                         "Sequence Groups: %u\n",\r
1182                         hdr->numbones,\r
1183                         hdr->numbonecontrollers,\r
1184                         hdr->numhitboxes,\r
1185                         hdr->numseq,\r
1186                         hdr->numseqgroups\r
1187                         );\r
1188                 printf (\r
1189                         "Textures: %u\n"\r
1190                         "Skin Families: %u\n"\r
1191                         "Bodyparts: %u\n"\r
1192                         "Attachments: %u\n"\r
1193                         "Transitions: %d\n",\r
1194                         hdr->numtextures,\r
1195                         hdr->numskinfamilies,\r
1196                         hdr->numbodyparts,\r
1197                         hdr->numattachments,\r
1198                         hdr->numtransitions);\r
1199                 return;\r
1200         }\r
1201 \r
1202         printf("id: %c%c%c%c\n", phdr[0], phdr[1], phdr[2], phdr[3]);\r
1203         printf("version: %d\n", hdr->version);\r
1204         printf("name: \"%s\"\n", hdr->name);\r
1205         printf("length: %d\n\n", hdr->length);\r
1206 \r
1207         printf("eyeposition: %f %f %f\n", hdr->eyeposition[0], hdr->eyeposition[1], hdr->eyeposition[2]);\r
1208         printf("min: %f %f %f\n", hdr->min[0], hdr->min[1], hdr->min[2]);\r
1209         printf("max: %f %f %f\n", hdr->max[0], hdr->max[1], hdr->max[2]);\r
1210         printf("bbmin: %f %f %f\n", hdr->bbmin[0], hdr->bbmin[1], hdr->bbmin[2]);\r
1211         printf("bbmax: %f %f %f\n", hdr->bbmax[0], hdr->bbmax[1], hdr->bbmax[2]);\r
1212 \r
1213         printf("flags: %d\n\n", hdr->flags);\r
1214 \r
1215         printf("numbones: %u\n", hdr->numbones);\r
1216         for (u32 i = 0; i < hdr->numbones; i++)\r
1217         {\r
1218                 const SHalflifeBone *bone = (const SHalflifeBone *) (phdr + hdr->boneindex);\r
1219                 printf("bone %u.name: \"%s\"\n", i + 1, bone[i].name);\r
1220                 printf("bone %u.parent: %d\n", i + 1, bone[i].parent);\r
1221                 printf("bone %u.flags: %d\n", i + 1, bone[i].flags);\r
1222                 printf("bone %u.bonecontroller: %d %d %d %d %d %d\n", i + 1, bone[i].bonecontroller[0], bone[i].bonecontroller[1], bone[i].bonecontroller[2], bone[i].bonecontroller[3], bone[i].bonecontroller[4], bone[i].bonecontroller[5]);\r
1223                 printf("bone %u.value: %f %f %f %f %f %f\n", i + 1, bone[i].value[0], bone[i].value[1], bone[i].value[2], bone[i].value[3], bone[i].value[4], bone[i].value[5]);\r
1224                 printf("bone %u.scale: %f %f %f %f %f %f\n", i + 1, bone[i].scale[0], bone[i].scale[1], bone[i].scale[2], bone[i].scale[3], bone[i].scale[4], bone[i].scale[5]);\r
1225         }\r
1226 \r
1227         printf("\nnumbonecontrollers: %u\n", hdr->numbonecontrollers);\r
1228         const SHalflifeBoneController *bonecontrollers = (const SHalflifeBoneController *) (phdr + hdr->bonecontrollerindex);\r
1229         for (u32 i = 0; i < hdr->numbonecontrollers; i++)\r
1230         {\r
1231                 printf("bonecontroller %u.bone: %d\n", i + 1, bonecontrollers[i].bone);\r
1232                 printf("bonecontroller %u.type: %d\n", i + 1, bonecontrollers[i].type);\r
1233                 printf("bonecontroller %u.start: %f\n", i + 1, bonecontrollers[i].start);\r
1234                 printf("bonecontroller %u.end: %f\n", i + 1, bonecontrollers[i].end);\r
1235                 printf("bonecontroller %u.rest: %d\n", i + 1, bonecontrollers[i].rest);\r
1236                 printf("bonecontroller %u.index: %d\n", i + 1, bonecontrollers[i].index);\r
1237         }\r
1238 \r
1239         printf("\nnumhitboxes: %u\n", hdr->numhitboxes);\r
1240         const SHalflifeBBox *box = (const SHalflifeBBox *) (phdr + hdr->hitboxindex);\r
1241         for (u32 i = 0; i < hdr->numhitboxes; i++)\r
1242         {\r
1243                 printf("hitbox %u.bone: %d\n", i + 1, box[i].bone);\r
1244                 printf("hitbox %u.group: %d\n", i + 1, box[i].group);\r
1245                 printf("hitbox %u.bbmin: %f %f %f\n", i + 1, box[i].bbmin[0], box[i].bbmin[1], box[i].bbmin[2]);\r
1246                 printf("hitbox %u.bbmax: %f %f %f\n", i + 1, box[i].bbmax[0], box[i].bbmax[1], box[i].bbmax[2]);\r
1247         }\r
1248 \r
1249         printf("\nnumseq: %u\n", hdr->numseq);\r
1250         const SHalflifeSequence *seq = (const SHalflifeSequence *) (phdr + hdr->seqindex);\r
1251         for (u32 i = 0; i < hdr->numseq; i++)\r
1252         {\r
1253                 printf("seqdesc %u.label: \"%s\"\n", i + 1, seq[i].label);\r
1254                 printf("seqdesc %u.fps: %f\n", i + 1, seq[i].fps);\r
1255                 printf("seqdesc %u.flags: %d\n", i + 1, seq[i].flags);\r
1256                 printf("<...>\n");\r
1257         }\r
1258 \r
1259         printf("\nnumseqgroups: %u\n", hdr->numseqgroups);\r
1260         for (u32 i = 0; i < hdr->numseqgroups; i++)\r
1261         {\r
1262                 const SHalflifeSequenceGroup *group = (const SHalflifeSequenceGroup *) (phdr + hdr->seqgroupindex);\r
1263                 printf("\nseqgroup %u.label: \"%s\"\n", i + 1, group[i].label);\r
1264                 printf("\nseqgroup %u.namel: \"%s\"\n", i + 1, group[i].name);\r
1265                 printf("\nseqgroup %u.data: %d\n", i + 1, group[i].data);\r
1266         }\r
1267 \r
1268         printf("\nnumskinref: %u\n", hdr->numskinref);\r
1269         printf("numskinfamilies: %u\n", hdr->numskinfamilies);\r
1270 \r
1271         printf("\nnumbodyparts: %u\n", hdr->numbodyparts);\r
1272         const SHalflifeBody *pbodyparts = (const SHalflifeBody*) ((const u8*) hdr + hdr->bodypartindex);\r
1273         for (u32 i = 0; i < hdr->numbodyparts; i++)\r
1274         {\r
1275                 printf("bodypart %u.name: \"%s\"\n", i + 1, pbodyparts[i].name);\r
1276                 printf("bodypart %u.nummodels: %u\n", i + 1, pbodyparts[i].nummodels);\r
1277                 printf("bodypart %u.base: %u\n", i + 1, pbodyparts[i].base);\r
1278                 printf("bodypart %u.modelindex: %u\n", i + 1, pbodyparts[i].modelindex);\r
1279         }\r
1280 \r
1281         printf("\nnumattachments: %u\n", hdr->numattachments);\r
1282         for (u32 i = 0; i < hdr->numattachments; i++)\r
1283         {\r
1284                 const SHalflifeAttachment *attach = (const SHalflifeAttachment *) ((const u8*) hdr + hdr->attachmentindex);\r
1285                 printf("attachment %u.name: \"%s\"\n", i + 1, attach[i].name);\r
1286         }\r
1287 \r
1288         hdr = TextureHeader;\r
1289         printf("\nnumtextures: %u\n", hdr->numtextures);\r
1290         printf("textureindex: %u\n", hdr->textureindex);\r
1291         printf("texturedataindex: %u\n", hdr->texturedataindex);\r
1292         const SHalflifeTexture *ptextures = (const SHalflifeTexture *) ((const u8*) hdr + hdr->textureindex);\r
1293         for (u32 i = 0; i < hdr->numtextures; i++)\r
1294         {\r
1295                 printf("texture %u.name: \"%s\"\n", i + 1, ptextures[i].name);\r
1296                 printf("texture %u.flags: %d\n", i + 1, ptextures[i].flags);\r
1297                 printf("texture %u.width: %d\n", i + 1, ptextures[i].width);\r
1298                 printf("texture %u.height: %d\n", i + 1, ptextures[i].height);\r
1299                 printf("texture %u.index: %d\n", i + 1, ptextures[i].index);\r
1300         }\r
1301 }\r
1302 \r
1303 \r
1304 /*!\r
1305 */\r
1306 void CAnimatedMeshHalfLife::ExtractBbox(s32 sequence, core::aabbox3df &box) const\r
1307 {\r
1308         const SHalflifeSequence *seq = (const SHalflifeSequence *)((const u8*)Header + Header->seqindex) + sequence;\r
1309 \r
1310         box.MinEdge.X = seq[0].bbmin[0];\r
1311         box.MinEdge.Y = seq[0].bbmin[1];\r
1312         box.MinEdge.Z = seq[0].bbmin[2];\r
1313 \r
1314         box.MaxEdge.X = seq[0].bbmax[0];\r
1315         box.MaxEdge.Y = seq[0].bbmax[1];\r
1316         box.MaxEdge.Z = seq[0].bbmax[2];\r
1317 }\r
1318 \r
1319 \r
1320 /*!\r
1321 */\r
1322 void CAnimatedMeshHalfLife::calcBoneAdj()\r
1323 {\r
1324         const SHalflifeBoneController *bonecontroller =\r
1325                 (const SHalflifeBoneController *)((const u8*) Header + Header->bonecontrollerindex);\r
1326 \r
1327         for (u32 j = 0; j < Header->numbonecontrollers; j++)\r
1328         {\r
1329                 const s32 i = bonecontroller[j].index;\r
1330                 // check for 360% wrapping\r
1331                 f32 value;\r
1332                 if (bonecontroller[j].type & STUDIO_RLOOP)\r
1333                 {\r
1334                         value = BoneController[i] * (360.f/256.f) + bonecontroller[j].start;\r
1335                 }\r
1336                 else\r
1337                 {\r
1338                         const f32 range = i <= 3 ? 255.f : 64.f;\r
1339                         value = core::clamp(BoneController[i] / range,0.f,1.f);\r
1340                         value = (1.f - value) * bonecontroller[j].start + value * bonecontroller[j].end;\r
1341                 }\r
1342 \r
1343                 switch(bonecontroller[j].type & STUDIO_TYPES)\r
1344                 {\r
1345                 case STUDIO_XR:\r
1346                 case STUDIO_YR:\r
1347                 case STUDIO_ZR:\r
1348                         BoneAdj[j] = value * core::DEGTORAD;\r
1349                         break;\r
1350                 case STUDIO_X:\r
1351                 case STUDIO_Y:\r
1352                 case STUDIO_Z:\r
1353                         BoneAdj[j] = value;\r
1354                         break;\r
1355                 }\r
1356         }\r
1357 }\r
1358 \r
1359 \r
1360 /*!\r
1361 */\r
1362 void CAnimatedMeshHalfLife::calcBoneQuaternion(const s32 frame, const SHalflifeBone * const bone,\r
1363                 SHalflifeAnimOffset *anim, const u32 j, f32& angle1, f32& angle2) const\r
1364 {\r
1365         // three vector components\r
1366         if (anim->offset[j+3] == 0)\r
1367         {\r
1368                 angle2 = angle1 = bone->value[j+3]; // default\r
1369         }\r
1370         else\r
1371         {\r
1372                 SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j+3]);\r
1373                 s32 k = frame;\r
1374                 while (animvalue->num.total <= k)\r
1375                 {\r
1376                         k -= animvalue->num.total;\r
1377                         animvalue += animvalue->num.valid + 1;\r
1378                 }\r
1379                 // Bah, missing blend!\r
1380                 if (animvalue->num.valid > k)\r
1381                 {\r
1382                         angle1 = animvalue[k+1].value;\r
1383 \r
1384                         if (animvalue->num.valid > k + 1)\r
1385                         {\r
1386                                 angle2 = animvalue[k+2].value;\r
1387                         }\r
1388                         else\r
1389                         {\r
1390                                 if (animvalue->num.total > k + 1)\r
1391                                         angle2 = angle1;\r
1392                                 else\r
1393                                         angle2 = animvalue[animvalue->num.valid+2].value;\r
1394                         }\r
1395                 }\r
1396                 else\r
1397                 {\r
1398                         angle1 = animvalue[animvalue->num.valid].value;\r
1399                         if (animvalue->num.total > k + 1)\r
1400                         {\r
1401                                 angle2 = angle1;\r
1402                         }\r
1403                         else\r
1404                         {\r
1405                                 angle2 = animvalue[animvalue->num.valid + 2].value;\r
1406                         }\r
1407                 }\r
1408                 angle1 = bone->value[j+3] + angle1 * bone->scale[j+3];\r
1409                 angle2 = bone->value[j+3] + angle2 * bone->scale[j+3];\r
1410         }\r
1411 \r
1412         if (bone->bonecontroller[j+3] != -1)\r
1413         {\r
1414                 angle1 += BoneAdj[bone->bonecontroller[j+3]];\r
1415                 angle2 += BoneAdj[bone->bonecontroller[j+3]];\r
1416         }\r
1417 }\r
1418 \r
1419 \r
1420 /*!\r
1421 */\r
1422 void CAnimatedMeshHalfLife::calcBonePosition(const s32 frame, f32 s,\r
1423                 const SHalflifeBone * const bone, SHalflifeAnimOffset *anim, f32 *pos) const\r
1424 {\r
1425         for (s32 j = 0; j < 3; ++j)\r
1426         {\r
1427                 pos[j] = bone->value[j]; // default;\r
1428                 if (anim->offset[j] != 0)\r
1429                 {\r
1430                         SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j]);\r
1431 \r
1432                         s32 k = frame;\r
1433                         // find span of values that includes the frame we want\r
1434                         while (animvalue->num.total <= k)\r
1435                         {\r
1436                                 k -= animvalue->num.total;\r
1437                                 animvalue += animvalue->num.valid + 1;\r
1438                         }\r
1439                         // if we're inside the span\r
1440                         if (animvalue->num.valid > k)\r
1441                         {\r
1442                                 // and there's more data in the span\r
1443                                 if (animvalue->num.valid > k + 1)\r
1444                                 {\r
1445                                         pos[j] += (animvalue[k+1].value * (1.f - s) + s * animvalue[k+2].value) * bone->scale[j];\r
1446                                 }\r
1447                                 else\r
1448                                 {\r
1449                                         pos[j] += animvalue[k+1].value * bone->scale[j];\r
1450                                 }\r
1451                         }\r
1452                         else\r
1453                         {\r
1454                                 // are we at the end of the repeating values section and there's another section with data?\r
1455                                 if (animvalue->num.total <= k + 1)\r
1456                                 {\r
1457                                         pos[j] += (animvalue[animvalue->num.valid].value * (1.f - s) + s * animvalue[animvalue->num.valid + 2].value) * bone->scale[j];\r
1458                                 }\r
1459                                 else\r
1460                                 {\r
1461                                         pos[j] += animvalue[animvalue->num.valid].value * bone->scale[j];\r
1462                                 }\r
1463                         }\r
1464                 }\r
1465                 if (bone->bonecontroller[j] != -1)\r
1466                 {\r
1467                         pos[j] += BoneAdj[bone->bonecontroller[j]];\r
1468                 }\r
1469         }\r
1470 }\r
1471 \r
1472 \r
1473 /*!\r
1474 */\r
1475 void CAnimatedMeshHalfLife::calcRotations(vec3_hl *pos, vec4_hl *q,\r
1476                 SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f)\r
1477 {\r
1478         const s32 frame = (s32)f;\r
1479         const f32 s = (f - frame);\r
1480 \r
1481         // add in programatic controllers\r
1482         calcBoneAdj();\r
1483 \r
1484         SHalflifeBone *bone = (SHalflifeBone *)((u8 *)Header + Header->boneindex);\r
1485         for ( u32 i = 0; i < Header->numbones; i++, bone++, anim++)\r
1486         {\r
1487                 core::vector3df angle1, angle2;\r
1488                 calcBoneQuaternion(frame, bone, anim, 0, angle1.X, angle2.X);\r
1489                 calcBoneQuaternion(frame, bone, anim, 1, angle1.Y, angle2.Y);\r
1490                 calcBoneQuaternion(frame, bone, anim, 2, angle1.Z, angle2.Z);\r
1491 \r
1492                 if (!angle1.equals(angle2))\r
1493                 {\r
1494                         vec4_hl q1, q2;\r
1495                         AngleQuaternion( angle1, q1 );\r
1496                         AngleQuaternion( angle2, q2 );\r
1497                         QuaternionSlerp( q1, q2, s, q[i] );\r
1498                 }\r
1499                 else\r
1500                 {\r
1501                         AngleQuaternion( angle1, q[i] );\r
1502                 }\r
1503 \r
1504                 calcBonePosition(frame, s, bone, anim, pos[i]);\r
1505         }\r
1506 \r
1507         if (seq->motiontype & STUDIO_X)\r
1508                 pos[seq->motionbone][0] = 0.f;\r
1509         if (seq->motiontype & STUDIO_Y)\r
1510                 pos[seq->motionbone][1] = 0.f;\r
1511         if (seq->motiontype & STUDIO_Z)\r
1512                 pos[seq->motionbone][2] = 0.f;\r
1513 }\r
1514 \r
1515 \r
1516 /*!\r
1517 */\r
1518 SHalflifeAnimOffset * CAnimatedMeshHalfLife::getAnim( SHalflifeSequence *seq )\r
1519 {\r
1520         SHalflifeSequenceGroup *seqgroup = (SHalflifeSequenceGroup *)((u8*)Header + Header->seqgroupindex) + seq->seqgroup;\r
1521 \r
1522         if (seq->seqgroup == 0)\r
1523         {\r
1524                 return (SHalflifeAnimOffset *)((u8*)Header + seqgroup->data + seq->animindex);\r
1525         }\r
1526 \r
1527         return (SHalflifeAnimOffset *)((u8*)AnimationHeader[seq->seqgroup] + seq->animindex);\r
1528 }\r
1529 \r
1530 \r
1531 /*!\r
1532 */\r
1533 void CAnimatedMeshHalfLife::slerpBones(vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s)\r
1534 {\r
1535         if (s < 0)\r
1536                 s = 0;\r
1537         else if (s > 1.f)\r
1538                 s = 1.f;\r
1539 \r
1540         f32 s1 = 1.f - s;\r
1541 \r
1542         for ( u32 i = 0; i < Header->numbones; i++)\r
1543         {\r
1544                 vec4_hl q3;\r
1545                 QuaternionSlerp( q1[i], q2[i], s, q3 );\r
1546                 q1[i][0] = q3[0];\r
1547                 q1[i][1] = q3[1];\r
1548                 q1[i][2] = q3[2];\r
1549                 q1[i][3] = q3[3];\r
1550                 pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s;\r
1551                 pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s;\r
1552                 pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s;\r
1553         }\r
1554 }\r
1555 \r
1556 \r
1557 /*!\r
1558 */\r
1559 void CAnimatedMeshHalfLife::setUpBones()\r
1560 {\r
1561         static vec3_hl pos[MAXSTUDIOBONES];\r
1562         f32 bonematrix[3][4];\r
1563         static vec4_hl q[MAXSTUDIOBONES];\r
1564 \r
1565         static vec3_hl pos2[MAXSTUDIOBONES];\r
1566         static vec4_hl q2[MAXSTUDIOBONES];\r
1567         static vec3_hl pos3[MAXSTUDIOBONES];\r
1568         static vec4_hl q3[MAXSTUDIOBONES];\r
1569         static vec3_hl pos4[MAXSTUDIOBONES];\r
1570         static vec4_hl q4[MAXSTUDIOBONES];\r
1571 \r
1572         if (SequenceIndex >= Header->numseq)\r
1573                 SequenceIndex = 0;\r
1574 \r
1575         SHalflifeSequence *seq = (SHalflifeSequence *)((u8*) Header + Header->seqindex) + SequenceIndex;\r
1576 \r
1577         SHalflifeAnimOffset *anim = getAnim(seq);\r
1578         calcRotations(pos, q, seq, anim, CurrentFrame);\r
1579 \r
1580         if (seq->numblends > 1)\r
1581         {\r
1582                 anim += Header->numbones;\r
1583                 calcRotations( pos2, q2, seq, anim, CurrentFrame );\r
1584                 f32 s = Blending[0] / 255.f;\r
1585 \r
1586                 slerpBones( q, pos, q2, pos2, s );\r
1587 \r
1588                 if (seq->numblends == 4)\r
1589                 {\r
1590                         anim += Header->numbones;\r
1591                         calcRotations( pos3, q3, seq, anim, CurrentFrame );\r
1592 \r
1593                         anim += Header->numbones;\r
1594                         calcRotations( pos4, q4, seq, anim, CurrentFrame );\r
1595 \r
1596                         s = Blending[0] / 255.f;\r
1597                         slerpBones( q3, pos3, q4, pos4, s );\r
1598 \r
1599                         s = Blending[1] / 255.f;\r
1600                         slerpBones( q, pos, q3, pos3, s );\r
1601                 }\r
1602         }\r
1603 \r
1604         const SHalflifeBone *bone = (SHalflifeBone *)((u8*) Header + Header->boneindex);\r
1605 \r
1606         for (u32 i = 0; i < Header->numbones; i++)\r
1607         {\r
1608                 QuaternionMatrix( q[i], bonematrix );\r
1609 \r
1610                 bonematrix[0][3] = pos[i][0];\r
1611                 bonematrix[1][3] = pos[i][1];\r
1612                 bonematrix[2][3] = pos[i][2];\r
1613 \r
1614                 if (bone[i].parent == -1) {\r
1615                         memcpy(BoneTransform[i], bonematrix, sizeof(f32) * 12);\r
1616                 }\r
1617                 else {\r
1618                         R_ConcatTransforms (BoneTransform[bone[i].parent], bonematrix, BoneTransform[i]);\r
1619                 }\r
1620         }\r
1621 }\r
1622 \r
1623 \r
1624 //! Returns an axis aligned bounding box\r
1625 const core::aabbox3d<f32>& CAnimatedMeshHalfLife::getBoundingBox() const\r
1626 {\r
1627         return MeshIPol->BoundingBox;\r
1628 }\r
1629 \r
1630 \r
1631 //! Returns the type of the animated mesh.\r
1632 E_ANIMATED_MESH_TYPE CAnimatedMeshHalfLife::getMeshType() const\r
1633 {\r
1634         return EAMT_MDL_HALFLIFE;\r
1635 }\r
1636 \r
1637 \r
1638 //! returns amount of mesh buffers.\r
1639 u32 CAnimatedMeshHalfLife::getMeshBufferCount() const\r
1640 {\r
1641         return MeshIPol->getMeshBufferCount();\r
1642 }\r
1643 \r
1644 \r
1645 //! returns pointer to a mesh buffer\r
1646 IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(u32 nr) const\r
1647 {\r
1648         return MeshIPol->getMeshBuffer(nr);\r
1649 }\r
1650 \r
1651 \r
1652 //! Returns pointer to a mesh buffer which fits a material\r
1653 /** \param material: material to search for\r
1654 \return Returns the pointer to the mesh buffer or\r
1655 NULL if there is no such mesh buffer. */\r
1656 IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(const video::SMaterial &material) const\r
1657 {\r
1658         return MeshIPol->getMeshBuffer(material);\r
1659 }\r
1660 \r
1661 \r
1662 void CAnimatedMeshHalfLife::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)\r
1663 {\r
1664         MeshIPol->setMaterialFlag ( flag, newvalue );\r
1665 }\r
1666 \r
1667 \r
1668 //! set user axis aligned bounding box\r
1669 void CAnimatedMeshHalfLife::setBoundingBox(const core::aabbox3df& box)\r
1670 {\r
1671         MeshIPol->setBoundingBox(box);\r
1672 }\r
1673 \r
1674 \r
1675 } // end namespace scene\r
1676 } // end namespace irr\r
1677 \r
1678 #endif // _IRR_COMPILE_WITH_MD3_LOADER_\r
1679 \r