From 449bff99be4d6e3d4aac8158879eec20f56a387e Mon Sep 17 00:00:00 2001 From: jonathanklein Date: Mon, 28 Sep 2009 16:53:33 +0000 Subject: [PATCH] Ogre Animations implemented but they don't work yet. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@485 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/OgreImporter.cpp | 314 ++++++++++++++++++++++------------- code/OgreImporter.h | 118 ++++--------- code/OgreXmlHelper.h | 76 +++++++++ doc/dox.h | 3 +- workspaces/vc8/assimp.vcproj | 4 + workspaces/vc9/assimp.vcproj | 4 + 6 files changed, 323 insertions(+), 196 deletions(-) create mode 100644 code/OgreXmlHelper.h diff --git a/code/OgreImporter.cpp b/code/OgreImporter.cpp index a174df9cd..3161a9140 100644 --- a/code/OgreImporter.cpp +++ b/code/OgreImporter.cpp @@ -71,15 +71,30 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass } - //-------------------Read all submeshs:----------------------- + //-------------------Read the submesh:----------------------- + SubMesh theSubMesh; XmlRead(MeshFile); - while(string(MeshFile->getNodeName())=="submesh")//read the index values (the faces): + if(MeshFile->getNodeName()==string("submesh")) { - SubMesh NewSubMesh; - NewSubMesh.MaterialName=GetAttribute(MeshFile, "material"); - DefaultLogger::get()->debug("Loading Submehs with Material: "+NewSubMesh.MaterialName); - ReadSubMesh(NewSubMesh, MeshFile); + theSubMesh.MaterialName=GetAttribute(MeshFile, "material"); + DefaultLogger::get()->debug("Loading Submehs with Material: "+theSubMesh.MaterialName); + ReadSubMesh(theSubMesh, MeshFile); + + //Load the Material: + aiMaterial* MeshMat=LoadMaterial(theSubMesh.MaterialName); + + //Set the Material: + if(m_CurrentScene->mMaterials) + throw new ImportErrorException("only 1 material supported at this time!"); + m_CurrentScene->mMaterials=new aiMaterial*[1]; + m_CurrentScene->mNumMaterials=1; + m_CurrentScene->mMaterials[0]=MeshMat; + theSubMesh.MaterialIndex=0; } + //check for second root node: + if(MeshFile->getNodeName()==string("submesh")) + throw new ImportErrorException("more than one submesh in the file, abording!"); + //____________________________________________________________ @@ -94,16 +109,22 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass //----------------Load the skeleton: ------------------------------- + vector Bones; + vector Animations; if(MeshFile->getNodeName()==string("skeletonlink")) { string SkeletonFile=GetAttribute(MeshFile, "name"); - LoadSkeleton(SkeletonFile); + LoadSkeleton(SkeletonFile, Bones, Animations); } else + { + DefaultLogger::get()->warn("No skeleton file will be loaded"); DefaultLogger::get()->warn(MeshFile->getNodeName()); + } //__________________________________________________________________ - + CreateAssimpSubMesh(theSubMesh, Bones); + CreateAssimpSkeleton(Bones, Animations); } @@ -121,12 +142,6 @@ void OgreImporter::SetupProperties(const Importer* pImp) void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader) { - vector FaceList; - vector Positions; bool HasPositions=false; - vector Normals; bool HasNormals=false; - vector Uvs; unsigned int NumUvs=0;//nearly always 2d, but assimp has always 3d texcoords - vector< vector > Weights; - XmlRead(Reader); //TODO: maybe we have alsways just 1 faces and 1 geometry and always in this order. this loop will only work correct, wenn the order //of faces and geometry changed, and not if we habe more than one of one @@ -149,7 +164,7 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader) { throw new ImportErrorException("Submesh has quads, only traingles are supported!"); } - FaceList.push_back(NewFace); + theSubMesh.FaceList.push_back(NewFace); } }//end of faces @@ -166,13 +181,13 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader) { throw new ImportErrorException("vertexbuffer node is not first in geometry node!"); } - HasPositions=GetAttribute(Reader, "positions"); - HasNormals=GetAttribute(Reader, "normals"); + theSubMesh.HasPositions=GetAttribute(Reader, "positions"); + theSubMesh.HasNormals=GetAttribute(Reader, "normals"); if(!Reader->getAttributeValue("texture_coords"))//we can have 1 or 0 uv channels, and if the mesh has no uvs, it also doesn't have the attribute - NumUvs=0; + theSubMesh.NumUvs=0; else - NumUvs=GetAttribute(Reader, "texture_coords"); - if(NumUvs>1) + theSubMesh.NumUvs=GetAttribute(Reader, "texture_coords"); + if(theSubMesh.NumUvs>1) throw new ImportErrorException("too many texcoords (just 1 supported!)"); //read all the vertices: @@ -182,35 +197,35 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader) //read all vertex attributes: //Position - if(HasPositions) + if(theSubMesh.HasPositions) { XmlRead(Reader); aiVector3D NewPos; NewPos.x=GetAttribute(Reader, "x"); NewPos.y=GetAttribute(Reader, "y"); NewPos.z=GetAttribute(Reader, "z"); - Positions.push_back(NewPos); + theSubMesh.Positions.push_back(NewPos); } //Normal - if(HasNormals) + if(theSubMesh.HasNormals) { XmlRead(Reader); aiVector3D NewNormal; NewNormal.x=GetAttribute(Reader, "x"); NewNormal.y=GetAttribute(Reader, "y"); NewNormal.z=GetAttribute(Reader, "z"); - Normals.push_back(NewNormal); + theSubMesh.Normals.push_back(NewNormal); } //Uv: - if(1==NumUvs) + if(1==theSubMesh.NumUvs) { XmlRead(Reader); aiVector3D NewUv; NewUv.x=GetAttribute(Reader, "u"); NewUv.y=GetAttribute(Reader, "v")*(-1)+1;//flip the uv vertikal, blender exports them so! - Uvs.push_back(NewUv); + theSubMesh.Uvs.push_back(NewUv); } XmlRead(Reader); } @@ -218,126 +233,168 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader) }//end of "geometry else if(string(Reader->getNodeName())=="boneassignments") { - Weights.resize(Positions.size()); + theSubMesh.Weights.resize(theSubMesh.Positions.size()); while(XmlRead(Reader) && Reader->getNodeName()==string("vertexboneassignment")) { Weight NewWeight; unsigned int VertexId=GetAttribute(Reader, "vertexindex"); NewWeight.BoneId=GetAttribute(Reader, "boneindex"); NewWeight.Value=GetAttribute(Reader, "weight"); + theSubMesh.BonesUsed=max(theSubMesh.BonesUsed, NewWeight.BoneId+1);//calculate the number of bones used (this is the highest id +1 becuase bone ids start at 0) - Weights[VertexId].push_back(NewWeight); + theSubMesh.Weights[VertexId].push_back(NewWeight); //XmlRead(Reader);//Once i had this line, and than i got only every second boneassignment, but my first test models had even boneassignment counts, so i thougt, everything would work. And yes, i HATE irrXML!!! } }//end of boneassignments } - DefaultLogger::get()->debug(str(format("Positionen: %1% Normale: %2% TexCoords: %3%") % Positions.size() % Normals.size() % Uvs.size())); + DefaultLogger::get()->debug(str(format("Positionen: %1% Normale: %2% TexCoords: %3%") % theSubMesh.Positions.size() % theSubMesh.Normals.size() % theSubMesh.Uvs.size())); DefaultLogger::get()->warn(Reader->getNodeName()); //---------------Make all Vertexes unique: (this is required by assimp)----------------------- - vector UniqueFaceList(FaceList.size()); - vector UniquePositions(FaceList.size()*3);//*3 because each face consits of 3 vertexes, because we only support triangles^^ - vector UniqueNormals(FaceList.size()*3); - vector UniqueUvs(FaceList.size()*3); - vector< vector > UniqueWeights(FaceList.size()*3); + vector UniqueFaceList(theSubMesh.FaceList.size()); + unsigned int UniqueVertexCount=theSubMesh.FaceList.size()*3;//*3 because each face consists of 3 vertexes, because we only support triangles^^ + vector UniquePositions(UniqueVertexCount); + vector UniqueNormals(UniqueVertexCount); + vector UniqueUvs(UniqueVertexCount); + vector< vector > UniqueWeights(UniqueVertexCount); - for(unsigned int i=0; i& Bones) +{ //Mesh is fully loaded, copy it into the aiScene: if(m_CurrentScene->mNumMeshes!=0) throw new ImportErrorException("Currently only one mesh per File is allowed!!"); - //---------------------Create the aiMesh:----------------------- aiMesh* NewAiMesh=new aiMesh(); - //Positions - NewAiMesh->mVertices=new aiVector3D[UniquePositions.size()]; - memcpy(NewAiMesh->mVertices, &UniquePositions[0], UniquePositions.size()*sizeof(aiVector3D)); - NewAiMesh->mNumVertices=UniquePositions.size(); - - //Normals - NewAiMesh->mNormals=new aiVector3D[UniqueNormals.size()]; - memcpy(NewAiMesh->mNormals, &UniqueNormals[0], UniqueNormals.size()*sizeof(aiVector3D)); - - //Uvs - if(0!=NumUvs) - { - NewAiMesh->mNumUVComponents[0]=2; - NewAiMesh->mTextureCoords[0]= new aiVector3D[UniqueUvs.size()]; - memcpy(NewAiMesh->mTextureCoords[0], &UniqueUvs[0], UniqueUvs.size()*sizeof(aiVector3D)); - } - - //Bones - /*NewAiMesh->mNumBones=UniqueWeights.size(); - NewAiMesh->mBones=new aiBone*[UniqueWeights.size()]; - for(un*/ - - - - //Faces - NewAiMesh->mFaces=new aiFace[UniqueFaceList.size()]; - for(unsigned int i=0; imFaces[i].mNumIndices=3; - NewAiMesh->mFaces[i].mIndices=new unsigned int[3]; - - NewAiMesh->mFaces[i].mIndices[0]=UniqueFaceList[i].VertexIndices[0]; - NewAiMesh->mFaces[i].mIndices[1]=UniqueFaceList[i].VertexIndices[1]; - NewAiMesh->mFaces[i].mIndices[2]=UniqueFaceList[i].VertexIndices[2]; - } - NewAiMesh->mNumFaces=UniqueFaceList.size(); - - //Set the Material: - NewAiMesh->mMaterialIndex=0; - if(m_CurrentScene->mMaterials) - throw new ImportErrorException("only 1 material supported at this time!"); - m_CurrentScene->mMaterials=new aiMaterial*[1]; - m_CurrentScene->mNumMaterials=1; - m_CurrentScene->mMaterials[0]=MeshMat; - //_____________________________________________________________________________ - - //Attach the mesh to the scene: m_CurrentScene->mNumMeshes=1; m_CurrentScene->mMeshes=new aiMesh*; m_CurrentScene->mMeshes[0]=NewAiMesh; + + + //Positions + NewAiMesh->mVertices=new aiVector3D[theSubMesh.Positions.size()]; + memcpy(NewAiMesh->mVertices, &theSubMesh.Positions[0], theSubMesh.Positions.size()*sizeof(aiVector3D)); + NewAiMesh->mNumVertices=theSubMesh.Positions.size(); + + //Normals + NewAiMesh->mNormals=new aiVector3D[theSubMesh.Normals.size()]; + memcpy(NewAiMesh->mNormals, &theSubMesh.Normals[0], theSubMesh.Normals.size()*sizeof(aiVector3D)); + + //Uvs + if(0!=theSubMesh.NumUvs) + { + NewAiMesh->mNumUVComponents[0]=2; + NewAiMesh->mTextureCoords[0]= new aiVector3D[theSubMesh.Uvs.size()]; + memcpy(NewAiMesh->mTextureCoords[0], &theSubMesh.Uvs[0], theSubMesh.Uvs.size()*sizeof(aiVector3D)); + } + + + //---------------------------------------- Bones -------------------------------------------- + //Copy the weights in in Bone-Vertices Struktur + //(we have them in a Vertex-Bones Struktur, this is much easier for making them unique, which is required by assimp + vector< vector > aiWeights(theSubMesh.BonesUsed);//now the outer list are the bones, and the inner vector the vertices + for(unsigned int VertexId=0; VertexId aiBones; + aiBones.reserve(theSubMesh.BonesUsed);//the vector might be smaller, because there might be empty bones (bones that are not attached to any vertex) + + //create all the bones and fill them with informations + for(unsigned int i=0; i0) + { + aiBone* NewBone=new aiBone(); + NewBone->mNumWeights=aiWeights[i].size(); + NewBone->mWeights=new aiVertexWeight[aiWeights[i].size()]; + memcpy(NewBone->mWeights, &(aiWeights[i][0]), sizeof(aiVertexWeight)*aiWeights[i].size()); + NewBone->mName=Bones[i].Name;//The bone list should be sorted after its ids, this was done in LoadSkeleton + NewBone->mOffsetMatrix=aiMatrix4x4(Bones[i].WorldToBoneSpace).Inverse();//we suggest, that the mesh space is the world space! + + aiBones.push_back(NewBone); + } + } + NewAiMesh->mNumBones=aiBones.size(); + NewAiMesh->mBones=new aiBone* [aiBones.size()]; + memcpy(NewAiMesh->mBones, &(aiBones[0]), aiBones.size()*sizeof(aiBone*)); + + //______________________________________________________________________________________________________ + + + + //Faces + NewAiMesh->mFaces=new aiFace[theSubMesh.FaceList.size()]; + for(unsigned int i=0; imFaces[i].mNumIndices=3; + NewAiMesh->mFaces[i].mIndices=new unsigned int[3]; + + NewAiMesh->mFaces[i].mIndices[0]=theSubMesh.FaceList[i].VertexIndices[0]; + NewAiMesh->mFaces[i].mIndices[1]=theSubMesh.FaceList[i].VertexIndices[1]; + NewAiMesh->mFaces[i].mIndices[2]=theSubMesh.FaceList[i].VertexIndices[2]; + } + NewAiMesh->mNumFaces=theSubMesh.FaceList.size(); + + //Link the material: + NewAiMesh->mMaterialIndex=theSubMesh.MaterialIndex;//the index is set by the function who called ReadSubMesh } -aiMaterial* OgreImporter::LoadMaterial(std::string MaterialName) +aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) { MaterialHelper *NewMaterial=new MaterialHelper(); @@ -501,7 +558,8 @@ aiMaterial* OgreImporter::LoadMaterial(std::string MaterialName) return NewMaterial; } -void OgreImporter::LoadSkeleton(std::string FileName) + +void OgreImporter::LoadSkeleton(std::string FileName, vector &Bones, vector &Animations) { //most likely the skeleton file will only end with .skeleton //But this is a xml reader, so we need: .skeleton.xml @@ -520,9 +578,6 @@ void OgreImporter::LoadSkeleton(std::string FileName) if(!SkeletonFile) throw new ImportErrorException(string("Failed to create XML Reader for ")+FileName); - //Variables to store the data from the skeleton file: - vector Bones; - //Quick note: Whoever read this should know this one thing: irrXml fucking sucks!!! XmlRead(SkeletonFile); @@ -618,11 +673,19 @@ void OgreImporter::LoadSkeleton(std::string FileName) } //_____________________________________________________________________________ + + //--------- Calculate the WorldToBoneSpace Matrix recursivly for all bones: ------------------ + BOOST_FOREACH(Bone theBone, Bones) + { + if(-1==theBone.ParentId) //the bone is a root bone + { + theBone.CalculateWorldToBoneSpaceMatrix(Bones); + } + } + //_______________________________________________________________________ - //---------------------------load animations----------------------------- - vector Animations; if(string("animations")==SkeletonFile->getNodeName())//animations are optional values { DefaultLogger::get()->debug("Loading Animations"); @@ -697,10 +760,11 @@ void OgreImporter::LoadSkeleton(std::string FileName) } //_____________________________________________________________________________ +} - - +void OgreImporter::CreateAssimpSkeleton(const std::vector &Bones, const std::vector &Animations) +{ //-----------------skeleton is completly loaded, now but it in the assimp scene:------------------------------- if(!m_CurrentScene->mRootNode) @@ -708,7 +772,7 @@ void OgreImporter::LoadSkeleton(std::string FileName) if(0!=m_CurrentScene->mRootNode->mNumChildren) throw new ImportErrorException("Root Node already has childnodes!"); - //--------------Creatre the assimp bone hierarchy----------------- + //--------------Createt the assimp bone hierarchy----------------- DefaultLogger::get()->debug("Root Bones"); vector RootBoneNodes; BOOST_FOREACH(Bone theBone, Bones) @@ -735,7 +799,7 @@ void OgreImporter::LoadSkeleton(std::string FileName) aiAnimation* NewAnimation=new aiAnimation(); NewAnimation->mName=Animations[i].Name; NewAnimation->mDuration=Animations[i].Length; - NewAnimation->mTicksPerSecond=0.05f; + NewAnimation->mTicksPerSecond=1.0f; //Create all tracks in this animation NewAnimation->mNumChannels=Animations[i].Tracks.size(); @@ -778,8 +842,7 @@ void OgreImporter::LoadSkeleton(std::string FileName) - -aiNode* CreateAiNodeFromBone(int BoneId, std::vector Bones, aiNode* ParentNode) +aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector &Bones, aiNode* ParentNode) { //----Create the node for this bone and set its values----- aiNode* NewNode=new aiNode(Bones[BoneId].Name); @@ -794,7 +857,7 @@ aiNode* CreateAiNodeFromBone(int BoneId, std::vector Bones, aiNode* Parent //__________________________________________________________ - //----recursivly create all children Nodes:------ + //---------- recursivly create all children Nodes: ---------- NewNode->mNumChildren=Bones[BoneId].Children.size(); NewNode->mChildren=new aiNode*[Bones[BoneId].Children.size()]; for(unsigned int i=0; i Bones, aiNode* Parent } +void Bone::CalculateWorldToBoneSpaceMatrix(vector &Bones) +{ + //Calculate the matrix for this bone: + if(-1==ParentId) + { + WorldToBoneSpace= aiMatrix4x4::Translation(Position, aiMatrix4x4()) + * aiMatrix4x4::Rotation(RotationAngle, RotationAxis, aiMatrix4x4()) + ; + } + else + { + WorldToBoneSpace= Bones[ParentId].WorldToBoneSpace + * aiMatrix4x4::Translation(Position, aiMatrix4x4()) + * aiMatrix4x4::Rotation(RotationAngle, RotationAxis, aiMatrix4x4()) + ; + + } + + //and recursivly for all children: + BOOST_FOREACH(int theChildren, Children) + { + Bones[theChildren].CalculateWorldToBoneSpaceMatrix(Bones); + } +} + }//namespace Ogre }//namespace Assimp diff --git a/code/OgreImporter.h b/code/OgreImporter.h index 076f9e88d..f268ee5c4 100644 --- a/code/OgreImporter.h +++ b/code/OgreImporter.h @@ -2,20 +2,19 @@ #include +#include "OgreXmlHelper.h" #include "irrXMLWrapper.h" -#include "fast_atof.h" namespace Assimp { namespace Ogre { -typedef irr::io::IrrXMLReader XmlReader; //Forward declarations: +struct SubMesh; struct Face; struct Weight; -struct SubMesh; struct Bone; struct Animation; struct Track; @@ -32,10 +31,15 @@ public: private: ///Helper Functions to read parts of the XML File - /** @param Filename We need this to check for a material File with the same name.*/ - void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader); - aiMaterial* LoadMaterial(std::string MaterialName); - void LoadSkeleton(std::string FileName); + void ReadSubMesh(SubMesh& theSubMesh, XmlReader* Reader);//the submesh reference is the result value + void LoadSkeleton(std::string FileName, std::vector &Bones, std::vector &Animations);///< writes the results in Bones and Animations, Filename is not const, because its call-by-value and the function will change it! + void CreateAssimpSubMesh(const SubMesh &theSubMesh, const std::vector& Bones); + void CreateAssimpSkeleton(const std::vector &Bones, const std::vector &Animations); + + aiMaterial* LoadMaterial(const std::string MaterialName); + + ///Recursivly creates a filled aiNode from a given root bone + aiNode* CreateAiNodeFromBone(int BoneId, const std::vector &Bones, aiNode* ParentNode); //Now we don't have to give theses parameters to all functions std::string m_CurrentFilename; @@ -44,71 +48,21 @@ private: aiScene *m_CurrentScene; }; +///A submesh from Ogre +struct SubMesh +{ + std::string Name; + std::string MaterialName; + std::vector FaceList; + std::vector Positions; bool HasPositions; + std::vector Normals; bool HasNormals; + std::vector Uvs; unsigned int NumUvs;//nearly always 2d, but assimp has always 3d texcoords + std::vector< std::vector > Weights;//a list of bones for each vertex + int MaterialIndex;///< The Index in the Assimp Materialarray from the material witch is attached to this submesh + unsigned int BonesUsed;//the highest index of a bone from a bone weight, this is needed to create the assimp bone structur (converting from Vertex-Bones to Bone-Vertices) - -//------------Helper Funktion to Get a Attribute Save--------------- -template inline t GetAttribute(XmlReader* Reader, std::string Name) -{ - throw std::exception("unimplemented Funtcion used!"); - return t(); -} - -template<> inline int GetAttribute(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - return atoi(Value); - else - throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} - -template<> inline float GetAttribute(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - return fast_atof(Value); - else - throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} - -template<> inline std::string GetAttribute(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - return std::string(Value); - else - throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} - -template<> inline bool GetAttribute(XmlReader* Reader, std::string Name) -{ - const char* Value=Reader->getAttributeValue(Name.c_str()); - if(Value) - { - if(Value==std::string("true")) - return true; - else if(Value==std::string("false")) - return false; - else - throw new ImportErrorException(std::string("Bool value has invalid value: "+Name+" / "+Value+" / "+Reader->getNodeName())); - } - else - throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); -} -//__________________________________________________________________ - -inline bool XmlRead(XmlReader* Reader) -{ - do - { - if(!Reader->read()) - return false; - } - while(Reader->getNodeType()!=irr::io::EXN_ELEMENT); - return true; -} - - + SubMesh(): HasPositions(false), HasNormals(false), NumUvs(0), MaterialIndex(-1), BonesUsed(0) {}//initialize everything +}; ///For the moment just triangles, no other polygon types! struct Face @@ -116,22 +70,21 @@ struct Face unsigned int VertexIndices[3]; }; +struct BoneAssignment +{ + unsigned int BoneId;//this is, what we get from ogre + std::string BoneName;//this is, what we need for assimp +}; + +///for a vertex->bone structur struct Weight { unsigned int BoneId; float Value; }; -/// Helper Class to describe a complete SubMesh -struct SubMesh -{ - std::string Name; - std::string MaterialName; - std::vector Faces; -}; - -/// Helper Class to describe an ogre-bone +/// Helper Class to describe an ogre-bone for the skeleton: /** All Id's are signed ints, because than we have -1 as a simple INVALID_ID Value (we start from 0 so 0 is a valid bone ID!*/ struct Bone { @@ -142,6 +95,7 @@ struct Bone float RotationAngle; aiVector3D RotationAxis; std::vector Children; + aiMatrix4x4 WorldToBoneSpace; ///ctor Bone(): Id(-1), ParentId(-1), RotationAngle(0.0f) {} @@ -151,11 +105,11 @@ struct Bone ///this operator is needed to find a bone by its name in a vector bool operator==(const std::string& rval) const {return Name==rval; } + + void CalculateWorldToBoneSpaceMatrix(std::vector& Bones); }; -///Recursivly creates a filled aiNode from a given root bone -aiNode* CreateAiNodeFromBone(int BoneId, std::vector Bones, aiNode* ParentNode); ///Describes an Ogre Animation diff --git a/code/OgreXmlHelper.h b/code/OgreXmlHelper.h new file mode 100644 index 000000000..a1f36adbe --- /dev/null +++ b/code/OgreXmlHelper.h @@ -0,0 +1,76 @@ + +#include "irrXMLWrapper.h" +#include "fast_atof.h" + +namespace Assimp +{ +namespace Ogre +{ + +typedef irr::io::IrrXMLReader XmlReader; + + +//------------Helper Funktion to Get a Attribute Save--------------- +template inline t GetAttribute(XmlReader* Reader, std::string Name) +{ + throw std::exception("unimplemented Funtcion used!"); + return t(); +} + +template<> inline int GetAttribute(XmlReader* Reader, std::string Name) +{ + const char* Value=Reader->getAttributeValue(Name.c_str()); + if(Value) + return atoi(Value); + else + throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); +} + +template<> inline float GetAttribute(XmlReader* Reader, std::string Name) +{ + const char* Value=Reader->getAttributeValue(Name.c_str()); + if(Value) + return fast_atof(Value); + else + throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); +} + +template<> inline std::string GetAttribute(XmlReader* Reader, std::string Name) +{ + const char* Value=Reader->getAttributeValue(Name.c_str()); + if(Value) + return std::string(Value); + else + throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); +} + +template<> inline bool GetAttribute(XmlReader* Reader, std::string Name) +{ + const char* Value=Reader->getAttributeValue(Name.c_str()); + if(Value) + { + if(Value==std::string("true")) + return true; + else if(Value==std::string("false")) + return false; + else + throw new ImportErrorException(std::string("Bool value has invalid value: "+Name+" / "+Value+" / "+Reader->getNodeName())); + } + else + throw new ImportErrorException(std::string("Attribute "+Name+" does not exist in "+Reader->getNodeName()).c_str()); +} +//__________________________________________________________________ + +inline bool XmlRead(XmlReader* Reader) +{ + do + { + if(!Reader->read()) + return false; + } + while(Reader->getNodeType()!=irr::io::EXN_ELEMENT); + return true; +} + +}//namespace Ogre +}//namespace Assimp \ No newline at end of file diff --git a/doc/dox.h b/doc/dox.h index 63c739907..6e126d300 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -1461,5 +1461,6 @@ Material: The right material in the file will be searched, the importer should w have 1 technique and 1 pass in this technique. From there, the texturename (for 1 color- and 1 normalmap) will be loaded. Also, the materialname will be set. -Skeleton: Skeleton with Bone hierarchie, names and transformations, but no animations. +Skeleton: Skeleton with Bone hierarchy (Position and Rotation, but no Scaling in the skeleton is supported), names and transformations, +animations with rotation, translation and scaling keys. */ \ No newline at end of file diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index f7480f433..af9cf0324 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -1946,6 +1946,10 @@ RelativePath="..\..\code\OgreImporter.h" > + + + +