* Read animation data from M2 files. No actual animation, just reading the data

* Cleaned up some of the texture handling (Render flags, Texture lookup), thx to bLuma for the heads-up
* bounding boxes should now work as expected
This commit is contained in:
shlainn 2008-10-12 20:08:57 +00:00
parent ba6b918a69
commit ebc0ea6ee2
7 changed files with 2268 additions and 126 deletions

130
src/Client/GUI/CBoneSceneNode.cpp Executable file
View File

@ -0,0 +1,130 @@
// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "irrlicht/irrlicht.h"
#include "CBoneSceneNode.h"
namespace irr
{
namespace scene
{
//! constructor
CBoneSceneNode::CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
u32 boneIndex, const c8* boneName)
: IBoneSceneNode(parent, mgr, id), BoneIndex(boneIndex), BoneName(boneName),
AnimationMode(EBAM_AUTOMATIC), SkinningSpace(EBSS_LOCAL)
{
#ifdef _DEBUG
setDebugName("CBoneSceneNode");
#endif
}
//! Returns the name of the bone
const c8* CBoneSceneNode::getBoneName() const
{
return BoneName.c_str();
}
//! Returns the index of the bone
u32 CBoneSceneNode::getBoneIndex() const
{
return BoneIndex;
}
//! Sets the animation mode of the bone. Returns true if successful.
bool CBoneSceneNode::setAnimationMode(E_BONE_ANIMATION_MODE mode)
{
AnimationMode = mode;
return true;
}
//! Gets the current animation mode of the bone
E_BONE_ANIMATION_MODE CBoneSceneNode::getAnimationMode() const
{
return AnimationMode;
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CBoneSceneNode::getBoundingBox() const
{
return Box;
}
/*
//! Returns the relative transformation of the scene node.
core::matrix4 CBoneSceneNode::getRelativeTransformation() const
{
return core::matrix4(); // RelativeTransformation;
}
*/
void CBoneSceneNode::OnAnimate(u32 timeMs)
{
if (IsVisible)
{
// animate this node with all animators
core::list<ISceneNodeAnimator*>::Iterator ait = Animators.begin();
for (; ait != Animators.end(); ++ait)
(*ait)->animateNode(this, timeMs);
// update absolute position
//updateAbsolutePosition();
// perform the post render process on all children
core::list<ISceneNode*>::Iterator it = Children.begin();
for (; it != Children.end(); ++it)
(*it)->OnAnimate(timeMs);
}
}
void CBoneSceneNode::helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node)
{
Node->updateAbsolutePosition();
core::list<ISceneNode*>::ConstIterator it = Node->getChildren().begin();
for (; it != Node->getChildren().end(); ++it)
{
helper_updateAbsolutePositionOfAllChildren( (*it) );
}
}
void CBoneSceneNode::updateAbsolutePositionOfAllChildren()
{
helper_updateAbsolutePositionOfAllChildren( this );
}
void CBoneSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
out->addInt("BoneIndex", BoneIndex);
out->addString("BoneName", BoneName.c_str());
out->addEnum("AnimationMode", AnimationMode, BoneAnimationModeNames);
}
void CBoneSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
BoneIndex = in->getAttributeAsInt("BoneIndex");
BoneName = in->getAttributeAsString("BoneName");
AnimationMode = (E_BONE_ANIMATION_MODE)in->getAttributeAsEnumeration("AnimationMode", BoneAnimationModeNames);
// TODO: add/replace bone in parent with bone from mesh
}
} // namespace scene
} // namespace irr

84
src/Client/GUI/CBoneSceneNode.h Executable file
View File

