#include "stdafx.h" #include "IResourceFactory.h" #include "GeometryBuffer.h" GeometryBuffer::GeometryBuffer(IEngine& argEngine) : m_Engine(argEngine) , m_VertexBuffer(NULL) , m_IndexBuffer(NULL) , m_InputElementDesc(NULL) , m_VertexCount(0) , m_VertexElementSize(0) , m_IndexCount(0) , m_VertexOffset(0) , m_VertexDataMapped(false) , m_IndexDataMapped(false) , m_RawVertexData_(NULL) , m_RawIndexData(NULL) , m_PrimitiveTopology(PrimitiveTopology::TriangleList) , m_IndexOffset(0) , m_UsableIndexCount(0) { m_Commands.push_back(new Command(this, CommandFlags::None, SetIndexBufferCommandType, 1)); m_Commands.push_back(new Command(this, CommandFlags::None, SetVertexBufferCommandType, 0)); m_Commands.push_back(new Command(this, CommandFlags::EndChain | CommandFlags::Unique, DrawGeometryCommandType, 6)); } GeometryBuffer::~GeometryBuffer() { this->Uninitialize(); m_Engine.get_ResourceFactory().DeleteGeometryBuffer(*const_cast(this), true); } void GeometryBuffer::Uninitialize() { if (m_Engine.get_EngineStates().LastIndexBufferProvider == this) m_Engine.get_EngineStates().LastIndexBufferProvider = NULL; if (m_Engine.get_EngineStates().LastVertexBufferProvider == this) m_Engine.get_EngineStates().LastVertexBufferProvider = NULL; this->DeleteVertexData(); this->DeleteIndexData(); } void GeometryBuffer::SetVertexData(uint32 argVertexCount, uint32 argVertexElementSize, void* a_VertexData_, const std::vector& argVertexElements, bool argNeedsDynamicAccess) { this->DeleteVertexData(); D3D10_BUFFER_DESC desc; desc.Usage = argNeedsDynamicAccess ? D3D10_USAGE_DYNAMIC : D3D10_USAGE_DEFAULT; desc.ByteWidth = argVertexElementSize * argVertexCount; desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; desc.CPUAccessFlags = argNeedsDynamicAccess ? D3D10_CPU_ACCESS_WRITE : 0; desc.MiscFlags = 0; D3D10_SUBRESOURCE_DATA initData; initData.pSysMem = a_VertexData_; if (S_OK != m_Engine.get_DX10Device().CreateBuffer(&desc, &initData, &m_VertexBuffer)) { throw L"GeometryBuffer: Unable to create vertex buffer."; } m_VertexCount = argVertexCount; m_VertexElementSize = argVertexElementSize; m_VertexElements = argVertexElements; m_RawVertexData_ = new char[argVertexElementSize * argVertexCount]; ::memcpy(m_RawVertexData_, a_VertexData_, argVertexElementSize * argVertexCount); if (m_InputElementDesc == NULL) { if (!m_VertexElements.empty()) { m_InputElementDesc = new D3D10_INPUT_ELEMENT_DESC[m_VertexElements.size()]; for (uint32 i = 0; i < m_VertexElements.size(); ++i) { D3D10_INPUT_ELEMENT_DESC desc; VertexElement& element = m_VertexElements[i]; desc.AlignedByteOffset = D3D10_APPEND_ALIGNED_ELEMENT; desc.Format = (DXGI_FORMAT)element.m_ElementFormat; desc.InputSlot = 0; // should this be a parameter too? desc.InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA; desc.InstanceDataStepRate = 0; desc.SemanticIndex = element.m_NameIndex; desc.SemanticName = element.m_SemanticName.c_str(); m_InputElementDesc[i] = desc; } } } } void GeometryBuffer::DeleteVertexData() { if (m_VertexBuffer != NULL) m_Engine.get_DX10Device().ClearState(); m_VertexElements.clear(); if (m_VertexBuffer != NULL) m_VertexBuffer->Release(); m_VertexBuffer = NULL; m_VertexCount = 0; m_VertexElementSize = 0; m_VertexDataMapped = false; if (m_RawVertexData_ != NULL) delete [] m_RawVertexData_; m_RawVertexData_ = NULL; if (m_InputElementDesc != NULL) delete [] m_InputElementDesc; m_InputElementDesc = NULL; } void GeometryBuffer::SetIndexData(uint32 argIndexCount, uint32* aui_IndexData_, bool argNeedsDynamicAccess) { this->DeleteIndexData(); D3D10_BUFFER_DESC desc; desc.Usage = D3D10_USAGE_DEFAULT; desc.ByteWidth = sizeof(uint32) * argIndexCount; desc.BindFlags = D3D10_BIND_INDEX_BUFFER; desc.CPUAccessFlags = argNeedsDynamicAccess ? D3D10_CPU_ACCESS_WRITE : 0; desc.MiscFlags = 0; D3D10_SUBRESOURCE_DATA initData; initData.pSysMem = aui_IndexData_; initData.SysMemPitch = 0; initData.SysMemSlicePitch = 0; if (S_OK != m_Engine.get_DX10Device().CreateBuffer(&desc, &initData, &m_IndexBuffer)) { throw L"GeometryBuffer: Unable to create index buffer."; } m_IndexCount = argIndexCount; m_UsableIndexCount = argIndexCount; m_IndexOffset = 0; m_RawIndexData = new uint32[m_IndexCount]; ::memcpy(m_RawIndexData, aui_IndexData_, sizeof(uint32) * m_IndexCount); } void GeometryBuffer::DeleteIndexData() { if (m_IndexBuffer != NULL) m_Engine.get_DX10Device().ClearState(); if (m_IndexBuffer != NULL) m_IndexBuffer->Release(); m_IndexBuffer = NULL; if (m_RawIndexData != NULL) delete [] m_RawIndexData; m_RawIndexData = NULL; m_IndexCount = 0; while (!m_VertexLayoutsPerShaderAndPass.empty()) { while (!m_VertexLayoutsPerShaderAndPass.begin()->second.empty()) { m_VertexLayoutsPerShaderAndPass.begin()->second.back()->Release(); m_VertexLayoutsPerShaderAndPass.begin()->second.pop_back(); } m_VertexLayoutsPerShaderAndPass.erase(m_VertexLayoutsPerShaderAndPass.begin()); } } void* GeometryBuffer::MapVertexBuffer(DataAccessMode::Enumeration argAccessMode) { if (m_VertexBuffer == NULL) { throw L"GeometryBuffer: Access forbidden until resource has been initialized."; } if (m_VertexDataMapped) { throw L"GeometryBuffer: Only one access to the vertex buffer at one time possible."; } void* dataPointer = NULL; if (S_OK != m_VertexBuffer->Map((D3D10_MAP)argAccessMode, 0, &dataPointer)) { throw L"GeometryBuffer: Access to the vertex buffer was not successfull."; } m_VertexDataMapped = true; return dataPointer; } void GeometryBuffer::UnmapVertexBuffer() { if (m_VertexBuffer == NULL) { throw L"GeometryBuffer: Access forbidden until resource has been initialized."; } if (!m_VertexDataMapped) { throw L"GeometryBuffer: No access was done ending the access to the vertex buffer is not possible."; } m_VertexBuffer->Unmap(); m_VertexDataMapped = false; } uint32* GeometryBuffer::MapIndexBuffer(DataAccessMode::Enumeration argAccessMode) { if (m_IndexBuffer == NULL) { throw L"GeometryBuffer: Access forbidden until resource has been initialized."; } if (m_IndexDataMapped) { throw L"GeometryBuffer: Only one access to the index buffer at one time possible."; } void* dataPointer = NULL; if (S_OK != m_IndexBuffer->Map((D3D10_MAP)argAccessMode, 0, &dataPointer)) { throw L"GeometryBuffer: Access to the index buffer was not successfull."; } m_IndexDataMapped = true; return (uint32*)dataPointer; } void GeometryBuffer::UnmapIndexBuffer() { if (m_IndexBuffer == NULL) { throw L"GeometryBuffer: Access forbidden until resource has been initialized."; } if (!m_IndexDataMapped) { throw L"GeometryBuffer: No access was done ending the access to the index buffer is not possible."; } m_IndexBuffer->Unmap(); m_IndexDataMapped = false; } void GeometryBuffer::ConvertToAdjacency() { switch (m_PrimitiveTopology) { case PrimitiveTopology::LineList: case PrimitiveTopology::LineStrip: case PrimitiveTopology::TriangleList: case PrimitiveTopology::TriangleStrip: break; default: return; } D3D10_INPUT_ELEMENT_DESC inputLayout[2] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "END", 0, DXGI_FORMAT_R8_UINT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; inputLayout[1].AlignedByteOffset = m_VertexElementSize - 1; // create the mesh uint32 numVertices = m_VertexCount; uint32 numIndices = m_IndexCount; uint32 Options = D3DX10_MESH_32_BIT; ID3DX10Mesh* mesh = NULL; if (S_OK != D3DX10CreateMesh(&m_Engine.get_DX10Device(), inputLayout, 2, inputLayout[0].SemanticName, numVertices, numIndices / 3, Options, &mesh ) ) { throw L"GeometryBuffer: Unable to create temp. mesh for adjacency data generation."; } //set the VB mesh->SetVertexData(0, (void*)m_RawVertexData_); //set the IB mesh->SetIndexData((void*)m_RawIndexData, numIndices); //generate adjacency const float epsilon = 0.0f; mesh->GenerateAdjacencyAndPointReps(epsilon); //generate adjacency indices mesh->GenerateGSAdjacency(); //get the adjacency data out of the mesh ID3DX10MeshBuffer* indexBufferMesh = NULL; unsigned char* adjIndices = NULL; SIZE_T Size = 0; if(S_OK != mesh->GetIndexBuffer(&indexBufferMesh)) { throw L"GeometryBuffer: Unable to retrive indexdata for adjacency data generation."; } if(S_OK != indexBufferMesh->Map((void**)&adjIndices, &Size)) { throw L"GeometryBuffer: Unable to map indexdata for adjacency data generation."; } this->SetIndexData((uint32)Size/sizeof(uint32), (uint32*)adjIndices, false); //cleanup indexBufferMesh->Unmap(); indexBufferMesh->Release(); mesh->Release(); switch (m_PrimitiveTopology) { case PrimitiveTopology::LineList: this->set_PrimitiveTopology(PrimitiveTopology::LineListAdjacency); break; case PrimitiveTopology::LineStrip: this->set_PrimitiveTopology(PrimitiveTopology::LineStripAdjacency); break; case PrimitiveTopology::TriangleList: this->set_PrimitiveTopology(PrimitiveTopology::TriangleListAdjacency); break; case PrimitiveTopology::TriangleStrip: this->set_PrimitiveTopology(PrimitiveTopology::TriangleStripAdjacency); break; } } CommandExecuteResult::Enumeration GeometryBuffer::ExecuteCommand(unsigned char argCommandType, ICommandBuffer& argCurrentBuffer, uint32 argCurrentPositon) { ID3D10Device& device = m_Engine.get_DX10Device(); if (argCommandType == GeometryBuffer::SetIndexBufferCommandType) { if (m_Engine.get_EngineStates().LastIndexBufferProvider != this) { device.IASetIndexBuffer(m_IndexBuffer, DXGI_FORMAT_R32_UINT, m_IndexOffset); m_Engine.get_EngineStates().LastIndexBufferProvider = this; } } else if (argCommandType == GeometryBuffer::SetVertexBufferCommandType) { if (m_Engine.get_EngineStates().LastVertexBufferProvider != this) { device.IASetVertexBuffers(0, 1, &m_VertexBuffer, &m_VertexElementSize, &m_VertexOffset); device.IASetPrimitiveTopology((D3D10_PRIMITIVE_TOPOLOGY)m_PrimitiveTopology); m_Engine.get_EngineStates().LastVertexBufferProvider = this; } } else if (argCommandType == GeometryBuffer::DrawGeometryCommandType) { if (m_Engine.get_EngineStates().LastShader == NULL) std::wcout << std::red << "GeometryBuffer could not render without a valid shader." << std::white << std::endl; else if (m_Engine.get_EngineStates().LastVertexBufferProvider == NULL) std::wcout << std::red << "GeometryBuffer could not render without a valid vertex buffer." << std::white << std::endl; else this->Render(*m_Engine.get_EngineStates().LastShader); } return CommandExecuteResult::None; } void GeometryBuffer::Render(IShader& argShader) { if (m_VertexElements.empty()) return; uint32 currentPass = argShader.get_CurrentRenderPass(); ID3D10EffectPass* currentEffectPass = argShader.get_DX10Technique()->GetPassByIndex(currentPass); ID3D10InputLayout* vertexLayout = NULL; tk_VertexLayoutsPerShaderAndPass::iterator found = m_VertexLayoutsPerShaderAndPass.find(&argShader); if (found != m_VertexLayoutsPerShaderAndPass.end() && found->second.size() > currentPass) { vertexLayout = found->second[currentPass]; } else { D3D10_PASS_DESC passDesc; currentEffectPass->GetDesc(&passDesc); if (S_OK == m_Engine.get_DX10Device().CreateInputLayout(m_InputElementDesc, m_VertexElements.size(), passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &vertexLayout )) { if (found == m_VertexLayoutsPerShaderAndPass.end()) { std::vector val; val.push_back(vertexLayout); m_VertexLayoutsPerShaderAndPass[&argShader] = val; } else found->second.push_back(vertexLayout); } } if (vertexLayout != NULL) { currentEffectPass->Apply(0); m_Engine.get_DX10Device().IASetInputLayout(vertexLayout); if (m_IndexBuffer == NULL) m_Engine.get_DX10Device().Draw(m_VertexCount, 0); else m_Engine.get_DX10Device().DrawIndexed(m_UsableIndexCount, m_IndexOffset, 0); } }