Model.h
#ifndef _MODEL_H_#define _MODEL_H_ #include "BasicIncludes.h"#include "VertexBuffer.h"#include "IndexBuffer.h"#include "Vertex.h" #include #include #include #include namespace NTEngine{struct Subset{Subset(){ZeroMemory(this, sizeof(Subset));} UINT ID;UINT VertexStart;UINT VertexCount;UINT FaceStart;UINT FaceCount;}; class Model{public:DLLEXPORT Model();virtual DLLEXPORT ~Model(); DLLEXPORT virtual VOID LoadFromFile(ID3D11Device* dev, const std::string& file) = 0; protected:DLLEXPORT VOID ExtractIndices(ID3D11Device* dev, const aiScene* scene);DLLEXPORT VOID LoadIndices(ID3D11Device* dev, std::vector& indices);VOID inline LoadDiffuseMap(aiMaterial* mat); protected:VertexBuffer* m_VertexBuffer;IndexBuffer* m_IndexBuffer; UINT m_NumVertices;UINT m_NumFaces;UINT m_Flags; bool m_HasNormalMaps; std::vector m_Subsets; std::vector m_DiffuseMaps; }; class BasicModel : public Model{public:BasicModel() {};~BasicModel() {}; DLLEXPORT VOID LoadFromFile(ID3D11Device* dev, const std::string& file); DLLEXPORT VOID inline Render(ID3D11DeviceContext* devcon); }; class NormalMappedModel : public Model{public:NormalMappedModel() {}~NormalMappedModel() {} DLLEXPORT VOID LoadFromFile(ID3D11Device* dev, const std::string& file); DLLEXPORT VOID inline Render(ID3D11DeviceContext* devcon); private:VOID inline LoadNormalMap(aiMaterial* mat); private:std::vector m_NormalMaps;}; } #endif
Model.cpp
#include "Model.h"#include "TextureManager.h"#include "Shaders.h" namespace NTEngine{ #pragma region BaseModelModel::Model(){m_VertexBuffer = new VertexBuffer();m_IndexBuffer = new IndexBuffer(); m_Flags = aiProcess_CalcTangentSpace |aiProcess_JoinIdenticalVertices |aiProcess_Triangulate |aiProcess_GenSmoothNormals |aiProcess_OptimizeMeshes |aiProcess_OptimizeGraph |aiProcess_RemoveRedundantMaterials |aiProcess_ConvertToLeftHanded |aiProcess_SortByPType;} Model::~Model(){SafeDelete(m_VertexBuffer);SafeDelete(m_IndexBuffer); #if defined(DEBUG) | defined(_DEBUG)OutputDebugString("Model released.\n");#endif} void Model::LoadIndices(ID3D11Device* dev, std::vector& indices){std::vector Indices16(indices.size()); bool UseIndices16 = false; //use USHORT for indices if we canif (indices.size() < USHRT_MAX){//convert to USHORT indicesfor (UINT k = 0; k < indices.size(); ++k){Indices16[k] = static_cast(indices[k]);} UseIndices16 = true;} if (UseIndices16)m_IndexBuffer->SetIndices(dev, &Indices16[0], Indices16.size(), DXGI_FORMAT_R16_UINT);elsem_IndexBuffer->SetIndices(dev, &indices[0], indices.size(), DXGI_FORMAT_R32_UINT);} void Model::ExtractIndices(ID3D11Device* dev, const aiScene* pScene){ #if defined(DEBUG) | defined(_DEBUG)assert(!m_Subsets.empty()); #endif std::vector indices; for (UINT i = 0; i < pScene->mNumMeshes; ++i){m_Subsets.FaceStart = indices.size() / 3; aiMesh* CurrentMesh = pScene->mMeshes; //for each triangle in this subsetfor (UINT j = 0; j < CurrentMesh->mNumFaces; ++j){//for each index in this trianglefor (UINT index = 0; index < CurrentMesh->mFaces[j].mNumIndices; ++index){indices.push_back(m_Subsets.VertexStart + CurrentMesh->mFaces[j].mIndices[index]);}} } LoadIndices(dev, indices); } void Model::LoadDiffuseMap(aiMaterial* mat){aiString path; ID3D11ShaderResourceView* SRV = nullptr; if (mat->GetTextureCount(aiTextureType_DIFFUSE) > 0 && mat->GetTexture(aiTextureType_DIFFUSE, 0, &path) == AI_SUCCESS){std::string FileName = path.C_Str(); FileName = removeExtension(FileName);FileName = "Textures\\" + FileName + ".dds"; if (!FileExists(FileName)){#if defined(DEBUG) | defined(_DEBUG)char s[200];sprintf_s(s, "File does not exists: %s\n", FileName.c_str()); OutputDebugString(s);#endif m_DiffuseMaps.push_back(SRV); return;} SRV = TextureManager::Instance()->Create(FileName); m_DiffuseMaps.push_back(SRV);}else{m_DiffuseMaps.push_back(SRV);}} #pragma endregion #pragma region BasicModel void BasicModel::LoadFromFile(ID3D11Device* dev, const std::string& file){ Assimp::Importer imp; const aiScene* pScene = imp.ReadFile(file, m_Flags); if (pScene == NULL)ShowError(imp.GetErrorString()); std::vector vertices; for (UINT i = 0; i < pScene->mNumMeshes; ++i){aiMesh* CurrentMesh = pScene->mMeshes; Subset subset; subset.VertexCount = CurrentMesh->mNumVertices;subset.VertexStart = vertices.size();subset.FaceCount = CurrentMesh->mNumFaces;subset.ID = CurrentMesh->mMaterialIndex; m_NumVertices += subset.VertexCount;m_NumFaces += subset.FaceCount; for (UINT j = 0; j < subset.VertexCount; ++j){Vertex::Basic32 vertex; vertex.Pos.x = CurrentMesh->mVertices[j].x;vertex.Pos.y = CurrentMesh->mVertices[j].y;vertex.Pos.z = CurrentMesh->mVertices[j].z; vertex.Normal.x = CurrentMesh->mNormals[j].x;vertex.Normal.y = CurrentMesh->mNormals[j].y;vertex.Normal.z = CurrentMesh->mNormals[j].z; if (CurrentMesh->HasTextureCoords(0)){vertex.Tex.x = CurrentMesh->mTextureCoords[0][j].x;vertex.Tex.y = CurrentMesh->mTextureCoords[0][j].y;} vertices.push_back(vertex);} aiMaterial* CurrentMeshMaterial = pScene->mMaterials[subset.ID]; //Extract diffuse mapsLoadDiffuseMap(CurrentMeshMaterial); m_Subsets.push_back(subset);} ExtractIndices(dev, pScene); m_VertexBuffer->SetVertices(dev, &vertices[0], vertices.size());} void BasicModel::Render(ID3D11DeviceContext* devcon){UINT offset = 0; const UINT& VertexStride = m_VertexBuffer->GetVertexStride(); ID3D11Buffer* VB = m_VertexBuffer->GetVertexBuffer();ID3D11Buffer* IB = m_IndexBuffer->GetIndexBuffer(); devcon->IASetVertexBuffers(0, 1, &VB, &VertexStride, &offset);devcon->IASetIndexBuffer(IB, m_IndexBuffer->GetIndexBufferFormat(), 0); devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); for (UINT i = 0; i < m_Subsets.size(); ++i){if (m_DiffuseMaps == nullptr)continue; Shaders::Basic->SetDiffuseMap(m_DiffuseMaps); devcon->DrawIndexed(m_Subsets.FaceCount * 3, m_Subsets.FaceStart * 3, 0);}} #pragma endregion #pragma region NormalMappedModel void NormalMappedModel::LoadFromFile(ID3D11Device* dev, const std::string& file){Assimp::Importer imp; const aiScene* pScene = imp.ReadFile(file, m_Flags); if (pScene == NULL)ShowError(imp.GetErrorString()); std::vector vertices; for (UINT i = 0; i < pScene->mNumMeshes; ++i){aiMesh* CurrentMesh = pScene->mMeshes; Subset subset; subset.VertexCount = CurrentMesh->mNumVertices;subset.VertexStart = vertices.size();subset.FaceCount = CurrentMesh->mNumFaces;subset.ID = CurrentMesh->mMaterialIndex; m_NumVertices += subset.VertexCount;m_NumFaces += subset.FaceCount; for (UINT j = 0; j < subset.VertexCount; ++j){Vertex::NormalMap vertex; vertex.Pos.x = CurrentMesh->mVertices[j].x;vertex.Pos.y = CurrentMesh->mVertices[j].y;vertex.Pos.z = CurrentMesh->mVertices[j].z; vertex.Normal.x = CurrentMesh->mNormals[j].x;vertex.Normal.y = CurrentMesh->mNormals[j].y;vertex.Normal.z = CurrentMesh->mNormals[j].z; if (CurrentMesh->HasTangentsAndBitangents()){vertex.Tangent.x = CurrentMesh->mTangents[j].x;vertex.Tangent.y = CurrentMesh->mTangents[j].y;vertex.Tangent.z = CurrentMesh->mTangents[j].z;} if (CurrentMesh->HasTextureCoords(0)){vertex.Tex.x = CurrentMesh->mTextureCoords[0][j].x;vertex.Tex.y = CurrentMesh->mTextureCoords[0][j].y;} vertices.push_back(vertex);} aiMaterial* CurrentMeshMaterial = pScene->mMaterials[subset.ID]; //Extract diffuse mapsLoadDiffuseMap(CurrentMeshMaterial); //Extract normal mapsLoadNormalMap(CurrentMeshMaterial); m_Subsets.push_back(subset);} ExtractIndices(dev, pScene); m_VertexBuffer->SetVertices(dev, &vertices[0], vertices.size());} void NormalMappedModel::LoadNormalMap(aiMaterial* mat){aiString path; ID3D11ShaderResourceView* SRV = nullptr; if (mat->GetTextureCount(aiTextureType_DIFFUSE) > 0 && mat->GetTexture(aiTextureType_DIFFUSE, 0, &path) == AI_SUCCESS){std::string FileName = path.C_Str(); FileName = removeExtension(FileName);FileName = "Textures\\" + FileName + "_nrm" + ".dds"; if (!FileExists(FileName)){#if defined(DEBUG) | defined(_DEBUG)char s[200];sprintf_s(s, "File does not exists: %s\n", FileName.c_str()); OutputDebugString(s);#endif m_NormalMaps.push_back(SRV); return;} SRV = TextureManager::Instance()->Create(FileName); m_NormalMaps.push_back(SRV);}else{m_NormalMaps.push_back(SRV);}} void NormalMappedModel::Render(ID3D11DeviceContext* devcon){UINT offset = 0; const UINT& VertexStride = m_VertexBuffer->GetVertexStride(); ID3D11Buffer* VB = m_VertexBuffer->GetVertexBuffer();ID3D11Buffer* IB = m_IndexBuffer->GetIndexBuffer(); devcon->IASetVertexBuffers(0, 1, &VB, &VertexStride, &offset);devcon->IASetIndexBuffer(IB, m_IndexBuffer->GetIndexBufferFormat(), 0); devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); for (UINT i = 0; i < m_Subsets.size(); ++i){//skip this mesh subset if diffuse map or normal map is missing//this is just a temporary hack and it's going to be removed soon if (m_DiffuseMaps == nullptr)continue; if (m_NormalMaps == nullptr)continue; Shaders::NormalMap->SetDiffuseAndNormalMap(m_DiffuseMaps, m_NormalMaps); devcon->DrawIndexed(m_Subsets.FaceCount * 3, m_Subsets.FaceStart * 3, 0);}} #pragma endregion }
Full source code with usage can be found here:
https://github.com/newtechnology/NT-Engine
For better reading, I suggest using the above github link.