@ -0,0 +1,84 @@
// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BONE_SCENE_NODE_H_INCLUDED__
#define __C_BONE_SCENE_NODE_H_INCLUDED__
// Used with SkinnedMesh and IAnimatedMeshSceneNode, for boned meshes
#include "irrlicht/irrlicht.h"
namespace irr
{
namespace scene
{
class CBoneSceneNode : public IBoneSceneNode
{
public:
//! constructor
CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr,
s32 id=-1, u32 boneIndex=0, const c8* boneName=0);
//! Returns the name of the bone
virtual const c8* getBoneName() const;
//! Returns the index of the bone
virtual u32 getBoneIndex() const;
//! Sets the animation mode of the bone. Returns true if successful.
virtual bool setAnimationMode(E_BONE_ANIMATION_MODE mode);
//! Gets the current animation mode of the bone
virtual E_BONE_ANIMATION_MODE getAnimationMode() const;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const;
/*
//! Returns the relative transformation of the scene node.
//virtual core::matrix4 getRelativeTransformation() const;
*/
virtual void OnAnimate(u32 timeMs);
virtual void updateAbsolutePositionOfAllChildren();
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
//! How the relative transformation of the bone is used
virtual void setSkinningSpace( E_BONE_SKINNING_SPACE space )
{
SkinningSpace=space;
}
virtual E_BONE_SKINNING_SPACE getSkinningSpace() const
{
return SkinningSpace;
}
private:
void helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node);
u32 BoneIndex;
core::stringc BoneName;
core::aabbox3d<f32> Box;
E_BONE_ANIMATION_MODE AnimationMode;
E_BONE_SKINNING_SPACE SkinningSpace;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -1,7 +1,32 @@
#include <iostream>
#include "CM2MeshFileLoader.h"
#include "SSkinnedMesh.h"
#define _DEBUG
#include "common.h"
#ifdef _DEBUG
#define DEBUG(code) code;
#else
#define DEBUG(code) ;
#endif
/*
void logdebug(const char *str, ...)
{
if(!str)
return;
va_list ap;
// _log_setcolor(true,LBLUE);
va_start(ap, str);
vprintf( str, ap );
va_end(ap);
// _log_resetcolor(true);
printf("\n");
fflush(stdout);
}*/
namespace irr
{
@ -32,14 +57,31 @@ bool CM2MeshFileLoader::isALoadableFileExtension(const c8* filename)const
//! See IUnknown::drop() for more information.
IAnimatedMesh* CM2MeshFileLoader::createMesh(io::IReadFile* file)
{
ILogger* logger =Device->getLogger();
if(!file)
return 0;
MeshFile = file;
AnimatedMesh = new scene::CSkinnedMesh();
DEBUG(logger->log("Trying to open file",file->getFileName(),ELL_INFORMATION));
if ( load() )
{
AnimatedMesh->finalize();
}
else
{
AnimatedMesh->drop();
AnimatedMesh = 0;
}
return AnimatedMesh;
}
bool CM2MeshFileLoader::load()
{
DEBUG(logdebug("Trying to open file %s",MeshFile->getFileName()));
file->read(&header,sizeof(ModelHeader));
if (header.version[0] != 4 && header.version[1] != 1 && header.version[2] != 0 && header.version[3] != 0) {
logger->log("Something wrong!",ELL_ERROR);
MeshFile->read(&header,sizeof(ModelHeader));
if (header.version[0] != 4 && header.version[1] != 1 && header.version[2] != 0 && header.version[3] != 0) {
printf("Wrong header! File version doesn't match or file is not a M2 file.");
return 0;
}
else
@ -60,11 +102,19 @@ if(!M2MVertices.empty())
M2MVertices.clear();
ModelVertex tempM2MVert;
file->seek(header.ofsVertices);
f32 tempYZ;
MeshFile->seek(header.ofsVertices);
for(u32 i =0;i<header.nVertices;i++)
{
file->read(&tempM2MVert,sizeof(ModelVertex));
MeshFile->read(&tempM2MVert,sizeof(ModelVertex));
tempYZ = tempM2MVert.pos.Y;
tempM2MVert.pos.Y=tempM2MVert.pos.Z;
tempM2MVert.pos.Z=tempYZ;
tempYZ = tempM2MVert.normal.Y;
tempM2MVert.normal.Y=tempM2MVert.normal.Z;
tempM2MVert.normal.Z=tempYZ;
M2MVertices.push_back(tempM2MVert);
}
DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices));
@ -73,10 +123,10 @@ DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices));
if(M2MViews.size()>0)
M2MViews.clear();
ModelView tempM2MView;
file->seek(header.ofsViews);
MeshFile->seek(header.ofsViews);
for(u32 i =0;i<header.nViews;i++)
{
file->read(&tempM2MView,sizeof(ModelView));
MeshFile->read(&tempM2MView,sizeof(ModelView));
M2MViews.push_back(tempM2MView);
}
//std::cout << "Read "<<M2MViews.size()<<"/"<<header.nViews<<" Views\n";
@ -89,10 +139,10 @@ if(M2MIndices.size()>0)
M2MIndices.clear();
u16 tempM2Index;
file->seek(M2MViews[0].ofsIndex);
MeshFile->seek(M2MViews[0].ofsIndex);
for(u32 i =0;i<M2MViews[0].nIndex;i++)
{
file->read(&tempM2Index,sizeof(u16));
MeshFile->read(&tempM2Index,sizeof(u16));
M2MIndices.push_back(tempM2Index);
}
DEBUG(logdebug("Read %u/%u Indices",M2MIndices.size(),M2MViews[0].nIndex));
@ -103,10 +153,10 @@ if(M2MTriangles.size()>0)
M2MTriangles.clear();
u16 tempM2Triangle;
file->seek(M2MViews[0].ofsTris);
MeshFile->seek(M2MViews[0].ofsTris);
for(u32 i =0;i<M2MViews[0].nTris;i++)
{
file->read(&tempM2Triangle,sizeof(u16));
MeshFile->read(&tempM2Triangle,sizeof(u16));
M2MTriangles.push_back(tempM2Triangle);
}
DEBUG(logdebug("Read %u/%u Triangles",M2MTriangles.size(),M2MViews[0].nTris));
@ -115,10 +165,10 @@ if(M2MSubmeshes.size()>0)
M2MSubmeshes.clear();
ModelViewSubmesh tempM2Submesh;
file->seek(M2MViews[0].ofsSub);
MeshFile->seek(M2MViews[0].ofsSub);
for(u32 i =0;i<M2MViews[0].nSub;i++)
{
file->read(&tempM2Submesh,sizeof(ModelViewSubmesh));
MeshFile->read(&tempM2Submesh,sizeof(ModelViewSubmesh));
M2MSubmeshes.push_back(tempM2Submesh);
// std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n";
}
@ -130,11 +180,12 @@ if(!M2MTextureUnit.empty())
{
M2MTextureUnit.clear();
}
file->seek(M2MViews[0].ofsTex);
MeshFile->seek(M2MViews[0].ofsTex);
for(u32 i=0;i<M2MViews[0].nTex;i++)
{
file->read(&tempM2TexUnit,sizeof(TextureUnit));
MeshFile->read(&tempM2TexUnit,sizeof(TextureUnit));
M2MTextureUnit.push_back(tempM2TexUnit);
DEBUG(logdebug(" TexUnit %u: Submesh: %u %u Render Flag: %u TextureUnitNumber: %u %u TTU: %u",i,tempM2TexUnit.submeshIndex1,tempM2TexUnit.submeshIndex2, tempM2TexUnit.renderFlagsIndex, tempM2TexUnit.TextureUnitNumber, tempM2TexUnit.TextureUnitNumber2 ,tempM2TexUnit.textureIndex));
}
DEBUG(logdebug("Read %u Texture Unit entries for View 0",M2MTextureUnit.size()));
@ -147,11 +198,12 @@ if(!M2MTextureLookup.empty())
{
M2MTextureLookup.clear();
}
file->seek(header.ofsTexLookup);
MeshFile->seek(header.ofsTexLookup);
for(u32 i=0;i<header.nTexLookup;i++)
{
file->read(&tempM2TexLookup,sizeof(u16));
MeshFile->read(&tempM2TexLookup,sizeof(u16));
M2MTextureLookup.push_back(tempM2TexLookup);
printf("Texture %u Type %u\n",i,tempM2TexLookup);
}
DEBUG(logdebug("Read %u Texture lookup entries",M2MTextureLookup.size()));
@ -161,11 +213,12 @@ if(!M2MTextureDef.empty())
{
M2MTextureDef.clear();
}
file->seek(header.ofsTextures);
MeshFile->seek(header.ofsTextures);
for(u32 i=0;i<header.nTextures;i++)
{
file->read(&tempM2TexDef,sizeof(TextureDefinition));
MeshFile->read(&tempM2TexDef,sizeof(TextureDefinition));
M2MTextureDef.push_back(tempM2TexDef);
printf("Texture %u Type %u\n",i,tempM2TexDef.texType);
}
DEBUG(logdebug("Read %u Texture Definition entries",M2MTextureDef.size()));
@ -175,11 +228,12 @@ if(!M2MRenderFlags.empty())
{
M2MRenderFlags.clear();
}
file->seek(header.ofsTexFlags);
MeshFile->seek(header.ofsTexFlags);
for(u32 i=0;i<header.nTexFlags;i++)
{
file->read(&tempM2RF,sizeof(RenderFlags));
MeshFile->read(&tempM2RF,sizeof(RenderFlags));
M2MRenderFlags.push_back(tempM2RF);
DEBUG(logdebug("Flag %u: (%u, %u)",i,tempM2RF.blending,tempM2RF.flags));
}
DEBUG(logdebug("Read %u Renderflags",M2MRenderFlags.size()));
@ -195,15 +249,218 @@ M2MTextureFiles.reallocate(M2MTextureDef.size());
for(u32 i=0; i<M2MTextureDef.size(); i++)
{
tempTexFileName.reserve(M2MTextureDef[i].texFileLen + 1);
file->seek(M2MTextureDef[i].texFileOfs);
file->read((void*)tempTexFileName.c_str(),M2MTextureDef[i].texFileLen);
MeshFile->seek(M2MTextureDef[i].texFileOfs);
MeshFile->read((void*)tempTexFileName.c_str(),M2MTextureDef[i].texFileLen);
M2MTextureFiles.push_back(tempTexFileName.c_str());
DEBUG(logdebug("Texture: %u (%s)",M2MTextureFiles.size(),M2MTextureFiles[i].c_str()));
}
// std::cout << "Read "<<M2MTextureFiles.size()<<"/"<<M2MTextureDef.size()<<" Texture file names\n";
///////////////////////////////////////
// Animation related stuff //
///////////////////////////////////////
printf("Global Sequences: %u\n",header.nGlobalSequences);
//Ignored at the moment, as wolf.m2 has none
printf("Animations: %u\n",header.nAnimations);
//Animations. This is global data
Animation tempAnimation;
if(!M2MAnimations.empty())
{
M2MAnimations.clear();
}
MeshFile->seek(header.ofsAnimations);
for(u32 i=0;i<header.nAnimations;i++)
{
MeshFile->read(&tempAnimation,sizeof(Animation));
M2MAnimations.push_back(tempAnimation);
//std::cout<<tempAnimation.start<<" "<<tempAnimation.end<<"\n";
}
DEBUG(logdebug("Read %u Animations",M2MAnimations.size()));
printf("Read %u Animations\n",M2MAnimations.size());
printf("Bones: %u\n",header.nBones);
//Bones. This is global data
Bone tempBone;
if(!M2MBones.empty())
{
M2MBones.clear();
}
MeshFile->seek(header.ofsBones);
for(u32 i=0;i<header.nBones;i++)
{
MeshFile->read(&tempBone,16);
MeshFile->read(&tempBone.translation.header,sizeof(AnimBlockHead));
MeshFile->read(&tempBone.rotation.header,sizeof(AnimBlockHead));
MeshFile->read(&tempBone.scaling.header,sizeof(AnimBlockHead));
MeshFile->read(&tempBone.PivotPoint,sizeof(core::vector3df));
tempYZ=tempBone.PivotPoint.Y;
tempBone.PivotPoint.Y=tempBone.PivotPoint.Z;
tempBone.PivotPoint.Z=tempYZ;
M2MBones.push_back(tempBone);
//std::cout<<i<<":"<<tempBone.flags<<" "<<tempBone.parentBone<<" |"<<tempBone.translation.header.interpolationType<<" "<<tempBone.translation.header.nInterpolationRange<<" "<<tempBone.translation.header.nTimeStamp<<" "<<tempBone.translation.header.nValues<<"|"<<tempBone.rotation.header.interpolationType<<" "<<tempBone.rotation.header.nInterpolationRange<<" "<<tempBone.rotation.header.nTimeStamp<<" "<<tempBone.rotation.header.nValues<<"|"<<tempBone.scaling.header.interpolationType<<" "<<tempBone.scaling.header.nInterpolationRange<<" "<<tempBone.scaling.header.nTimeStamp<<" "<<tempBone.scaling.header.nValues<<"\n";
}
//Fill in values referenced in Bones. local to each bone
InterpolationRange tempBoneIR;
u32 tempBoneTS;
float tempBoneValue;
for(u32 i=0; i<M2MBones.size(); i++)
{
if(M2MBones[i].translation.header.nInterpolationRange>0)
{
MeshFile->seek(M2MBones[i].translation.header.ofsInterpolationRange);
for(u32 j=0; j<M2MBones[i].translation.header.nInterpolationRange;j++)
{
MeshFile->read(&tempBoneIR, sizeof(InterpolationRange));
M2MBones[i].translation.keyframes.push_back(tempBoneIR);
}
}
if(M2MBones[i].rotation.header.nInterpolationRange>0)
{
MeshFile->seek(M2MBones[i].rotation.header.ofsInterpolationRange);
for(u32 j=0; j<M2MBones[i].rotation.header.nInterpolationRange;j++)
{
MeshFile->read(&tempBoneIR, sizeof(InterpolationRange));
M2MBones[i].rotation.keyframes.push_back(tempBoneIR);
}
}
if(M2MBones[i].scaling.header.nInterpolationRange>0)
{
MeshFile->seek(M2MBones[i].scaling.header.ofsInterpolationRange);
for(u32 j=0; j<M2MBones[i].scaling.header.nInterpolationRange;j++)
{
MeshFile->read(&tempBoneIR, sizeof(InterpolationRange));
M2MBones[i].scaling.keyframes.push_back(tempBoneIR);
}
}
if(M2MBones[i].translation.header.nTimeStamp>0)
{
MeshFile->seek(M2MBones[i].translation.header.ofsTimeStamp);
for(u32 j=0; j<M2MBones[i].translation.header.nTimeStamp;j++)
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].translation.timestamps.push_back(tempBoneTS);
}
}
if(M2MBones[i].rotation.header.nTimeStamp>0)
{
MeshFile->seek(M2MBones[i].rotation.header.ofsTimeStamp);
for(u32 j=0; j<M2MBones[i].rotation.header.nTimeStamp;j++)
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].rotation.timestamps.push_back(tempBoneTS);
}
}
if(M2MBones[i].scaling.header.nTimeStamp>0)
{
MeshFile->seek(M2MBones[i].scaling.header.ofsTimeStamp);
for(u32 j=0; j<M2MBones[i].scaling.header.nTimeStamp;j++)
{
MeshFile->read(&tempBoneTS, sizeof(u32));
M2MBones[i].scaling.timestamps.push_back(tempBoneTS);
}
}
if(M2MBones[i].translation.header.nValues>0)
{
MeshFile->seek(M2MBones[i].translation.header.ofsValues);
for(u32 j=0; j<M2MBones[i].translation.header.nValues*3;j++)
{
MeshFile->read(&tempBoneValue, sizeof(float));
M2MBones[i].translation.values.push_back(tempBoneValue);
}
}
if(M2MBones[i].rotation.header.nValues>0)
{
MeshFile->seek(M2MBones[i].rotation.header.ofsValues);
for(u32 j=0; j<M2MBones[i].rotation.header.nValues*4;j++)
{
s16 tempBoneShort;
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.nValues>0)
{
MeshFile->seek(M2MBones[i].scaling.header.ofsValues);
for(u32 j=0; j<M2MBones[i].scaling.header.nValues*3;j++)
{
MeshFile->read(&tempBoneValue, sizeof(float));
M2MBones[i].scaling.values.push_back(tempBoneValue);
}
}
}
DEBUG(logdebug("Read %u Bones",M2MBones.size()));
scene::CSkinnedMesh::SJoint* Joint;
for(u32 i=0;i<M2MBones.size();i++)
{
if(M2MBones[i].parentBone == -1)
{
ParentJoint=(scene::CSkinnedMesh::SJoint*)0;
}
else
{
ParentJoint=AnimatedMesh->getAllJoints()[M2MBones[i].parentBone];
}
Joint=AnimatedMesh->createJoint(ParentJoint);
//std::cout << i << " "<<Joint->GlobalMatrix.getTranslation().X<< " "<<Joint->GlobalMatrix.getTranslation().Y<< " "<<Joint->GlobalMatrix.getTranslation().Z<<'\n';
//std::cout << i << " "<<M2MBones[i].PivotPoint.X<< " "<<M2MBones[i].PivotPoint.Y<< " "<<M2MBones[i].PivotPoint.Z<<'\n';
/* for(u32 j=0;j<M2MBones[i].translation.header.nValues;j++)
{
scene::CSkinnedMesh::SPositionKey* pos=AnimatedMesh->createPositionKey(Joint);
pos->frame=M2MBones[i].translation.timestamps[j]*.01f;
pos->position=core::vector3df(M2MBones[i].translation.values[j*3],M2MBones[i].translation.values[j*3+1],M2MBones[i].translation.values[j*3+2]);
}
if(M2MBones[i].rotation.header.nValues>0)
{
for(u32 j=0;j<M2MBones[i].rotation.header.nValues;j++)
{
scene::CSkinnedMesh::SRotationKey* rot=AnimatedMesh->createRotationKey(Joint);
rot->frame=M2MBones[i].rotation.timestamps[j]*.01f;
core::quaternion tempQ=core::quaternion(M2MBones[i].rotation.values[j*4+0],M2MBones[i].rotation.values[j*4+1],M2MBones[i].rotation.values[j*4+2],M2MBones[i].rotation.values[j*4+3]);
rot->rotation=tempQ;
// std::cout <<" "<< M2MBones[i].rotation.values[j*4+0] <<" "<< M2MBones[i].rotation.values[j*4+1] <<" "<< M2MBones[i].rotation.values[j*4+2] <<" "<< M2MBones[i].rotation.values[j*4+3] <<'\n';
}
}
if(M2MBones[i].scaling.header.nValues>0){
for(u32 j=0;j<M2MBones[i].scaling.header.nValues;j++)
{
scene::CSkinnedMesh::SScaleKey* scale=AnimatedMesh->createScaleKey(Joint);
scale->frame=M2MBones[i].scaling.timestamps[j]*.01f;
scale->scale=core::vector3df(M2MBones[i].scaling.values[j*3],M2MBones[i].scaling.values[j*3+1],M2MBones[i].scaling.values[j*3+2]);
}
*/
// Joint->Animatedposition=M2MBones[i].PivotPoint;
// std::cout<<Joint->Animatedposition.X<<' '<<Joint->Animatedposition.Y<<' '<<Joint->Animatedposition.Z<<' '<<'\n';
// Joint->Animatedscale=core::vector3df(1.0f,1.0f,1.0f);
//Joint->Animatedrotation=core::quaternion(0.0f,0.0f,0.0f,0.0f);
core::matrix4 positionMatrix;
// positionMatrix.setTranslation( Joint->Animatedposition );
core::matrix4 scaleMatrix;
//scaleMatrix.setScale( Joint->Animatedscale );
core::matrix4 rotationMatrix;// = Joint->Animatedrotation.getMatrix();
Joint->GlobalMatrix = positionMatrix * rotationMatrix * scaleMatrix;//
if (ParentJoint)
{
core::matrix4 InverseParentGlobal;
ParentJoint->GlobalMatrix.getInverse(InverseParentGlobal);
Joint->LocalMatrix = InverseParentGlobal * Joint->GlobalMatrix;
}
else
Joint->LocalMatrix = Joint->GlobalMatrix;
}
//std::cout<<AnimatedMesh->getAllJoints()[1]->Children.size()<<" Children\n";
//And M2MVertices are not usable like this. Thus we transform
if(M2Vertices.size()>0)
@ -211,82 +468,89 @@ if(M2Vertices.size()>0)
for(u32 i=0;i<M2MVertices.size();i++)
{
M2Vertices.push_back(video::S3DVertex(core::vector3df(M2MVertices[i].pos.X,M2MVertices[i].pos.Z,M2MVertices[i].pos.Y),core::vector3df(M2MVertices[i].normal.X,M2MVertices[i].normal.Z,M2MVertices[i].normal.Y), video::SColor(255,100,100,100),M2MVertices[i].texcoords));
//M2Vertices.push_back(video::S3DVertex(core::vector3df(M2MVertices[i].pos.X,M2MVertices[i].pos.Z,M2MVertices[i].pos.Y),core::vector3df(M2MVertices[i].normal.X,M2MVertices[i].normal.Z,M2MVertices[i].normal.Y), video::SColor(255,100,100,100),M2MVertices[i].texcoords));
//rotation happens when reading from file, so swapping Y and Z here is no longer necessary
M2Vertices.push_back(video::S3DVertex(core::vector3df(M2MVertices[i].pos.X,M2MVertices[i].pos.Y,M2MVertices[i].pos.Z),core::vector3df(M2MVertices[i].normal.X,M2MVertices[i].normal.Y,M2MVertices[i].normal.Z), video::SColor(255,100,100,100),M2MVertices[i].texcoords));
}
if (Mesh)
Mesh->drop();
Mesh=new SMesh();
while(Mesh->getMeshBufferCount()>0)
{
Mesh->MeshBuffers.erase(0);
}
//Loop through the submeshes
for(u32 i=0; i < M2MViews[0].nSub;i++)//
{
//std::cout << "Proceeding with Submesh "<<i<<"/"<<M2MViews[0].nSub<<"\n";
//Now, M2MTriangles refers to M2MIndices and not to M2MVertices.
//Now, M2MTriangles refers to M2MIndices and not to M2MVertices.
scene::SSkinMeshBuffer *MeshBuffer = AnimatedMesh->createBuffer();
if(M2Indices.size()>0)
M2Indices.clear();
for(u32 j=M2MSubmeshes[i].ofsTris;j<M2MSubmeshes[i].ofsTris+M2MSubmeshes[i].nTris;j++)
{
M2Indices.push_back(M2MIndices[M2MTriangles[j]]);
}
//std::cout << "Sending "<<M2Vertices.size() <<" Vertices and " << M2Indices.size() <<" Indices to the MeshBuffer\n";
IMB = new SMeshBuffer;
IMB->append(M2Vertices.const_pointer(),M2Vertices.size(),M2Indices.const_pointer(),M2Indices.size());
IMB->recalculateBoundingBox();
//IMB->getMaterial().DiffuseColor.set(255,255-(u32)(255/(M2MSubmeshes.size()))*i,(u32)(255/(M2MSubmeshes.size()))*i,0);
//IMB->getMaterial().DiffuseColor.set(255,(M2MSubmeshes[i].meshpartId==0?0:255),(M2MSubmeshes[i].meshpartId==0?255:0),0);
std::string TexName=Texdir.c_str();
TexName+="/";
if(i<M2MTextureUnit.size())
TexName+=M2MTextureFiles[M2MTextureUnit[i].textureIndex].c_str();
while(TexName.find('\\')<TexName.size())//Replace \ by /
//Put the Indices and Vertices of the Submesh into a mesh buffer
//Each Submesh contains only the Indices and Vertices that belong to it.
//Because of this the Index values for the Submeshes must be corrected by the Vertex offset of the Submesh
for(u32 j=M2MSubmeshes[i].ofsTris;j<M2MSubmeshes[i].ofsTris+M2MSubmeshes[i].nTris;j++)
{
TexName.replace(TexName.find('\\'),1,"/");
MeshBuffer->Indices.push_back(M2MIndices[M2MTriangles[j]]-M2MSubmeshes[i].ofsVertex);
}
while(TexName.find(' ')<TexName.size())//Replace space by _
// std::cout << i << ": " << MeshBuffer->Indices.size() << "\n";
for(u32 j=M2MSubmeshes[i].ofsVertex;j<M2MSubmeshes[i].ofsVertex+M2MSubmeshes[i].nVertex;j++)
{
TexName.replace(TexName.find(' '),1,"_");
MeshBuffer->Vertices_Standard.push_back(M2Vertices[j]);
for(u32 k=0; k<4; k++)
{
//std::cout << (u32)M2MVertices[j].bones[k] << " ";
if((M2MVertices[j].weights[k]/255.0f)>0.0f)
{
scene::CSkinnedMesh::SWeight* weight = AnimatedMesh->createWeight(AnimatedMesh->getAllJoints()[(u32)M2MVertices[j].bones[k]]);
weight->strength=M2MVertices[j].weights[k]/255.0f;
weight->vertex_id=j-M2MSubmeshes[i].ofsVertex;
weight->buffer_id=i;
}
//std::cout<<weight->buffer_id << " " << weight->vertex_id << " " << weight->strength <<"|";
}
// std::cout<<'\n';
}
std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);
//std::cout << i << ": " << MeshBuffer->Vertices_Standard.size() <<" "<<M2MSubmeshes[i].ofsVertex<<" "<<M2MSubmeshes[i].nVertex<< "\n";
IMB->getMaterial().setTexture(0,Device->getVideoDriver()->getTexture(TexName.c_str()));
if(i<M2MRenderFlags.size())
{
DEBUG(logdebug("Render Flags: %u %u",M2MRenderFlags[i].flags,M2MRenderFlags[i].blending));
IMB->getMaterial().BackfaceCulling=(M2MRenderFlags[i].flags & 0x04)?false:true;
if(M2MRenderFlags[i].blending==1)
IMB->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
IMB->recalculateBoundingBox();
Mesh->addMeshBuffer(IMB);
IMB->drop();
//std::cout << "Mesh now has "<<Mesh->getMeshBufferCount()<<" Buffers\n";
}
Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation
Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure
aniMesh= new SAnimatedMesh();
aniMesh->addMesh(Mesh);
Mesh->drop();
Mesh = 0;
aniMesh->recalculateBoundingBox();
MeshBuffer->recalculateBoundingBox();
//MeshBuffer->getMaterial().DiffuseColor.set(255,255-(u32)(255/(M2MSubmeshes.size()))*i,(u32)(255/(M2MSubmeshes.size()))*i,0);
//MeshBuffer->getMaterial().DiffuseColor.set(255,(M2MSubmeshes[i].meshpartId==0?0:255),(M2MSubmeshes[i].meshpartId==0?255:0),0);
for(u32 j=0;j<M2MTextureUnit.size();j++)//Loop through texture units
{
if(M2MTextureUnit[j].submeshIndex1==i)//if a texture unit belongs to this submesh
{
std::string TexName=Texdir.c_str();
TexName+="/";
if(i<M2MTextureUnit.size())
TexName+=M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str();
while(TexName.find('\\')<TexName.size())//Replace \ by /
{
TexName.replace(TexName.find('\\'),1,"/");
}
while(TexName.find(' ')<TexName.size())//Replace space by _
{
TexName.replace(TexName.find(' '),1,"_");
}
std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);
MeshBuffer->getMaterial().setTexture(M2MTextureUnit[j].TextureUnitNumber,Device->getVideoDriver()->getTexture(TexName.c_str()));
DEBUG(logdebug("Render Flags: %u %u",M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags,M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending));
MeshBuffer->getMaterial().BackfaceCulling=(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags & 0x04)?false:true;
if(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending==1)
MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
}
//MeshBuffer->recalculateBoundingBox();
// Mesh->addMeshBuffer(MeshBuffer);
// Mesh->recalculateBoundingBox();
//MeshBuffer->drop();
//std::cout << "Mesh now has "<<Mesh->getMeshBufferCount()<<" Buffers\n";
}
Device->getSceneManager()->getMeshManipulator()->flipSurfaces(AnimatedMesh); //Fix inverted surfaces after the rotation
Device->getSceneManager()->getMeshManipulator()->recalculateNormals(AnimatedMesh,true);//just to be sure
AnimatedMesh->setInterpolationMode(scene::EIM_LINEAR);
M2MTriangles.clear();
M2Vertices.clear();
@ -300,8 +564,7 @@ M2MSubmeshes.clear();
M2MTextureFiles.clear();
M2MTextureLookup.clear();
M2MViews.clear();
return aniMesh;
return true;
}
}

