OgreImporter.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  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((theSubMesh.Weights.size() ? UniqueVertexCount : 0));
  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. if (theSubMesh.Weights.size()) {
  235. UniqueWeights[3*i+0]=theSubMesh.Weights[Vertex1];
  236. UniqueWeights[3*i+1]=theSubMesh.Weights[Vertex2];
  237. UniqueWeights[3*i+2]=theSubMesh.Weights[Vertex3];
  238. }
  239. //The indexvalues a just continuous numbers (0, 1, 2, 3, 4, 5, 6...)
  240. UniqueFaceList[i].VertexIndices[0]=3*i+0;
  241. UniqueFaceList[i].VertexIndices[1]=3*i+1;
  242. UniqueFaceList[i].VertexIndices[2]=3*i+2;
  243. }
  244. //_________________________________________________________________________________________
  245. //now we have the unique datas, but want them in the SubMesh, so we swap all the containers:
  246. theSubMesh.FaceList.swap(UniqueFaceList);
  247. theSubMesh.Positions.swap(UniquePositions);
  248. theSubMesh.Normals.swap(UniqueNormals);
  249. theSubMesh.Uvs.swap(UniqueUvs);
  250. theSubMesh.Weights.swap(UniqueWeights);
  251. //------------- normalize weights -----------------------------
  252. //The Blender exporter doesn't care about whether the sum of all boneweights for a single vertex equals 1 or not,
  253. //so we have to make this sure:
  254. for(unsigned int VertexId=0; VertexId<theSubMesh.Weights.size(); ++VertexId)//iterate over all vertices
  255. {
  256. float WeightSum=0.0f;
  257. for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
  258. {
  259. WeightSum+=theSubMesh.Weights[VertexId][BoneId].Value;
  260. }
  261. //check if the sum is too far away from 1
  262. if(WeightSum<1.0f-0.05f || WeightSum>1.0f+0.05f)
  263. {
  264. //normalize all weights:
  265. for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
  266. {
  267. theSubMesh.Weights[VertexId][BoneId].Value/=WeightSum;
  268. }
  269. }
  270. }
  271. //_________________________________________________________
  272. }
  273. void OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vector<Bone>& Bones)
  274. {
  275. //Mesh is fully loaded, copy it into the aiScene:
  276. if(m_CurrentScene->mNumMeshes!=0)
  277. throw DeadlyImportError("Currently only one mesh per File is allowed!!");
  278. aiMesh* NewAiMesh=new aiMesh();
  279. //Attach the mesh to the scene:
  280. m_CurrentScene->mNumMeshes=1;
  281. m_CurrentScene->mMeshes=new aiMesh*;
  282. m_CurrentScene->mMeshes[0]=NewAiMesh;
  283. //Positions
  284. NewAiMesh->mVertices=new aiVector3D[theSubMesh.Positions.size()];
  285. memcpy(NewAiMesh->mVertices, &theSubMesh.Positions[0], theSubMesh.Positions.size()*sizeof(aiVector3D));
  286. NewAiMesh->mNumVertices=theSubMesh.Positions.size();
  287. //Normals
  288. NewAiMesh->mNormals=new aiVector3D[theSubMesh.Normals.size()];
  289. memcpy(NewAiMesh->mNormals, &theSubMesh.Normals[0], theSubMesh.Normals.size()*sizeof(aiVector3D));
  290. //Uvs
  291. if(0!=theSubMesh.NumUvs)
  292. {
  293. NewAiMesh->mNumUVComponents[0]=2;
  294. NewAiMesh->mTextureCoords[0]= new aiVector3D[theSubMesh.Uvs.size()];
  295. memcpy(NewAiMesh->mTextureCoords[0], &theSubMesh.Uvs[0], theSubMesh.Uvs.size()*sizeof(aiVector3D));
  296. }
  297. //---------------------------------------- Bones --------------------------------------------
  298. //Copy the weights in in Bone-Vertices Struktur
  299. //(we have them in a Vertex-Bones Structur, this is much easier for making them unique, which is required by assimp
  300. vector< vector<aiVertexWeight> > aiWeights(theSubMesh.BonesUsed);//now the outer list are the bones, and the inner vector the vertices
  301. for(unsigned int VertexId=0; VertexId<theSubMesh.Weights.size(); ++VertexId)//iterate over all vertices
  302. {
  303. for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
  304. {
  305. aiVertexWeight NewWeight;
  306. NewWeight.mVertexId=VertexId;//the current Vertex, we can't use the Id form the submehs weights, because they are bone id's
  307. NewWeight.mWeight=theSubMesh.Weights[VertexId][BoneId].Value;
  308. aiWeights[theSubMesh.Weights[VertexId][BoneId].BoneId].push_back(NewWeight);
  309. }
  310. }
  311. vector<aiBone*> aiBones;
  312. aiBones.reserve(theSubMesh.BonesUsed);//the vector might be smaller, because there might be empty bones (bones that are not attached to any vertex)
  313. //create all the bones and fill them with informations
  314. for(unsigned int i=0; i<theSubMesh.BonesUsed; ++i)
  315. {
  316. if(aiWeights[i].size()>0)
  317. {
  318. aiBone* NewBone=new aiBone();
  319. NewBone->mNumWeights=aiWeights[i].size();
  320. NewBone->mWeights=new aiVertexWeight[aiWeights[i].size()];
  321. memcpy(NewBone->mWeights, &(aiWeights[i][0]), sizeof(aiVertexWeight)*aiWeights[i].size());
  322. NewBone->mName=Bones[i].Name;//The bone list should be sorted after its id's, this was done in LoadSkeleton
  323. NewBone->mOffsetMatrix=Bones[i].BoneToWorldSpace;
  324. aiBones.push_back(NewBone);
  325. }
  326. }
  327. NewAiMesh->mNumBones=aiBones.size();
  328. // mBones must be NULL if mNumBones is non 0 or the validation fails.
  329. if (aiBones.size()) {
  330. NewAiMesh->mBones=new aiBone* [aiBones.size()];
  331. memcpy(NewAiMesh->mBones, &(aiBones[0]), aiBones.size()*sizeof(aiBone*));
  332. }
  333. //______________________________________________________________________________________________________
  334. //Faces
  335. NewAiMesh->mFaces=new aiFace[theSubMesh.FaceList.size()];
  336. for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
  337. {
  338. NewAiMesh->mFaces[i].mNumIndices=3;
  339. NewAiMesh->mFaces[i].mIndices=new unsigned int[3];
  340. NewAiMesh->mFaces[i].mIndices[0]=theSubMesh.FaceList[i].VertexIndices[0];
  341. NewAiMesh->mFaces[i].mIndices[1]=theSubMesh.FaceList[i].VertexIndices[1];
  342. NewAiMesh->mFaces[i].mIndices[2]=theSubMesh.FaceList[i].VertexIndices[2];
  343. }
  344. NewAiMesh->mNumFaces=theSubMesh.FaceList.size();
  345. //Link the material:
  346. NewAiMesh->mMaterialIndex=theSubMesh.MaterialIndex;//the index is set by the function who called ReadSubMesh
  347. }
  348. void OgreImporter::LoadSkeleton(std::string FileName, vector<Bone> &Bones, vector<Animation> &Animations)
  349. {
  350. //most likely the skeleton file will only end with .skeleton
  351. //But this is a xml reader, so we need: .skeleton.xml
  352. FileName+=".xml";
  353. DefaultLogger::get()->debug(string("Loading Skeleton: ")+FileName);
  354. //Open the File:
  355. boost::scoped_ptr<IOStream> File(m_CurrentIOHandler->Open(FileName));
  356. if(NULL==File.get())
  357. throw DeadlyImportError("Failed to open skeleton file "+FileName+".");
  358. //Read the Mesh File:
  359. boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(File.get()));
  360. XmlReader* SkeletonFile = irr::io::createIrrXMLReader(mIOWrapper.get());
  361. if(!SkeletonFile)
  362. throw DeadlyImportError(string("Failed to create XML Reader for ")+FileName);
  363. //Quick note: Whoever read this should know this one thing: irrXml fucking sucks!!!
  364. XmlRead(SkeletonFile);
  365. if(string("skeleton")!=SkeletonFile->getNodeName())
  366. throw DeadlyImportError("No <skeleton> node in SkeletonFile: "+FileName);
  367. //------------------------------------load bones-----------------------------------------
  368. XmlRead(SkeletonFile);
  369. if(string("bones")!=SkeletonFile->getNodeName())
  370. throw DeadlyImportError("No bones node in skeleton "+FileName);
  371. XmlRead(SkeletonFile);
  372. while(string("bone")==SkeletonFile->getNodeName())
  373. {
  374. //TODO: Maybe we can have bone ids for the errrors, but normaly, they should never appear, so what....
  375. //read a new bone:
  376. Bone NewBone;
  377. NewBone.Id=GetAttribute<int>(SkeletonFile, "id");
  378. NewBone.Name=GetAttribute<string>(SkeletonFile, "name");
  379. //load the position:
  380. XmlRead(SkeletonFile);
  381. if(string("position")!=SkeletonFile->getNodeName())
  382. throw DeadlyImportError("Position is not first node in Bone!");
  383. NewBone.Position.x=GetAttribute<float>(SkeletonFile, "x");
  384. NewBone.Position.y=GetAttribute<float>(SkeletonFile, "y");
  385. NewBone.Position.z=GetAttribute<float>(SkeletonFile, "z");
  386. //Rotation:
  387. XmlRead(SkeletonFile);
  388. if(string("rotation")!=SkeletonFile->getNodeName())
  389. throw DeadlyImportError("Rotation is not the second node in Bone!");
  390. NewBone.RotationAngle=GetAttribute<float>(SkeletonFile, "angle");
  391. XmlRead(SkeletonFile);
  392. if(string("axis")!=SkeletonFile->getNodeName())
  393. throw DeadlyImportError("No axis specified for bone rotation!");
  394. NewBone.RotationAxis.x=GetAttribute<float>(SkeletonFile, "x");
  395. NewBone.RotationAxis.y=GetAttribute<float>(SkeletonFile, "y");
  396. NewBone.RotationAxis.z=GetAttribute<float>(SkeletonFile, "z");
  397. //append the newly loaded bone to the bone list
  398. Bones.push_back(NewBone);
  399. //Proceed to the next bone:
  400. XmlRead(SkeletonFile);
  401. }
  402. //The bones in the file a not neccesarly ordered by there id's so we do it now:
  403. std::sort(Bones.begin(), Bones.end());
  404. //now the id of each bone should be equal to its position in the vector:
  405. //so we do a simple check:
  406. {
  407. bool IdsOk=true;
  408. for(int i=0; i<static_cast<signed int>(Bones.size()); ++i)//i is signed, because all Id's are also signed!
  409. {
  410. if(Bones[i].Id!=i)
  411. IdsOk=false;
  412. }
  413. if(!IdsOk)
  414. throw DeadlyImportError("Bone Ids are not valid!"+FileName);
  415. }
  416. DefaultLogger::get()->debug(str(format("Number of bones: %1%") % Bones.size()));
  417. //________________________________________________________________________________
  418. //----------------------------load bonehierarchy--------------------------------
  419. if(string("bonehierarchy")!=SkeletonFile->getNodeName())
  420. throw DeadlyImportError("no bonehierarchy node in "+FileName);
  421. DefaultLogger::get()->debug("loading bonehierarchy...");
  422. XmlRead(SkeletonFile);
  423. while(string("boneparent")==SkeletonFile->getNodeName())
  424. {
  425. string Child, Parent;
  426. Child=GetAttribute<string>(SkeletonFile, "bone");
  427. Parent=GetAttribute<string>(SkeletonFile, "parent");
  428. unsigned int ChildId, ParentId;
  429. ChildId=find(Bones.begin(), Bones.end(), Child)->Id;
  430. ParentId=find(Bones.begin(), Bones.end(), Parent)->Id;
  431. Bones[ChildId].ParentId=ParentId;
  432. Bones[ParentId].Children.push_back(ChildId);
  433. XmlRead(SkeletonFile);//i once forget this line, which led to an endless loop, did i mentioned, that irrxml sucks??
  434. }
  435. //_____________________________________________________________________________
  436. //--------- Calculate the WorldToBoneSpace Matrix recursivly for all bones: ------------------
  437. BOOST_FOREACH(Bone theBone, Bones)
  438. {
  439. if(-1==theBone.ParentId) //the bone is a root bone
  440. {
  441. theBone.CalculateBoneToWorldSpaceMatrix(Bones);
  442. }
  443. }
  444. //_______________________________________________________________________
  445. //---------------------------load animations-----------------------------
  446. if(string("animations")==SkeletonFile->getNodeName())//animations are optional values
  447. {
  448. DefaultLogger::get()->debug("Loading Animations");
  449. XmlRead(SkeletonFile);
  450. while(string("animation")==SkeletonFile->getNodeName())
  451. {
  452. Animation NewAnimation;
  453. NewAnimation.Name=GetAttribute<string>(SkeletonFile, "name");
  454. NewAnimation.Length=GetAttribute<float>(SkeletonFile, "length");
  455. //Load all Tracks
  456. XmlRead(SkeletonFile);
  457. if(string("tracks")!=SkeletonFile->getNodeName())
  458. throw DeadlyImportError("no tracks node in animation");
  459. XmlRead(SkeletonFile);
  460. while(string("track")==SkeletonFile->getNodeName())
  461. {
  462. Track NewTrack;
  463. NewTrack.BoneName=GetAttribute<string>(SkeletonFile, "bone");
  464. //Load all keyframes;
  465. XmlRead(SkeletonFile);
  466. if(string("keyframes")!=SkeletonFile->getNodeName())
  467. throw DeadlyImportError("no keyframes node!");
  468. XmlRead(SkeletonFile);
  469. while(string("keyframe")==SkeletonFile->getNodeName())
  470. {
  471. Keyframe NewKeyframe;
  472. NewKeyframe.Time=GetAttribute<float>(SkeletonFile, "time");
  473. //Position:
  474. XmlRead(SkeletonFile);
  475. if(string("translate")!=SkeletonFile->getNodeName())
  476. throw DeadlyImportError("translate node not first in keyframe");
  477. NewKeyframe.Position.x=GetAttribute<float>(SkeletonFile, "x");
  478. NewKeyframe.Position.y=GetAttribute<float>(SkeletonFile, "y");
  479. NewKeyframe.Position.z=GetAttribute<float>(SkeletonFile, "z");
  480. //Rotation:
  481. XmlRead(SkeletonFile);
  482. if(string("rotate")!=SkeletonFile->getNodeName())
  483. throw DeadlyImportError("rotate is not second node in keyframe");
  484. float RotationAngle=GetAttribute<float>(SkeletonFile, "angle");
  485. aiVector3D RotationAxis;
  486. XmlRead(SkeletonFile);
  487. if(string("axis")!=SkeletonFile->getNodeName())
  488. throw DeadlyImportError("No axis for keyframe rotation!");
  489. RotationAxis.x=GetAttribute<float>(SkeletonFile, "x");
  490. RotationAxis.y=GetAttribute<float>(SkeletonFile, "y");
  491. RotationAxis.z=GetAttribute<float>(SkeletonFile, "z");
  492. NewKeyframe.Rotation=aiQuaternion(RotationAxis, RotationAngle);
  493. //Scaling:
  494. XmlRead(SkeletonFile);
  495. if(string("scale")!=SkeletonFile->getNodeName())
  496. throw DeadlyImportError("no scalling key in keyframe!");
  497. NewKeyframe.Scaling.x=GetAttribute<float>(SkeletonFile, "x");
  498. NewKeyframe.Scaling.y=GetAttribute<float>(SkeletonFile, "y");
  499. NewKeyframe.Scaling.z=GetAttribute<float>(SkeletonFile, "z");
  500. NewTrack.Keyframes.push_back(NewKeyframe);
  501. XmlRead(SkeletonFile);
  502. }
  503. NewAnimation.Tracks.push_back(NewTrack);
  504. }
  505. Animations.push_back(NewAnimation);
  506. }
  507. }
  508. //_____________________________________________________________________________
  509. }
  510. void OgreImporter::CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations)
  511. {
  512. //-----------------skeleton is completly loaded, now put it in the assimp scene:-------------------------------
  513. if(!m_CurrentScene->mRootNode)
  514. throw DeadlyImportError("No root node exists!!");
  515. if(0!=m_CurrentScene->mRootNode->mNumChildren)
  516. throw DeadlyImportError("Root Node already has childnodes!");
  517. //--------------Createt the assimp bone hierarchy-----------------
  518. DefaultLogger::get()->debug("Root Bones");
  519. vector<aiNode*> RootBoneNodes;
  520. BOOST_FOREACH(Bone theBone, Bones)
  521. {
  522. if(-1==theBone.ParentId) //the bone is a root bone
  523. {
  524. DefaultLogger::get()->debug(theBone.Name);
  525. RootBoneNodes.push_back(CreateAiNodeFromBone(theBone.Id, Bones, m_CurrentScene->mRootNode));//which will recursily add all other nodes
  526. }
  527. }
  528. m_CurrentScene->mRootNode->mNumChildren=RootBoneNodes.size();
  529. m_CurrentScene->mRootNode->mChildren=new aiNode*[RootBoneNodes.size()];
  530. memcpy(m_CurrentScene->mRootNode->mChildren, &RootBoneNodes[0], sizeof(aiNode*)*RootBoneNodes.size());
  531. //_______________________________________________________________
  532. //-----------------Create the Assimp Animations --------------------
  533. 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
  534. {
  535. m_CurrentScene->mNumAnimations=Animations.size();
  536. m_CurrentScene->mAnimations=new aiAnimation*[Animations.size()];
  537. for(unsigned int i=0; i<Animations.size(); ++i)//create all animations
  538. {
  539. aiAnimation* NewAnimation=new aiAnimation();
  540. NewAnimation->mName=Animations[i].Name;
  541. NewAnimation->mDuration=Animations[i].Length;
  542. NewAnimation->mTicksPerSecond=1.0f;
  543. //Create all tracks in this animation
  544. NewAnimation->mNumChannels=Animations[i].Tracks.size();
  545. NewAnimation->mChannels=new aiNodeAnim*[Animations[i].Tracks.size()];
  546. for(unsigned int j=0; j<Animations[i].Tracks.size(); ++j)
  547. {
  548. aiNodeAnim* NewNodeAnim=new aiNodeAnim();
  549. NewNodeAnim->mNodeName=Animations[i].Tracks[j].BoneName;
  550. //we need this, to acces the bones default pose, which we need to make keys absolute
  551. vector<Bone>::const_iterator CurBone=find(Bones.begin(), Bones.end(), NewNodeAnim->mNodeName);
  552. aiMatrix4x4 t0, t1;
  553. aiMatrix4x4 DefBonePose=//The default bone pose doesnt have a scaling value
  554. aiMatrix4x4::Rotation(CurBone->RotationAngle, CurBone->RotationAxis, t0)
  555. * aiMatrix4x4::Translation(CurBone->Position, t1);
  556. //Create the keyframe arrays...
  557. unsigned int KeyframeCount=Animations[i].Tracks[j].Keyframes.size();
  558. NewNodeAnim->mNumPositionKeys=KeyframeCount;
  559. NewNodeAnim->mPositionKeys=new aiVectorKey[KeyframeCount];
  560. NewNodeAnim->mNumRotationKeys=KeyframeCount;
  561. NewNodeAnim->mRotationKeys=new aiQuatKey[KeyframeCount];
  562. NewNodeAnim->mNumScalingKeys=KeyframeCount;
  563. NewNodeAnim->mScalingKeys=new aiVectorKey[KeyframeCount];
  564. //...and fill them
  565. for(unsigned int k=0; k<KeyframeCount; ++k)
  566. {
  567. aiMatrix4x4 t2, t3;
  568. //Create a matrix to transfrom a vector from the bones default pose to the bone bones in this animation key
  569. aiMatrix4x4 PoseToKey=aiMatrix4x4::Scaling(Animations[i].Tracks[j].Keyframes[k].Scaling, t2) //scale
  570. * aiMatrix4x4(Animations[i].Tracks[j].Keyframes[k].Rotation.GetMatrix()) //rot
  571. * aiMatrix4x4::Translation(Animations[i].Tracks[j].Keyframes[k].Position, t3); //pos
  572. //calculate the complete transformation from world space to bone space
  573. aiMatrix4x4 CompleteTransform=DefBonePose * PoseToKey;
  574. aiVector3D Pos;
  575. aiQuaternion Rot;
  576. aiVector3D Scale;
  577. CompleteTransform.Decompose(Scale, Rot, Pos);
  578. NewNodeAnim->mPositionKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  579. NewNodeAnim->mPositionKeys[k].mValue=Pos;
  580. NewNodeAnim->mRotationKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  581. NewNodeAnim->mRotationKeys[k].mValue=Rot;
  582. NewNodeAnim->mScalingKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  583. NewNodeAnim->mScalingKeys[k].mValue=Scale;
  584. }
  585. NewAnimation->mChannels[j]=NewNodeAnim;
  586. }
  587. m_CurrentScene->mAnimations[i]=NewAnimation;
  588. }
  589. }
  590. //TODO: Auf nicht vorhandene Animationskeys achten!
  591. #pragma warning (s.o.)
  592. //__________________________________________________________________
  593. }
  594. aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode)
  595. {
  596. //----Create the node for this bone and set its values-----
  597. aiNode* NewNode=new aiNode(Bones[BoneId].Name);
  598. NewNode->mParent=ParentNode;
  599. aiMatrix4x4 t0,t1;
  600. //create a matrix from the transformation values of the ogre bone
  601. NewNode->mTransformation=aiMatrix4x4::Rotation(Bones[BoneId].RotationAngle, Bones[BoneId].RotationAxis, t1)
  602. * aiMatrix4x4::Translation(Bones[BoneId].Position, t0)
  603. ;
  604. //__________________________________________________________
  605. //---------- recursivly create all children Nodes: ----------
  606. NewNode->mNumChildren=Bones[BoneId].Children.size();
  607. NewNode->mChildren=new aiNode*[Bones[BoneId].Children.size()];
  608. for(unsigned int i=0; i<Bones[BoneId].Children.size(); ++i)
  609. {
  610. NewNode->mChildren[i]=CreateAiNodeFromBone(Bones[BoneId].Children[i], Bones, NewNode);
  611. }
  612. //____________________________________________________
  613. return NewNode;
  614. }
  615. void Bone::CalculateBoneToWorldSpaceMatrix(vector<Bone> &Bones)
  616. {
  617. //Calculate the matrix for this bone:
  618. aiMatrix4x4 t0,t1;
  619. aiMatrix4x4 Transf=aiMatrix4x4::Translation(-Position, t0)
  620. * aiMatrix4x4::Rotation(-RotationAngle, RotationAxis, t1)
  621. ;
  622. if(-1==ParentId)
  623. {
  624. BoneToWorldSpace=Transf;
  625. }
  626. else
  627. {
  628. BoneToWorldSpace=Transf*Bones[ParentId].BoneToWorldSpace;
  629. }
  630. //and recursivly for all children:
  631. BOOST_FOREACH(int theChildren, Children)
  632. {
  633. Bones[theChildren].CalculateBoneToWorldSpaceMatrix(Bones);
  634. }
  635. }
  636. }//namespace Ogre
  637. }//namespace Assimp
  638. #endif // !! ASSIMP_BUILD_NO_OGRE_IMPORTER