diff --git a/src/Client/GUI/CM2Mesh.cpp b/src/Client/GUI/CM2Mesh.cpp index c25d369..9db37d0 100755 --- a/src/Client/GUI/CM2Mesh.cpp +++ b/src/Client/GUI/CM2Mesh.cpp @@ -454,7 +454,7 @@ void CM2Mesh::SkinJoint(SJoint *joint, SJoint *parentJoint) E_ANIMATED_MESH_TYPE CM2Mesh::getMeshType() const { - return EAMT_SKINNED; + return EAMT_M2; } @@ -1374,9 +1374,55 @@ void CM2Mesh::calculateTangents( } +void CM2Mesh::getFrameLoop(u32 id, s32 &start, s32 &end) +{ + core::map >::Node* n =AnimationLookup.find(id); + if(n) + { + f32 r = (rand() % 32767)/32767.0f; + u8 x = 0; + bool found = false; + M2Animation a; + while(!found && x < n->getValue().size()) + { + a = Animations[n->getValue()[x]]; + if(r>a.probability) + x++; + else + found=true; + } + start = a.begin; + end = a.end; + } + else + return; + +} +void CM2Mesh::newAnimation(u32 id, s32 start, s32 end, f32 probability) +{ + core::array temp; + f32 prev_prob; + if(AnimationLookup.find(id)==0) + { + prev_prob = 0.0f; + } + else + { + temp = AnimationLookup[id]; + prev_prob = Animations[temp[temp.size()-1]].probability; + } + temp.push_back(Animations.size()); + AnimationLookup[id] = temp; + M2Animation a; + a.begin = start; + a.end = end; + a.probability = probability + prev_prob; + Animations.push_back(a); + +} diff --git a/src/Client/GUI/CM2Mesh.h b/src/Client/GUI/CM2Mesh.h index b292fce..82e2b3a 100755 --- a/src/Client/GUI/CM2Mesh.h +++ b/src/Client/GUI/CM2Mesh.h @@ -8,6 +8,13 @@ namespace irr namespace scene { + struct M2Animation + { + f32 probability; + u32 begin; + u32 end; + }; + class IAnimatedMeshSceneNode; class IBoneSceneNode; @@ -135,7 +142,10 @@ namespace scene virtual SScaleKey *createScaleKey(SJoint *joint); virtual SWeight *createWeight(SJoint *joint); - + + //Retrieve animation information + void getFrameLoop(u32 animId, s32 &start, s32 &end); + void newAnimation(u32 id, s32 start, s32 end, f32 probability); private: void checkForAnimation(); @@ -185,6 +195,9 @@ private: core::aabbox3d BoundingBox; core::array< core::array > Vertices_Moved; + + core::array< M2Animation > Animations; + core::map > AnimationLookup; }; } // end namespace scene diff --git a/src/Client/GUI/CM2MeshFileLoader.cpp b/src/Client/GUI/CM2MeshFileLoader.cpp index 05a355d..c03f3ed 100644 --- a/src/Client/GUI/CM2MeshFileLoader.cpp +++ b/src/Client/GUI/CM2MeshFileLoader.cpp @@ -272,153 +272,126 @@ numofs tempBoneNumOfs; core::array tempNumOfsList; float tempBoneValue; s16 tempBoneShort; -for(u32 i=0; i0) + use_animfile = (M2MAnimations[i].flags & 0x20) == 0; + if(use_animfile) + { + std::string AnimName = MeshFile->getFileName(); + c8 ext[13]; + sprintf(ext,"%04d-%02d.anim",M2MAnimations[i].animationID,M2MAnimations[i].subanimationID); + AnimName = AnimName.substr(0, AnimName.length()-3) + ext; + AnimFile = io::IrrCreateIReadFileBasic(Device, AnimName.c_str()); + if (!AnimFile) { - tempNumOfsList.clear(); - MeshFile->seek(M2MBones[i].translation.header.TimeStamp.ofs); - for(u32 j=0; jread(&tempBoneNumOfs, sizeof(numofs)); - tempNumOfsList.push_back(tempBoneNumOfs); - } - for(u32 j=0; j 0 && M2MAnimations[j].flags & 0x20) - { - MeshFile->seek(n.ofs); - for(u32 k=0; kread(&tempBoneTS, sizeof(u32)); - M2MBones[i].translation.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline. - } - } + logerror("We actually expected this error - Where is the data for this animation???"); } + continue; } - if(M2MBones[i].rotation.header.TimeStamp.num>0) + } + else + { + AnimFile = MeshFile; + } + for(u32 j=0; j0 && M2MBones[j].translation.header.Values.num>0) { - tempNumOfsList.clear(); - MeshFile->seek(M2MBones[i].rotation.header.TimeStamp.ofs); - for(u32 j=0; jseek(M2MBones[j].translation.header.TimeStamp.ofs+8*i); + MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); + if(tempBoneNumOfs.num > 0) + { + AnimFile->seek(tempBoneNumOfs.ofs); + for(u32 k=0; kread(&tempBoneNumOfs, sizeof(numofs)); - tempNumOfsList.push_back(tempBoneNumOfs); + AnimFile->read(&tempBoneTS, sizeof(u32)); + M2MBones[j].translation.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline. } - for(u32 j=0; jseek(M2MBones[j].translation.header.Values.ofs+8*i); + MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); + if(tempBoneNumOfs.num > 0) + { + AnimFile->seek(tempBoneNumOfs.ofs); + for(u32 k=0; k 0 && M2MAnimations[j].flags & 0x20) - { - MeshFile->seek(n.ofs); - for(u32 k=0; kread(&tempBoneTS, sizeof(u32)); - M2MBones[i].rotation.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline. - } - } + AnimFile->read(&tempBoneValue, sizeof(float)); + M2MBones[j].translation.values.push_back(tempBoneValue); } + } } - if(M2MBones[i].scaling.header.TimeStamp.num>0) + if(M2MBones[j].rotation.header.TimeStamp.num>0 && M2MBones[j].rotation.header.Values.num>0) { - tempNumOfsList.clear(); - MeshFile->seek(M2MBones[i].scaling.header.TimeStamp.ofs); - for(u32 j=0; jseek(M2MBones[j].rotation.header.TimeStamp.ofs+8*i); + MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); + if(tempBoneNumOfs.num > 0) + { + AnimFile->seek(tempBoneNumOfs.ofs); + for(u32 k=0; kread(&tempBoneNumOfs, sizeof(numofs)); - tempNumOfsList.push_back(tempBoneNumOfs); + AnimFile->read(&tempBoneTS, sizeof(u32)); + M2MBones[j].rotation.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline. } - for(u32 j=0; jseek(M2MBones[j].rotation.header.Values.ofs+8*i); + MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); + if(tempBoneNumOfs.num > 0) + { + AnimFile->seek(tempBoneNumOfs.ofs); + for(u32 k=0; k 0 && M2MAnimations[j].flags & 0x20) - { - MeshFile->seek(n.ofs); - for(u32 k=0; kread(&tempBoneTS, sizeof(u32)); - M2MBones[i].scaling.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline. - } - } + AnimFile->read(&tempBoneShort, sizeof(s16)); + tempBoneValue=(tempBoneShort>0?tempBoneShort-32767:tempBoneShort+32767)/32767.0f; + M2MBones[j].rotation.values.push_back(tempBoneValue); } + } } - - if(M2MBones[i].translation.header.Values.num>0) + if(M2MBones[j].scaling.header.TimeStamp.num>0 && M2MBones[j].scaling.header.Values.num>0) { - tempNumOfsList.clear(); - MeshFile->seek(M2MBones[i].translation.header.Values.ofs); - for(u32 j=0; jseek(M2MBones[j].scaling.header.TimeStamp.ofs+8*i); + MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); + if(tempBoneNumOfs.num > 0) + { + AnimFile->seek(tempBoneNumOfs.ofs); + for(u32 k=0; kread(&tempBoneNumOfs, sizeof(numofs)); - tempNumOfsList.push_back(tempBoneNumOfs); + AnimFile->read(&tempBoneTS, sizeof(u32)); + M2MBones[j].scaling.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline. } - for(u32 j=0; jseek(M2MBones[j].scaling.header.Values.ofs+8*i); + MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); + if(tempBoneNumOfs.num > 0) + { + AnimFile->seek(tempBoneNumOfs.ofs); + for(u32 k=0; k 0 && M2MAnimations[j].flags & 0x20) - { - MeshFile->seek(n.ofs); - - for(u32 k=0; kread(&tempBoneValue, sizeof(float)); - M2MBones[i].translation.values.push_back(tempBoneValue); - } - } + AnimFile->read(&tempBoneValue, sizeof(float)); + M2MBones[j].scaling.values.push_back(tempBoneValue); } + } } - if(M2MBones[i].rotation.header.Values.num>0) - { - tempNumOfsList.clear(); - MeshFile->seek(M2MBones[i].rotation.header.Values.ofs); - for(u32 j=0; jread(&tempBoneNumOfs, sizeof(numofs)); - tempNumOfsList.push_back(tempBoneNumOfs); - } - for(u32 j=0; j 0 && M2MAnimations[j].flags & 0x20) - { - MeshFile->seek(n.ofs); - for(u32 k=0; kread(&tempBoneShort, sizeof(s16)); - tempBoneValue=(tempBoneShort>0?tempBoneShort-32767:tempBoneShort+32767)/32767.0f; - M2MBones[i].rotation.values.push_back(tempBoneValue); - } - } - } - } - - if(M2MBones[i].scaling.header.Values.num>0) - { - tempNumOfsList.clear(); - MeshFile->seek(M2MBones[i].scaling.header.Values.ofs); - for(u32 j=0; jread(&tempBoneNumOfs, sizeof(numofs)); - tempNumOfsList.push_back(tempBoneNumOfs); - } - for(u32 j=0; j 0 && M2MAnimations[j].flags & 0x20) - { - MeshFile->seek(n.ofs); - for(u32 k=0; kread(&tempBoneValue, sizeof(float)); - M2MBones[i].scaling.values.push_back(tempBoneValue); - } - } - } - } - + } + if(use_animfile) + { + AnimFile->drop(); + } + AnimFile=0; } - DEBUG(logdebug("Read %u Bones",M2MBones.size())); @@ -427,7 +400,6 @@ DEBUG(logdebug("Read %u Bones",M2MBones.size())); void CM2MeshFileLoader::ReadAnimationData() { -logdebug("Reading Animation Data"); //Global Sequences. This is global data u32 tempGlobalSeq; if(!M2MGlobalSequences.empty()) @@ -487,8 +459,9 @@ logdebug("Reading Animation Data"); { RawAnimation tempRaw; MeshFile->read(&tempRaw,sizeof(RawAnimation)); + tempAnimation.animationID = tempRaw.animationID; - tempAnimation.flags = tempRaw.flags; + tempAnimation.probability = tempRaw.probability / 32767.0f; tempAnimation.start = tempRaw.start; tempAnimation.end = tempRaw.end; } @@ -499,6 +472,7 @@ logdebug("Reading Animation Data"); tempAnimation.animationID = tempRaw.animationID; tempAnimation.subanimationID = tempRaw.subanimationID; tempAnimation.flags = tempRaw.flags; + tempAnimation.probability = tempRaw.probability / 32767.0f; tempAnimation.start = laststart; tempAnimation.end = laststart + tempRaw.length; laststart += tempRaw.length + 1000; @@ -659,6 +633,11 @@ switch(header.version) /////////////////////////////////////// // Animation related stuff // /////////////////////////////////////// +for(u32 i=0;inewAnimation(M2MAnimations[i].animationID,M2MAnimations[i].start,M2MAnimations[i].end,M2MAnimations[i].probability); +} + scene::CM2Mesh::SJoint* Joint; for(u32 i=0;iaddAnimatedMeshSceneNode(mesh); + scene::IAnimatedMeshSceneNode* aninode = (scene::IAnimatedMeshSceneNode*)node; + + aninode->setAnimationSpeed(1000); + aninode->setM2Animation(0); //video::ITexture *tex = _device->getVideoDriver()->getTexture("data/misc/square.jpg"); //node->setMaterialTexture(0, tex); } diff --git a/src/dep/include/irrlicht/IAnimatedMesh.h b/src/dep/include/irrlicht/IAnimatedMesh.h index 2befba1..7b91a59 100644 --- a/src/dep/include/irrlicht/IAnimatedMesh.h +++ b/src/dep/include/irrlicht/IAnimatedMesh.h @@ -47,6 +47,9 @@ namespace scene can be loaded directly by Irrlicht */ EAMT_OCT, + //! WoW M2 files + EAMT_M2, + //! generic skinned mesh EAMT_SKINNED }; diff --git a/src/dep/include/irrlicht/IAnimatedMeshSceneNode.h b/src/dep/include/irrlicht/IAnimatedMeshSceneNode.h index ca1a2b4..f8fbec0 100644 --- a/src/dep/include/irrlicht/IAnimatedMeshSceneNode.h +++ b/src/dep/include/irrlicht/IAnimatedMeshSceneNode.h @@ -135,7 +135,10 @@ namespace scene //! Deprecated command, please use getJointNode virtual ISceneNode* getXJointNode(const c8* jointName) = 0; - //! Starts a default MD2 animation. + //! Starts a M2 animation. + virtual bool setM2Animation(u32 anim) = 0; + + //! Starts a default MD2 animation. /** With this method it is easily possible to start a Run, Attack, Die or whatever animation, if the mesh contained in this scene node is an md2 mesh. Otherwise, nothing happens. diff --git a/src/dep/src/irrlicht/CAnimatedMeshSceneNode.cpp b/src/dep/src/irrlicht/CAnimatedMeshSceneNode.cpp index 4a6f00e..b737896 100644 --- a/src/dep/src/irrlicht/CAnimatedMeshSceneNode.cpp +++ b/src/dep/src/irrlicht/CAnimatedMeshSceneNode.cpp @@ -22,6 +22,7 @@ #include "IGUIFont.h" #include "ISceneCollisionManager.h" +#include "../../../Client/GUI/CM2Mesh.h" namespace irr { @@ -428,7 +429,7 @@ void CAnimatedMeshSceneNode::render() // show skeleton if ( DebugDataVisible & scene::EDS_SKELETON ) { - if (Mesh->getMeshType() == EAMT_SKINNED) + if (Mesh->getMeshType() == EAMT_SKINNED || Mesh->getMeshType() == EAMT_M2) { // draw skeleton ISceneCollisionManager* Coll = SceneManager->getSceneCollisionManager(); @@ -714,6 +715,24 @@ bool CAnimatedMeshSceneNode::removeChild(ISceneNode* child) return false; } +//! Starts a M2 animation. +bool CAnimatedMeshSceneNode::setM2Animation(u32 animID) +{ + if (!Mesh || Mesh->getMeshType() != EAMT_M2) + return false; + + CM2Mesh* m = (CM2Mesh*)Mesh; + + s32 begin = -1, end = -1; + m->getFrameLoop(animID, begin, end); //Eventually different speeds are necessary? + if(begin == -1 || end == -1) + return false; + +// setAnimationSpeed( f32(speed) ); + setFrameLoop(begin, end); + return true; +} + //! Starts a MD2 animation. bool CAnimatedMeshSceneNode::setMD2Animation(EMD2_ANIMATION_TYPE anim) diff --git a/src/dep/src/irrlicht/CAnimatedMeshSceneNode.h b/src/dep/src/irrlicht/CAnimatedMeshSceneNode.h index efb67f7..8fba544 100644 --- a/src/dep/src/irrlicht/CAnimatedMeshSceneNode.h +++ b/src/dep/src/irrlicht/CAnimatedMeshSceneNode.h @@ -96,8 +96,11 @@ namespace scene //! or to remove attached childs. virtual bool removeChild(ISceneNode* child); - //! Starts a MD2 animation. - virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim); + //! Starts a M2 animation. + virtual bool setM2Animation(u32 anim); + + //! Starts a MD2 animation. + virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim); //! Starts a special MD2 animation. virtual bool setMD2Animation(const c8* animationName);