View File

@ -1,5 +1,6 @@
#include "irrlicht/irrlicht.h"
#include "irrlicht/IMeshLoader.h"
#include "SSkinnedMesh.h"
#include <string>
#include <vector>
#include <algorithm>
@ -100,34 +101,12 @@ struct TextureDefinition {
u32 texFileOfs;
};
class CM2MeshFileLoader : public IMeshLoader
{
public:
//! Constructor
CM2MeshFileLoader(IrrlichtDevice* device, c8* texdir);
//! destructor
virtual ~CM2MeshFileLoader();
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".cob")
virtual bool isALoadableFileExtension(const c8* fileName)const;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IUnknown::drop() for more information.
virtual scene::IAnimatedMesh* createMesh(irr::io::IReadFile* file);
private:
ModelHeader header;
struct ModelVertex {
core::vector3df pos;//Use Irrlicht Vector here!
core::vector3df pos;
u8 weights[4];
u8 bones[4];
core::vector3df normal;//Use Irrlicht Vector here!
core::vector2df texcoords;//Use Irrlicht Vector here!
core::vector3df normal;
core::vector2df texcoords;
u32 unk1, unk2; // always 0,0 so this is probably unused
};
@ -170,15 +149,87 @@ struct RenderFlags{
u16 blending;
};
//
io::IFileSystem* FileSystem;
struct Animation{
u32 animationID;
u32 start, end;
float movespeed;
u32 loop, flags, unk1, unk2;
u32 playbackspeed;
float bbox[6];
float radius;
s16 indexSameID;
u16 unk3;
};
struct AnimBlockHead{
s16 interpolationType;
s16 globalSequenceID;
u32 nInterpolationRange;
u32 ofsInterpolationRange;
u32 nTimeStamp;
u32 ofsTimeStamp;
u32 nValues;
u32 ofsValues;
};
struct InterpolationRange{
u32 start, end;
};
struct AnimBlock{
AnimBlockHead header;
core::array<InterpolationRange> keyframes;
core::array<u32> timestamps;
core::array<float> values;
};
struct Bone{
s32 indexF;
u32 flags;
s16 parentBone;
u16 unk1;
u32 unk2;
AnimBlock translation, rotation, scaling;
core::vector3df PivotPoint;
};
class CM2MeshFileLoader : public IMeshLoader
{
public:
//! Constructor
CM2MeshFileLoader(IrrlichtDevice* device, c8* texdir);
//! destructor
virtual ~CM2MeshFileLoader();
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".cob")
virtual bool isALoadableFileExtension(const c8* fileName)const;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IUnknown::drop() for more information.
virtual scene::IAnimatedMesh* createMesh(io::IReadFile* file);
private:
bool load();
IrrlichtDevice* Device;
// scene::IMeshManipulator* Manipulator;
core::stringc M2MeshName;
core::stringc Texdir;
SAnimatedMesh* aniMesh;
io::IReadFile* MeshFile;
CSkinnedMesh* AnimatedMesh;
scene::CSkinnedMesh::SJoint* ParentJoint;
ModelHeader header;
core::stringc M2MeshName;
SMesh* Mesh;
SMeshBuffer* IMB;
//SSkinMeshBuffer* MeshBuffer;
//Taken from the Model file, thus m2M*
core::array<ModelVertex> M2MVertices;
core::array<ModelView> M2MViews;
@ -190,9 +241,13 @@ struct RenderFlags{
core::array<std::string> M2MTextureFiles;
core::array<TextureUnit> M2MTextureUnit;
core::array<RenderFlags> M2MRenderFlags;
core::array<Animation> M2MAnimations;
core::array<Bone> M2MBones;
//Used for the Mesh, thus m2_noM_*
core::array<video::S3DVertex> M2Vertices;
core::array<u16> M2Indices;
core::array<scene::ISkinnedMesh::SJoint> M2Joints;
};
}//namespace scene

