OgreImporter.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  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 new ImportErrorException("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 new ImportErrorException("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 new ImportErrorException("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 new ImportErrorException("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 new ImportErrorException("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 new ImportErrorException("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::string &append)
  101. {
  102. append+="*.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 new ImportErrorException("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 new ImportErrorException("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 new ImportErrorException("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%") % theSubMesh.Positions.size() % theSubMesh.Normals.size() % theSubMesh.Uvs.size()));
  207. DefaultLogger::get()->warn(Reader->getNodeName());
  208. //---------------Make all Vertexes unique: (this is required by assimp)-----------------------
  209. vector<Face> UniqueFaceList(theSubMesh.FaceList.size());
  210. unsigned int UniqueVertexCount=theSubMesh.FaceList.size()*3;//*3 because each face consists of 3 vertexes, because we only support triangles^^
  211. vector<aiVector3D> UniquePositions(UniqueVertexCount);
  212. vector<aiVector3D> UniqueNormals(UniqueVertexCount);
  213. vector<aiVector3D> UniqueUvs(UniqueVertexCount);
  214. vector< vector<Weight> > UniqueWeights(UniqueVertexCount);
  215. for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
  216. {
  217. //We precalculate the index vlaues her, because we need them in all vertex attributes
  218. unsigned int Vertex1=theSubMesh.FaceList[i].VertexIndices[0];
  219. unsigned int Vertex2=theSubMesh.FaceList[i].VertexIndices[1];
  220. unsigned int Vertex3=theSubMesh.FaceList[i].VertexIndices[2];
  221. UniquePositions[3*i+0]=theSubMesh.Positions[Vertex1];
  222. UniquePositions[3*i+1]=theSubMesh.Positions[Vertex2];
  223. UniquePositions[3*i+2]=theSubMesh.Positions[Vertex3];
  224. UniqueNormals[3*i+0]=theSubMesh.Normals[Vertex1];
  225. UniqueNormals[3*i+1]=theSubMesh.Normals[Vertex2];
  226. UniqueNormals[3*i+2]=theSubMesh.Normals[Vertex3];
  227. if(1==theSubMesh.NumUvs)
  228. {
  229. UniqueUvs[3*i+0]=theSubMesh.Uvs[Vertex1];
  230. UniqueUvs[3*i+1]=theSubMesh.Uvs[Vertex2];
  231. UniqueUvs[3*i+2]=theSubMesh.Uvs[Vertex3];
  232. }
  233. UniqueWeights[3*i+0]=theSubMesh.Weights[Vertex1];
  234. UniqueWeights[3*i+1]=theSubMesh.Weights[Vertex2];
  235. UniqueWeights[3*i+2]=theSubMesh.Weights[Vertex3];
  236. //The indexvalues a just continuous numbers (0, 1, 2, 3, 4, 5, 6...)
  237. UniqueFaceList[i].VertexIndices[0]=3*i+0;
  238. UniqueFaceList[i].VertexIndices[1]=3*i+1;
  239. UniqueFaceList[i].VertexIndices[2]=3*i+2;
  240. }
  241. //_________________________________________________________________________________________
  242. //now we have the unique datas, but want them in the SubMesh, so we swap all the containers:
  243. theSubMesh.FaceList.swap(UniqueFaceList);
  244. theSubMesh.Positions.swap(UniquePositions);
  245. theSubMesh.Normals.swap(UniqueNormals);
  246. theSubMesh.Uvs.swap(UniqueUvs);
  247. theSubMesh.Weights.swap(UniqueWeights);
  248. }
  249. void OgreImporter::CreateAssimpSubMesh(const SubMesh& theSubMesh, const vector<Bone>& Bones)
  250. {
  251. //Mesh is fully loaded, copy it into the aiScene:
  252. if(m_CurrentScene->mNumMeshes!=0)
  253. throw new ImportErrorException("Currently only one mesh per File is allowed!!");
  254. aiMesh* NewAiMesh=new aiMesh();
  255. //Attach the mesh to the scene:
  256. m_CurrentScene->mNumMeshes=1;
  257. m_CurrentScene->mMeshes=new aiMesh*;
  258. m_CurrentScene->mMeshes[0]=NewAiMesh;
  259. //Positions
  260. NewAiMesh->mVertices=new aiVector3D[theSubMesh.Positions.size()];
  261. memcpy(NewAiMesh->mVertices, &theSubMesh.Positions[0], theSubMesh.Positions.size()*sizeof(aiVector3D));
  262. NewAiMesh->mNumVertices=theSubMesh.Positions.size();
  263. //Normals
  264. NewAiMesh->mNormals=new aiVector3D[theSubMesh.Normals.size()];
  265. memcpy(NewAiMesh->mNormals, &theSubMesh.Normals[0], theSubMesh.Normals.size()*sizeof(aiVector3D));
  266. //Uvs
  267. if(0!=theSubMesh.NumUvs)
  268. {
  269. NewAiMesh->mNumUVComponents[0]=2;
  270. NewAiMesh->mTextureCoords[0]= new aiVector3D[theSubMesh.Uvs.size()];
  271. memcpy(NewAiMesh->mTextureCoords[0], &theSubMesh.Uvs[0], theSubMesh.Uvs.size()*sizeof(aiVector3D));
  272. }
  273. //---------------------------------------- Bones --------------------------------------------
  274. //Copy the weights in in Bone-Vertices Struktur
  275. //(we have them in a Vertex-Bones Struktur, this is much easier for making them unique, which is required by assimp
  276. vector< vector<aiVertexWeight> > aiWeights(theSubMesh.BonesUsed);//now the outer list are the bones, and the inner vector the vertices
  277. for(unsigned int VertexId=0; VertexId<theSubMesh.Weights.size(); ++VertexId)//iterate over all vertices
  278. {
  279. for(unsigned int BoneId=0; BoneId<theSubMesh.Weights[VertexId].size(); ++BoneId)//iterate over all bones
  280. {
  281. aiVertexWeight NewWeight;
  282. NewWeight.mVertexId=VertexId;//the current Vertex, we can't use the Id form the submehs weights, because they are bone id's
  283. NewWeight.mWeight=theSubMesh.Weights[VertexId][BoneId].Value;
  284. aiWeights[theSubMesh.Weights[VertexId][BoneId].BoneId].push_back(NewWeight);
  285. }
  286. }
  287. vector<aiBone*> aiBones;
  288. aiBones.reserve(theSubMesh.BonesUsed);//the vector might be smaller, because there might be empty bones (bones that are not attached to any vertex)
  289. //create all the bones and fill them with informations
  290. for(unsigned int i=0; i<theSubMesh.BonesUsed; ++i)
  291. {
  292. if(aiWeights[i].size()>0)
  293. {
  294. aiBone* NewBone=new aiBone();
  295. NewBone->mNumWeights=aiWeights[i].size();
  296. NewBone->mWeights=new aiVertexWeight[aiWeights[i].size()];
  297. memcpy(NewBone->mWeights, &(aiWeights[i][0]), sizeof(aiVertexWeight)*aiWeights[i].size());
  298. NewBone->mName=Bones[i].Name;//The bone list should be sorted after its ids, this was done in LoadSkeleton
  299. NewBone->mOffsetMatrix=aiMatrix4x4(Bones[i].WorldToBoneSpace).Inverse();//we suggest, that the mesh space is the world space!
  300. aiBones.push_back(NewBone);
  301. }
  302. }
  303. NewAiMesh->mNumBones=aiBones.size();
  304. NewAiMesh->mBones=new aiBone* [aiBones.size()];
  305. memcpy(NewAiMesh->mBones, &(aiBones[0]), aiBones.size()*sizeof(aiBone*));
  306. //______________________________________________________________________________________________________
  307. //Faces
  308. NewAiMesh->mFaces=new aiFace[theSubMesh.FaceList.size()];
  309. for(unsigned int i=0; i<theSubMesh.FaceList.size(); ++i)
  310. {
  311. NewAiMesh->mFaces[i].mNumIndices=3;
  312. NewAiMesh->mFaces[i].mIndices=new unsigned int[3];
  313. NewAiMesh->mFaces[i].mIndices[0]=theSubMesh.FaceList[i].VertexIndices[0];
  314. NewAiMesh->mFaces[i].mIndices[1]=theSubMesh.FaceList[i].VertexIndices[1];
  315. NewAiMesh->mFaces[i].mIndices[2]=theSubMesh.FaceList[i].VertexIndices[2];
  316. }
  317. NewAiMesh->mNumFaces=theSubMesh.FaceList.size();
  318. //Link the material:
  319. NewAiMesh->mMaterialIndex=theSubMesh.MaterialIndex;//the index is set by the function who called ReadSubMesh
  320. }
  321. aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName)
  322. {
  323. MaterialHelper *NewMaterial=new MaterialHelper();
  324. aiString ts(MaterialName.c_str());
  325. NewMaterial->AddProperty(&ts, AI_MATKEY_NAME);
  326. /*For bettetr understanding of the material parser, here is a material example file:
  327. material Sarg
  328. {
  329. receive_shadows on
  330. technique
  331. {
  332. pass
  333. {
  334. ambient 0.500000 0.500000 0.500000 1.000000
  335. diffuse 0.640000 0.640000 0.640000 1.000000
  336. specular 0.500000 0.500000 0.500000 1.000000 12.500000
  337. emissive 0.000000 0.000000 0.000000 1.000000
  338. texture_unit
  339. {
  340. texture SargTextur.tga
  341. tex_address_mode wrap
  342. filtering linear linear none
  343. }
  344. }
  345. }
  346. }
  347. */
  348. string MaterialFileName=m_CurrentFilename.substr(0, m_CurrentFilename.find('.'))+".material";
  349. DefaultLogger::get()->info(str(format("Trying to load %1%") % MaterialFileName));
  350. //Read the file into memory and put it in a stringstream
  351. stringstream ss;
  352. {// after this block, the temporarly loaded data will be released
  353. IOStream* MatFilePtr=m_CurrentIOHandler->Open(MaterialFileName);
  354. if(NULL==MatFilePtr)
  355. {
  356. MatFilePtr=m_CurrentIOHandler->Open(m_MaterialLibFilename);
  357. if(NULL==MatFilePtr)
  358. {
  359. DefaultLogger::get()->error(m_MaterialLibFilename+" and "+MaterialFileName + " could not be opned, Material will not be loaded!");
  360. return NewMaterial;
  361. }
  362. }
  363. scoped_ptr<IOStream> MaterialFile(MatFilePtr);
  364. vector<char> FileData(MaterialFile->FileSize());
  365. MaterialFile->Read(&FileData[0], MaterialFile->FileSize(), 1);
  366. BaseImporter::ConvertToUTF8(FileData);
  367. ss << &FileData[0];
  368. }
  369. string Line;
  370. ss >> Line;
  371. unsigned int Level=0;//Hierarchielevels in the material file, like { } blocks into another
  372. while(!ss.eof())
  373. {
  374. if(Line=="material")
  375. {
  376. ss >> Line;
  377. if(Line==MaterialName)//Load the next material
  378. {
  379. ss >> Line;
  380. if(Line!="{")
  381. throw new ImportErrorException("empty material!");
  382. while(Line!="}")//read until the end of the material
  383. {
  384. //Proceed to the first technique
  385. ss >> Line;
  386. if(Line=="technique")
  387. {
  388. ss >> Line;
  389. if(Line!="{")
  390. throw new ImportErrorException("empty technique!");
  391. while(Line!="}")//read until the end of the technique
  392. {
  393. ss >> Line;
  394. if(Line=="pass")
  395. {
  396. ss >> Line;
  397. if(Line!="{")
  398. throw new ImportErrorException("empty pass!");
  399. while(Line!="}")//read until the end of the pass
  400. {
  401. ss >> Line;
  402. if(Line=="ambient")
  403. {
  404. //read the ambient light values:
  405. }
  406. else if(Line=="diffuse")
  407. {
  408. }
  409. else if(Line=="specular")
  410. {
  411. }
  412. else if(Line=="emmisive")
  413. {
  414. }
  415. else if(Line=="texture_unit")
  416. {
  417. ss >> Line;
  418. if(Line!="{")
  419. throw new ImportErrorException("empty texture unit!");
  420. while(Line!="}")//read until the end of the texture_unit
  421. {
  422. ss >> Line;
  423. if(Line=="texture")
  424. {
  425. ss >> Line;
  426. aiString ts(Line.c_str());
  427. NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
  428. }
  429. }//end of texture unit
  430. }
  431. }
  432. }
  433. }//end of technique
  434. }
  435. DefaultLogger::get()->info(Line);
  436. //read informations from a custom material:
  437. if(Line=="set")
  438. {
  439. ss >> Line;
  440. if(Line=="$specular")//todo load this values:
  441. {
  442. }
  443. if(Line=="$diffuse")
  444. {
  445. }
  446. if(Line=="$ambient")
  447. {
  448. }
  449. if(Line=="$colormap")
  450. {
  451. ss >> Line;
  452. aiString ts(Line.c_str());
  453. NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
  454. }
  455. if(Line=="$normalmap")
  456. {
  457. ss >> Line;
  458. aiString ts(Line.c_str());
  459. NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
  460. }
  461. }
  462. }//end of material
  463. }
  464. else {} //this is the wrong material, proceed the file until we reach the next material
  465. }
  466. ss >> Line;
  467. }
  468. return NewMaterial;
  469. }
  470. void OgreImporter::LoadSkeleton(std::string FileName, vector<Bone> &Bones, vector<Animation> &Animations)
  471. {
  472. //most likely the skeleton file will only end with .skeleton
  473. //But this is a xml reader, so we need: .skeleton.xml
  474. FileName+=".xml";
  475. DefaultLogger::get()->debug(string("Loading Skeleton: ")+FileName);
  476. //Open the File:
  477. boost::scoped_ptr<IOStream> File(m_CurrentIOHandler->Open(FileName));
  478. if(NULL==File.get())
  479. throw new ImportErrorException("Failed to open skeleton file "+FileName+".");
  480. //Read the Mesh File:
  481. boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(File.get()));
  482. XmlReader* SkeletonFile = irr::io::createIrrXMLReader(mIOWrapper.get());
  483. if(!SkeletonFile)
  484. throw new ImportErrorException(string("Failed to create XML Reader for ")+FileName);
  485. //Quick note: Whoever read this should know this one thing: irrXml fucking sucks!!!
  486. XmlRead(SkeletonFile);
  487. if(string("skeleton")!=SkeletonFile->getNodeName())
  488. throw new ImportErrorException("No <skeleton> node in SkeletonFile: "+FileName);
  489. //------------------------------------load bones-----------------------------------------
  490. XmlRead(SkeletonFile);
  491. if(string("bones")!=SkeletonFile->getNodeName())
  492. throw new ImportErrorException("No bones node in skeleton "+FileName);
  493. XmlRead(SkeletonFile);
  494. while(string("bone")==SkeletonFile->getNodeName())
  495. {
  496. //TODO: Maybe we can have bone ids for the errrors, but normaly, they should never appera, so what....
  497. //read a new bone:
  498. Bone NewBone;
  499. NewBone.Id=GetAttribute<int>(SkeletonFile, "id");
  500. NewBone.Name=GetAttribute<string>(SkeletonFile, "name");
  501. //load the position:
  502. XmlRead(SkeletonFile);
  503. if(string("position")!=SkeletonFile->getNodeName())
  504. throw new ImportErrorException("Position is not first node in Bone!");
  505. NewBone.Position.x=GetAttribute<float>(SkeletonFile, "x");
  506. NewBone.Position.y=GetAttribute<float>(SkeletonFile, "y");
  507. NewBone.Position.z=GetAttribute<float>(SkeletonFile, "z");
  508. //Rotation:
  509. XmlRead(SkeletonFile);
  510. if(string("rotation")!=SkeletonFile->getNodeName())
  511. throw new ImportErrorException("Rotation is not the second node in Bone!");
  512. NewBone.RotationAngle=GetAttribute<float>(SkeletonFile, "angle");
  513. XmlRead(SkeletonFile);
  514. if(string("axis")!=SkeletonFile->getNodeName())
  515. throw new ImportErrorException("No axis specified for bone rotation!");
  516. NewBone.RotationAxis.x=GetAttribute<float>(SkeletonFile, "x");
  517. NewBone.RotationAxis.y=GetAttribute<float>(SkeletonFile, "y");
  518. NewBone.RotationAxis.z=GetAttribute<float>(SkeletonFile, "z");
  519. //append the newly loaded bone to the bone list
  520. Bones.push_back(NewBone);
  521. //Proceed to the next bone:
  522. XmlRead(SkeletonFile);
  523. }
  524. //The bones in the file a not neccesarly ordered by there id's so we do it now:
  525. std::sort(Bones.begin(), Bones.end());
  526. //now the id of each bone should be equal to its position in the vector:
  527. //so we do a simple check:
  528. {
  529. bool IdsOk=true;
  530. for(int i=0; i<static_cast<signed int>(Bones.size()); ++i)//i is signed, because all Id's are also signed!
  531. {
  532. if(Bones[i].Id!=i)
  533. IdsOk=false;
  534. }
  535. if(!IdsOk)
  536. throw new ImportErrorException("Bone Ids are not valid!"+FileName);
  537. }
  538. DefaultLogger::get()->debug(str(format("Number of bones: %1%") % Bones.size()));
  539. //________________________________________________________________________________
  540. //----------------------------load bonehierarchy--------------------------------
  541. if(string("bonehierarchy")!=SkeletonFile->getNodeName())
  542. throw new ImportErrorException("no bonehierarchy node in "+FileName);
  543. DefaultLogger::get()->debug("loading bonehierarchy...");
  544. XmlRead(SkeletonFile);
  545. while(string("boneparent")==SkeletonFile->getNodeName())
  546. {
  547. string Child, Parent;
  548. Child=GetAttribute<string>(SkeletonFile, "bone");
  549. Parent=GetAttribute<string>(SkeletonFile, "parent");
  550. unsigned int ChildId, ParentId;
  551. ChildId=find(Bones.begin(), Bones.end(), Child)->Id;
  552. ParentId=find(Bones.begin(), Bones.end(), Parent)->Id;
  553. Bones[ChildId].ParentId=ParentId;
  554. Bones[ParentId].Children.push_back(ChildId);
  555. XmlRead(SkeletonFile);//i once forget this line, which led to an endless loop, did i mentioned, that irrxml sucks??
  556. }
  557. //_____________________________________________________________________________
  558. //--------- Calculate the WorldToBoneSpace Matrix recursivly for all bones: ------------------
  559. BOOST_FOREACH(Bone theBone, Bones)
  560. {
  561. if(-1==theBone.ParentId) //the bone is a root bone
  562. {
  563. theBone.CalculateWorldToBoneSpaceMatrix(Bones);
  564. }
  565. }
  566. //_______________________________________________________________________
  567. //---------------------------load animations-----------------------------
  568. if(string("animations")==SkeletonFile->getNodeName())//animations are optional values
  569. {
  570. DefaultLogger::get()->debug("Loading Animations");
  571. XmlRead(SkeletonFile);
  572. while(string("animation")==SkeletonFile->getNodeName())
  573. {
  574. Animation NewAnimation;
  575. NewAnimation.Name=GetAttribute<string>(SkeletonFile, "name");
  576. NewAnimation.Length=GetAttribute<float>(SkeletonFile, "length");
  577. //Load all Tracks
  578. XmlRead(SkeletonFile);
  579. if(string("tracks")!=SkeletonFile->getNodeName())
  580. throw new ImportErrorException("no tracks node in animation");
  581. XmlRead(SkeletonFile);
  582. while(string("track")==SkeletonFile->getNodeName())
  583. {
  584. Track NewTrack;
  585. NewTrack.BoneName=GetAttribute<string>(SkeletonFile, "bone");
  586. //Load all keyframes;
  587. XmlRead(SkeletonFile);
  588. if(string("keyframes")!=SkeletonFile->getNodeName())
  589. throw new ImportErrorException("no keyframes node!");
  590. XmlRead(SkeletonFile);
  591. while(string("keyframe")==SkeletonFile->getNodeName())
  592. {
  593. Keyframe NewKeyframe;
  594. NewKeyframe.Time=GetAttribute<float>(SkeletonFile, "time");
  595. //Position:
  596. XmlRead(SkeletonFile);
  597. if(string("translate")!=SkeletonFile->getNodeName())
  598. throw new ImportErrorException("translate node not first in keyframe");
  599. NewKeyframe.Position.x=GetAttribute<float>(SkeletonFile, "x");
  600. NewKeyframe.Position.y=GetAttribute<float>(SkeletonFile, "y");
  601. NewKeyframe.Position.z=GetAttribute<float>(SkeletonFile, "z");
  602. //Rotation:
  603. XmlRead(SkeletonFile);
  604. if(string("rotate")!=SkeletonFile->getNodeName())
  605. throw new ImportErrorException("rotate is not second node in keyframe");
  606. float RotationAngle=GetAttribute<float>(SkeletonFile, "angle");
  607. aiVector3D RotationAxis;
  608. XmlRead(SkeletonFile);
  609. if(string("axis")!=SkeletonFile->getNodeName())
  610. throw new ImportErrorException("No axis for keyframe rotation!");
  611. RotationAxis.x=GetAttribute<float>(SkeletonFile, "x");
  612. RotationAxis.y=GetAttribute<float>(SkeletonFile, "y");
  613. RotationAxis.z=GetAttribute<float>(SkeletonFile, "z");
  614. NewKeyframe.Rotation=aiQuaternion(RotationAxis, RotationAngle);
  615. //Scaling:
  616. XmlRead(SkeletonFile);
  617. if(string("scale")!=SkeletonFile->getNodeName())
  618. throw new ImportErrorException("no scalling key in keyframe!");
  619. NewKeyframe.Scaling.x=GetAttribute<float>(SkeletonFile, "x");
  620. NewKeyframe.Scaling.y=GetAttribute<float>(SkeletonFile, "y");
  621. NewKeyframe.Scaling.z=GetAttribute<float>(SkeletonFile, "z");
  622. NewTrack.Keyframes.push_back(NewKeyframe);
  623. XmlRead(SkeletonFile);
  624. }
  625. NewAnimation.Tracks.push_back(NewTrack);
  626. }
  627. Animations.push_back(NewAnimation);
  628. }
  629. }
  630. //_____________________________________________________________________________
  631. }
  632. void OgreImporter::CreateAssimpSkeleton(const std::vector<Bone> &Bones, const std::vector<Animation> &Animations)
  633. {
  634. //-----------------skeleton is completly loaded, now but it in the assimp scene:-------------------------------
  635. if(!m_CurrentScene->mRootNode)
  636. throw new ImportErrorException("No root node exists!!");
  637. if(0!=m_CurrentScene->mRootNode->mNumChildren)
  638. throw new ImportErrorException("Root Node already has childnodes!");
  639. //--------------Createt the assimp bone hierarchy-----------------
  640. DefaultLogger::get()->debug("Root Bones");
  641. vector<aiNode*> RootBoneNodes;
  642. BOOST_FOREACH(Bone theBone, Bones)
  643. {
  644. if(-1==theBone.ParentId) //the bone is a root bone
  645. {
  646. DefaultLogger::get()->debug(theBone.Name);
  647. RootBoneNodes.push_back(CreateAiNodeFromBone(theBone.Id, Bones, m_CurrentScene->mRootNode));
  648. }
  649. }
  650. m_CurrentScene->mRootNode->mNumChildren=RootBoneNodes.size();
  651. m_CurrentScene->mRootNode->mChildren=new aiNode*[RootBoneNodes.size()];
  652. memcpy(m_CurrentScene->mRootNode->mChildren, &RootBoneNodes[0], sizeof(aiNode*)*RootBoneNodes.size());
  653. //_______________________________________________________________
  654. //-----------------Create the Assimp Animations --------------------
  655. 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
  656. {
  657. m_CurrentScene->mNumAnimations=Animations.size();
  658. m_CurrentScene->mAnimations=new aiAnimation*[Animations.size()];
  659. for(unsigned int i=0; i<Animations.size(); ++i)//create all animations
  660. {
  661. aiAnimation* NewAnimation=new aiAnimation();
  662. NewAnimation->mName=Animations[i].Name;
  663. NewAnimation->mDuration=Animations[i].Length;
  664. NewAnimation->mTicksPerSecond=1.0f;
  665. //Create all tracks in this animation
  666. NewAnimation->mNumChannels=Animations[i].Tracks.size();
  667. NewAnimation->mChannels=new aiNodeAnim*[Animations[i].Tracks.size()];
  668. for(unsigned int j=0; j<Animations[i].Tracks.size(); ++j)
  669. {
  670. aiNodeAnim* NewNodeAnim=new aiNodeAnim();
  671. NewNodeAnim->mNodeName=Animations[i].Tracks[j].BoneName;
  672. //Create the keyframe arrays...
  673. unsigned int KeyframeCount=Animations[i].Tracks[j].Keyframes.size();
  674. NewNodeAnim->mNumPositionKeys=KeyframeCount;
  675. NewNodeAnim->mPositionKeys=new aiVectorKey[KeyframeCount];
  676. NewNodeAnim->mNumRotationKeys=KeyframeCount;
  677. NewNodeAnim->mRotationKeys=new aiQuatKey[KeyframeCount];
  678. NewNodeAnim->mNumScalingKeys=KeyframeCount;
  679. NewNodeAnim->mScalingKeys=new aiVectorKey[KeyframeCount];
  680. //...and fill them
  681. for(unsigned int k=0; k<KeyframeCount; ++k)
  682. {
  683. NewNodeAnim->mPositionKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  684. NewNodeAnim->mPositionKeys[k].mValue=Animations[i].Tracks[j].Keyframes[k].Position;
  685. NewNodeAnim->mRotationKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  686. NewNodeAnim->mRotationKeys[k].mValue=Animations[i].Tracks[j].Keyframes[k].Rotation;
  687. NewNodeAnim->mScalingKeys[k].mTime=Animations[i].Tracks[j].Keyframes[k].Time;
  688. NewNodeAnim->mScalingKeys[k].mValue=Animations[i].Tracks[j].Keyframes[k].Scaling;
  689. }
  690. NewAnimation->mChannels[j]=NewNodeAnim;
  691. }
  692. m_CurrentScene->mAnimations[i]=NewAnimation;
  693. }
  694. }
  695. //__________________________________________________________________
  696. }
  697. aiNode* OgreImporter::CreateAiNodeFromBone(int BoneId, const std::vector<Bone> &Bones, aiNode* ParentNode)
  698. {
  699. //----Create the node for this bone and set its values-----
  700. aiNode* NewNode=new aiNode(Bones[BoneId].Name);
  701. NewNode->mParent=ParentNode;
  702. aiMatrix4x4 t0,t1;
  703. //create a matrix from the transformation values of the ogre bone
  704. NewNode->mTransformation=aiMatrix4x4::Translation(Bones[BoneId].Position, t0)
  705. *
  706. aiMatrix4x4::Rotation(Bones[BoneId].RotationAngle, Bones[BoneId].RotationAxis, t1)
  707. ;
  708. //__________________________________________________________
  709. //---------- recursivly create all children Nodes: ----------
  710. NewNode->mNumChildren=Bones[BoneId].Children.size();
  711. NewNode->mChildren=new aiNode*[Bones[BoneId].Children.size()];
  712. for(unsigned int i=0; i<Bones[BoneId].Children.size(); ++i)
  713. {
  714. NewNode->mChildren[i]=CreateAiNodeFromBone(Bones[BoneId].Children[i], Bones, NewNode);
  715. }
  716. //____________________________________________________
  717. return NewNode;
  718. }
  719. void Bone::CalculateWorldToBoneSpaceMatrix(vector<Bone> &Bones)
  720. {
  721. //Calculate the matrix for this bone:
  722. aiMatrix4x4 t0,t1;
  723. if(-1==ParentId)
  724. {
  725. WorldToBoneSpace= aiMatrix4x4::Translation(Position, t0)
  726. * aiMatrix4x4::Rotation(RotationAngle, RotationAxis, t1)
  727. ;
  728. }
  729. else
  730. {
  731. WorldToBoneSpace= Bones[ParentId].WorldToBoneSpace
  732. * aiMatrix4x4::Translation(Position, t0)
  733. * aiMatrix4x4::Rotation(RotationAngle, RotationAxis, t1)
  734. ;
  735. }
  736. //and recursivly for all children:
  737. BOOST_FOREACH(int theChildren, Children)
  738. {
  739. Bones[theChildren].CalculateWorldToBoneSpaceMatrix(Bones);
  740. }
  741. }
  742. }//namespace Ogre
  743. }//namespace Assimp
  744. #endif // !! ASSIMP_BUILD_NO_OGRE_IMPORTER