* Read .anim files for 3.3.5
This commit is contained in:
parent
9c5990d97f
commit
73efbaf339
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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++)
|
||||
|
||||
@ -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{
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -47,6 +47,9 @@ namespace scene
|
||||
can be loaded directly by Irrlicht */
|
||||
EAMT_OCT,
|
||||
|
||||
//! WoW M2 files
|
||||
EAMT_M2,
|
||||
|
||||
//! generic skinned mesh
|
||||
EAMT_SKINNED
|
||||
};
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user