View File

@ -1,5 +1,5 @@
## Process this file with automake to produce Makefile.in
AM_CPPFLAGS = -I$(top_builddir)/src/Client -I$(top_builddir)/src/shared -I$(top_builddir)/src/Client/DefScript -I$(top_builddir)/src/Client/World -I$(top_builddir)/src/Client/Realm -Wall
AM_CPPFLAGS = -I$(top_builddir)/src/Client -I$(top_builddir)/src/shared -I$(top_builddir)/src/Client/DefScript -I$(top_builddir)/src/Client/World -I$(top_builddir)/src/Client/Realm -Wall -D_DEBUG
## Build pseuwow
noinst_LIBRARIES = libgui.a
libgui_a_SOURCES =CCursorController.cpp DrawObject.cpp MInput.h Scene.h SImage.h\
@ -10,7 +10,7 @@ CM2MeshFileLoader.cpp SceneData.h ShTlTerrainSceneNode.h\
CM2MeshFileLoader.h MCamera.h SceneGuiStart.cpp SImage.cpp SceneCharselection.cpp\
CIrrKlangAudioStreamLoaderMP3.cpp CIrrKlangAudioStreamLoaderMP3.h CIrrKlangAudioStreamMP3.cpp CIrrKlangAudioStreamMP3.h\
ikpMP3.cpp decoder/bits.c decoder/internal.h decoder/mpaudec.c decoder/mpaudec.h decoder/mpaudectab.h decoder/mpegaudio.h\
irrKlangSceneNode.cpp irrKlangSceneNode.h
irrKlangSceneNode.cpp irrKlangSceneNode.h CBoneSceneNode.cpp CBoneSceneNode.h SSkinnedMesh.cpp SSkinnedMesh.h
libgui_a_LIBADD = $(top_builddir)/src/shared/libshared.a $(top_builddir)/src/shared/Auth/libauth.a $(top_builddir)/src/shared/Network/libnetwork.a

