#include "ModelLoader.h" ModelLoader::ModelLoader() : dev_(nullptr), devcon_(nullptr), meshes_(), directory_(), textures_loaded_(), hwnd_(nullptr) { // empty } ModelLoader::~ModelLoader() { // empty } bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) { Assimp::Importer importer; const aiScene* pScene = importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_ConvertToLeftHanded); if (pScene == nullptr) return false; this->directory_ = filename.substr(0, filename.find_last_of("/\\")); this->dev_ = dev; this->devcon_ = devcon; this->hwnd_ = hwnd; processNode(pScene->mRootNode, pScene); return true; } void ModelLoader::Draw(ID3D11DeviceContext * devcon) { for (size_t i = 0; i < meshes_.size(); ++i ) { meshes_[i].Draw(devcon); } } Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) { // Data to fill std::vector vertices; std::vector indices; std::vector textures; // Walk through each of the mesh's vertices for (UINT i = 0; i < mesh->mNumVertices; i++) { VERTEX vertex; vertex.X = mesh->mVertices[i].x; vertex.Y = mesh->mVertices[i].y; vertex.Z = mesh->mVertices[i].z; if (mesh->mTextureCoords[0]) { vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x; vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y; } vertices.push_back(vertex); } for (UINT i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for (UINT j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } if (mesh->mMaterialIndex >= 0) { aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; std::vector diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); } return Mesh(dev_, vertices, indices, textures); } std::vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, std::string typeName, const aiScene * scene) { std::vector textures; for (UINT i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture bool skip = false; for (UINT j = 0; j < textures_loaded_.size(); j++) { if (std::strcmp(textures_loaded_[j].path.c_str(), str.C_Str()) == 0) { textures.push_back(textures_loaded_[j]); skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization) break; } } if (!skip) { // If texture hasn't been loaded already, load it HRESULT hr; Texture texture; const aiTexture* embeddedTexture = scene->GetEmbeddedTexture(str.C_Str()); if (embeddedTexture != nullptr) { texture.texture = loadEmbeddedTexture(embeddedTexture); } else { std::string filename = std::string(str.C_Str()); filename = directory_ + '/' + filename; std::wstring filenamews = std::wstring(filename.begin(), filename.end()); hr = CreateWICTextureFromFile(dev_, devcon_, filenamews.c_str(), nullptr, &texture.texture); if (FAILED(hr)) MessageBox(hwnd_, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK); } texture.type = typeName; texture.path = str.C_Str(); textures.push_back(texture); this->textures_loaded_.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures. } } return textures; } void ModelLoader::Close() { for (auto& t : textures_loaded_) t.Release(); for (size_t i = 0; i < meshes_.size(); i++) { meshes_[i].Close(); } } void ModelLoader::processNode(aiNode * node, const aiScene * scene) { for (UINT i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; meshes_.push_back(this->processMesh(mesh, scene)); } for (UINT i = 0; i < node->mNumChildren; i++) { this->processNode(node->mChildren[i], scene); } } ID3D11ShaderResourceView * ModelLoader::loadEmbeddedTexture(const aiTexture* embeddedTexture) { HRESULT hr; ID3D11ShaderResourceView *texture = nullptr; if (embeddedTexture->mHeight != 0) { // Load an uncompressed ARGB8888 embedded texture D3D11_TEXTURE2D_DESC desc; desc.Width = embeddedTexture->mWidth; desc.Height = embeddedTexture->mHeight; desc.MipLevels = 1; desc.ArraySize = 1; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA subresourceData; subresourceData.pSysMem = embeddedTexture->pcData; subresourceData.SysMemPitch = embeddedTexture->mWidth * 4; subresourceData.SysMemSlicePitch = embeddedTexture->mWidth * embeddedTexture->mHeight * 4; ID3D11Texture2D *texture2D = nullptr; hr = dev_->CreateTexture2D(&desc, &subresourceData, &texture2D); if (FAILED(hr)) MessageBox(hwnd_, "CreateTexture2D failed!", "Error!", MB_ICONERROR | MB_OK); hr = dev_->CreateShaderResourceView(texture2D, nullptr, &texture); if (FAILED(hr)) MessageBox(hwnd_, "CreateShaderResourceView failed!", "Error!", MB_ICONERROR | MB_OK); return texture; } // mHeight is 0, so try to load a compressed texture of mWidth bytes const size_t size = embeddedTexture->mWidth; hr = CreateWICTextureFromMemory(dev_, devcon_, reinterpret_cast(embeddedTexture->pcData), size, nullptr, &texture); if (FAILED(hr)) MessageBox(hwnd_, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK); return texture; }