MD3Loader.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /** @file Implementation of the MD3 importer class */
  2. #include "MD3Loader.h"
  3. #include "MaterialSystem.h"
  4. #include "../include/IOStream.h"
  5. #include "../include/IOSystem.h"
  6. #include "../include/aiMesh.h"
  7. #include "../include/aiScene.h"
  8. #include "../include/aiAssert.h"
  9. #include <boost/scoped_ptr.hpp>
  10. using namespace Assimp;
  11. // ------------------------------------------------------------------------------------------------
  12. // Constructor to be privately used by Importer
  13. MD3Importer::MD3Importer()
  14. {
  15. }
  16. // ------------------------------------------------------------------------------------------------
  17. // Destructor, private as well
  18. MD3Importer::~MD3Importer()
  19. {
  20. }
  21. // ------------------------------------------------------------------------------------------------
  22. // Returns whether the class can handle the format of the given file.
  23. bool MD3Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
  24. {
  25. // simple check of file extension is enough for the moment
  26. std::string::size_type pos = pFile.find_last_of('.');
  27. // no file extension - can't read
  28. if( pos == std::string::npos)
  29. return false;
  30. std::string extension = pFile.substr( pos);
  31. // not brilliant but working ;-)
  32. if( extension == ".md3" || extension == ".MD3" ||
  33. extension == ".mD3" || extension == ".Md3")
  34. return true;
  35. return false;
  36. }
  37. // ------------------------------------------------------------------------------------------------
  38. // Imports the given file into the given scene structure.
  39. void MD3Importer::InternReadFile(
  40. const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
  41. {
  42. boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
  43. // Check whether we can read from the file
  44. if( file.get() == NULL)
  45. {
  46. throw new ImportErrorException( "Failed to open md3 file " + pFile + ".");
  47. }
  48. // check whether the md3 file is large enough to contain
  49. // at least the file header
  50. size_t fileSize = file->FileSize();
  51. if( fileSize < sizeof(MD3::Header))
  52. {
  53. throw new ImportErrorException( ".md3 File is too small.");
  54. }
  55. // allocate storage and copy the contents of the file to a memory buffer
  56. this->mBuffer = new unsigned char[fileSize];
  57. file->Read( (void*)mBuffer, 1, fileSize);
  58. this->m_pcHeader = (const MD3::Header*)this->mBuffer;
  59. // check magic number
  60. if (this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_BE &&
  61. this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_LE)
  62. {
  63. throw new ImportErrorException( "Invalid md3 file: Magic bytes not found");
  64. }
  65. // check file format version
  66. if (this->m_pcHeader->VERSION > 15)
  67. {
  68. throw new ImportErrorException( "Unsupported md3 file version");
  69. }
  70. // check some values whether they are valid
  71. if (0 == this->m_pcHeader->NUM_FRAMES)
  72. {
  73. throw new ImportErrorException( "Invalid md3 file: NUM_FRAMES is 0");
  74. }
  75. if (0 == this->m_pcHeader->NUM_SURFACES)
  76. {
  77. throw new ImportErrorException( "Invalid md3 file: NUM_SURFACES is 0");
  78. }
  79. if (this->m_pcHeader->OFS_EOF > (int32_t)fileSize)
  80. {
  81. throw new ImportErrorException( "Invalid md3 file: File is too small");
  82. }
  83. // now navigate to the list of surfaces
  84. const MD3::Surface* pcSurfaces = (const MD3::Surface*)
  85. (this->mBuffer + this->m_pcHeader->OFS_SURFACES);
  86. // allocate output storage
  87. pScene->mNumMeshes = this->m_pcHeader->NUM_SURFACES;
  88. pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
  89. pScene->mNumMaterials = this->m_pcHeader->NUM_SURFACES;
  90. pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];
  91. unsigned int iNum = this->m_pcHeader->NUM_SURFACES;
  92. unsigned int iNumMaterials = 0;
  93. unsigned int iDefaultMatIndex = 0xFFFFFFFF;
  94. while (iNum-- > 0)
  95. {
  96. // navigate to the vertex list of the surface
  97. const MD3::Vertex* pcVertices = (const MD3::Vertex*)
  98. (((unsigned char*)pcSurfaces) + pcSurfaces->OFS_XYZNORMAL);
  99. // navigate to the triangle list of the surface
  100. const MD3::Triangle* pcTriangles = (const MD3::Triangle*)
  101. (((unsigned char*)pcSurfaces) + pcSurfaces->OFS_TRIANGLES);
  102. // navigate to the texture coordinate list of the surface
  103. const MD3::TexCoord* pcUVs = (const MD3::TexCoord*)
  104. (((unsigned char*)pcSurfaces) + pcSurfaces->OFS_ST);
  105. // navigate to the shader list of the surface
  106. const MD3::Shader* pcShaders = (const MD3::Shader*)
  107. (((unsigned char*)pcSurfaces) + pcSurfaces->OFS_SHADERS);
  108. // if the submesh is empty ignore it
  109. if (0 == pcSurfaces->NUM_VERTICES || 0 == pcSurfaces->NUM_TRIANGLES)
  110. {
  111. pcSurfaces = (const MD3::Surface*)(((unsigned char*)pcSurfaces) + pcSurfaces->OFS_END);
  112. pScene->mNumMeshes--;
  113. continue;
  114. }
  115. // allocate the output mesh
  116. pScene->mMeshes[iNum] = new aiMesh();
  117. aiMesh* pcMesh = pScene->mMeshes[iNum];
  118. pcMesh->mNumVertices = pcSurfaces->NUM_VERTICES;
  119. pcMesh->mNumBones = 0;
  120. pcMesh->mColors[0] = pcMesh->mColors[1] = pcMesh->mColors[2] = pcMesh->mColors[3] = NULL;
  121. pcMesh->mNumFaces = pcSurfaces->NUM_TRIANGLES;
  122. pcMesh->mFaces = new aiFace[pcSurfaces->NUM_TRIANGLES];
  123. pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
  124. pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
  125. pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
  126. pcMesh->mTextureCoords[1] = pcMesh->mTextureCoords[2] = pcMesh->mTextureCoords[3] = NULL;
  127. pcMesh->mNumUVComponents[0] = 2;
  128. // fill in all vertices and normals
  129. // fill in all texture coordinates
  130. for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_VERTICES;++i)
  131. {
  132. pcMesh->mVertices[i].x = pcVertices->X;
  133. pcMesh->mVertices[i].y = pcVertices->Y;
  134. pcMesh->mVertices[i].z = -1.0f*pcVertices->Z;
  135. // convert the normal vector to uncompressed float3 format
  136. LatLngNormalToVec3(pcVertices->NORMAL,(float*)&pcMesh->mNormals[i]);
  137. // read texture coordinates
  138. pcMesh->mTextureCoords[0][i].x = pcUVs->U;
  139. pcMesh->mTextureCoords[0][i].y = 1.0f - pcUVs->V;
  140. pcVertices++;
  141. pcUVs++;
  142. }
  143. // fill in all triangles
  144. for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++i)
  145. {
  146. pcMesh->mFaces[i].mIndices = new unsigned int[3];
  147. pcMesh->mFaces[i].mNumIndices = 3;
  148. pcMesh->mFaces[i].mIndices[0] = pcTriangles->INDEXES[0];
  149. pcMesh->mFaces[i].mIndices[1] = pcTriangles->INDEXES[1];
  150. pcMesh->mFaces[i].mIndices[2] = pcTriangles->INDEXES[2];
  151. pcTriangles++;
  152. }
  153. // get the first shader (= texture?) assigned to the surface
  154. if (0 != pcSurfaces->NUM_SHADER)
  155. {
  156. // make a relative path.
  157. // if the MD3's internal path itself and the given path are using
  158. // the same directory remove it
  159. const char* szEndDir1 = strrchr((const char*)this->m_pcHeader->NAME,'\\');
  160. if (!szEndDir1)szEndDir1 = strrchr((const char*)this->m_pcHeader->NAME,'/');
  161. const char* szEndDir2 = strrchr((const char*)pcShaders->NAME,'\\');
  162. if (!szEndDir2)szEndDir2 = strrchr((const char*)pcShaders->NAME,'/');
  163. if (szEndDir1 && szEndDir2)
  164. {
  165. // both of them are valid
  166. const unsigned int iLen1 = (unsigned int)(szEndDir1 - (const char*)this->m_pcHeader->NAME);
  167. const unsigned int iLen2 = std::min (iLen1, (unsigned int)(szEndDir2 - (const char*)pcShaders->NAME) );
  168. bool bSuccess = true;
  169. for (unsigned int a = 0; a < iLen2;++a)
  170. {
  171. char sz = tolower ( pcShaders->NAME[a] );
  172. char sz2 = tolower ( this->m_pcHeader->NAME[a] );
  173. if (sz != sz2)
  174. {
  175. bSuccess = false;
  176. break;
  177. }
  178. }
  179. if (bSuccess)
  180. {
  181. // use the file name only
  182. szEndDir2++;
  183. }
  184. else
  185. {
  186. // use the full path
  187. szEndDir2 = (const char*)pcShaders->NAME;
  188. }
  189. }
  190. // now try to find out whether we have this shader already
  191. bool bHave = false;
  192. for (unsigned int p = 0; p < iNumMaterials;++p)
  193. {
  194. if (iDefaultMatIndex == p)continue;
  195. aiString szOut;
  196. if(AI_SUCCESS == aiGetMaterialString ( (aiMaterial*)pScene->mMaterials[p],
  197. AI_MATKEY_TEXBLEND_DIFFUSE(0),&szOut))
  198. {
  199. if (0 == ASSIMP_stricmp(szOut.data,szEndDir2))
  200. {
  201. // equal. reuse this material (texture)
  202. bHave = true;
  203. pcMesh->mMaterialIndex = p;
  204. break;
  205. }
  206. }
  207. }
  208. if (!bHave)
  209. {
  210. MaterialHelper* pcHelper = new MaterialHelper();
  211. aiString szString;
  212. const size_t iLen = strlen(szEndDir2);
  213. memcpy(szString.data,szEndDir2,iLen+1);
  214. szString.length = iLen-1;
  215. pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
  216. int iMode = (int)aiShadingMode_Gouraud;
  217. pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  218. aiColor3D clr;
  219. clr.b = clr.g = clr.r = 1.0f;
  220. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  221. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  222. clr.b = clr.g = clr.r = 0.05f;
  223. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  224. pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper;
  225. pcMesh->mMaterialIndex = iNumMaterials++;
  226. }
  227. }
  228. else
  229. {
  230. if (0xFFFFFFFF != iDefaultMatIndex)
  231. {
  232. pcMesh->mMaterialIndex = iDefaultMatIndex;
  233. }
  234. else
  235. {
  236. MaterialHelper* pcHelper = new MaterialHelper();
  237. // fill in a default material
  238. int iMode = (int)aiShadingMode_Gouraud;
  239. pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
  240. aiColor3D clr;
  241. clr.b = clr.g = clr.r = 0.6f;
  242. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
  243. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
  244. clr.b = clr.g = clr.r = 0.05f;
  245. pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
  246. pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper;
  247. pcMesh->mMaterialIndex = iNumMaterials++;
  248. }
  249. }
  250. pcSurfaces = (const MD3::Surface*)(((unsigned char*)pcSurfaces) + pcSurfaces->OFS_END);
  251. }
  252. if (0 == pScene->mNumMeshes)
  253. {
  254. // cleanup before returning
  255. delete pScene;
  256. throw new ImportErrorException( "Invalid md3 file: File contains no valid mesh");
  257. }
  258. pScene->mNumMaterials = iNumMaterials;
  259. // now we need to generate an empty node graph
  260. pScene->mRootNode = new aiNode();
  261. pScene->mRootNode->mNumChildren = pScene->mNumMeshes;
  262. pScene->mRootNode->mChildren = new aiNode*[pScene->mNumMeshes];
  263. for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
  264. {
  265. pScene->mRootNode->mChildren[i] = new aiNode();
  266. pScene->mRootNode->mChildren[i]->mParent = pScene->mRootNode;
  267. pScene->mRootNode->mChildren[i]->mNumMeshes = 1;
  268. pScene->mRootNode->mChildren[i]->mMeshes = new unsigned int[1];
  269. pScene->mRootNode->mChildren[i]->mMeshes[0] = i;
  270. }
  271. delete[] this->mBuffer;
  272. return;
  273. }