1414
src/Client/GUI/SSkinnedMesh.cpp Executable file

File diff suppressed because it is too large Load Diff

196
src/Client/GUI/SSkinnedMesh.h Executable file
View File

@ -0,0 +1,196 @@
// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
//New skinned mesh
#ifndef __C_SKINNED_MESH_H_INCLUDED__
#define __C_SKINNED_MESH_H_INCLUDED__
#include "irrlicht/irrlicht.h"
namespace irr
{
namespace scene
{
class IAnimatedMeshSceneNode;
class IBoneSceneNode;
class CSkinnedMesh: public ISkinnedMesh
{
public:
//! constructor
CSkinnedMesh();
//! destructor
virtual ~CSkinnedMesh();
//! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh.
virtual u32 getFrameCount() const;
//! returns the animated mesh based on a detail level (which is ignored)
virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1);
//! Animates this mesh's joints based on frame input
//! blend: {0-old position, 1-New position}
virtual void animateMesh(f32 frame, f32 blend);
//! Preforms a software skin on this mesh based of joint positions
virtual void skinMesh();
//! returns amount of mesh buffers.
virtual u32 getMeshBufferCount() const;
//! returns pointer to a mesh buffer
virtual IMeshBuffer* getMeshBuffer(u32 nr) const;
//! Returns pointer to a mesh buffer which fits a material
/** \param material: material to search for
\return Returns the pointer to the mesh buffer or
NULL if there is no such mesh buffer. */
virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const;
//! returns an axis aligned bounding box
virtual const core::aabbox3d<f32>& getBoundingBox() const;
//! set user axis aligned bounding box
virtual void setBoundingBox( const core::aabbox3df& box);
//! sets a flag of all contained materials to a new value
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue);
//! Returns the type of the animated mesh.
virtual E_ANIMATED_MESH_TYPE getMeshType() const;
//! Gets joint count.
virtual u32 getJointCount() const;
//! Gets the name of a joint.
virtual const c8* getJointName(u32 number) const;
//! Gets a joint number from its name
virtual s32 getJointNumber(const c8* name) const;
//! uses animation from another mesh
virtual bool useAnimationFrom(const ISkinnedMesh *mesh);
//! Update Normals when Animating
//! False= Don't (default)
//! True = Update normals, slower
virtual void updateNormalsWhenAnimating(bool on);
//! Sets Interpolation Mode
virtual void setInterpolationMode(E_INTERPOLATION_MODE mode);
//! Recovers the joints from the mesh
virtual void recoverJointsFromMesh(core::array<IBoneSceneNode*> &JointChildSceneNodes);
//! Tranfers the joint data to the mesh
virtual void transferJointsToMesh(const core::array<IBoneSceneNode*> &JointChildSceneNodes);
//! Tranfers the joint hints to the mesh
virtual void transferOnlyJointsHintsToMesh(const core::array<IBoneSceneNode*> &JointChildSceneNodes);
//! Creates an array of joints from this mesh
virtual void createJoints(core::array<IBoneSceneNode*> &JointChildSceneNodes,
IAnimatedMeshSceneNode* AnimatedMeshSceneNode,
ISceneManager* SceneManager);
//! Convertes the mesh to contain tangent information
virtual void convertMeshToTangents();
//! Does the mesh have no animation
virtual bool isStatic();
//! (This feature is not implemented in irrlicht yet)
virtual bool setHardwareSkinning(bool on);
//Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_
//these functions will use the needed arrays, set vaules, etc to help the loaders
//! exposed for loaders to add mesh buffers
virtual core::array<SSkinMeshBuffer*> &getMeshBuffers();
//! alternative method for adding joints
virtual core::array<SJoint*> &getAllJoints();
//! alternative method for adding joints
virtual const core::array<SJoint*> &getAllJoints() const;
//! loaders should call this after populating the mesh
virtual void finalize();
virtual SSkinMeshBuffer *createBuffer();
virtual SJoint *createJoint(SJoint *parent=0);
virtual SPositionKey *createPositionKey(SJoint *joint);
virtual SRotationKey *createRotationKey(SJoint *joint);
virtual SScaleKey *createScaleKey(SJoint *joint);
virtual SWeight *createWeight(SJoint *joint);
private:
void checkForAnimation();
void normalizeWeights();
void buildAll_LocalAnimatedMatrices(); //public?
void buildAll_GlobalAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0);
void getFrameData(f32 frame, SJoint *Node,
core::vector3df &position, s32 &positionHint,
core::vector3df &scale, s32 &scaleHint,
core::quaternion &rotation, s32 &rotationHint);
void CalculateGlobalMatrices(SJoint *Joint,SJoint *ParentJoint);
void SkinJoint(SJoint *Joint, SJoint *ParentJoint);
void calculateTangents(core::vector3df& normal,
core::vector3df& tangent, core::vector3df& binormal,
core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3,
core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3);
core::array<SSkinMeshBuffer*> *SkinningBuffers; //Meshbuffer to skin, default is to skin localBuffers
core::array<SSkinMeshBuffer*> LocalBuffers;
core::array<SJoint*> AllJoints;
core::array<SJoint*> RootJoints;
bool HasAnimation;
bool PreparedForSkinning;
f32 AnimationFrames;
f32 LastAnimatedFrame;
f32 LastSkinnedFrame;
bool BoneControlUsed;
bool AnimateNormals;
bool HardwareSkinning;
E_INTERPOLATION_MODE InterpolationMode;
core::aabbox3d<f32> BoundingBox;
core::array< core::array<bool> > Vertices_Moved;
};
} // end namespace scene
} // end namespace irr
#endif