ModelLoader.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include "ModelLoader.h"
  2. ModelLoader::ModelLoader()
  3. {
  4. }
  5. ModelLoader::~ModelLoader()
  6. {
  7. }
  8. bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename)
  9. {
  10. Assimp::Importer importer;
  11. const aiScene* pScene = importer.ReadFile(filename,
  12. aiProcess_Triangulate |
  13. aiProcess_ConvertToLeftHanded);
  14. if (pScene == NULL)
  15. return false;
  16. this->directory = filename.substr(0, filename.find_last_of('/'));
  17. this->dev = dev;
  18. this->hwnd = hwnd;
  19. processNode(pScene->mRootNode, pScene);
  20. return true;
  21. }
  22. void ModelLoader::Draw(ID3D11DeviceContext * devcon)
  23. {
  24. for (int i = 0; i < meshes.size(); i++)
  25. {
  26. meshes[i].Draw(devcon);
  27. }
  28. }
  29. string textype;
  30. Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene)
  31. {
  32. // Data to fill
  33. vector<VERTEX> vertices;
  34. vector<UINT> indices;
  35. vector<Texture> textures;
  36. if (mesh->mMaterialIndex >= 0)
  37. {
  38. aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
  39. if (textype.empty()) textype = determineTextureType(scene, mat);
  40. }
  41. // Walk through each of the mesh's vertices
  42. for (UINT i = 0; i < mesh->mNumVertices; i++)
  43. {
  44. VERTEX vertex;
  45. vertex.X = mesh->mVertices[i].x;
  46. vertex.Y = mesh->mVertices[i].y;
  47. vertex.Z = mesh->mVertices[i].z;
  48. if (mesh->mTextureCoords[0])
  49. {
  50. vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x;
  51. vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y;
  52. }
  53. vertices.push_back(vertex);
  54. }
  55. for (UINT i = 0; i < mesh->mNumFaces; i++)
  56. {
  57. aiFace face = mesh->mFaces[i];
  58. for (UINT j = 0; j < face.mNumIndices; j++)
  59. indices.push_back(face.mIndices[j]);
  60. }
  61. if (mesh->mMaterialIndex >= 0)
  62. {
  63. aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
  64. vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
  65. textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
  66. }
  67. return Mesh(dev, vertices, indices, textures);
  68. }
  69. vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene)
  70. {
  71. vector<Texture> textures;
  72. for (UINT i = 0; i < mat->GetTextureCount(type); i++)
  73. {
  74. aiString str;
  75. mat->GetTexture(type, i, &str);
  76. // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
  77. bool skip = false;
  78. for (UINT j = 0; j < textures_loaded.size(); j++)
  79. {
  80. if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0)
  81. {
  82. textures.push_back(textures_loaded[j]);
  83. skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)
  84. break;
  85. }
  86. }
  87. if (!skip)
  88. { // If texture hasn't been loaded already, load it
  89. HRESULT hr;
  90. Texture texture;
  91. if (textype == "embedded compressed texture")
  92. {
  93. int textureindex = getTextureIndex(&str);
  94. texture.texture = getTextureFromModel(scene, textureindex);
  95. }
  96. else
  97. {
  98. string filename = string(str.C_Str());
  99. filename = directory + '/' + filename;
  100. wstring filenamews = wstring(filename.begin(), filename.end());
  101. hr = CreateWICTextureFromFile(dev, devcon, filenamews.c_str(), nullptr, &texture.texture);
  102. if (FAILED(hr))
  103. MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK);
  104. }
  105. texture.type = typeName;
  106. texture.path = str.C_Str();
  107. textures.push_back(texture);
  108. this->textures_loaded.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
  109. }
  110. }
  111. return textures;
  112. }
  113. void ModelLoader::Close()
  114. {
  115. for (int i = 0; i < meshes.size(); i++)
  116. {
  117. meshes[i].Close();
  118. }
  119. dev->Release();
  120. }
  121. void ModelLoader::processNode(aiNode * node, const aiScene * scene)
  122. {
  123. for (UINT i = 0; i < node->mNumMeshes; i++)
  124. {
  125. aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
  126. meshes.push_back(this->processMesh(mesh, scene));
  127. }
  128. for (UINT i = 0; i < node->mNumChildren; i++)
  129. {
  130. this->processNode(node->mChildren[i], scene);
  131. }
  132. }
  133. string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat)
  134. {
  135. aiString textypeStr;
  136. mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
  137. string textypeteststr = textypeStr.C_Str();
  138. if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5")
  139. {
  140. if (scene->mTextures[0]->mHeight == 0)
  141. {
  142. return "embedded compressed texture";
  143. }
  144. else
  145. {
  146. return "embedded non-compressed texture";
  147. }
  148. }
  149. if (textypeteststr.find('.') != string::npos)
  150. {
  151. return "textures are on disk";
  152. }
  153. }
  154. int ModelLoader::getTextureIndex(aiString * str)
  155. {
  156. string tistr;
  157. tistr = str->C_Str();
  158. tistr = tistr.substr(1);
  159. return stoi(tistr);
  160. }
  161. ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex)
  162. {
  163. HRESULT hr;
  164. ID3D11ShaderResourceView *texture;
  165. int* size = reinterpret_cast<int*>(&scene->mTextures[textureindex]->mWidth);
  166. hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast<unsigned char*>(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture);
  167. if (FAILED(hr))
  168. MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);
  169. return texture;
  170. }