OgreImporter.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. #include "AssimpPCH.h"
  2. #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
  3. #include <vector>
  4. #include <sstream>
  5. using namespace std;
  6. //#include "boost/format.hpp"
  7. //#include "boost/foreach.hpp"
  8. using namespace boost;
  9. #include "OgreImporter.h"
  10. #include "irrXMLWrapper.h"
  11. namespace Assimp
  12. {
  13. namespace Ogre
  14. {
  15. bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const
  16. {
  17. if(!checkSig)//Check File Extension
  18. {
  19. std::string extension("mesh.xml");
  20. int l=extension.length();
  21. return pFile.substr(pFile.length()-l, l)==extension;
  22. }
  23. else//Check file Header
  24. {
  25. const char* tokens[] = {"<mesh>"};
  26. return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
  27. }
  28. }
  29. void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler)
  30. {
  31. m_CurrentFilename=pFile;
  32. m_CurrentIOHandler=pIOHandler;
  33. m_CurrentScene=pScene;
  34. //Open the File:
  35. boost::scoped_ptr<IOStream> file(pIOHandler->Open(pFile));
  36. if( file.get() == NULL)
  37. throw DeadlyImportError("Failed to open file "+pFile+".");
  38. //Read the Mesh File:
  39. boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
  40. XmlReader* MeshFile = irr::io::createIrrXMLReader(mIOWrapper.get());
  41. if(!MeshFile)//parse the xml file
  42. throw DeadlyImportError("Failed to create XML Reader for "+pFile);
  43. DefaultLogger::get()->debug("Mesh File opened");
  44. //Read root Node:
  45. if(!(XmlRead(MeshFile) && string(MeshFile->getNodeName())=="mesh"))
  46. {
  47. throw DeadlyImportError("Root Node is not <mesh>! "+pFile+" "+MeshFile->getNodeName());
  48. }
  49. //Go to the submeshs:
  50. if(!(XmlRead(MeshFile) && string(MeshFile->getNodeName())=="submeshes"))
  51. {
  52. throw DeadlyImportError("No <submeshes> node in <mesh> node! "+pFile);
  53. }
  54. //-------------------Read the submesh:-----------------------
  55. SubMesh theSubMesh;
  56. XmlRead(MeshFile);
  57. if(MeshFile->getNodeName()==string("submesh"))
  58. {
  59. theSubMesh.MaterialName=GetAttribute<string>(MeshFile, "material");
  60. DefaultLogger::get()->debug("Loading Submehs with Material: "+theSubMesh.MaterialName);
  61. ReadSubMesh(theSubMesh, MeshFile);
  62. //Load the Material:
  63. aiMaterial* MeshMat=LoadMaterial(theSubMesh.MaterialName);
  64. //Set the Material:
  65. if(m_CurrentScene->mMaterials)
  66. throw DeadlyImportError("only 1 material supported at this time!");
  67. m_CurrentScene->mMaterials=new aiMaterial*[1];
  68. m_CurrentScene->mNumMaterials=1;
  69. m_CurrentScene->mMaterials[0]=MeshMat;
  70. theSubMesh.MaterialIndex=0;
  71. }
  72. //check for second root node:
  73. if(MeshFile->getNodeName()==string("submesh"))
  74. throw DeadlyImportError("more than one submesh in the file, abording!");
  75. //____________________________________________________________
  76. //-----------------Create the root node-----------------------
  77. pScene->mRootNode=new aiNode("root");
  78. //link the mesh with the root node:
  79. pScene->mRootNode->mMeshes=new unsigned int[1];
  80. pScene->mRootNode->mMeshes[0]=0;
  81. pScene->mRootNode->mNumMeshes=1;
  82. //____________________________________________________________
  83. //----------------Load the skeleton: -------------------------------
  84. vector<Bone> Bones;
  85. vector<Animation> Animations;
  86. if(MeshFile->getNodeName()==string("skeletonlink"))
  87. {
  88. string SkeletonFile=GetAttribute<string>(MeshFile, "name");
  89. LoadSkeleton(SkeletonFile, Bones, Animations);
  90. }
  91. else
  92. {
  93. DefaultLogger::get()->warn("No skeleton file will be loaded");
  94. DefaultLogger::get()->warn(MeshFile->getNodeName());
  95. }
  96. //__________________________________________________________________
  97. CreateAssimpSubMesh(theSubMesh, Bones);
  98. CreateAssimpSkeleton(Bones, Animations);
  99. }
  100. void OgreImporter::GetExtensionList(std::set<std::string>& extensions)
  101. {
  102. extensions.insert("mesh.xml");
  103. }
  104. void OgreImporter::SetupProperties(const Importer* pImp)
  105. {
  106. m_MaterialLibFilename=pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material");
  107. }
  108. void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
  109. {
  110. XmlRead(Reader);
  111. //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
  112. //of faces and geometry changed, and not if we habe more than one of one
  113. while(Reader->getNodeName()==string("faces") || string(Reader->getNodeName())=="geometry" || Reader->getNodeName()==string("boneassignments"))
  114. {
  115. if(string(Reader->getNodeName())=="faces")//Read the face list
  116. {
  117. //some info logging:
  118. unsigned int NumFaces=GetAttribute<int>(Reader, "count");
  119. stringstream ss; ss <<"Submesh has " << NumFaces << " Faces.";
  120. DefaultLogger::get()->debug(ss.str());
  121. while(XmlRead(Reader) && Reader->getNodeName()==string("face"))
  122. {
  123. Face NewFace;
  124. NewFace.VertexIndices[0]=GetAttribute<int>(Reader, "v1");
  125. NewFace.VertexIndices[1]=GetAttribute<int>(Reader, "v2");
  126. NewFace.VertexIndices[2]=GetAttribute<int>(Reader, "v3");
  127. if(Reader->getAttributeValue("v4"))//this should be supported in the future
  128. {
  129. throw DeadlyImportError("Submesh has quads, only traingles are supported!");
  130. }
  131. theSubMesh.FaceList.push_back(NewFace);
  132. }
  133. }//end of faces
  134. else if(string(Reader->getNodeName())=="geometry")//Read the vertexdata
  135. {
  136. //some info logging:
  137. unsigned int NumVertices=GetAttribute<int>(Reader, "vertexcount");
  138. stringstream ss; ss<<"VertexCount: "<<NumVertices;
  139. DefaultLogger::get()->debug(ss.str());
  140. //General Informations about vertices
  141. XmlRead(Reader);
  142. if(!(Reader->getNodeName()==string("vertexbuffer")))
  143. {
  144. throw DeadlyImportError("vertexbuffer node is not first in geometry node!");
  145. }
  146. theSubMesh.HasPositions=GetAttribute<bool>(Reader, "positions");
  147. theSubMesh.HasNormals=GetAttribute<bool>(Reader, "normals");
  148. 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
  149. theSubMesh.NumUvs=0;
  150. else
  151. theSubMesh.NumUvs=GetAttribute<int>(Reader, "texture_coords");
  152. if(theSubMesh.NumUvs>1)
  153. throw DeadlyImportError("too many texcoords (just 1 supported!)");
  154. //read all the vertices:
  155. XmlRead(Reader);
  156. while(Reader->getNodeName()==string("vertex"))
  157. {
  158. //read all vertex attributes:
  159. //Position
  160. if(theSubMesh.HasPositions)
  161. {
  162. XmlRead(Reader);
  163. aiVector3D NewPos;
  164. NewPos.x=GetAttribute<float>(Reader, "x");
  165. NewPos.y=GetAttribute<float>(Reader, "y");
  166. NewPos.z=GetAttribute<float>(Reader, "z");
  167. theSubMesh.Positions.push_back(NewPos);
  168. }
  169. //Normal
  170. if(theSubMesh.HasNormals)
  171. {
  172. XmlRead(Reader);
  173. aiVector3D NewNormal;
  174. NewNormal.x=GetAttribute<float>(Reader, "x");
  175. NewNormal.y=GetAttribute<float>(Reader, "y");
  176. NewNormal.z=GetAttribute<float>(Reader, "z");
  177. theSubMesh.Normals.push_back(NewNormal);
  178. }
  179. //Uv:
  180. if(1==theSubMesh.NumUvs)
  181. {
  182. XmlRead(Reader);
  183. aiVector3D NewUv;
  184. NewUv.x=GetAttribute<float>(Reader, "u");
  185. NewUv.y=GetAttribute<float>(Reader, "v")*(-1)+1;//flip the uv vertikal, blender exports them so!
  186. theSubMesh.Uvs.push_back(NewUv);
  187. }
  188. XmlRead(Reader);
  189. }
  190. }//end of "geometry
  191. else if(string(Reader->getNodeName())=="boneassignments")
  192. {
  193. theSubMesh.Weights.resize(theSubMesh.Positions.size());
  194. while(XmlRead(Reader) && Reader->getNodeName()==string("vertexboneassignment"))
  195. {
  196. Weight NewWeight;
  197. unsigned int VertexId=GetAttribute<int>(Reader, "vertexindex");
  198. NewWeight.BoneId=GetAttribute<int>(Reader, "boneindex");
  199. NewWeight.Value=GetAttribute<float>(Reader, "weight");
  200. 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)
  201. theSubMesh.Weights[VertexId].push_back(NewWeight);
  202. //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!!!
  203. }
  204. }//end of boneassignments
  205. }
  206. DefaultLogger::get()->debug(str(format("Positionen: %1% Normale: %2% TexCoords: %3%")
  207. % theSubMesh.Positions.size() % theSubMesh.Normals.size() % theSubMesh.Uvs.size()));
  208. DefaultLogger::get()->warn(Reader->getNodeName());
  209. //---------------Make all Vertexes unique: (this is required by assimp)-----------------------
  210. vector<Face> UniqueFaceList(theSubMesh.FaceList.size());
  211. unsigned int UniqueVertexCount=theSubMesh.FaceList.size()*3;//*3 because each face consists of 3 vertexes, because we only support triangles^^
  212. vector<aiVector3D> UniquePositions(UniqueVertexCount);
  213. vector<aiVector3D> UniqueNormals(UniqueVertexCount);
  214. vector<aiVector3D> UniqueUvs(UniqueVertexCount);
  215. vector< vector<Weight> > UniqueWeights(UniqueVertexCount);
  216. for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
  217. {
  218. //We precalculate the index vlaues her, because we need them in all vertex attributes
  219. unsigned int Vertex1=theSubMesh.FaceList[i].VertexIndices[0];
  220. unsigned int Vertex2=theSubMesh.FaceList[i].VertexIndices[1];
  221. unsigned int Vertex3=theSubMesh.FaceList[i].VertexIndices[2];
  222. UniquePositions[3*i+0]=theSubMesh.Positions[Vertex1];
  223. UniquePositions[3*i+1]=theSubMesh.Positions[Vertex2];
  224. UniquePositions[3*i+2]=theSubMesh.Positions[Vertex3];
  225. UniqueNormals[3*i+0]=theSubMesh.Normals[Vertex1];
  226. UniqueNormals[3*i+1]=theSubMesh.Normals[Vertex2];
  227. UniqueNormals[3*i+2]=theSubMesh.Normals[Vertex3];
  228. if(1==theSubMesh.NumUvs)
  229. {
  230. UniqueUvs[3*i+0]=theSubMesh.Uvs[Vertex1];
  231. UniqueUvs[3*i+1]=theSubMesh.Uvs[Vertex2];
  232. UniqueUvs[3*i+2]=theSubMesh.Uvs[Vertex3];
  233. }
  234. UniqueWeights[3*i+0]=theSubMesh.Weights[Vertex1];
  235. UniqueWeights[3*i+1]=theSubMesh.Weights[Vertex2];
  236. UniqueWeights[3*i+2]=theSubMesh.Weights[Vertex3];
  237. //The indexvalues a just continuous numbers (0, 1, 2, 3, 4, 5, 6...)
  238. UniqueFaceList[i].VertexIndices[0]=3*i+0;
  239. UniqueFaceList[i].VertexIndices[1]=3*i+1;
  240. UniqueFaceList[i].VertexIndices[2]=3*i+2;
  241. }
  242. //_________________________________________________________________________________________
  243. //now we have the unique datas, but want them in the SubMesh, so we swap all the containers:
  244. theSubMesh.FaceList.swap(UniqueFaceList);
  245. theSubMesh.Positions.swap(UniquePositions);
  246. theSubMesh.Normals.swap(UniqueNormals);
  247. theSubMesh.Uvs.swap(UniqueUvs);
  248. theSubMesh.Weights.swap(UniqueWeights);
  249. }
  250. void OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vector<Bone>& Bones)
  251. {
  252. //Mesh is fully loaded, copy it into the aiScene:
  253. if(m_CurrentScene->mNumMeshes!=0)
  254. throw DeadlyImportError("Currently only one mesh per File is allowed!!");
  255. aiMesh* NewAiMesh=new aiMesh();
  256. //Attach the mesh to the scene:
  257. m_CurrentScene->mNumMeshes=1;
  258. m_CurrentScene->mMeshes=new aiMesh*;
  259. m_CurrentScene->mMeshes[0]=NewAiMesh;
  260. //Positions
  261. NewAiMesh->mVertices=new aiVector3D[theSubMesh.Positions.size()];
  262. memcpy(NewAiMesh->mVertices, &theSubMesh.Positions[0], theSubMesh.Positions.size()*sizeof(aiVector3D));
  263. NewAiMesh->mNumVertices=theSubMesh.Positions.size();
  264. //Normals
  265. NewAiMesh->mNormals=new aiVector3D[theSubMesh.Normals.size()];
  266. memcpy(NewAiMesh->mNormals, &theSubMesh.Normals[0], theSubMesh.Normals.size()*sizeof(aiVector3D));
  267. //Uvs
  268. if(0!=theSubMesh.NumUvs)
  269. {
  270. NewAiMesh->mNumUVComponents[0]=2;
  271. NewAiMesh->mTextureCoords[0]= new aiVector3D[theSubMesh.Uvs.size()];
  272. memcpy(NewAiMesh->mTextureCoords[0], &theSubMesh.Uvs[0], theSubMesh.Uvs.size()*sizeof(aiVector3D));
  273. }
  274. //---------------------------------------- Bones --------------------------------------------
  275. //Copy the weights in in Bone-Vertices Struktur
  276. //(we have them in a Vertex-Bones Struktur, this is much easier for making them unique, which is required by assimp
  277. vector< vector<aiVertexWeight> > aiWeights(theSubMesh.BonesUsed);//now the outer list are the bones, and the inner vector the vertices
  278. for(unsigned int VertexId=0; VertexId<theSubMesh.Weights.size(); ++VertexId)//iterate over all vertices
  279. {
  280. for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
  281. {
  282. aiVertexWeight NewWeight;
  283. NewWeight.mVertexId=VertexId;//the current Vertex, we can't use the Id form the submehs weights, because they are bone id's
  284. NewWeight.mWeight=theSubMesh.Weights[VertexId][BoneId].Value;
  285. aiWeights[theSubMesh.Weights[VertexId][BoneId].BoneId].push_back(NewWeight);
  286. }
  287. }
  288. vector<aiBone*> aiBones;
  289. aiBones.reserve(theSubMesh.BonesUsed);//the vector might be smaller, because there might be empty bones (bones that are not attached to any vertex)
  290. //create all the bones and fill them with informations
  291. for(unsigned int i=0; i<theSubMesh.BonesUsed; ++i)
  292. {
  293. if(aiWeights[i].size()>0)
  294. {
  295. aiBone* NewBone=new aiBone();
  296. NewBone->mNumWeights=aiWeights[i].size();
  297. NewBone->mWeights=new aiVertexWeight[aiWeights[i].size()];
  298. memcpy(NewBone->mWeights, &(aiWeights[i][0]), sizeof(aiVertexWeight)*aiWeights[i].size());
  299. NewBone->mName=Bones[i].Name;//The bone list should be sorted after its id's, this was done in LoadSkeleton
  300. NewBone->mOffsetMatrix=Bones[i].BoneToWorldSpace;
  301. aiBones.push_back(NewBone);
  302. }
  303. }
  304. NewAiMesh->mNumBones=aiBones.size();
  305. NewAiMesh->mBones=new aiBone* [aiBones.size()];
  306. memcpy(NewAiMesh->mBones, &(aiBones[0]), aiBones.size()*sizeof(aiBone*));
  307. //______________________________________________________________________________________________________
  308. //Faces
  309. NewAiMesh->mFaces=new aiFace[theSubMesh.FaceList.size()];
  310. for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
  311. {
  312. NewAiMesh->mFaces[i].mNumIndices=3;
  313. NewAiMesh->mFaces[i].mIndices=new unsigned int[3];
  314. NewAiMesh->mFaces[i].mIndices[0]=theSubMesh.FaceList[i].VertexIndices[0];
  315. NewAiMesh->mFaces[i].mIndices[1]=theSubMesh.FaceList[i].VertexIndices[1];
  316. NewAiMesh->mFaces[i].mIndices[2]=theSubMesh.FaceList[i].VertexIndices[2];
  317. }
  318. NewAiMesh->mNumFaces=theSubMesh.FaceList.size();
  319. //Link the material:
  320. NewAiMesh->mMaterialIndex=theSubMesh.MaterialIndex;//the index is set by the function who called ReadSubMesh
  321. }
  322. void OgreImporter::LoadSkeleton(std::string FileName, vector<Bone> &Bones, vector<Animation> &Animations)
  323. {
  324. //most likely the skeleton file will only end with .skeleton
  325. //But this is a xml reader, so we need: .skeleton.xml
  326. FileName+=".xml";
  327. DefaultLogger::get()->debug(string("Loading Skeleton: ")+FileName);
  328. //Open the File:
  329. boost::scoped_ptr<IOStream> File(m_CurrentIOHandler->Open(FileName));
  330. if(NULL==File.get())
  331. throw DeadlyImportError("Failed to open skeleton file "+FileName+".");
  332. //Read the Mesh File:
  333. boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(File.get()));
  334. XmlReader* SkeletonFile = irr::io::createIrrXMLReader(mIOWrapper.get());
  335. if(!SkeletonFile)
  336. throw DeadlyImportError(string("Failed to create XML Reader for ")+FileName);
  337. //Quick note: Whoever read this should know this one thing: irrXml fucking sucks!!!
  338. XmlRead(SkeletonFile);
  339. if(string("skeleton")!=SkeletonFile->getNodeName())
  340. throw DeadlyImportError("No <skeleton> node in SkeletonFile: "+FileName);
  341. //------------------------------------load bones-----------------------------------------
  342. XmlRead(SkeletonFile);
  343. if(string("bones")!=SkeletonFile->getNodeName())
  344. throw DeadlyImportError("No bones node in skeleton "+FileName);
  345. XmlRead(SkeletonFile);
  346. while(string("bone")==SkeletonFile->getNodeName())
  347. {
  348. //TODO: Maybe we can have bone ids for the errrors, but normaly, they should never appear, so what....
  349. //read a new bone:
  350. Bone NewBone;
  351. NewBone.Id=GetAttribute<int>(SkeletonFile, "id");
  352. NewBone.Name=GetAttribute<string>(SkeletonFile, "name");
  353. //load the position:
  354. XmlRead(SkeletonFile);
  355. if(string("position")!=SkeletonFile->getNodeName())
  356. throw DeadlyImportError("Position is not first node in Bone!");
  357. NewBone.Position.x=GetAttribute<float>(SkeletonFile, "x");
  358. NewBone.Position.y=GetAttribute<float>(SkeletonFile, "y");
  359. NewBone.Position.z=GetAttribute<float>(SkeletonFile, "z");
  360. //Rotation:
  361. XmlRead(SkeletonFile);
  362. if(string("rotation")!=SkeletonFile->getNodeName())
  363. throw DeadlyImportError("Rotation is not the second node in Bone!");
  364. NewBone.RotationAngle=GetAttribute<float>(SkeletonFile, "angle");
  365. XmlRead(SkeletonFile);
  366. if(string("axis")!=SkeletonFile->getNodeName())
  367. throw DeadlyImportError("No axis specified for bone rotation!");
  368. NewBone.RotationAxis.x=GetAttribute<float>(SkeletonFile, "x");
  369. NewBone.RotationAxis.y=GetAttribute<float>(SkeletonFile, "y");
  370. NewBone.RotationAxis.z=GetAttribute<float>(SkeletonFile, "z");
  371. //append the newly loaded bone to the bone list
  372. Bones.push_back(NewBone);
  373. //Proceed to the next bone:
  374. XmlRead(SkeletonFile);
  375. }
  376. //The bones in the file a not neccesarly ordered by there id's so we do it now:
  377. std::sort(Bones.begin(), Bones.end());
  378. //now the id of each bone should be equal to its position in the vector:
  379. //so we do a simple check:
  380. {
  381. bool IdsOk=true;
  382. for(int i=0; i<static_cast<signed int>(Bones.size()); ++i)//i is signed, because all Id's are also signed!
  383. {
  384. if(Bones[i].Id!=i)
  385. IdsOk=false;
  386. }
  387. if(!IdsOk)
  388. throw DeadlyImportError("Bone Ids are not valid!"+FileName);
  389. }
  390. DefaultLogger::get()->debug(str(format("Number of bones: %1%") % Bones.size()));
  391. //________________________________________________________________________________
  392. //----------------------------load bonehierarchy--------------------------------
  393. if(string("bonehierarchy")!=SkeletonFile->getNodeName())
  394. throw DeadlyImportError("no bonehierarchy node in "+FileName);
  395. DefaultLogger::get()->debug("loading bonehierarchy...");
  396. XmlRead(SkeletonFile);
  397. while(string("boneparent")==SkeletonFile->getNodeName())
  398. {
  399. string Child, Parent;
  400. Child=GetAttribute<string>(SkeletonFile, "bone");
  401. Parent=GetAttribute<string>(SkeletonFile, "parent");
  402. unsigned int ChildId, ParentId;
  403. ChildId=find(Bones.begin(), Bones.end(), Child)->Id;
  404. ParentId=find(Bones.begin(), Bones.end(), Parent)->Id;
  405. Bones[ChildId].ParentId=ParentId;
  406. Bones[ParentId].Children.push_back(ChildId);
  407. XmlRead(SkeletonFile);//i once forget this line, which led to an endless loop, did i mentioned, that irrxml sucks??
  408. }
  409. //_____________________________________________________________________________
  410. //--------- Calculate the WorldToBoneSpace Matrix recursivly for all bones: ------------------
  411. BOOST_FOREACH(Bone theBone, Bones)
  412. {
  413. if(-1==theBone.ParentId) //the bone is a root bone
  414. {
  415. theBone.CalculateBoneToWorldSpaceMatrix(Bones);
  416. }
  417. }
  418. //_______________________________________________________________________
  419. //---------------------------load animations-----------------------------
  420. if(string("animations")==SkeletonFile->getNodeName())//animations are optional values
  421. {
  422. DefaultLogger::get()->debug("Loading Animations");
  423. XmlRead(SkeletonFile);
  424. while(string("animation")==SkeletonFile->getNodeName())
  425. {
  426. Animation NewAnimation;
  427. NewAnimation.Name=GetAttribute<string>(SkeletonFile, "name");
  428. NewAnimation.Length=GetAttribute<float>(SkeletonFile, "length");
  429. //Load all Tracks
  430. XmlRead(SkeletonFile);
  431. if(string("tracks")!=SkeletonFile->getNodeName())
  432. throw DeadlyImportError("no tracks node in animation");
  433. XmlRead(SkeletonFile);
  434. while(string("track")==SkeletonFile->getNodeName())
  435. {
  436. Track NewTrack;
  437. NewTrack.BoneName=GetAttribute<string>(SkeletonFile, "bone");
  438. //Load all keyframes;
  439. XmlRead(SkeletonFile);
  440. if(string("keyframes")!=SkeletonFile->getNodeName())
  441. throw DeadlyImportError("no keyframes node!");
  442. XmlRead(SkeletonFile);
  443. while(string("keyframe")==SkeletonFile->getNodeName())
  444. {
  445. Keyframe NewKeyframe;
  446. NewKeyframe.Time=GetAttribute<float>(SkeletonFile, "time");
  447. //Position:
  448. XmlRead(SkeletonFile);
  449. if(string("translate")!=SkeletonFile->getNodeName())
  450. throw DeadlyImportError("translate node not first in keyframe");
  451. NewKeyframe.Position.x=GetAttribute<float>(SkeletonFile, "x");
  452. NewKeyframe.Position.y=GetAttribute<float>(SkeletonFile, "y");
  453. NewKeyframe.Position.z=GetAttribute<float>(SkeletonFile, "z");
  454. //Rotation:
  455. XmlRead(SkeletonFile);
  456. if(string("rotate")!=SkeletonFile->getNodeName())
  457. throw DeadlyImportError("rotate is not second node in keyframe");
  458. float RotationAngle=GetAttribute<float>(SkeletonFile, "angle");
  459. aiVector3D RotationAxis;
  460. XmlRead(SkeletonFile);
  461. if(string("axis")!=SkeletonFile->getNodeName())
  462. throw DeadlyImportError("No axis for keyframe rotation!");
  463. RotationAxis.x=GetAttribute<float>(SkeletonFile, "x");
  464. RotationAxis.y=GetAttribute<float>(SkeletonFile, "y");
  465. RotationAxis.z=GetAttribute<float>(SkeletonFile, "z");
  466. NewKeyframe.Rotation=aiQuaternion(RotationAxis, RotationAngle);
  467. //Scaling:
  468. XmlRead(SkeletonFile);
  469. if(string("scale")!=SkeletonFile->getNodeName())
  470. throw DeadlyImportError("no scalling key in keyframe!");
  471. NewKeyframe.Scaling.x=GetAttribute<float>(SkeletonFile, "x");
  472. NewKeyframe.Scaling.y=GetAttribute<float>(SkeletonFile, "y");
  473. NewKeyframe.Scaling.z=GetAttribute<float>(SkeletonFile, "z");
  474. NewTrack.Keyframes.push_back(NewKeyframe);
  475. XmlRead(SkeletonFile);
  476. }
  477. NewAnimation.Tracks.push_back(NewTrack);
  478. }
  479. Animations.push_back(NewAnimation);
  480. }
  481. }
  482. //_____________________________________________________________________________
  483. }
  484. void OgreImporter::CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations)
  485. {
  486. //-----------------skeleton is completly loaded, now put it in the assimp scene:-------------------------------
  487. if(!m_CurrentScene->mRootNode)
  488. throw DeadlyImportError("No root node exists!!");
  489. if(0!=m_CurrentScene->mRootNode->mNumChildren)
  490. throw DeadlyImportError("Root Node already has childnodes!");
  491. //--------------Createt the assimp bone hierarchy-----------------
  492. DefaultLogger::get()->debug("Root Bones");
  493. vector<aiNode*> RootBoneNodes;
  494. BOOST_FOREACH(Bone theBone, Bones)
  495. {
  496. if(-1==theBone.ParentId) //the bone is a root bone
  497. {
  498. DefaultLogger::get()->debug(theBone.Name);
  499. RootBoneNodes.push_back(CreateAiNodeFromBone(theBone.Id, Bones, m_CurrentScene->mRootNode));//which will recursily add all other nodes
  500. }
  501. }
  502. m_CurrentScene->mRootNode->mNumChildren=RootBoneNodes.size();
  503. m_CurrentScene->mRootNode->mChildren=new aiNode*[RootBoneNodes.size()];
  504. memcpy(m_CurrentScene->mRootNode->mChildren, &RootBoneNodes[0], sizeof(aiNode*)*RootBoneNodes.size());
  505. //_______________________________________________________________
  506. //-----------------Create the Assimp Animations --------------------
  507. if(Animations.size()>0)//Maybe the model had only a skeleton and no animations. (If it also has no skeleton, this function would'nt have benn called
  508. {
  509. m_CurrentScene->mNumAnimations=Animations.size();
  510. m_CurrentScene->mAnimations=new aiAnimation*[Animations.size()];
  511. for(unsigned int i=0; i<Animations.size(); ++i)//create all animations
  512. {
  513. aiAnimation* NewAnimation=new aiAnimation();
  514. NewAnimation->mName=Animations[i].Name;
  515. NewAnimation->mDuration=Animations[i].Length;
  516. NewAnimation->mTicksPerSecond=1.0f;
  517. //Create all tracks in this animation
  518. NewAnimation->mNumChannels=Animations[i].Tracks.size();
  519. NewAnimation->mChannels=new aiNodeAnim*[Animations[i].Tracks.size()];
  520. for(unsigned int j=0; j<Animations[i].Tracks.size(); ++j)
  521. {
  522. aiNodeAnim* NewNodeAnim=new aiNodeAnim();
  523. NewNodeAnim->mNodeName=Animations[i].Tracks[j].BoneName;
  524. //we need this, to acces the bones default pose, which we need to make keys absolute
  525. vector<Bone>::const_iterator CurBone=find(Bones.begin(), Bones.end(), NewNodeAnim->mNodeName);
  526. //Create the keyframe arrays...
  527. unsigned int KeyframeCount=Animations[i].Tracks[j].Keyframes.size();
  528. NewNodeAnim->mNumPositionKeys=KeyframeCount;
  529. NewNodeAnim->mPositionKeys=new aiVectorKey[KeyframeCount];
  530. NewNodeAnim->mNumRotationKeys=KeyframeCount;
  531. NewNodeAnim->mRotationKeys=new aiQuatKey[KeyframeCount];
  532. NewNodeAnim->mNumScalingKeys=KeyframeCount;
  533. NewNodeAnim->mScalingKeys=new aiVectorKey[KeyframeCount];
  534. //...and fill them
  535. for(unsigned int k=0; k<KeyframeCount; ++k)
  536. {
  537. aiMatrix4x4 t0, t1, t2, t3, t4;
  538. //Create a matrix to transfrom a vector from the bones default pose to the bone bones in this animation key
  539. aiMatrix4x4 PoseToKey=aiMatrix4x4::Scaling(Animations[i].Tracks[j].Keyframes[k].Scaling, t1) //scale
  540. * aiMatrix4x4(Animations[i].Tracks[j].Keyframes[k].Rotation.GetMatrix()) //rot
  541. * aiMatrix4x4::Translation(Animations[i].Tracks[j].Keyframes[k].Position, t0); //pos
  542. aiMatrix4x4 DefBonePose=aiMatrix4x4::Rotation(CurBone->RotationAngle, CurBone->RotationAxis, t3)
  543. * aiMatrix4x4::Translation(CurBone->Position, t2);
  544. //The defautl bone pose doesnt have a scaling value
  545. //calculate the complete transformation from world space to bone space
  546. aiMatrix4x4 CompleteTransform=DefBonePose * PoseToKey;
  547. aiVector3D Pos;
  548. aiQuaternion Rot;
  549. aiVector3D Scale;
  550. CompleteTransform.Decompose(Scale, Rot, Pos);
  551. NewNodeAnim->mPositionKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  552. NewNodeAnim->mPositionKeys[k].mValue=Pos;
  553. NewNodeAnim->mRotationKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  554. NewNodeAnim->mRotationKeys[k].mValue=Rot;
  555. NewNodeAnim->mScalingKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  556. NewNodeAnim->mScalingKeys[k].mValue=Scale;
  557. }
  558. NewAnimation->mChannels[j]=NewNodeAnim;
  559. }
  560. m_CurrentScene->mAnimations[i]=NewAnimation;
  561. }
  562. }
  563. //__________________________________________________________________
  564. }
  565. aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode)
  566. {
  567. //----Create the node for this bone and set its values-----
  568. aiNode* NewNode=new aiNode(Bones[BoneId].Name);
  569. NewNode->mParent=ParentNode;
  570. aiMatrix4x4 t0,t1;
  571. //create a matrix from the transformation values of the ogre bone
  572. NewNode->mTransformation=aiMatrix4x4::Rotation(Bones[BoneId].RotationAngle, Bones[BoneId].RotationAxis, t1)
  573. * aiMatrix4x4::Translation(Bones[BoneId].Position, t0)
  574. ;
  575. //__________________________________________________________
  576. //---------- recursivly create all children Nodes: ----------
  577. NewNode->mNumChildren=Bones[BoneId].Children.size();
  578. NewNode->mChildren=new aiNode*[Bones[BoneId].Children.size()];
  579. for(unsigned int i=0; i<Bones[BoneId].Children.size(); ++i)
  580. {
  581. NewNode->mChildren[i]=CreateAiNodeFromBone(Bones[BoneId].Children[i], Bones, NewNode);
  582. }
  583. //____________________________________________________
  584. return NewNode;
  585. }
  586. void Bone::CalculateBoneToWorldSpaceMatrix(vector<Bone> &Bones)
  587. {
  588. //Calculate the matrix for this bone:
  589. aiMatrix4x4 t0,t1;
  590. aiMatrix4x4 Transf=aiMatrix4x4::Translation(-Position, t0)
  591. * aiMatrix4x4::Rotation(-RotationAngle, RotationAxis, t1)
  592. ;
  593. if(-1==ParentId)
  594. {
  595. BoneToWorldSpace=Transf;
  596. }
  597. else
  598. {
  599. BoneToWorldSpace=Transf*Bones[ParentId].BoneToWorldSpace;
  600. }
  601. //and recursivly for all children:
  602. BOOST_FOREACH(int theChildren, Children)
  603. {
  604. Bones[theChildren].CalculateBoneToWorldSpaceMatrix(Bones);
  605. }
  606. }
  607. }//namespace Ogre
  608. }//namespace Assimp
  609. #endif // !! ASSIMP_BUILD_NO_OGRE_IMPORTER