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
15namespace 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}