#include "modelclass.h" ModelClass::ModelClass() { m_vertexBuffer = 0; m_indexBuffer = 0; m_Textures = 0; m_model = 0; } ModelClass::ModelClass(const ModelClass& other) { } ModelClass::~ModelClass() { } bool ModelClass::Initialize(ID3D11Device* device, ID3D11DeviceContext* deviceContext, char* modelFilename, vector filename) { Logger::Get().Log("Initializing model class", __FILE__, __LINE__, Logger::LogLevel::Initialize); bool result; // Load in the model data. result = LoadModel(modelFilename); if (!result) { Logger::Get().Log("Failed to load model data", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } // Calculate the tangent and binormal vectors for the model. CalculateModelVectors(); // Initialize the vertex and index buffers. result = InitializeBuffers(device); if (!result) { Logger::Get().Log("Failed to initialize buffers", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } // Load the textures for this model. result = LoadTextures(device, deviceContext, filename); if (!result) { Logger::Get().Log("Failed to load textures", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } Logger::Get().Log("Model class initialized", __FILE__, __LINE__, Logger::LogLevel::Initialize); return true; } void ModelClass::Shutdown() { // Release the model textures. ReleaseTextures(); // Shutdown the vertex and index buffers. ShutdownBuffers(); // Release the model data. ReleaseModel(); return; } void ModelClass::Render(ID3D11DeviceContext* deviceContext) { // Put the vertex and index buffers on the graphics pipeline to prepare them for drawing. RenderBuffers(deviceContext); return; } int ModelClass::GetIndexCount() { return m_indexCount; } ID3D11ShaderResourceView* ModelClass::GetTexture(int index) { return m_Textures[index].GetTexture(); } bool ModelClass::InitializeBuffers(ID3D11Device* device) { Logger::Get().Log("Initializing buffers", __FILE__, __LINE__, Logger::LogLevel::Initialize); VertexType* vertices; unsigned long* indices; D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc; D3D11_SUBRESOURCE_DATA vertexData, indexData; HRESULT result; int i; // Create the vertex array. vertices = new VertexType[m_vertexCount]; // Create the index array. indices = new unsigned long[m_indexCount]; // Load the vertex array and index array with data. for (i = 0; i < m_vertexCount; i++) { vertices[i].position = XMFLOAT3(m_model[i].x, m_model[i].y, m_model[i].z); vertices[i].texture = XMFLOAT2(m_model[i].tu, m_model[i].tv); vertices[i].normal = XMFLOAT3(m_model[i].nx, m_model[i].ny, m_model[i].nz); vertices[i].tangent = XMFLOAT3(m_model[i].tx, m_model[i].ty, m_model[i].tz); vertices[i].binormal = XMFLOAT3(m_model[i].bx, m_model[i].by, m_model[i].bz); indices[i] = i; } // Set up the description of the static vertex buffer. vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; vertexBufferDesc.StructureByteStride = 0; // Give the subresource structure a pointer to the vertex data. vertexData.pSysMem = vertices; vertexData.SysMemPitch = 0; vertexData.SysMemSlicePitch = 0; // Now create the vertex buffer. result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer); if (FAILED(result)) { Logger::Get().Log("Failed to create vertex buffer", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } // Set up the description of the static index buffer. indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; indexBufferDesc.StructureByteStride = 0; // Give the subresource structure a pointer to the index data. indexData.pSysMem = indices; indexData.SysMemPitch = 0; indexData.SysMemSlicePitch = 0; // Create the index buffer. result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer); if (FAILED(result)) { Logger::Get().Log("Failed to create index buffer", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } // Release the arrays now that the vertex and index buffers have been created and loaded. delete[] vertices; vertices = 0; delete[] indices; indices = 0; Logger::Get().Log("Buffers initialized", __FILE__, __LINE__, Logger::LogLevel::Initialize); return true; } void ModelClass::ShutdownBuffers() { Logger::Get().Log("Shutting down buffers", __FILE__, __LINE__, Logger::LogLevel::Shutdown); // Release the index buffer. if (m_indexBuffer) { m_indexBuffer->Release(); m_indexBuffer = 0; } // Release the vertex buffer. if (m_vertexBuffer) { m_vertexBuffer->Release(); m_vertexBuffer = 0; } Logger::Get().Log("Buffers shut down", __FILE__, __LINE__, Logger::LogLevel::Shutdown); return; } void ModelClass::RenderBuffers(ID3D11DeviceContext* deviceContext) { unsigned int stride; unsigned int offset; // Set vertex buffer stride and offset. stride = sizeof(VertexType); offset = 0; // Set the vertex buffer to active in the input assembler so it can be rendered. deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset); // Set the index buffer to active in the input assembler so it can be rendered. deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0); // Set the type of primitive that should be rendered from this vertex buffer, in this case triangles. deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); return; } bool ModelClass::LoadTextures(ID3D11Device* device, ID3D11DeviceContext* deviceContext, vector textureFile) { Logger::Get().Log("Loading textures", __FILE__, __LINE__); bool result; // Create and initialize the texture object array. m_Textures = new TextureClass[textureFile.size()]; for (int i = 0; i < textureFile.size(); i++) { result = m_Textures[i].Initialize(device, deviceContext, textureFile[i]); if (!result) { Logger::Get().Log("Failed to initialize texture", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } } Logger::Get().Log("Textures loaded", __FILE__, __LINE__); return true; } void ModelClass::ReleaseTextures() { Logger::Get().Log("Releasing textures", __FILE__, __LINE__); // Release the texture object array. if (m_Textures) { m_Textures[0].Shutdown(); m_Textures[1].Shutdown(); m_Textures[2].Shutdown(); m_Textures[3].Shutdown(); m_Textures[4].Shutdown(); m_Textures[5].Shutdown(); delete[] m_Textures; m_Textures = 0; } Logger::Get().Log("Textures released", __FILE__, __LINE__); return; } bool ModelClass::LoadModel(char* filename) { Logger::Get().Log("Loading model", __FILE__, __LINE__); ifstream fin; char input; int i; // Open the model file. fin.open(filename); // If it could not open the file then exit. if (fin.fail()) { Logger::Get().Log("Failed to open model file", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } // Read up to the value of vertex count. fin.get(input); while (input != ':') { fin.get(input); } // Read in the vertex count. fin >> m_vertexCount; // Set the number of indices to be the same as the vertex count. m_indexCount = m_vertexCount; // Create the model using the vertex count that was read in. m_model = new ModelType[m_vertexCount]; // Read up to the beginning of the data. fin.get(input); while (input != ':') { fin.get(input); } fin.get(input); fin.get(input); // Read in the vertex data. for (i = 0; i < m_vertexCount; i++) { fin >> m_model[i].x >> m_model[i].y >> m_model[i].z; fin >> m_model[i].tu >> m_model[i].tv; fin >> m_model[i].nx >> m_model[i].ny >> m_model[i].nz; } // Close the model file. fin.close(); Logger::Get().Log("Model loaded", __FILE__, __LINE__); return true; } void ModelClass::CalculateModelVectors() { Logger::Get().Log("Calculating model vectors", __FILE__, __LINE__); int faceCount, i, index; TempVertexType vertex1, vertex2, vertex3; VectorType tangent, binormal; // Calculate the number of faces in the model. faceCount = m_vertexCount / 3; // Initialize the index to the model data. index = 0; // Go through all the faces and calculate the the tangent and binormal vectors. for (i = 0; i < faceCount; i++) { // Get the three vertices for this face from the model. vertex1.x = m_model[index].x; vertex1.y = m_model[index].y; vertex1.z = m_model[index].z; vertex1.tu = m_model[index].tu; vertex1.tv = m_model[index].tv; index++; vertex2.x = m_model[index].x; vertex2.y = m_model[index].y; vertex2.z = m_model[index].z; vertex2.tu = m_model[index].tu; vertex2.tv = m_model[index].tv; index++; vertex3.x = m_model[index].x; vertex3.y = m_model[index].y; vertex3.z = m_model[index].z; vertex3.tu = m_model[index].tu; vertex3.tv = m_model[index].tv; index++; // Calculate the tangent and binormal of that face. CalculateTangentBinormal(vertex1, vertex2, vertex3, tangent, binormal); // Store the tangent and binormal for this face back in the model structure. m_model[index - 1].tx = tangent.x; m_model[index - 1].ty = tangent.y; m_model[index - 1].tz = tangent.z; m_model[index - 1].bx = binormal.x; m_model[index - 1].by = binormal.y; m_model[index - 1].bz = binormal.z; m_model[index - 2].tx = tangent.x; m_model[index - 2].ty = tangent.y; m_model[index - 2].tz = tangent.z; m_model[index - 2].bx = binormal.x; m_model[index - 2].by = binormal.y; m_model[index - 2].bz = binormal.z; m_model[index - 3].tx = tangent.x; m_model[index - 3].ty = tangent.y; m_model[index - 3].tz = tangent.z; m_model[index - 3].bx = binormal.x; m_model[index - 3].by = binormal.y; m_model[index - 3].bz = binormal.z; } Logger::Get().Log("Model vectors calculated", __FILE__, __LINE__); return; } void ModelClass::CalculateTangentBinormal(TempVertexType vertex1, TempVertexType vertex2, TempVertexType vertex3, VectorType& tangent, VectorType& binormal) { float vector1[3], vector2[3]; float tuVector[2], tvVector[2]; float den; float length; // Calculate the two vectors for this face. vector1[0] = vertex2.x - vertex1.x; vector1[1] = vertex2.y - vertex1.y; vector1[2] = vertex2.z - vertex1.z; vector2[0] = vertex3.x - vertex1.x; vector2[1] = vertex3.y - vertex1.y; vector2[2] = vertex3.z - vertex1.z; // Calculate the tu and tv texture space vectors. tuVector[0] = vertex2.tu - vertex1.tu; tvVector[0] = vertex2.tv - vertex1.tv; tuVector[1] = vertex3.tu - vertex1.tu; tvVector[1] = vertex3.tv - vertex1.tv; // Calculate the denominator of the tangent/binormal equation. den = 1.0f / (tuVector[0] * tvVector[1] - tuVector[1] * tvVector[0]); // Calculate the cross products and multiply by the coefficient to get the tangent and binormal. tangent.x = (tvVector[1] * vector1[0] - tvVector[0] * vector2[0]) * den; tangent.y = (tvVector[1] * vector1[1] - tvVector[0] * vector2[1]) * den; tangent.z = (tvVector[1] * vector1[2] - tvVector[0] * vector2[2]) * den; binormal.x = (tuVector[0] * vector2[0] - tuVector[1] * vector1[0]) * den; binormal.y = (tuVector[0] * vector2[1] - tuVector[1] * vector1[1]) * den; binormal.z = (tuVector[0] * vector2[2] - tuVector[1] * vector1[2]) * den; // Calculate the length of this normal. length = sqrt((tangent.x * tangent.x) + (tangent.y * tangent.y) + (tangent.z * tangent.z)); // Normalize the normal and then store it tangent.x = tangent.x / length; tangent.y = tangent.y / length; tangent.z = tangent.z / length; // Calculate the length of this normal. length = sqrt((binormal.x * binormal.x) + (binormal.y * binormal.y) + (binormal.z * binormal.z)); // Normalize the normal and then store it binormal.x = binormal.x / length; binormal.y = binormal.y / length; binormal.z = binormal.z / length; return; } void ModelClass::ReleaseModel() { Logger::Get().Log("Releasing model", __FILE__, __LINE__); if (m_model) { delete[] m_model; m_model = 0; } Logger::Get().Log("Model released", __FILE__, __LINE__); return; } bool ModelClass::ChangeTexture(ID3D11Device* device, ID3D11DeviceContext* deviceContext, std::wstring filename, int index) { bool result; // convert wstring to string std::string str(filename.begin(), filename.end()); // Release the old texture object. m_Textures[index].Shutdown(); // Initialize the new texture object. result = m_Textures[index].Initialize(device, deviceContext, str); if (!result) { Logger::Get().Log("Failed to initialize texture", __FILE__, __LINE__, Logger::LogLevel::Error); return false; } Logger::Get().Log("Texture changed", __FILE__, __LINE__); return true; }