* 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;
@ -135,7 +142,10 @@ namespace scene
virtual SScaleKey *createScaleKey(SJoint *joint); virtual SScaleKey *createScaleKey(SJoint *joint);
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)
{
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(); logerror("Error! Anim file not found: %s", AnimName.c_str());
MeshFile->seek(M2MBones[i].translation.header.TimeStamp.ofs); if(M2MAnimations[i].flags & 0x40)
for(u32 j=0; j<M2MBones[i].translation.header.TimeStamp.num;j++)
{ {
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); logerror("We actually expected this error - Where is the data for this animation???");
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;k++)
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].translation.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline.
}
}
} }
continue;
} }
if(M2MBones[i].rotation.header.TimeStamp.num>0) }
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)
{ {
tempNumOfsList.clear(); //Timestamps
MeshFile->seek(M2MBones[i].rotation.header.TimeStamp.ofs); MeshFile->seek(M2MBones[j].translation.header.TimeStamp.ofs+8*i);
for(u32 j=0; j<M2MBones[i].rotation.header.TimeStamp.num;j++) MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
if(tempBoneNumOfs.num > 0)
{
AnimFile->seek(tempBoneNumOfs.ofs);
for(u32 k=0; k<tempBoneNumOfs.num;k++)
{ {
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); AnimFile->read(&tempBoneTS, sizeof(u32));
tempNumOfsList.push_back(tempBoneNumOfs); M2MBones[j].translation.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline.
} }
for(u32 j=0; j<tempNumOfsList.size();j++) }
//Values
MeshFile->seek(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<tempBoneNumOfs.num*3;k++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->read(&tempBoneValue, sizeof(float));
if(n.num > 0 && M2MAnimations[j].flags & 0x20) M2MBones[j].translation.values.push_back(tempBoneValue);
{
MeshFile->seek(n.ofs);
for(u32 k=0; k<n.num;k++)
{
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[i].scaling.header.TimeStamp.num>0) if(M2MBones[j].rotation.header.TimeStamp.num>0 && M2MBones[j].rotation.header.Values.num>0)
{ {
tempNumOfsList.clear(); //Timestamps
MeshFile->seek(M2MBones[i].scaling.header.TimeStamp.ofs); MeshFile->seek(M2MBones[j].rotation.header.TimeStamp.ofs+8*i);
for(u32 j=0; j<M2MBones[i].scaling.header.TimeStamp.num;j++) MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
if(tempBoneNumOfs.num > 0)
{
AnimFile->seek(tempBoneNumOfs.ofs);
for(u32 k=0; k<tempBoneNumOfs.num;k++)
{ {
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); AnimFile->read(&tempBoneTS, sizeof(u32));
tempNumOfsList.push_back(tempBoneNumOfs); M2MBones[j].rotation.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline.
} }
for(u32 j=0; j<tempNumOfsList.size();j++) }
//Values
MeshFile->seek(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<tempBoneNumOfs.num*4;k++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->read(&tempBoneShort, sizeof(s16));
if(n.num > 0 && M2MAnimations[j].flags & 0x20) tempBoneValue=(tempBoneShort>0?tempBoneShort-32767:tempBoneShort+32767)/32767.0f;
{ M2MBones[j].rotation.values.push_back(tempBoneValue);
MeshFile->seek(n.ofs);
for(u32 k=0; k<n.num;k++)
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].scaling.timestamps.push_back(tempBoneTS+M2MAnimations[j].start);//Bit of a HACK squash Multitimeline into single timeline.
}
}
} }
}
} }
if(M2MBones[j].scaling.header.TimeStamp.num>0 && M2MBones[j].scaling.header.Values.num>0)
if(M2MBones[i].translation.header.Values.num>0)
{ {
tempNumOfsList.clear(); //Timestamps
MeshFile->seek(M2MBones[i].translation.header.Values.ofs); MeshFile->seek(M2MBones[j].scaling.header.TimeStamp.ofs+8*i);
for(u32 j=0; j<M2MBones[i].translation.header.Values.num;j++) MeshFile->read(&tempBoneNumOfs, sizeof(numofs));
if(tempBoneNumOfs.num > 0)
{
AnimFile->seek(tempBoneNumOfs.ofs);
for(u32 k=0; k<tempBoneNumOfs.num;k++)
{ {
MeshFile->read(&tempBoneNumOfs, sizeof(numofs)); AnimFile->read(&tempBoneTS, sizeof(u32));
tempNumOfsList.push_back(tempBoneNumOfs); M2MBones[j].scaling.timestamps.push_back(tempBoneTS+M2MAnimations[i].start);//Bit of a HACK squash Multitimeline into single timeline.
} }
for(u32 j=0; j<tempNumOfsList.size();j++) }
//Values
MeshFile->seek(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<tempBoneNumOfs.num*3;k++)
{ {
numofs n = tempNumOfsList[j]; AnimFile->read(&tempBoneValue, sizeof(float));
if(n.num > 0 && M2MAnimations[j].flags & 0x20) M2MBones[j].scaling.values.push_back(tempBoneValue);
{
MeshFile->seek(n.ofs);
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) }
{ if(use_animfile)
tempNumOfsList.clear(); {
MeshFile->seek(M2MBones[i].rotation.header.Values.ofs); AnimFile->drop();
for(u32 j=0; j<M2MBones[i].rotation.header.Values.num;j++) }
{ AnimFile=0;
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;
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; j<M2MBones[i].scaling.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*3;k++)
{
MeshFile->read(&tempBoneValue, sizeof(float));
M2MBones[i].scaling.values.push_back(tempBoneValue);
}
}
}
}
} }
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,7 +135,10 @@ 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 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, /** 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
this scene node is an md2 mesh. Otherwise, nothing happens. this scene node is an md2 mesh. Otherwise, nothing happens.

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,8 +96,11 @@ namespace scene
//! or to remove attached childs. //! or to remove attached childs.
virtual bool removeChild(ISceneNode* child); virtual bool removeChild(ISceneNode* child);
//! Starts a MD2 animation. //! Starts a M2 animation.
virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim); virtual bool setM2Animation(u32 anim);
//! Starts a MD2 animation.
virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim);
//! Starts a special MD2 animation. //! Starts a special MD2 animation.
virtual bool setMD2Animation(const c8* animationName); virtual bool setMD2Animation(const c8* animationName);