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
5 #include "IrrCompileConfig.h"
\r
6 #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
\r
8 #include "CAnimatedMeshHalfLife.h"
\r
10 #include "CColorConverter.h"
\r
12 #include "coreutil.h"
\r
13 #include "SMeshBuffer.h"
\r
14 #include "IVideoDriver.h"
\r
15 #include "IFileSystem.h"
\r
22 using namespace video;
\r
24 void AngleQuaternion(const core::vector3df& angles, vec4_hl quaternion)
\r
26 // FIXME: rescale the inputs to 1/2 angle
\r
27 double angle = angles.Z * 0.5;
\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
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
44 void QuaternionMatrix( const vec4_hl quaternion, f32 (*matrix)[4] )
\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
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
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
59 void QuaternionSlerp( const vec4_hl p, vec4_hl q, f32 t, vec4_hl qt )
\r
61 // decide if one of the quaternions is backwards
\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
69 for (s32 i = 0; i < 4; i++) {
\r
75 const double cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
\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
88 for (s32 i = 0; i < 4; i++) {
\r
89 qt[i] = f32(sclp * p[i] + sclq * q[i]);
\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
105 void R_ConcatTransforms (const f32 in1[3][4], const f32 in2[3][4], f32 out[3][4])
\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
121 #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
\r
123 inline void VectorTransform(const vec3_hl in1, const f32 in2[3][4], core::vector3df& out)
\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
130 static f32 BoneTransform[MAXSTUDIOBONES][3][4]; // bone transformation matrix
\r
132 void getBoneVector ( core::vector3df &out, u32 index )
\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
139 void getBoneBox ( core::aabbox3df &box, u32 index, f32 size = 0.5f )
\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
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
151 void getTransformedBoneVector ( core::vector3df &out, u32 index, const vec3_hl in)
\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
161 CHalflifeMDLMeshFileLoader::CHalflifeMDLMeshFileLoader(
\r
162 scene::ISceneManager* smgr) : SceneManager(smgr)
\r
165 setDebugName("CHalflifeMDLMeshFileLoader");
\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
174 return core::hasFileExtension(filename, "mdl");
\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
184 CAnimatedMeshHalfLife* msh = new CAnimatedMeshHalfLife();
\r
187 if (msh->loadModelFile(file, SceneManager))
\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
206 setDebugName("CAnimatedMeshHalfLife");
\r
212 loads a complete model
\r
214 bool CAnimatedMeshHalfLife::loadModelFile(io::IReadFile* file,
\r
215 ISceneManager* smgr)
\r
220 SceneManager = smgr;
\r
222 if ( loadModel(file, file->getFileName()) )
\r
224 if ( postLoadModel ( file->getFileName() ) )
\r
227 //dumpModelInfo ( 1 );
\r
236 CAnimatedMeshHalfLife::~CAnimatedMeshHalfLife()
\r
238 delete [] (u8*) Header;
\r
240 delete [] (u8*) TextureHeader;
\r
242 for (u32 i = 0; i < 32; ++i)
\r
243 delete [] (u8*) AnimationHeader[i];
\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
257 //! set the hardware mapping hint, for driver
\r
258 void CAnimatedMeshHalfLife::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,E_BUFFER_TYPE buffer)
\r
263 //! flags the meshbuffer as changed, reloads hardware buffers
\r
264 void CAnimatedMeshHalfLife::setDirty(E_BUFFER_TYPE buffer)
\r
269 static core::vector3df TransformedVerts[MAXSTUDIOVERTS]; // transformed vertices
\r
270 //static core::vector3df TransformedNormals[MAXSTUDIOVERTS]; // light surface normals
\r
275 void CAnimatedMeshHalfLife::initModel()
\r
277 // init Sequences to Animation
\r
278 KeyFrameInterpolation ipol;
\r
279 ipol.Name.reserve ( 64 );
\r
284 const SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex);
\r
285 for (u32 i = 0; i < Header->numseq; i++)
\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
295 FrameCount += ipol.Frames;
\r
298 // initBoneControllers
\r
300 SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex);
\r
301 for ( i = 0; i < Header->numbonecontrollers; i++)
\r
303 printf ( "BoneController%d index:%d%s range:%f - %f\n",
\r
305 bonecontroller[i].index, bonecontroller[i].index == MOUTH_CONTROLLER ? " (Mouth)": "",
\r
306 bonecontroller[i].start,bonecontroller[i].end
\r
311 for (i = 0; i < TextureHeader->numskinfamilies; i++)
\r
313 printf ( "Skin%d\n", i + 1);
\r
318 u32 meshBuffer = 0;
\r
320 const SHalflifeBody *body = (const SHalflifeBody *) ((u8*) Header + Header->bodypartindex);
\r
321 for (u32 i=0; i < Header->numbodyparts; ++i)
\r
324 part.name = body[i].name;
\r
325 part.defaultModel = core::max_ ( 0, (s32) body[i].base - 1 );
\r
327 const SHalflifeModel * model = (SHalflifeModel *)((u8*) Header + body[i].modelindex);
\r
328 for ( u32 g = 0; g < body[i].nummodels; ++g)
\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
338 BodyList.push_back ( part );
\r
342 CurrentFrame = 0.f;
\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
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
358 core::vector2df tex_scale;
\r
359 core::vector2di tex_trans ( 0, 0 );
\r
361 #ifdef HL_TEXTURE_ATLAS
\r
362 TextureAtlas.getScale(tex_scale);
\r
365 for (u32 bodypart=0 ; bodypart < Header->numbodyparts ; ++bodypart)
\r
367 body = (const SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart;
\r
369 for (u32 modelnr = 0; modelnr < body->nummodels; ++modelnr)
\r
371 const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr;
\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
376 for (u32 i = 0; i < model->nummesh; ++i)
\r
378 const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i;
\r
379 const SHalflifeTexture *currentex = &tex[skinref[mesh->skinref]];
\r
381 #ifdef HL_TEXTURE_ATLAS
\r
382 TextureAtlas.getTranslation ( currentex->name, tex_trans );
\r
384 tex_scale.X = 1.f/(f32)currentex->width;
\r
385 tex_scale.Y = 1.f/(f32)currentex->height;
\r
388 SMeshBuffer * buffer = new SMeshBuffer();
\r
390 // count index vertex size indexcount = mesh->numtris * 3
\r
391 u32 indexCount = 0;
\r
392 u32 vertexCount = 0;
\r
394 const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex);
\r
396 while ( (c = *(tricmd++)) )
\r
401 indexCount += ( c - 2 ) * 3;
\r
403 tricmd += ( 4 * c );
\r
407 buffer->Indices.set_used ( indexCount );
\r
408 buffer->Vertices.set_used ( vertexCount );
\r
410 // fill in static indices and vertex
\r
411 u16 *index = buffer->Indices.pointer();
\r
412 video::S3DVertex * v = buffer->Vertices.pointer();
\r
414 // blow up gl_triangle_fan/gl_triangle_strip to indexed triangle list
\r
415 E_PRIMITIVE_TYPE type;
\r
418 tricmd = (s16*)((u8*)Header + mesh->triindex);
\r
419 while ( (c = *(tricmd++)) )
\r
425 type = EPT_TRIANGLE_FAN;
\r
429 type = EPT_TRIANGLE_STRIP;
\r
432 for ( s32 g = 0; g < c; ++g, v += 1, tricmd += 4 )
\r
436 const f32 *av = studioverts[tricmd[0]];
\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
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
454 v->Color.color = 0xFFFFFFFF;
\r
459 if ( type == EPT_TRIANGLE_FAN )
\r
461 index[indexCount+0] = vertexCount;
\r
462 index[indexCount+1] = vertexCount+g+1;
\r
463 index[indexCount+2] = vertexCount+g+2;
\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
475 index[indexCount+0] = vertexCount+g+0;
\r
476 index[indexCount+1] = vertexCount+g+1;
\r
477 index[indexCount+2] = vertexCount+g+2;
\r
489 video::SMaterial &m = buffer->getMaterial();
\r
491 m.MaterialType = video::EMT_SOLID;
\r
492 m.BackfaceCulling = true;
\r
494 if ( currentex->flags & STUDIO_NF_CHROME )
\r
496 // don't know what to do with chrome here
\r
499 #ifdef HL_TEXTURE_ATLAS
\r
500 io::path store = TextureBaseName + "atlas";
\r
504 core::splitFilename ( currentex->name, 0, &fname, &ext );
\r
505 io::path store = TextureBaseName + fname;
\r
507 m.TextureLayer[0].Texture = SceneManager->getVideoDriver()->getTexture ( store );
\r
508 m.Lighting = false;
\r
510 MeshIPol->addMeshBuffer(buffer);
\r
511 buffer->recalculateBoundingBox();
\r
514 MeshIPol->recalculateBoundingBox();
\r
522 void CAnimatedMeshHalfLife::buildVertices()
\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
529 u32 meshBufferNr = 0;
\r
530 for ( u32 bodypart = 0 ; bodypart < Header->numbodyparts; ++bodypart)
\r
532 const SHalflifeBody *body = (SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart;
\r
534 for ( u32 modelnr = 0; modelnr < body->nummodels; ++modelnr )
\r
536 const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr;
\r
538 const u8 *vertbone = ((u8*)Header + model->vertinfoindex);
\r
540 const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex);
\r
542 for (u32 i = 0; i < model->numverts; i++)
\r
544 VectorTransform ( studioverts[i], BoneTransform[vertbone[i]], TransformedVerts[i] );
\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
551 VectorTransform ( studionorms[i], BoneTransform[normbone[i]], TransformedNormals[i] );
\r
554 for (u32 i = 0; i < model->nummesh; i++)
\r
556 const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i;
\r
558 IMeshBuffer * buffer = MeshIPol->getMeshBuffer ( meshBufferNr++ );
\r
559 video::S3DVertex* v = (video::S3DVertex* ) buffer->getVertices();
\r
561 const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex);
\r
563 while ( (c = *(tricmd++)) )
\r
568 for (s32 g = 0; g < c; ++g, v += 1, tricmd += 4 )
\r
571 const core::vector3df& av = TransformedVerts[tricmd[0]];
\r
574 const core::vector3df& an = TransformedNormals[tricmd[1]];
\r
576 //v->Normal.normalize();
\r
589 void CAnimatedMeshHalfLife::renderModel(u32 param, IVideoDriver * driver, const core::matrix4 &absoluteTransformation)
\r
591 const SHalflifeBone *bone = (SHalflifeBone *) ((u8 *) Header + Header->boneindex);
\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
598 core::aabbox3df box;
\r
600 for (u32 i = 0; i < Header->numbones; i++)
\r
602 if (bone[i].parent >= 0)
\r
604 getBoneVector ( box.MinEdge, bone[i].parent );
\r
605 getBoneVector ( box.MaxEdge, i );
\r
606 driver->draw3DLine ( box.MinEdge, box.MaxEdge, blue );
\r
608 // draw parent bone node
\r
609 if (bone[bone[i].parent].parent >=0 )
\r
611 getBoneBox ( box, bone[i].parent );
\r
612 driver->draw3DBox ( box, blue );
\r
614 getBoneBox ( box, i );
\r
615 driver->draw3DBox ( box, blue );
\r
619 // draw parent bone node
\r
620 getBoneBox ( box, i, 1.f );
\r
621 driver->draw3DBox ( box , red );
\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
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
640 SHalflifeBBox *hitbox = (SHalflifeBBox *) ((u8*) Header + Header->hitboxindex);
\r
642 for (u32 i = 0; i < Header->numhitboxes; i++)
\r
644 f32 *bbmin = hitbox[i].bbmin;
\r
645 f32 *bbmax = hitbox[i].bbmax;
\r
647 v2[0][0] = bbmin[0];
\r
648 v2[0][1] = bbmax[1];
\r
649 v2[0][2] = bbmin[2];
\r
651 v2[1][0] = bbmin[0];
\r
652 v2[1][1] = bbmin[1];
\r
653 v2[1][2] = bbmin[2];
\r
655 v2[2][0] = bbmax[0];
\r
656 v2[2][1] = bbmax[1];
\r
657 v2[2][2] = bbmin[2];
\r
659 v2[3][0] = bbmax[0];
\r
660 v2[3][1] = bbmin[1];
\r
661 v2[3][2] = bbmin[2];
\r
663 v2[4][0] = bbmax[0];
\r
664 v2[4][1] = bbmax[1];
\r
665 v2[4][2] = bbmax[2];
\r
667 v2[5][0] = bbmax[0];
\r
668 v2[5][1] = bbmin[1];
\r
669 v2[5][2] = bbmax[2];
\r
671 v2[6][0] = bbmin[0];
\r
672 v2[6][1] = bbmax[1];
\r
673 v2[6][2] = bbmax[2];
\r
675 v2[7][0] = bbmin[0];
\r
676 v2[7][1] = bbmin[1];
\r
677 v2[7][2] = bbmax[2];
\r
679 for ( u32 g = 0; g < 8; ++g )
\r
680 getTransformedBoneVector ( v[g],hitbox[i].bone,v2[g] );
\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
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
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
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
703 const f32 frame = frameInt + (detailLevel * 0.001f);
\r
704 const u32 frameA = core::floor32 ( frame );
\r
705 // f32 blend = core::fract ( frame );
\r
707 SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex);
\r
709 // find SequenceIndex from summed list
\r
710 u32 frameCount = 0;
\r
711 for (u32 i = 0; i < Header->numseq; ++i)
\r
713 const u32 val = core::max_ ( 1, seq[i].numframes - 1 );
\r
714 if ( frameCount + val > frameA )
\r
717 CurrentFrame = frame - frameCount;
\r
723 seq += SequenceIndex;
\r
725 //SetBodyPart ( 1, 1 );
\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
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
743 void CAnimatedMeshHalfLife::initData ()
\r
747 OwnTexModel = false;
\r
749 for (u32 i = 0; i < 32; ++i )
\r
750 AnimationHeader[i] = 0;
\r
753 CurrentFrame = 0.f;
\r
755 for (u32 i = 0; i < 5; ++i )
\r
756 BoneController[i] = 0;
\r
758 for (u32 i = 0; i < 2; ++i )
\r
761 SkinGroupSelection = 0;
\r
767 MeshIPol = new SMesh();
\r
770 #ifdef HL_TEXTURE_ATLAS
\r
771 TextureAtlas.release();
\r
778 void STextureAtlas::release()
\r
780 for (u32 i = 0; i < atlas.size(); i++)
\r
782 if ( atlas[i].image )
\r
784 atlas[i].image->drop();
\r
785 atlas[i].image = 0;
\r
794 void STextureAtlas::addSource ( const c8 * name, video::IImage * image )
\r
796 TextureAtlasEntry entry;
\r
798 entry.image = image;
\r
799 entry.width = image->getDimension().Width;
\r
800 entry.height = image->getDimension().Height;
\r
803 atlas.push_back ( entry );
\r
809 void STextureAtlas::getScale(core::vector2df& scale)
\r
811 for (s32 i = static_cast<s32>(atlas.size()) - 1; i >= 0; --i)
\r
813 if ( atlas[i].name == "_merged_" )
\r
815 scale.X = 1.f / atlas[i].width;
\r
816 scale.Y = 1.f / atlas[i].height;
\r
827 void STextureAtlas::getTranslation(const c8* name, core::vector2di& pos)
\r
829 for ( u32 i = 0; i < atlas.size(); ++i)
\r
831 if ( atlas[i].name == name )
\r
833 pos = atlas[i].pos;
\r
842 void STextureAtlas::create(u32 border, E_TEXTURE_CLAMP texmode)
\r
850 ECOLOR_FORMAT format = ECF_R8G8B8;
\r
852 const s32 frame = core::s32_max ( 0, (border - 1 ) / 2 );
\r
854 // sort for biggest coming first
\r
859 for (u32 i = 0; i < atlas.size(); i++)
\r
862 w2 = atlas[i].width + border;
\r
865 w2 = (w2 + 1) & ~1;
\r
868 u32 splitsize = 256;
\r
876 for (u32 i = 0; i < atlas.size(); i++)
\r
878 if ( atlas[i].image->getColorFormat() == ECF_A8R8G8B8 )
\r
880 format = ECF_A8R8G8B8;
\r
884 w2 = atlas[i].width + border;
\r
885 h2 = atlas[i].height + border;
\r
888 w2 = (w2 + 1) & ~1;
\r
889 h2 = (h2 + 1) & ~1;
\r
891 h = core::s32_max ( h, h2 );
\r
893 if ( w + w2 >= splitsize )
\r
896 wsum = core::s32_max ( wsum, w );
\r
901 atlas[i].pos.X = w;
\r
902 atlas[i].pos.Y = hsum;
\r
908 wsum = core::s32_max ( wsum, w );
\r
911 const core::dimension2d<u32> dim = core::dimension2d<u32>( wsum, hsum ).getOptimalSize();
\r
912 IImage* master = new CImage(format, dim);
\r
915 video::SColor col[2];
\r
917 static const u8 wrap[][4] =
\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
925 for (u32 i = 0; i < atlas.size(); i++)
\r
927 atlas[i].image->copyTo ( master, atlas[i].pos );
\r
929 // clamp/wrap ( copy edges, filtering needs it )
\r
931 for (s32 b = 0; b < frame; ++b )
\r
933 for (s32 a = 0 - b; a <= (s32) atlas[i].width + b; ++a )
\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
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
942 for (s32 a = -1 - b; a <= (s32) atlas[i].height + b; ++a )
\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
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
953 addSource ( "_merged_", master );
\r
960 SHalflifeHeader* CAnimatedMeshHalfLife::loadModel(io::IReadFile* file, const io::path& filename)
\r
962 bool closefile = false;
\r
964 // if secondary files are needed, open here and mark for closing
\r
967 file = SceneManager->getFileSystem()->createAndOpenFile(filename);
\r
974 // read into memory
\r
975 u8* pin = new u8[file->getSize()];
\r
976 file->read(pin, file->getSize());
\r
978 SHalflifeHeader* header = (SHalflifeHeader*) pin;
\r
980 const bool idst = (0 == strncmp(header->id, "IDST", 4));
\r
981 const bool idsq = (0 == strncmp(header->id, "IDSQ", 4));
\r
983 if ( (!idst && !idsq) || (idsq && !Header) )
\r
985 os::Printer::log("MDL Halflife Loader: Wrong file header", file->getFileName(), ELL_WARNING);
\r
995 // don't know the real header.. idsg might be different
\r
996 if (header->textureindex && idst )
\r
1002 core::splitFilename(file->getFileName(), &path, &fname, &ext);
\r
1003 TextureBaseName = path + fname + "_";
\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
1009 const u8 *src = pin + tex[i].index;
\r
1011 // convert rgb to argb palette
\r
1013 const u8 *pal = src + tex[i].width * tex[i].height;
\r
1014 for( u32 g=0; g<256; ++g )
\r
1016 palette[g] = 0xFF000000 | pal[0] << 16 | pal[1] << 8 | pal[2];
\r
1021 IImage* image = SceneManager->getVideoDriver()->createImage(ECF_R8G8B8, core::dimension2d<u32>(tex[i].width, tex[i].height));
\r
1023 CColorConverter::convert8BitTo24Bit(src, (u8*)image->getData(), tex[i].width, tex[i].height, (u8*) palette, 0, false);
\r
1025 #ifdef HL_TEXTURE_ATLAS
\r
1026 TextureAtlas.addSource ( tex[i].name, image );
\r
1028 core::splitFilename ( tex[i].name, 0, &fname, &ext );
\r
1029 SceneManager->getVideoDriver()->addTexture ( TextureBaseName + fname, image );
\r
1033 delete [] palette;
\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
1057 f32 CAnimatedMeshHalfLife::SetController( s32 controllerIndex, f32 value )
\r
1062 SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex);
\r
1064 // find first controller that matches the index
\r
1066 for (i = 0; i < Header->numbonecontrollers; i++, bonecontroller++)
\r
1068 if (bonecontroller->index == controllerIndex)
\r
1071 if (i >= Header->numbonecontrollers)
\r
1074 // wrap 0..360 if it's a rotational controller
\r
1075 if (bonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR))
\r
1077 // ugly hack, invert value if end < start
\r
1078 if (bonecontroller->end < bonecontroller->start)
\r
1081 // does the controller not wrap?
\r
1082 if (bonecontroller->start + 359.f >= bonecontroller->end)
\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
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
1098 const s32 range = controllerIndex == MOUTH_CONTROLLER ? 64 : 255;
\r
1100 s32 setting = (s32) ( (f32) range * (value - bonecontroller->start) / (bonecontroller->end - bonecontroller->start));
\r
1102 if (setting < 0) setting = 0;
\r
1103 if (setting > range) setting = range;
\r
1105 BoneController[controllerIndex] = setting;
\r
1107 return setting * (1.f / (f32) range ) * (bonecontroller->end - bonecontroller->start) + bonecontroller->start;
\r
1113 u32 CAnimatedMeshHalfLife::SetSkin( u32 value )
\r
1115 if (value < Header->numskinfamilies)
\r
1116 SkinGroupSelection = value;
\r
1118 return SkinGroupSelection;
\r
1124 bool CAnimatedMeshHalfLife::postLoadModel( const io::path &filename )
\r
1128 io::path submodel;
\r
1130 core::splitFilename ( filename ,&path, &texname, 0 );
\r
1132 // preload textures
\r
1133 // if no textures are stored in main file, use texfile
\r
1134 if (Header->numtextures == 0)
\r
1136 submodel = path + texname + "T.mdl";
\r
1137 TextureHeader = loadModel(0, submodel);
\r
1138 if (!TextureHeader)
\r
1140 OwnTexModel = true;
\r
1144 TextureHeader = Header;
\r
1145 OwnTexModel = false;
\r
1148 // preload animations
\r
1149 if (Header->numseqgroups > 1)
\r
1152 for (u32 i = 1; i < Header->numseqgroups; i++)
\r
1154 snprintf_irr( seq, 8, "%02u.mdl", i );
\r
1155 submodel = path + texname + seq;
\r
1157 AnimationHeader[i] = loadModel(0, submodel);
\r
1158 if (!AnimationHeader[i])
\r
1169 void CAnimatedMeshHalfLife::dumpModelInfo(u32 level) const
\r
1171 const u8 *phdr = (const u8*) Header;
\r
1172 const SHalflifeHeader * hdr = Header;
\r
1178 "Bone Controllers: %u\n"
\r
1181 "Sequence Groups: %u\n",
\r
1183 hdr->numbonecontrollers,
\r
1190 "Skin Families: %u\n"
\r
1192 "Attachments: %u\n"
\r
1193 "Transitions: %d\n",
\r
1195 hdr->numskinfamilies,
\r
1196 hdr->numbodyparts,
\r
1197 hdr->numattachments,
\r
1198 hdr->numtransitions);
\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
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
1213 printf("flags: %d\n\n", hdr->flags);
\r
1215 printf("numbones: %u\n", hdr->numbones);
\r
1216 for (u32 i = 0; i < hdr->numbones; i++)
\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
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
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
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
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
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
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
1259 printf("\nnumseqgroups: %u\n", hdr->numseqgroups);
\r
1260 for (u32 i = 0; i < hdr->numseqgroups; i++)
\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
1268 printf("\nnumskinref: %u\n", hdr->numskinref);
\r
1269 printf("numskinfamilies: %u\n", hdr->numskinfamilies);
\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
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
1281 printf("\nnumattachments: %u\n", hdr->numattachments);
\r
1282 for (u32 i = 0; i < hdr->numattachments; i++)
\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
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
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
1306 void CAnimatedMeshHalfLife::ExtractBbox(s32 sequence, core::aabbox3df &box) const
\r
1308 const SHalflifeSequence *seq = (const SHalflifeSequence *)((const u8*)Header + Header->seqindex) + sequence;
\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
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
1322 void CAnimatedMeshHalfLife::calcBoneAdj()
\r
1324 const SHalflifeBoneController *bonecontroller =
\r
1325 (const SHalflifeBoneController *)((const u8*) Header + Header->bonecontrollerindex);
\r
1327 for (u32 j = 0; j < Header->numbonecontrollers; j++)
\r
1329 const s32 i = bonecontroller[j].index;
\r
1330 // check for 360% wrapping
\r
1332 if (bonecontroller[j].type & STUDIO_RLOOP)
\r
1334 value = BoneController[i] * (360.f/256.f) + bonecontroller[j].start;
\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
1343 switch(bonecontroller[j].type & STUDIO_TYPES)
\r
1348 BoneAdj[j] = value * core::DEGTORAD;
\r
1353 BoneAdj[j] = value;
\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
1365 // three vector components
\r
1366 if (anim->offset[j+3] == 0)
\r
1368 angle2 = angle1 = bone->value[j+3]; // default
\r
1372 SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j+3]);
\r
1374 while (animvalue->num.total <= k)
\r
1376 k -= animvalue->num.total;
\r
1377 animvalue += animvalue->num.valid + 1;
\r
1379 // Bah, missing blend!
\r
1380 if (animvalue->num.valid > k)
\r
1382 angle1 = animvalue[k+1].value;
\r
1384 if (animvalue->num.valid > k + 1)
\r
1386 angle2 = animvalue[k+2].value;
\r
1390 if (animvalue->num.total > k + 1)
\r
1393 angle2 = animvalue[animvalue->num.valid+2].value;
\r
1398 angle1 = animvalue[animvalue->num.valid].value;
\r
1399 if (animvalue->num.total > k + 1)
\r
1405 angle2 = animvalue[animvalue->num.valid + 2].value;
\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
1412 if (bone->bonecontroller[j+3] != -1)
\r
1414 angle1 += BoneAdj[bone->bonecontroller[j+3]];
\r
1415 angle2 += BoneAdj[bone->bonecontroller[j+3]];
\r
1422 void CAnimatedMeshHalfLife::calcBonePosition(const s32 frame, f32 s,
\r
1423 const SHalflifeBone * const bone, SHalflifeAnimOffset *anim, f32 *pos) const
\r
1425 for (s32 j = 0; j < 3; ++j)
\r
1427 pos[j] = bone->value[j]; // default;
\r
1428 if (anim->offset[j] != 0)
\r
1430 SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j]);
\r
1433 // find span of values that includes the frame we want
\r
1434 while (animvalue->num.total <= k)
\r
1436 k -= animvalue->num.total;
\r
1437 animvalue += animvalue->num.valid + 1;
\r
1439 // if we're inside the span
\r
1440 if (animvalue->num.valid > k)
\r
1442 // and there's more data in the span
\r
1443 if (animvalue->num.valid > k + 1)
\r
1445 pos[j] += (animvalue[k+1].value * (1.f - s) + s * animvalue[k+2].value) * bone->scale[j];
\r
1449 pos[j] += animvalue[k+1].value * bone->scale[j];
\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
1457 pos[j] += (animvalue[animvalue->num.valid].value * (1.f - s) + s * animvalue[animvalue->num.valid + 2].value) * bone->scale[j];
\r
1461 pos[j] += animvalue[animvalue->num.valid].value * bone->scale[j];
\r
1465 if (bone->bonecontroller[j] != -1)
\r
1467 pos[j] += BoneAdj[bone->bonecontroller[j]];
\r
1475 void CAnimatedMeshHalfLife::calcRotations(vec3_hl *pos, vec4_hl *q,
\r
1476 SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f)
\r
1478 const s32 frame = (s32)f;
\r
1479 const f32 s = (f - frame);
\r
1481 // add in programatic controllers
\r
1484 SHalflifeBone *bone = (SHalflifeBone *)((u8 *)Header + Header->boneindex);
\r
1485 for ( u32 i = 0; i < Header->numbones; i++, bone++, anim++)
\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
1492 if (!angle1.equals(angle2))
\r
1495 AngleQuaternion( angle1, q1 );
\r
1496 AngleQuaternion( angle2, q2 );
\r
1497 QuaternionSlerp( q1, q2, s, q[i] );
\r
1501 AngleQuaternion( angle1, q[i] );
\r
1504 calcBonePosition(frame, s, bone, anim, pos[i]);
\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
1518 SHalflifeAnimOffset * CAnimatedMeshHalfLife::getAnim( SHalflifeSequence *seq )
\r
1520 SHalflifeSequenceGroup *seqgroup = (SHalflifeSequenceGroup *)((u8*)Header + Header->seqgroupindex) + seq->seqgroup;
\r
1522 if (seq->seqgroup == 0)
\r
1524 return (SHalflifeAnimOffset *)((u8*)Header + seqgroup->data + seq->animindex);
\r
1527 return (SHalflifeAnimOffset *)((u8*)AnimationHeader[seq->seqgroup] + seq->animindex);
\r
1533 void CAnimatedMeshHalfLife::slerpBones(vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s)
\r
1542 for ( u32 i = 0; i < Header->numbones; i++)
\r
1545 QuaternionSlerp( q1[i], q2[i], s, q3 );
\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
1559 void CAnimatedMeshHalfLife::setUpBones()
\r
1561 static vec3_hl pos[MAXSTUDIOBONES];
\r
1562 f32 bonematrix[3][4];
\r
1563 static vec4_hl q[MAXSTUDIOBONES];
\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
1572 if (SequenceIndex >= Header->numseq)
\r
1573 SequenceIndex = 0;
\r
1575 SHalflifeSequence *seq = (SHalflifeSequence *)((u8*) Header + Header->seqindex) + SequenceIndex;
\r
1577 SHalflifeAnimOffset *anim = getAnim(seq);
\r
1578 calcRotations(pos, q, seq, anim, CurrentFrame);
\r
1580 if (seq->numblends > 1)
\r
1582 anim += Header->numbones;
\r
1583 calcRotations( pos2, q2, seq, anim, CurrentFrame );
\r
1584 f32 s = Blending[0] / 255.f;
\r
1586 slerpBones( q, pos, q2, pos2, s );
\r
1588 if (seq->numblends == 4)
\r
1590 anim += Header->numbones;
\r
1591 calcRotations( pos3, q3, seq, anim, CurrentFrame );
\r
1593 anim += Header->numbones;
\r
1594 calcRotations( pos4, q4, seq, anim, CurrentFrame );
\r
1596 s = Blending[0] / 255.f;
\r
1597 slerpBones( q3, pos3, q4, pos4, s );
\r
1599 s = Blending[1] / 255.f;
\r
1600 slerpBones( q, pos, q3, pos3, s );
\r
1604 const SHalflifeBone *bone = (SHalflifeBone *)((u8*) Header + Header->boneindex);
\r
1606 for (u32 i = 0; i < Header->numbones; i++)
\r
1608 QuaternionMatrix( q[i], bonematrix );
\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
1614 if (bone[i].parent == -1) {
\r
1615 memcpy(BoneTransform[i], bonematrix, sizeof(f32) * 12);
\r
1618 R_ConcatTransforms (BoneTransform[bone[i].parent], bonematrix, BoneTransform[i]);
\r
1624 //! Returns an axis aligned bounding box
\r
1625 const core::aabbox3d<f32>& CAnimatedMeshHalfLife::getBoundingBox() const
\r
1627 return MeshIPol->BoundingBox;
\r
1631 //! Returns the type of the animated mesh.
\r
1632 E_ANIMATED_MESH_TYPE CAnimatedMeshHalfLife::getMeshType() const
\r
1634 return EAMT_MDL_HALFLIFE;
\r
1638 //! returns amount of mesh buffers.
\r
1639 u32 CAnimatedMeshHalfLife::getMeshBufferCount() const
\r
1641 return MeshIPol->getMeshBufferCount();
\r
1645 //! returns pointer to a mesh buffer
\r
1646 IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(u32 nr) const
\r
1648 return MeshIPol->getMeshBuffer(nr);
\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
1658 return MeshIPol->getMeshBuffer(material);
\r
1662 void CAnimatedMeshHalfLife::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
\r
1664 MeshIPol->setMaterialFlag ( flag, newvalue );
\r
1668 //! set user axis aligned bounding box
\r
1669 void CAnimatedMeshHalfLife::setBoundingBox(const core::aabbox3df& box)
\r
1671 MeshIPol->setBoundingBox(box);
\r
1675 } // end namespace scene
\r
1676 } // end namespace irr
\r
1678 #endif // _IRR_COMPILE_WITH_MD3_LOADER_
\r