#include "CmMeshData.h" #include "CmVector2.h" #include "CmVector3.h" #include "CmHardwareBufferManager.h" #include "CmMeshDataRTTI.h" #include "CmVertexDeclaration.h" #include "CmException.h" namespace CamelotEngine { MeshData::MeshData(IndexBuffer::IndexType indexType) :mIndexType(indexType) { } MeshData::~MeshData() { for(auto& vertElems : mVertexData) { for(auto& vertElem : vertElems.second) { if(vertElem.data != nullptr) delete[] vertElem.data; } } for(auto& indexData : mIndices) { if(indexData.indices != nullptr) delete[] indexData.indices; } } Vector2* MeshData::addPositionsVec2(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT2, VES_POSITION, numElements, 0, streamIdx)); } Vector3* MeshData::addPositionsVec3(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT3, VES_POSITION, numElements, 0, streamIdx)); } Vector4* MeshData::addPositionsVec4(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT4, VES_POSITION, numElements, 0, streamIdx)); } Vector3* MeshData::addNormals(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT3, VES_NORMAL, numElements, 0, streamIdx)); } Vector3* MeshData::addTangentsVec3(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT3, VES_TANGENT, numElements, 0, streamIdx)); } Vector4* MeshData::addTangentsVec4(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT4, VES_TANGENT, numElements, 0, streamIdx)); } Vector3* MeshData::addBitangents(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT3, VES_BITANGENT, numElements, 0, streamIdx)); } Vector2* MeshData::addUV0(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT2, VES_TEXCOORD, numElements, 0, streamIdx)); } Vector2* MeshData::addUV1(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT2, VES_TEXCOORD, numElements, 1, streamIdx)); } Color* MeshData::addColorsFloat(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_FLOAT4, VES_COLOR, numElements, 0, streamIdx)); } UINT32* MeshData::addColorsDWORD(UINT32 numElements, UINT32 streamIdx) { return reinterpret_cast(addVertexElementData(VET_COLOR, VES_COLOR, numElements, 0, streamIdx)); } UINT8* MeshData::addVertexElementData(VertexElementType type, VertexElementSemantic semantic, UINT32 numElements, UINT32 semanticIdx, UINT32 streamIdx) { clearIfItExists(type, semantic, semanticIdx, streamIdx); UINT32 elemSize = VertexElement::getTypeSize(type); UINT8* elements = new UINT8[elemSize * numElements]; vector::type& elemData = mVertexData[streamIdx]; VertexElementData newElement(type, semantic, semanticIdx, streamIdx, elements, numElements); elemData.push_back(newElement); return elements; } UINT32* MeshData::addIndices32(UINT32 numIndices, UINT32 subMesh) { if(mIndexType != IndexBuffer::IT_32BIT) CM_EXCEPT(InvalidParametersException, "Trying to set 32bit indices but the MeshData was initialized as 16bit."); if(subMesh >= mIndices.size()) mIndices.resize(subMesh + 1); IndexElementData indexData = mIndices[subMesh]; if(indexData.indices != nullptr) delete[] indexData.indices; UINT32* indices = new UINT32[numIndices]; indexData.indices = (UINT8*)indices; indexData.numIndices = numIndices; indexData.elementSize = getIndexElementSize(); indexData.subMesh = subMesh; mIndices[subMesh] = indexData; return indices; } UINT16* MeshData::addIndices16(UINT32 numIndices, UINT32 subMesh) { if(mIndexType != IndexBuffer::IT_16BIT) CM_EXCEPT(InvalidParametersException, "Trying to set 16bit indices but the MeshData was initialized as 32bit."); if(subMesh >= mIndices.size()) mIndices.resize(subMesh + 1); IndexElementData indexData = mIndices[subMesh]; if(indexData.indices != nullptr) delete[] indexData.indices; UINT16* indices = new UINT16[numIndices]; indexData.indices = (UINT8*)indices; indexData.numIndices = numIndices; indexData.elementSize = getIndexElementSize(); indexData.subMesh = subMesh; mIndices[subMesh] = indexData; return indices; } VertexDeclarationPtr MeshData::createDeclaration() const { VertexDeclarationPtr declaration = HardwareBufferManager::instance().createVertexDeclaration(); for(auto& vertElems : mVertexData) { UINT32 offset = 0; for(auto& vertElem : vertElems.second) { declaration->addElement(vertElems.first, offset, vertElem.element.getType(), vertElem.element.getSemantic(), vertElem.element.getIndex()); offset += vertElem.element.getSize(); } } return declaration; } UINT32 MeshData::getNumVertices() const { UINT32 numVertices = 0; auto vertElemDataPerStream = mVertexData; MeshData::VertexElementData* firstElemData = nullptr; if(vertElemDataPerStream.size() > 0) { auto vertElemData = vertElemDataPerStream.begin()->second; auto firstVertElem = vertElemData.begin(); if(firstVertElem != vertElemData.end()) { numVertices = firstVertElem->elementCount; } } for(auto& vertElems : mVertexData) { for(auto& vertElem : vertElems.second) { if(vertElem.elementCount != numVertices) { CM_EXCEPT(InvalidParametersException, "All vertex element arrays in MeshData need to be of the same size. Found an array with semantic: " \ + toString(vertElem.element.getSemantic()) + " and element count: " + toString(vertElem.elementCount) + ". This doesn't match with other " \ + "element with semantic: " + toString(firstElemData->element.getSemantic()) + " and element count: " + toString(firstElemData->elementCount)); } } } return numVertices; } UINT32 MeshData::getNumIndices(UINT32 subMesh) const { return mIndices.at(subMesh).numIndices; } UINT16* MeshData::getIndices16(UINT32 subMesh) const { return (UINT16*)mIndices.at(subMesh).indices; } UINT32* MeshData::getIndices32(UINT32 subMesh) const { return (UINT32*)mIndices.at(subMesh).indices; } vector::type MeshData::getVertexElements() const { vector::type elements; for(auto& vertElems : mVertexData) { UINT32 offset = 0; for(auto& vertElem : vertElems.second) { elements.push_back(vertElem.element); } } return elements; } MeshDataPtr MeshData::combine(const vector::type& elements) { MeshDataPtr combinedMeshData(new MeshData()); UINT32 subMeshIndex = 0; vector::type combinedVertexElements; vector::type vertexElemData; vector::type bufferOffsets; UINT32 totalVertexCount = 0; UINT32 vertexIndexOffset = 0; for(auto& meshData : elements) { for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++) { UINT32 numIndices = meshData->getNumIndices(i); UINT32* indices = combinedMeshData->addIndices32(numIndices, subMeshIndex); UINT32* sourceIndices = meshData->getIndices32(i); for(UINT32 j = 0; j < numIndices; j++) indices[j] = sourceIndices[j] + vertexIndexOffset; subMeshIndex++; } UINT32 numVertices = meshData->getNumVertices(); totalVertexCount += numVertices; vertexIndexOffset += numVertices; } UINT32 vertexOffset = 0; for(auto& meshData : elements) { vector::type vertexElements = meshData->getVertexElements(); UINT32 numVertices = meshData->getNumVertices(); for(auto& newElement : vertexElements) { INT32 alreadyExistsIdx = -1; UINT32 idx = 0; for(auto& existingElement : combinedVertexElements) { if(newElement == existingElement) { alreadyExistsIdx = idx; break; } idx++; } if(alreadyExistsIdx == -1) { combinedVertexElements.push_back(newElement); UINT8* newBuffer = combinedMeshData->addVertexElementData(newElement.getType(), newElement.getSemantic(), totalVertexCount, newElement.getIndex(), newElement.getSource()); UINT32 newBufferSize = totalVertexCount * newElement.getSize(); memset(newBuffer, 0, newBufferSize); vertexElemData.push_back(newBuffer); bufferOffsets.push_back(0); alreadyExistsIdx = (UINT32)vertexElemData.size() - 1; } UINT8* source = meshData->getVertElemData(newElement.getType(), newElement.getSemantic(), newElement.getIndex(), newElement.getSource()).data; UINT32 offset = vertexOffset * newElement.getSize(); memcpy(&(vertexElemData[alreadyExistsIdx]) + offset, source, numVertices * newElement.getSize()); } vertexOffset += meshData->getNumVertices(); } return combinedMeshData; } bool MeshData::hasElement(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const { auto elemDataIter = mVertexData.find(streamIdx); if(elemDataIter == mVertexData.end()) return false; const vector::type& elemData = elemDataIter->second; auto findIter = std::find_if(elemData.begin(), elemData.end(), [semantic, semanticIdx] (const VertexElementData& x) { return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; }); if(findIter != elemData.end()) return true; return false; } void MeshData::clearIfItExists(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { vector::type& elemData = mVertexData[streamIdx]; auto findIter = std::find_if(elemData.begin(), elemData.end(), [type, semantic, semanticIdx] (const VertexElementData& x) { return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; }); if(findIter != elemData.end()) { if(findIter->data != nullptr) delete[] findIter->data; elemData.erase(findIter); } } MeshData::VertexElementData& MeshData::getVertElemData(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { vector::type& elemData = mVertexData[streamIdx]; auto findIter = std::find_if(elemData.begin(), elemData.end(), [type, semantic, semanticIdx] (const VertexElementData& x) { return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; }); if(findIter == elemData.end()) CM_EXCEPT(InvalidParametersException, "No vertex element of specified type exists."); return *findIter; } /************************************************************************/ /* SERIALIZATION */ /************************************************************************/ RTTITypeBase* MeshData::VertexElementData::getRTTIStatic() { return VertexElementDataRTTI::instance(); } RTTITypeBase* MeshData::VertexElementData::getRTTI() const { return VertexElementData::getRTTIStatic(); } RTTITypeBase* MeshData::IndexElementData::getRTTIStatic() { return IndexElementDataRTTI::instance(); } RTTITypeBase* MeshData::IndexElementData::getRTTI() const { return IndexElementData::getRTTIStatic(); } RTTITypeBase* MeshData::getRTTIStatic() { return MeshDataRTTI::instance(); } RTTITypeBase* MeshData::getRTTI() const { return MeshData::getRTTIStatic(); } }