| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
| 3 | #include "Mesh/BsMeshData.h" |
| 4 | #include "Math/BsVector2.h" |
| 5 | #include "Math/BsVector3.h" |
| 6 | #include "Math/BsSphere.h" |
| 7 | #include "Math/BsAABox.h" |
| 8 | #include "Managers/BsHardwareBufferManager.h" |
| 9 | #include "Private/RTTI/BsMeshDataRTTI.h" |
| 10 | #include "RenderAPI/BsVertexDeclaration.h" |
| 11 | #include "RenderAPI/BsVertexDataDesc.h" |
| 12 | #include "Error/BsException.h" |
| 13 | #include "Debug/BsDebug.h" |
| 14 | |
| 15 | namespace bs |
| 16 | { |
| 17 | MeshData::MeshData(UINT32 numVertices, UINT32 numIndexes, const SPtr<VertexDataDesc>& vertexData, IndexType indexType) |
| 18 | :mNumVertices(numVertices), mNumIndices(numIndexes), mIndexType(indexType), mVertexData(vertexData) |
| 19 | { |
| 20 | allocateInternalBuffer(); |
| 21 | } |
| 22 | |
| 23 | MeshData::MeshData() |
| 24 | :mNumVertices(0), mNumIndices(0), mIndexType(IT_32BIT) |
| 25 | { } |
| 26 | |
| 27 | MeshData::~MeshData() |
| 28 | { } |
| 29 | |
| 30 | UINT32 MeshData::getNumIndices() const |
| 31 | { |
| 32 | return mNumIndices; |
| 33 | } |
| 34 | |
| 35 | UINT16* MeshData::getIndices16() const |
| 36 | { |
| 37 | if(mIndexType != IT_16BIT) |
| 38 | BS_EXCEPT(InternalErrorException, "Attempting to get 16bit index buffer, but internally allocated buffer is 32 bit." ); |
| 39 | |
| 40 | UINT32 indexBufferOffset = getIndexBufferOffset(); |
| 41 | |
| 42 | return (UINT16*)(getData() + indexBufferOffset); |
| 43 | } |
| 44 | |
| 45 | UINT32* MeshData::getIndices32() const |
| 46 | { |
| 47 | if(mIndexType != IT_32BIT) |
| 48 | BS_EXCEPT(InternalErrorException, "Attempting to get 32bit index buffer, but internally allocated buffer is 16 bit." ); |
| 49 | |
| 50 | UINT32 indexBufferOffset = getIndexBufferOffset(); |
| 51 | |
| 52 | return (UINT32*)(getData() + indexBufferOffset); |
| 53 | } |
| 54 | |
| 55 | UINT32 MeshData::getInternalBufferSize() const |
| 56 | { |
| 57 | return getIndexBufferSize() + getStreamSize(); |
| 58 | } |
| 59 | |
| 60 | // TODO - This doesn't handle the case where multiple elements in same slot have different data types |
| 61 | SPtr<MeshData> MeshData::combine(const Vector<SPtr<MeshData>>& meshes, const Vector<Vector<SubMesh>>& allSubMeshes, |
| 62 | Vector<SubMesh>& subMeshes) |
| 63 | { |
| 64 | UINT32 totalVertexCount = 0; |
| 65 | UINT32 totalIndexCount = 0; |
| 66 | for(auto& meshData : meshes) |
| 67 | { |
| 68 | totalVertexCount += meshData->getNumVertices(); |
| 69 | totalIndexCount += meshData->getNumIndices(); |
| 70 | } |
| 71 | |
| 72 | SPtr<VertexDataDesc> vertexData = bs_shared_ptr_new<VertexDataDesc>(); |
| 73 | |
| 74 | Vector<VertexElement> combinedVertexElements; |
| 75 | for(auto& meshData : meshes) |
| 76 | { |
| 77 | for(UINT32 i = 0; i < meshData->getVertexDesc()->getNumElements(); i++) |
| 78 | { |
| 79 | const VertexElement& newElement = meshData->getVertexDesc()->getElement(i); |
| 80 | |
| 81 | INT32 alreadyExistsIdx = -1; |
| 82 | UINT32 idx = 0; |
| 83 | |
| 84 | for(auto& existingElement : combinedVertexElements) |
| 85 | { |
| 86 | if(newElement.getSemantic() == existingElement.getSemantic() && newElement.getSemanticIdx() == existingElement.getSemanticIdx() |
| 87 | && newElement.getStreamIdx() == existingElement.getStreamIdx()) |
| 88 | { |
| 89 | if(newElement.getType() != existingElement.getType()) |
| 90 | { |
| 91 | BS_EXCEPT(NotImplementedException, "Two elements have same semantics but different types. This is not supported." ); |
| 92 | } |
| 93 | |
| 94 | alreadyExistsIdx = idx; |
| 95 | break; |
| 96 | } |
| 97 | |
| 98 | idx++; |
| 99 | } |
| 100 | |
| 101 | if(alreadyExistsIdx == -1) |
| 102 | { |
| 103 | combinedVertexElements.push_back(newElement); |
| 104 | vertexData->addVertElem(newElement.getType(), newElement.getSemantic(), newElement.getSemanticIdx(), newElement.getStreamIdx()); |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | SPtr<MeshData> combinedMeshData = bs_shared_ptr_new<MeshData>(totalVertexCount, totalIndexCount, vertexData); |
| 110 | |
| 111 | // Copy indices |
| 112 | UINT32 vertexOffset = 0; |
| 113 | UINT32 indexOffset = 0; |
| 114 | UINT32* idxPtr = combinedMeshData->getIndices32(); |
| 115 | for(auto& meshData : meshes) |
| 116 | { |
| 117 | UINT32 numIndices = meshData->getNumIndices(); |
| 118 | UINT32* srcData = meshData->getIndices32(); |
| 119 | |
| 120 | for(UINT32 j = 0; j < numIndices; j++) |
| 121 | idxPtr[j] = srcData[j] + vertexOffset; |
| 122 | |
| 123 | indexOffset += numIndices; |
| 124 | idxPtr += numIndices; |
| 125 | vertexOffset += meshData->getNumVertices(); |
| 126 | } |
| 127 | |
| 128 | // Copy sub-meshes |
| 129 | UINT32 meshIdx = 0; |
| 130 | indexOffset = 0; |
| 131 | for(auto& meshData : meshes) |
| 132 | { |
| 133 | UINT32 numIndices = meshData->getNumIndices(); |
| 134 | const Vector<SubMesh> curSubMeshes = allSubMeshes[meshIdx]; |
| 135 | |
| 136 | for(auto& subMesh : curSubMeshes) |
| 137 | { |
| 138 | subMeshes.push_back(SubMesh(subMesh.indexOffset + indexOffset, subMesh.indexCount, subMesh.drawOp)); |
| 139 | } |
| 140 | |
| 141 | indexOffset += numIndices; |
| 142 | meshIdx++; |
| 143 | } |
| 144 | |
| 145 | // Copy vertices |
| 146 | vertexOffset = 0; |
| 147 | for(auto& meshData : meshes) |
| 148 | { |
| 149 | for(auto& element : combinedVertexElements) |
| 150 | { |
| 151 | UINT32 dstVertexStride = vertexData->getVertexStride(element.getStreamIdx()); |
| 152 | UINT8* dstData = combinedMeshData->getElementData(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx()); |
| 153 | dstData += vertexOffset * dstVertexStride; |
| 154 | |
| 155 | UINT32 numSrcVertices = meshData->getNumVertices(); |
| 156 | UINT32 vertexSize = vertexData->getElementSize(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx()); |
| 157 | |
| 158 | if(meshData->getVertexDesc()->hasElement(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx())) |
| 159 | { |
| 160 | UINT32 srcVertexStride = meshData->getVertexDesc()->getVertexStride(element.getStreamIdx()); |
| 161 | UINT8* srcData = meshData->getElementData(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx()); |
| 162 | |
| 163 | for(UINT32 i = 0; i < numSrcVertices; i++) |
| 164 | { |
| 165 | memcpy(dstData, srcData, vertexSize); |
| 166 | dstData += dstVertexStride; |
| 167 | srcData += srcVertexStride; |
| 168 | } |
| 169 | } |
| 170 | else |
| 171 | { |
| 172 | for(UINT32 i = 0; i < numSrcVertices; i++) |
| 173 | { |
| 174 | memset(dstData, 0, vertexSize); |
| 175 | dstData += dstVertexStride; |
| 176 | } |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | vertexOffset += meshData->getNumVertices(); |
| 181 | } |
| 182 | |
| 183 | return combinedMeshData; |
| 184 | } |
| 185 | |
| 186 | void MeshData::setVertexData(VertexElementSemantic semantic, void* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx) |
| 187 | { |
| 188 | assert(data != nullptr); |
| 189 | |
| 190 | if(!mVertexData->hasElement(semantic, semanticIdx, streamIdx)) |
| 191 | { |
| 192 | LOGWRN("MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: " |
| 193 | + toString(semanticIdx) + ", Stream index: " + toString(streamIdx)); |
| 194 | return; |
| 195 | } |
| 196 | |
| 197 | UINT32 elementSize = mVertexData->getElementSize(semantic, semanticIdx, streamIdx); |
| 198 | UINT32 totalSize = elementSize * mNumVertices; |
| 199 | |
| 200 | if(totalSize != size) |
| 201 | { |
| 202 | BS_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size)); |
| 203 | } |
| 204 | |
| 205 | UINT32 indexBufferOffset = getIndexBufferSize(); |
| 206 | |
| 207 | UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx); |
| 208 | UINT32 vertexStride = mVertexData->getVertexStride(streamIdx); |
| 209 | |
| 210 | UINT8* dst = getData() + indexBufferOffset + elementOffset; |
| 211 | UINT8* src = (UINT8*)data; |
| 212 | for(UINT32 i = 0; i < mNumVertices; i++) |
| 213 | { |
| 214 | memcpy(dst, src, elementSize); |
| 215 | dst += vertexStride; |
| 216 | src += elementSize; |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | void MeshData::getVertexData(VertexElementSemantic semantic, void* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx) |
| 221 | { |
| 222 | assert(data != nullptr); |
| 223 | |
| 224 | if (!mVertexData->hasElement(semantic, semanticIdx, streamIdx)) |
| 225 | { |
| 226 | LOGWRN("MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: " |
| 227 | + toString(semanticIdx) + ", Stream index: " + toString(streamIdx)); |
| 228 | return; |
| 229 | } |
| 230 | |
| 231 | UINT32 elementSize = mVertexData->getElementSize(semantic, semanticIdx, streamIdx); |
| 232 | UINT32 totalSize = elementSize * mNumVertices; |
| 233 | |
| 234 | if (totalSize != size) |
| 235 | { |
| 236 | BS_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size)); |
| 237 | } |
| 238 | |
| 239 | UINT32 indexBufferOffset = getIndexBufferSize(); |
| 240 | |
| 241 | UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx); |
| 242 | UINT32 vertexStride = mVertexData->getVertexStride(streamIdx); |
| 243 | |
| 244 | UINT8* src = getData() + indexBufferOffset + elementOffset; |
| 245 | UINT8* dst = (UINT8*)data; |
| 246 | for (UINT32 i = 0; i < mNumVertices; i++) |
| 247 | { |
| 248 | memcpy(dst, src, elementSize); |
| 249 | dst += elementSize; |
| 250 | src += vertexStride; |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | VertexElemIter<Vector2> MeshData::getVec2DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) |
| 255 | { |
| 256 | UINT8* data; |
| 257 | UINT32 vertexStride; |
| 258 | getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); |
| 259 | |
| 260 | return VertexElemIter<Vector2>(data, vertexStride, mNumVertices); |
| 261 | } |
| 262 | |
| 263 | VertexElemIter<Vector3> MeshData::getVec3DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) |
| 264 | { |
| 265 | UINT8* data; |
| 266 | UINT32 vertexStride; |
| 267 | getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); |
| 268 | |
| 269 | return VertexElemIter<Vector3>(data, vertexStride, mNumVertices); |
| 270 | } |
| 271 | |
| 272 | VertexElemIter<Vector4> MeshData::getVec4DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) |
| 273 | { |
| 274 | UINT8* data; |
| 275 | UINT32 vertexStride; |
| 276 | getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); |
| 277 | |
| 278 | return VertexElemIter<Vector4>(data, vertexStride, mNumVertices); |
| 279 | } |
| 280 | |
| 281 | VertexElemIter<UINT32> MeshData::getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) |
| 282 | { |
| 283 | UINT8* data; |
| 284 | UINT32 vertexStride; |
| 285 | getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride); |
| 286 | |
| 287 | return VertexElemIter<UINT32>(data, vertexStride, mNumVertices); |
| 288 | } |
| 289 | |
| 290 | void MeshData::getDataForIterator(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8*& data, UINT32& stride) const |
| 291 | { |
| 292 | if(!mVertexData->hasElement(semantic, semanticIdx, streamIdx)) |
| 293 | { |
| 294 | BS_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: " |
| 295 | + toString(semanticIdx) + ", Stream index: " + toString(streamIdx)); |
| 296 | } |
| 297 | |
| 298 | UINT32 indexBufferOffset = getIndexBufferSize(); |
| 299 | |
| 300 | UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx); |
| 301 | |
| 302 | data = getData() + indexBufferOffset + elementOffset; |
| 303 | stride = mVertexData->getVertexStride(streamIdx); |
| 304 | } |
| 305 | |
| 306 | UINT32 MeshData::getIndexBufferOffset() const |
| 307 | { |
| 308 | return 0; |
| 309 | } |
| 310 | |
| 311 | UINT32 MeshData::getStreamOffset(UINT32 streamIdx) const |
| 312 | { |
| 313 | UINT32 streamOffset = mVertexData->getStreamOffset(streamIdx); |
| 314 | |
| 315 | return streamOffset * mNumVertices; |
| 316 | } |
| 317 | |
| 318 | UINT8* MeshData::getElementData(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const |
| 319 | { |
| 320 | return getData() + getIndexBufferSize() + getElementOffset(semantic, semanticIdx, streamIdx); |
| 321 | } |
| 322 | |
| 323 | UINT8* MeshData::getStreamData(UINT32 streamIdx) const |
| 324 | { |
| 325 | return getData() + getIndexBufferSize() + getStreamOffset(streamIdx); |
| 326 | } |
| 327 | |
| 328 | UINT32 MeshData::getIndexElementSize() const |
| 329 | { |
| 330 | return mIndexType == IT_32BIT ? sizeof(UINT32) : sizeof(UINT16); |
| 331 | } |
| 332 | |
| 333 | UINT32 MeshData::getElementOffset(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const |
| 334 | { |
| 335 | return getStreamOffset(streamIdx) + mVertexData->getElementOffsetFromStream(semantic, semanticIdx, streamIdx); |
| 336 | } |
| 337 | |
| 338 | UINT32 MeshData::getIndexBufferSize() const |
| 339 | { |
| 340 | return mNumIndices * getIndexElementSize(); |
| 341 | } |
| 342 | |
| 343 | UINT32 MeshData::getStreamSize(UINT32 streamIdx) const |
| 344 | { |
| 345 | return mVertexData->getVertexStride(streamIdx) * mNumVertices; |
| 346 | } |
| 347 | |
| 348 | UINT32 MeshData::getStreamSize() const |
| 349 | { |
| 350 | return mVertexData->getVertexStride() * mNumVertices; |
| 351 | } |
| 352 | |
| 353 | Bounds MeshData::calculateBounds() const |
| 354 | { |
| 355 | Bounds bounds; |
| 356 | |
| 357 | SPtr<VertexDataDesc> vertexDesc = getVertexDesc(); |
| 358 | for (UINT32 i = 0; i < vertexDesc->getNumElements(); i++) |
| 359 | { |
| 360 | const VertexElement& curElement = vertexDesc->getElement(i); |
| 361 | |
| 362 | if (curElement.getSemantic() != VES_POSITION || (curElement.getType() != VET_FLOAT3 && curElement.getType() != VET_FLOAT4)) |
| 363 | continue; |
| 364 | |
| 365 | UINT8* data = getElementData(curElement.getSemantic(), curElement.getSemanticIdx(), curElement.getStreamIdx()); |
| 366 | UINT32 stride = vertexDesc->getVertexStride(curElement.getStreamIdx()); |
| 367 | |
| 368 | if (getNumVertices() > 0) |
| 369 | { |
| 370 | Vector3 curPosition = *(Vector3*)data; |
| 371 | Vector3 accum = curPosition; |
| 372 | Vector3 min = curPosition; |
| 373 | Vector3 max = curPosition; |
| 374 | |
| 375 | for (UINT32 i = 1; i < getNumVertices(); i++) |
| 376 | { |
| 377 | curPosition = *(Vector3*)(data + stride * i); |
| 378 | accum += curPosition; |
| 379 | min = Vector3::min(min, curPosition); |
| 380 | max = Vector3::max(max, curPosition); |
| 381 | } |
| 382 | |
| 383 | Vector3 center = accum / (float)getNumVertices(); |
| 384 | float radiusSqrd = 0.0f; |
| 385 | |
| 386 | for (UINT32 i = 0; i < getNumVertices(); i++) |
| 387 | { |
| 388 | curPosition = *(Vector3*)(data + stride * i); |
| 389 | float dist = center.squaredDistance(curPosition); |
| 390 | |
| 391 | if (dist > radiusSqrd) |
| 392 | radiusSqrd = dist; |
| 393 | } |
| 394 | |
| 395 | float radius = Math::sqrt(radiusSqrd); |
| 396 | |
| 397 | bounds = Bounds(AABox(min, max), Sphere(center, radius)); |
| 398 | break; |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | return bounds; |
| 403 | } |
| 404 | |
| 405 | /************************************************************************/ |
| 406 | /* SERIALIZATION */ |
| 407 | /************************************************************************/ |
| 408 | |
| 409 | RTTITypeBase* MeshData::getRTTIStatic() |
| 410 | { |
| 411 | return MeshDataRTTI::instance(); |
| 412 | } |
| 413 | |
| 414 | RTTITypeBase* MeshData::getRTTI() const |
| 415 | { |
| 416 | return MeshData::getRTTIStatic(); |
| 417 | } |
| 418 | } |