* Read .anim files for 3.3.5

This commit is contained in:
Shlainn 2011-11-22 20:29:14 +01:00
parent 9c5990d97f
commit 73efbaf339
9 changed files with 203 additions and 132 deletions

View File

@ -454,7 +454,7 @@ void CM2Mesh::SkinJoint(SJoint *joint, SJoint *parentJoint)
E_ANIMATED_MESH_TYPE CM2Mesh::getMeshType() const 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<u32, core::array<u32> >::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<u32> 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);
}

View File

@ -8,6 +8,13 @@ namespace irr
namespace scene namespace scene
{ {
struct M2Animation
{
f32 probability;
u32 begin;
u32 end;
};
class IAnimatedMeshSceneNode; class IAnimatedMeshSceneNode;
class IBoneSceneNode; class IBoneSceneNode;
@ -136,6 +143,9 @@ namespace scene
virtual SWeight *createWeight(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: private:
void checkForAnimation(); void checkForAnimation();
@ -185,6 +195,9 @@ private:
core::aabbox3d<f32> BoundingBox; core::aabbox3d<f32> BoundingBox;
core::array< core::array<bool> > Vertices_Moved; core::array< core::array<bool> > Vertices_Moved;
core::array< M2Animation > Animations;
core::map<u32, core::array<u32> > AnimationLookup;
}; };
} // end namespace scene } // end namespace scene

View File

