* 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
{
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
{
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<f32> BoundingBox;
core::array< core::array<bool> > Vertices_Moved;
core::array< M2Animation > Animations;
core::map<u32, core::array<u32> > AnimationLookup;
};
} // end namespace scene

View File

@ -272,153 +272,126 @@ numofs tempBoneNumOfs;
core::array<numofs> tempNumOfsList;
float tempBoneValue;
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();
MeshFile->seek(M2MBones[i].translation.header.TimeStamp.ofs);
for(u32 j=0; j<M2MBones[i].translation.header.TimeStamp.num;j++)
logerror("Error! Anim file not found: %s", AnimName.c_str());
if(M2MAnimations[i].flags & 0x40)
{
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;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.
}
}
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; j<M2MBones.size(); j++)
{
if(M2MBones[j].translation.header.TimeStamp.num>0 && M2MBones[j].translation.header.Values.num>0)
{
tempNumOfsList.clear();
MeshFile->seek(M2MBones[i].rotation.header.TimeStamp.ofs);
for(u32 j=0; j<M2MBones[i].rotation.header.TimeStamp.num;j++)
//Timestamps
MeshFile->seek(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; k<tempBoneNumOfs.num;k++)
{
MeshFile->read(&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; 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];
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].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; j<M2MBones[i].scaling.header.TimeStamp.num;j++)
//Timestamps
MeshFile->seek(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; k<tempBoneNumOfs.num;k++)
{
MeshFile->read(&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; 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];
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].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; j<M2MBones[i].translation.header.Values.num;j++)
//Timestamps
MeshFile->seek(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; k<tempBoneNumOfs.num;k++)
{
MeshFile->read(&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; 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];
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].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; 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;
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);
}
}
}
}
}
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;i<M2MAnimations.size();i++)
{
AnimatedMesh->newAnimation(M2MAnimations[i].animationID,M2MAnimations[i].start,M2MAnimations[i].end,M2MAnimations[i].probability);
}
scene::CM2Mesh::SJoint* Joint;
for(u32 i=0;i<M2MBones.size();i++)

View File

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

View File

@ -145,6 +145,10 @@ void DrawObject::_Init(void)
if(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");
//node->setMaterialTexture(0, tex);
}

View File

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

View File

@ -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.

View File

@ -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)

View File

@ -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);