#include "CmMeshData.h" #include "CmVector2.h" #include "CmVector3.h" #include "CmHardwareBufferManager.h" #include "CmMeshDataRTTI.h" #include "CmVertexDeclaration.h" #include "CmException.h" namespace CamelotFramework { MeshData::MeshData(UINT32 numVertices, IndexBuffer::IndexType indexType) :mNumVertices(numVertices), mIndexType(indexType), mData(nullptr), mDescBuilding(false) { } MeshData::~MeshData() { } void MeshData::beginDesc() { if(mDescBuilding) CM_EXCEPT(InternalErrorException, "beginDesc() but description building has already began."); mVertexElements.clear(); mSubMeshes.clear(); mDescBuilding = true; } void MeshData::endDesc() { if(!mDescBuilding) CM_EXCEPT(InternalErrorException, "endDesc() called without beginDesc()."); allocateInternalBuffer(); mDescBuilding = false; } void MeshData::addVertElem(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { if(!mDescBuilding) CM_EXCEPT(InternalErrorException, "Cannot add vertex element when not building description. Call beginDesc() first."); clearIfItExists(type, semantic, semanticIdx, streamIdx); VertexElement newElement(streamIdx, 0, type, semantic, semanticIdx); // Insert it so it is sorted by stream UINT32 insertToIndex = (UINT32)mVertexElements.size(); UINT32 idx = 0; for(auto& elem : mVertexElements) { if(elem.getStreamIdx() > streamIdx) { insertToIndex = idx; break; } idx++; } mVertexElements.insert(mVertexElements.begin() + insertToIndex, newElement); } void MeshData::addSubMesh(UINT32 numIndices, UINT32 subMesh) { if(!mDescBuilding) CM_EXCEPT(InternalErrorException, "Cannot add indices when not building description. Call beginDesc() first."); if(subMesh >= mSubMeshes.size()) mSubMeshes.resize(subMesh + 1); IndexElementData indexData = mSubMeshes[subMesh]; indexData.numIndices = numIndices; indexData.elementSize = getIndexElementSize(); indexData.subMesh = subMesh; mSubMeshes[subMesh] = indexData; } VertexDeclarationPtr MeshData::createDeclaration() const { VertexDeclarationPtr declaration = HardwareBufferManager::instance().createVertexDeclaration(); UINT32 maxStreamIdx = getMaxStreamIdx(); UINT32 numStreams = maxStreamIdx + 1; UINT32* streamOffsets = CM_NEW_ARRAY(UINT32, numStreams, ScratchAlloc); for(UINT32 i = 0; i < numStreams; i++) streamOffsets[i] = 0; for(auto& vertElem : mVertexElements) { UINT32 streamIdx = vertElem.getStreamIdx(); declaration->addElement(streamIdx, streamOffsets[streamIdx], vertElem.getType(), vertElem.getSemantic(), vertElem.getSemanticIdx()); streamOffsets[streamIdx] += vertElem.getSize(); } CM_DELETE_ARRAY(streamOffsets, UINT32, numStreams,ScratchAlloc); return declaration; } UINT32 MeshData::getNumIndices(UINT32 subMesh) const { return mSubMeshes.at(subMesh).numIndices; } UINT32 MeshData::getNumIndices() const { UINT32 count = 0; for(UINT32 i = 0; i < getNumSubmeshes(); i++) { count += mSubMeshes[i].numIndices; } return count; } UINT16* MeshData::getIndices16(UINT32 subMesh) const { if(mIndexType != IndexBuffer::IT_16BIT) CM_EXCEPT(InternalErrorException, "Attempting to get 16bit index buffer, but internally allocated buffer is 32 bit."); UINT32 indexBufferOffset = getIndexBufferOffset(subMesh); return (UINT16*)(getData() + indexBufferOffset); } UINT32* MeshData::getIndices32(UINT32 subMesh) const { if(mIndexType != IndexBuffer::IT_32BIT) CM_EXCEPT(InternalErrorException, "Attempting to get 32bit index buffer, but internally allocated buffer is 16 bit."); UINT32 indexBufferOffset = getIndexBufferOffset(subMesh); return (UINT32*)(getData() + indexBufferOffset); } vector::type MeshData::getVertexElements() const { return mVertexElements; } UINT32 MeshData::getMaxStreamIdx() const { UINT32 maxStreamIdx = 0; for(auto& vertElems : mVertexElements) { UINT32 offset = 0; for(auto& vertElem : mVertexElements) { maxStreamIdx = std::max((UINT32)maxStreamIdx, (UINT32)vertElem.getStreamIdx()); } } return maxStreamIdx; } bool MeshData::hasStream(UINT32 streamIdx) const { for(auto& vertElem : mVertexElements) { if(vertElem.getStreamIdx() == streamIdx) return true; } return false; } UINT32 MeshData::getInternalBufferSize() { return getIndexBufferSize() + getStreamSize(); } MeshDataPtr MeshData::combine(const vector::type& meshes) { UINT32 totalVertexCount = 0; for(auto& meshData : meshes) { UINT32 numVertices = meshData->getNumVertices(); totalVertexCount += numVertices; } MeshDataPtr combinedMeshData(CM_NEW(MeshData, PoolAlloc) MeshData(totalVertexCount), &MemAllocDeleter::deleter); //UINT32 subMeshIndex = 0; //UINT32 vertexIndexOffset = 0; //for(auto& meshData : meshes) //{ // for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++) // { // UINT32 numIndices = meshData->getNumIndices(i); // UINT32* indices = combinedMeshData->addSubMesh(numIndices, subMeshIndex); // UINT32* sourceIndices = meshData->getIndices32(i); // for(UINT32 j = 0; j < numIndices; j++) // indices[j] = sourceIndices[j] + vertexIndexOffset; // subMeshIndex++; // } // UINT32 numVertices = meshData->getNumVertices(); // vertexIndexOffset += numVertices; //} //vector::type combinedVertexElements; //for(auto& meshData : meshes) //{ // 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); // combinedMeshData->addVertElem(newElement.getType(), newElement.getSemantic(), newElement.getSemanticIdx(), newElement.getStreamIdx()); // } // } //} //combinedMeshData->allocateInternalBuffer(); //UINT32 vertexOffset = 0; //for(auto& element : combinedVertexElements) //{ // for(auto& meshData : meshes) // { // if(meshData->hasElement(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx())) // { // } // } // vector::type vertexElements = meshData->getVertexElements(); // UINT32 numVertices = meshData->getNumVertices(); // for(auto& newElement : vertexElements) // { // // TODO // } // vertexOffset += meshData->getNumVertices(); //} return combinedMeshData; } bool MeshData::hasElement(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const { auto findIter = std::find_if(mVertexElements.begin(), mVertexElements.end(), [semantic, semanticIdx, streamIdx] (const VertexElement& x) { return x.getSemantic() == semantic && x.getSemanticIdx() == semanticIdx && x.getStreamIdx() == streamIdx; }); if(findIter != mVertexElements.end()) { return true; } return false; } void MeshData::setVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx) { assert(data != nullptr); if(!hasElement(semantic, semanticIdx, streamIdx)) { CM_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: " + toString(semanticIdx) + ", Stream index: " + toString(streamIdx)); } UINT32 elementSize = getElementSize(semantic, semanticIdx, streamIdx); UINT32 totalSize = elementSize * mNumVertices; if(totalSize != size) { CM_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size)); } UINT32 indexBufferOffset = getIndexBufferSize(); UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx); UINT32 vertexStride = getVertexStride(streamIdx); UINT8* dst = getData() + indexBufferOffset + elementOffset; UINT8* src = data; for(UINT32 i = 0; i < mNumVertices; i++) { memcpy(dst, src, elementSize); dst += vertexStride; src += elementSize; } } VertexElemIter MeshData::getVec2DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { UINT8* data; UINT32 vertexStride; getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); return VertexElemIter(data, vertexStride, mNumVertices); } VertexElemIter MeshData::getVec3DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { UINT8* data; UINT32 vertexStride; getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); return VertexElemIter(data, vertexStride, mNumVertices); } VertexElemIter MeshData::getVec4DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { UINT8* data; UINT32 vertexStride; getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); return VertexElemIter(data, vertexStride, mNumVertices); } VertexElemIter MeshData::getColorDataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { UINT8* data; UINT32 vertexStride; getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); return VertexElemIter(data, vertexStride, mNumVertices); } VertexElemIter MeshData::getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { UINT8* data; UINT32 vertexStride; getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); return VertexElemIter(data, vertexStride, mNumVertices); } void MeshData::getDataForIterator(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8*& data, UINT32& stride) const { if(!hasElement(semantic, semanticIdx, streamIdx)) { CM_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: " + toString(semanticIdx) + ", Stream index: " + toString(streamIdx)); } UINT32 indexBufferOffset = getIndexBufferSize(); UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx); data = getData() + indexBufferOffset + elementOffset; stride = getVertexStride(streamIdx); } UINT32 MeshData::getIndexBufferOffset(UINT32 subMesh) const { if(subMesh < 0 || (subMesh > (UINT32)mSubMeshes.size())) { CM_EXCEPT(InvalidParametersException, "Submesh out of range: " + toString(subMesh) + ". Allowed range: 0 .. " + toString((UINT32)mSubMeshes.size())); } UINT32 offset = 0; for(UINT32 i = 0; i < subMesh; i++) { offset += mSubMeshes[i].numIndices * getIndexElementSize(); } return offset; } UINT32 MeshData::getStreamOffset(UINT32 streamIdx) const { UINT32 streamOffset = 0; bool found = false; for(auto& element : mVertexElements) { if(element.getStreamIdx() == streamIdx) { found = true; break; } streamOffset += element.getSize(); } if(!found) CM_EXCEPT(InternalErrorException, "Cannot find the specified stream: " + toString(streamIdx)); return streamOffset * mNumVertices; } UINT32 MeshData::getElementSize(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const { for(auto& element : mVertexElements) { if(element.getSemantic() == semantic && element.getSemanticIdx() == semanticIdx && element.getStreamIdx() == streamIdx) return element.getSize(); } return -1; } UINT8* MeshData::getElementData(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const { return getData() + getIndexBufferSize() + getElementOffset(semantic, semanticIdx, streamIdx); } UINT8* MeshData::getStreamData(UINT32 streamIdx) const { return getData() + getIndexBufferSize() + getStreamOffset(streamIdx); } UINT32 MeshData::getIndexElementSize() const { return mIndexType == IndexBuffer::IT_32BIT ? sizeof(UINT32) : sizeof(UINT16); } UINT32 MeshData::getElementOffset(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const { UINT32 streamOffset = getStreamOffset(streamIdx); UINT32 vertexOffset = 0; for(auto& element : mVertexElements) { if(element.getStreamIdx() != streamIdx) continue; if(element.getSemantic() == semantic && element.getSemanticIdx() == semanticIdx) break; vertexOffset += element.getSize(); } return streamOffset * mNumVertices + vertexOffset; } UINT32 MeshData::getStreamSize(UINT32 streamIdx) const { UINT32 vertexStride = 0; for(auto& element : mVertexElements) { if(element.getStreamIdx() == streamIdx) vertexStride += element.getSize(); } return vertexStride * mNumVertices; } UINT32 MeshData::getStreamSize() const { UINT32 vertexStride = 0; for(auto& element : mVertexElements) { vertexStride += element.getSize(); } return vertexStride * mNumVertices; } UINT32 MeshData::getVertexStride(UINT32 streamIdx) const { UINT32 vertexStride = 0; for(auto& element : mVertexElements) { if(element.getStreamIdx() == streamIdx) vertexStride += element.getSize(); } return vertexStride; } void MeshData::clearIfItExists(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) { auto findIter = std::find_if(mVertexElements.begin(), mVertexElements.end(), [semantic, semanticIdx, streamIdx] (const VertexElement& x) { return x.getSemantic() == semantic && x.getSemanticIdx() == semanticIdx && x.getStreamIdx() == streamIdx; }); if(findIter != mVertexElements.end()) { mVertexElements.erase(findIter); } } /************************************************************************/ /* SERIALIZATION */ /************************************************************************/ RTTITypeBase* MeshData::getRTTIStatic() { return MeshDataRTTI::instance(); } RTTITypeBase* MeshData::getRTTI() const { return MeshData::getRTTIStatic(); } }