@ -272,153 +272,126 @@ numofs tempBoneNumOfs;
core::array<numofs> tempNumOfsList; core::array<numofs> tempNumOfsList;
float tempBoneValue; float tempBoneValue;
s16 tempBoneShort; s16 tempBoneShort;
for(u32 i=0; i<M2MBones.size(); i++) //Animations can now be stored in anim files. To read quickly we need to swap the order of things.
//We are not loading stuff by bone but by animation - every bone has data for all the animations (I hope...)
//Animations MUST BE LOADED FIRST!!!!!
bool use_animfile;
io::IReadFile* AnimFile;
for(u32 i=0; i<M2MAnimations.size(); i++)
{ {
if(M2MBones[i].translation.header.TimeStamp.num>0) use_animfile = (M2MAnimations[i].flags & 0x20) == 0;
if(use_animfile)
{ {
tempNumOfsList.clear(); std::string AnimName = MeshFile->getFileName();
MeshFile->seek(M2MBones[i].translation.header.TimeStamp.ofs); c8 ext[13];
for(u32 j=0; j<M2MBones[i].translation.header.TimeStamp.num;j++) 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)
{ {
logerror("Error! Anim file not found: %s", AnimName.c_str());
if(M2MAnimations[i].flags & 0x40)
{
logerror("We actually expected this error - Where is the data for this animation???");
}
continue;
}
}
else
{
AnimFile = MeshFile;
}
for(u32 j=0; j<M2MBones.size(); j++)
{
if(M2MBones[j].translation.header.TimeStamp.num>0 && M2MBones[j].translation.header.Values.num>0)
{
//Timestamps
MeshFile->seek(M2MBones[j].translation.header.TimeStamp.ofs+8*i);
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
tempNumOfsList.push_back(tempBoneNumOfs); if(tempBoneNumOfs.num > 0)
}
for(u32 j=0; j<tempNumOfsList.size();j++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->seek(tempBoneNumOfs.ofs);
if(n.num > 0 && M2MAnimations[j].flags & 0x20) for(u32 k=0; k<tempBoneNumOfs.num;k++)
{ {
MeshFile->seek(n.ofs); AnimFile->read(&tempBoneTS, sizeof(u32));
for(u32 k=0; k<n.num;k++) M2MBones[j].translation.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline.
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].translation.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline.
} }
} }
} //Values
} MeshFile->seek(M2MBones[j].translation.header.Values.ofs+8*i);
if(M2MBones[i].rotation.header.TimeStamp.num>0)
{
tempNumOfsList.clear();
MeshFile->seek(M2MBones[i].rotation.header.TimeStamp.ofs);
for(u32 j=0; j<M2MBones[i].rotation.header.TimeStamp.num;j++)
{
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
tempNumOfsList.push_back(tempBoneNumOfs); if(tempBoneNumOfs.num > 0)
}
for(u32 j=0; j<tempNumOfsList.size();j++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->seek(tempBoneNumOfs.ofs);
if(n.num > 0 && M2MAnimations[j].flags & 0x20) for(u32 k=0; k<tempBoneNumOfs.num*3;k++)
{ {
MeshFile->seek(n.ofs); AnimFile->read(&tempBoneValue, sizeof(float));
for(u32 k=0; k<n.num;k++) M2MBones[j].translation.values.push_back(tempBoneValue);
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].rotation.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline.
} }
} }
} }
} if(M2MBones[j].rotation.header.TimeStamp.num>0 && M2MBones[j].rotation.header.Values.num>0)
if(M2MBones[i].scaling.header.TimeStamp.num>0)
{
tempNumOfsList.clear();
MeshFile->seek(M2MBones[i].scaling.header.TimeStamp.ofs);
for(u32 j=0; j<M2MBones[i].scaling.header.TimeStamp.num;j++)
{ {
//Timestamps
MeshFile->seek(M2MBones[j].rotation.header.TimeStamp.ofs+8*i);
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
tempNumOfsList.push_back(tempBoneNumOfs); if(tempBoneNumOfs.num > 0)
}
for(u32 j=0; j<tempNumOfsList.size();j++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->seek(tempBoneNumOfs.ofs);
if(n.num > 0 && M2MAnimations[j].flags & 0x20) for(u32 k=0; k<tempBoneNumOfs.num;k++)
{ {
MeshFile->seek(n.ofs); AnimFile->read(&tempBoneTS, sizeof(u32));
for(u32 k=0; k<n.num;k++) M2MBones[j].rotation.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline.
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].scaling.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline.
} }
} }
} //Values
} MeshFile->seek(M2MBones[j].rotation.header.Values.ofs+8*i);
if(M2MBones[i].translation.header.Values.num>0)
{
tempNumOfsList.clear();
MeshFile->seek(M2MBones[i].translation.header.Values.ofs);
for(u32 j=0; j<M2MBones[i].translation.header.Values.num;j++)
{
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
tempNumOfsList.push_back(tempBoneNumOfs); if(tempBoneNumOfs.num > 0)
}
for(u32 j=0; j<tempNumOfsList.size();j++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->seek(tempBoneNumOfs.ofs);
if(n.num > 0 && M2MAnimations[j].flags & 0x20) for(u32 k=0; k<tempBoneNumOfs.num*4;k++)
{ {
MeshFile->seek(n.ofs); AnimFile->read(&tempBoneShort, sizeof(s16));
for(u32 k=0; k<n.num*3;k++)
{
MeshFile->read(&tempBoneValue, sizeof(float));
M2MBones[i].translation.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; j<M2MBones[i].rotation.header.Values.num;j++)
{
MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
tempNumOfsList.push_back(tempBoneNumOfs);
}
for(u32 j=0; j<tempNumOfsList.size();j++)
{
numofs n = tempNumOfsList[j];
if(n.num > 0 && M2MAnimations[j].flags & 0x20)
{
MeshFile->seek(n.ofs);
for(u32 k=0; k<n.num*4;k++)
{
MeshFile->read(&tempBoneShort, sizeof(s16));
tempBoneValue=(tempBoneShort>0?tempBoneShort-32767:tempBoneShort+32767)/32767.0f; tempBoneValue=(tempBoneShort>0?tempBoneShort-32767:tempBoneShort+32767)/32767.0f;
M2MBones[i].rotation.values.push_back(tempBoneValue); M2MBones[j].rotation.values.push_back(tempBoneValue);
} }
} }
} }
} if(M2MBones[j].scaling.header.TimeStamp.num>0 && M2MBones[j].scaling.header.Values.num>0)
if(M2MBones[i].scaling.header.Values.num>0)
{
tempNumOfsList.clear();
MeshFile->seek(M2MBones[i].scaling.header.Values.ofs);
for(u32 j=0; j<M2MBones[i].scaling.header.Values.num;j++)
{ {
//Timestamps
MeshFile->seek(M2MBones[j].scaling.header.TimeStamp.ofs+8*i);
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
tempNumOfsList.push_back(tempBoneNumOfs); if(tempBoneNumOfs.num > 0)
}
for(u32 j=0; j<tempNumOfsList.size();j++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->seek(tempBoneNumOfs.ofs);
if(n.num > 0 && M2MAnimations[j].flags & 0x20) for(u32 k=0; k<tempBoneNumOfs.num;k++)
{ {
MeshFile->seek(n.ofs); AnimFile->read(&tempBoneTS, sizeof(u32));
for(u32 k=0; k<n.num*3;k++) M2MBones[j].scaling.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline.
}
}
//Values
MeshFile->seek(M2MBones[j].scaling.header.Values.ofs+8*i);
MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
if(tempBoneNumOfs.num > 0)
{ {
MeshFile->read(&tempBoneValue, sizeof(float)); AnimFile->seek(tempBoneNumOfs.ofs);
M2MBones[i].scaling.values.push_back(tempBoneValue); for(u32 k=0; k<tempBoneNumOfs.num*3;k++)
{
AnimFile->read(&tempBoneValue, sizeof(float));
M2MBones[j].scaling.values.push_back(tempBoneValue);
} }
} }
} }
} }
if(use_animfile)
{
AnimFile->drop();
}
AnimFile=0;
} }
DEBUG(logdebug("Read %u Bones",M2MBones.size())); DEBUG(logdebug("Read %u Bones",M2MBones.size()));
@ -427,7 +400,6 @@ DEBUG(logdebug("Read %u Bones",M2MBones.size()));
void CM2MeshFileLoader::ReadAnimationData() void CM2MeshFileLoader::ReadAnimationData()
{ {
logdebug("Reading Animation Data");
//Global Sequences. This is global data //Global Sequences. This is global data
u32 tempGlobalSeq; u32 tempGlobalSeq;
if(!M2MGlobalSequences.empty()) if(!M2MGlobalSequences.empty())
@ -487,8 +459,9 @@ logdebug("Reading Animation Data");
{ {
RawAnimation tempRaw; RawAnimation tempRaw;
MeshFile->read(&tempRaw,sizeof(RawAnimation)); MeshFile->read(&tempRaw,sizeof(RawAnimation));
tempAnimation.animationID = tempRaw.animationID; tempAnimation.animationID = tempRaw.animationID;
tempAnimation.flags = tempRaw.flags; tempAnimation.probability = tempRaw.probability / 32767.0f;
tempAnimation.start = tempRaw.start; tempAnimation.start = tempRaw.start;
tempAnimation.end = tempRaw.end; tempAnimation.end = tempRaw.end;
} }
@ -499,6 +472,7 @@ logdebug("Reading Animation Data");
tempAnimation.animationID = tempRaw.animationID; tempAnimation.animationID = tempRaw.animationID;
tempAnimation.subanimationID = tempRaw.subanimationID; tempAnimation.subanimationID = tempRaw.subanimationID;
tempAnimation.flags = tempRaw.flags; tempAnimation.flags = tempRaw.flags;
tempAnimation.probability = tempRaw.probability / 32767.0f;
tempAnimation.start = laststart; tempAnimation.start = laststart;
tempAnimation.end = laststart + tempRaw.length; tempAnimation.end = laststart + tempRaw.length;
laststart += tempRaw.length + 1000; laststart += tempRaw.length + 1000;
@ -659,6 +633,11 @@ switch(header.version)
/////////////////////////////////////// ///////////////////////////////////////
// Animation related stuff // // Animation related stuff //
/////////////////////////////////////// ///////////////////////////////////////
for(u32 i=0;i<M2MAnimations.size();i++)
{
AnimatedMesh->newAnimation(M2MAnimations[i].animationID,M2MAnimations[i].start,M2MAnimations[i].end,M2MAnimations[i].probability);
}
scene::CM2Mesh::SJoint* Joint; scene::CM2Mesh::SJoint* Joint;
for(u32 i=0;i<M2MBones.size();i++) for(u32 i=0;i<M2MBones.size();i++)

View File

@ -123,7 +123,7 @@ struct RawAnimation{
u32 animationID; u32 animationID;
u32 start, end; u32 start, end;
float movespeed; float movespeed;
u32 loop, flags, unk1, unk2; u32 loop, probability, unk1, unk2;
u32 playbackspeed; u32 playbackspeed;
float bbox[6]; float bbox[6];
float radius; float radius;
@ -149,6 +149,7 @@ struct Animation{
u32 subanimationID; u32 subanimationID;
u32 start, end; u32 start, end;
u32 flags; u32 flags;
f32 probability;
}; };
struct AnimBlockHead{ struct AnimBlockHead{

View File

@ -145,6 +145,10 @@ void DrawObject::_Init(void)
if(mesh) if(mesh)
{ {
node = _smgr->addAnimatedMeshSceneNode(mesh); node = _smgr->addAnimatedMeshSceneNode(mesh);
scene::IAnimatedMeshSceneNode* aninode = (scene::IAnimatedMeshSceneNode*)node;
aninode->setAnimationSpeed(1000);
aninode->setM2Animation(0);
//video::ITexture *tex = _device->getVideoDriver()->getTexture("data/misc/square.jpg"); //video::ITexture *tex = _device->getVideoDriver()->getTexture("data/misc/square.jpg");
//node->setMaterialTexture(0, tex); //node->setMaterialTexture(0, tex);
} }

View File

@ -47,6 +47,9 @@ namespace scene
can be loaded directly by Irrlicht */ can be loaded directly by Irrlicht */
EAMT_OCT, EAMT_OCT,
//! WoW M2 files
EAMT_M2,
//! generic skinned mesh //! generic skinned mesh
EAMT_SKINNED EAMT_SKINNED
}; };

View File

@ -135,6 +135,9 @@ namespace scene
//! Deprecated command, please use getJointNode //! Deprecated command, please use getJointNode
virtual ISceneNode* getXJointNode(const c8* jointName) = 0; virtual ISceneNode* getXJointNode(const c8* jointName) = 0;
//! Starts a M2 animation.
virtual bool setM2Animation(u32 anim) = 0;
//! Starts a default MD2 animation. //! Starts a default MD2 animation.
/** With this method it is easily possible to start a Run, /** With this method it is easily possible to start a Run,
Attack, Die or whatever animation, if the mesh contained in Attack, Die or whatever animation, if the mesh contained in

View File

@ -22,6 +22,7 @@
#include "IGUIFont.h" #include "IGUIFont.h"
#include "ISceneCollisionManager.h" #include "ISceneCollisionManager.h"
#include "../../../Client/GUI/CM2Mesh.h"
namespace irr namespace irr
{ {
@ -428,7 +429,7 @@ void CAnimatedMeshSceneNode::render()
// show skeleton // show skeleton
if ( DebugDataVisible & scene::EDS_SKELETON ) if ( DebugDataVisible & scene::EDS_SKELETON )
{ {
if (Mesh->getMeshType() == EAMT_SKINNED) if (Mesh->getMeshType() == EAMT_SKINNED || Mesh->getMeshType() == EAMT_M2)
{ {
// draw skeleton // draw skeleton
ISceneCollisionManager* Coll = SceneManager->getSceneCollisionManager(); ISceneCollisionManager* Coll = SceneManager->getSceneCollisionManager();
@ -714,6 +715,24 @@ bool CAnimatedMeshSceneNode::removeChild(ISceneNode* child)
return false; 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. //! Starts a MD2 animation.
bool CAnimatedMeshSceneNode::setMD2Animation(EMD2_ANIMATION_TYPE anim) bool CAnimatedMeshSceneNode::setMD2Animation(EMD2_ANIMATION_TYPE anim)

View File

@ -96,6 +96,9 @@ namespace scene
//! or to remove attached childs. //! or to remove attached childs.
virtual bool removeChild(ISceneNode* child); virtual bool removeChild(ISceneNode* child);
//! Starts a M2 animation.
virtual bool setM2Animation(u32 anim);
//! Starts a MD2 animation. //! Starts a MD2 animation.
virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim); virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim);