ModelLoader.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #include "ModelLoader.h"
  2. ModelLoader::ModelLoader() :
  3. dev_(nullptr),
  4. devcon_(nullptr),
  5. meshes_(),
  6. directory_(),
  7. textures_loaded_(),
  8. hwnd_(nullptr) {
  9. // empty
  10. }
  11. ModelLoader::~ModelLoader() {
  12. // empty
  13. }
  14. bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) {
  15. Assimp::Importer importer;
  16. const aiScene* pScene = importer.ReadFile(filename,
  17. aiProcess_Triangulate |
  18. aiProcess_ConvertToLeftHanded);
  19. if (pScene == nullptr)
  20. return false;
  21. this->directory_ = filename.substr(0, filename.find_last_of("/\\"));
  22. this->dev_ = dev;
  23. this->devcon_ = devcon;
  24. this->hwnd_ = hwnd;
  25. processNode(pScene->mRootNode, pScene);
  26. return true;
  27. }
  28. void ModelLoader::Draw(ID3D11DeviceContext * devcon) {
  29. for (size_t i = 0; i < meshes_.size(); ++i ) {
  30. meshes_[i].Draw(devcon);
  31. }
  32. }
  33. Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) {
  34. // Data to fill
  35. std::vector<VERTEX> vertices;
  36. std::vector<UINT> indices;
  37. std::vector<Texture> textures;
  38. // Walk through each of the mesh's vertices
  39. for (UINT i = 0; i < mesh->mNumVertices; i++) {
  40. VERTEX vertex;
  41. vertex.X = mesh->mVertices[i].x;
  42. vertex.Y = mesh->mVertices[i].y;
  43. vertex.Z = mesh->mVertices[i].z;
  44. if (mesh->mTextureCoords[0]) {
  45. vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x;
  46. vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y;
  47. }
  48. vertices.push_back(vertex);
  49. }
  50. for (UINT i = 0; i < mesh->mNumFaces; i++) {
  51. aiFace face = mesh->mFaces[i];
  52. for (UINT j = 0; j < face.mNumIndices; j++)
  53. indices.push_back(face.mIndices[j]);
  54. }
  55. if (mesh->mMaterialIndex >= 0) {
  56. aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
  57. std::vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
  58. textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
  59. }
  60. return Mesh(dev_, vertices, indices, textures);
  61. }
  62. std::vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, std::string typeName, const aiScene * scene) {
  63. std::vector<Texture> textures;
  64. for (UINT i = 0; i < mat->GetTextureCount(type); i++) {
  65. aiString str;
  66. mat->GetTexture(type, i, &str);
  67. // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
  68. bool skip = false;
  69. for (UINT j = 0; j < textures_loaded_.size(); j++) {
  70. if (std::strcmp(textures_loaded_[j].path.c_str(), str.C_Str()) == 0) {
  71. textures.push_back(textures_loaded_[j]);
  72. skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)
  73. break;
  74. }
  75. }
  76. if (!skip) { // If texture hasn't been loaded already, load it
  77. HRESULT hr;
  78. Texture texture;
  79. const aiTexture* embeddedTexture = scene->GetEmbeddedTexture(str.C_Str());
  80. if (embeddedTexture != nullptr) {
  81. texture.texture = loadEmbeddedTexture(embeddedTexture);
  82. } else {
  83. std::string filename = std::string(str.C_Str());
  84. filename = directory_ + '/' + filename;
  85. std::wstring filenamews = std::wstring(filename.begin(), filename.end());
  86. hr = CreateWICTextureFromFile(dev_, devcon_, filenamews.c_str(), nullptr, &texture.texture);
  87. if (FAILED(hr))
  88. MessageBox(hwnd_, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK);
  89. }
  90. texture.type = typeName;
  91. texture.path = str.C_Str();
  92. textures.push_back(texture);
  93. this->textures_loaded_.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
  94. }
  95. }
  96. return textures;
  97. }
  98. void ModelLoader::Close() {
  99. for (auto& t : textures_loaded_)
  100. t.Release();
  101. for (size_t i = 0; i < meshes_.size(); i++) {
  102. meshes_[i].Close();
  103. }
  104. }
  105. void ModelLoader::processNode(aiNode * node, const aiScene * scene) {
  106. for (UINT i = 0; i < node->mNumMeshes; i++) {
  107. aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
  108. meshes_.push_back(this->processMesh(mesh, scene));
  109. }
  110. for (UINT i = 0; i < node->mNumChildren; i++) {
  111. this->processNode(node->mChildren[i], scene);
  112. }
  113. }
  114. ID3D11ShaderResourceView * ModelLoader::loadEmbeddedTexture(const aiTexture* embeddedTexture) {
  115. HRESULT hr;
  116. ID3D11ShaderResourceView *texture = nullptr;
  117. if (embeddedTexture->mHeight != 0) {
  118. // Load an uncompressed ARGB8888 embedded texture
  119. D3D11_TEXTURE2D_DESC desc;
  120. desc.Width = embeddedTexture->mWidth;
  121. desc.Height = embeddedTexture->mHeight;
  122. desc.MipLevels = 1;
  123. desc.ArraySize = 1;
  124. desc.SampleDesc.Count = 1;
  125. desc.SampleDesc.Quality = 0;
  126. desc.Usage = D3D11_USAGE_DEFAULT;
  127. desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  128. desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
  129. desc.CPUAccessFlags = 0;
  130. desc.MiscFlags = 0;
  131. D3D11_SUBRESOURCE_DATA subresourceData;
  132. subresourceData.pSysMem = embeddedTexture->pcData;
  133. subresourceData.SysMemPitch = embeddedTexture->mWidth * 4;
  134. subresourceData.SysMemSlicePitch = embeddedTexture->mWidth * embeddedTexture->mHeight * 4;
  135. ID3D11Texture2D *texture2D = nullptr;
  136. hr = dev_->CreateTexture2D(&desc, &subresourceData, &texture2D);
  137. if (FAILED(hr))
  138. MessageBox(hwnd_, "CreateTexture2D failed!", "Error!", MB_ICONERROR | MB_OK);
  139. hr = dev_->CreateShaderResourceView(texture2D, nullptr, &texture);
  140. if (FAILED(hr))
  141. MessageBox(hwnd_, "CreateShaderResourceView failed!", "Error!", MB_ICONERROR | MB_OK);
  142. return texture;
  143. }
  144. // mHeight is 0, so try to load a compressed texture of mWidth bytes
  145. const size_t size = embeddedTexture->mWidth;
  146. hr = CreateWICTextureFromMemory(dev_, devcon_, reinterpret_cast<const unsigned char*>(embeddedTexture->pcData), size, nullptr, &texture);
  147. if (FAILED(hr))
  148. MessageBox(hwnd_, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);
  149. return texture;
  150. }