CmMesh.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include "CmMesh.h"
  2. #include "CmMeshRTTI.h"
  3. #include "CmMeshData.h"
  4. #include "CmVector2.h"
  5. #include "CmVector3.h"
  6. #include "CmDebug.h"
  7. #include "CmHardwareBufferManager.h"
  8. #include "CmMeshManager.h"
  9. #include "CmCoreThread.h"
  10. #include "CmAsyncOp.h"
  11. #include "CmAABox.h"
  12. #include "CmVertexDataDesc.h"
  13. #include "CmProfiler.h"
  14. namespace CamelotFramework
  15. {
  16. Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
  17. MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
  18. :mVertexData(nullptr), mIndexData(nullptr), mNumVertices(numVertices), mNumIndices(numIndices),
  19. mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType),
  20. mDefaultSubMesh(0, numIndices, drawOp)
  21. {
  22. mSubMeshes.reserve(10);
  23. }
  24. Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
  25. const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
  26. :mVertexData(nullptr), mIndexData(nullptr), mNumVertices(numVertices), mNumIndices(numIndices),
  27. mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType),
  28. mTempInitialMeshData(initialMeshData), mDefaultSubMesh(0, numIndices, drawOp)
  29. {
  30. mSubMeshes.reserve(10);
  31. }
  32. Mesh::Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
  33. :mVertexData(nullptr), mIndexData(nullptr), mNumVertices(initialMeshData->getNumVertices()),
  34. mNumIndices(initialMeshData->getNumIndices()), mBufferType(bufferType), mIndexType(initialMeshData->getIndexType()),
  35. mVertexDesc(initialMeshData->getVertexDesc()), mTempInitialMeshData(initialMeshData),
  36. mDefaultSubMesh(0, initialMeshData->getNumIndices(), drawOp)
  37. {
  38. mSubMeshes.reserve(10);
  39. }
  40. Mesh::Mesh()
  41. :mVertexData(nullptr), mIndexData(nullptr), mNumVertices(0), mNumIndices(0),
  42. mBufferType(MeshBufferType::Static), mIndexType(IndexBuffer::IT_32BIT),
  43. mDefaultSubMesh(0, 0, DOT_TRIANGLE_LIST)
  44. {
  45. mSubMeshes.reserve(10);
  46. }
  47. Mesh::~Mesh()
  48. {
  49. }
  50. void Mesh::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer)
  51. {
  52. THROW_IF_NOT_CORE_THREAD;
  53. if(data.getTypeId() != TID_MeshData)
  54. CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only MeshData is supported.");
  55. if(discardEntireBuffer)
  56. {
  57. if(mBufferType == MeshBufferType::Static)
  58. {
  59. LOGWRN("Buffer discard is enabled but buffer was not created as dynamic. Disabling discard.");
  60. discardEntireBuffer = false;
  61. }
  62. }
  63. else
  64. {
  65. if(mBufferType == MeshBufferType::Dynamic)
  66. {
  67. LOGWRN("Buffer discard is not enabled but buffer was created as dynamic. Enabling discard.");
  68. discardEntireBuffer = true;
  69. }
  70. }
  71. const MeshData& meshData = static_cast<const MeshData&>(data);
  72. // Indices
  73. UINT32 indexOffset = meshData.getResourceIndexOffset() * meshData.getIndexElementSize();
  74. UINT32 indicesSize = meshData.getIndexBufferSize();
  75. UINT8* srcIdxData = meshData.getIndexData();
  76. if((indexOffset + indicesSize) > mIndexData->indexBuffer->getSizeInBytes())
  77. CM_EXCEPT(InvalidParametersException, "Index buffer values are being written out of valid range.");
  78. mIndexData->indexBuffer->writeData(indexOffset, indicesSize, srcIdxData, discardEntireBuffer);
  79. // Vertices
  80. for(UINT32 i = 0; i <= meshData.getVertexDesc()->getMaxStreamIdx(); i++)
  81. {
  82. if(!meshData.getVertexDesc()->hasStream(i))
  83. continue;
  84. if(i >= mVertexData->getBufferCount())
  85. CM_EXCEPT(InvalidParametersException, "Attempting to write to a vertex stream that doesn't exist on this mesh.");
  86. VertexBufferPtr vertexBuffer = mVertexData->getBuffer(i);
  87. UINT32 bufferOffset = meshData.getResourceVertexOffset() * meshData.getVertexDesc()->getVertexStride(i);
  88. UINT32 bufferSize = meshData.getStreamSize(i);
  89. UINT8* srcVertBufferData = meshData.getStreamData(i);
  90. if((bufferOffset + bufferSize) > vertexBuffer->getSizeInBytes())
  91. CM_EXCEPT(InvalidParametersException, "Vertex buffer values for stream \"" + toString(i) + "\" are being written out of valid range.");
  92. if(vertexBuffer->vertexColorReqRGBFlip())
  93. {
  94. UINT8* bufferCopy = (UINT8*)cm_alloc(bufferSize);
  95. memcpy(bufferCopy, srcVertBufferData, bufferSize); // TODO Low priority - Attempt to avoid this copy
  96. UINT32 vertexStride = meshData.getVertexDesc()->getVertexStride(i);
  97. for(INT32 semanticIdx = 0; semanticIdx < VertexBuffer::MAX_SEMANTIC_IDX; semanticIdx++)
  98. {
  99. if(!meshData.getVertexDesc()->hasElement(VES_COLOR, semanticIdx, i))
  100. continue;
  101. UINT8* colorData = bufferCopy + meshData.getElementOffset(VES_COLOR, semanticIdx, i);
  102. for(UINT32 j = 0; j < mVertexData->vertexCount; j++)
  103. {
  104. UINT32* curColor = (UINT32*)colorData;
  105. (*curColor) = ((*curColor) & 0xFF00FF00) | ((*curColor >> 16) & 0x000000FF) | ((*curColor << 16) & 0x00FF0000);
  106. colorData += vertexStride;
  107. }
  108. }
  109. vertexBuffer->writeData(bufferOffset, bufferSize, bufferCopy, discardEntireBuffer);
  110. cm_free(bufferCopy);
  111. }
  112. else
  113. {
  114. vertexBuffer->writeData(bufferOffset, bufferSize, srcVertBufferData, discardEntireBuffer);
  115. }
  116. }
  117. }
  118. void Mesh::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
  119. {
  120. THROW_IF_NOT_CORE_THREAD;
  121. if(data.getTypeId() != TID_MeshData)
  122. CM_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only MeshData is supported.");
  123. IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
  124. if(mIndexData)
  125. indexType = mIndexData->indexBuffer->getType();
  126. MeshData& meshData = static_cast<MeshData&>(data);
  127. if(mIndexData)
  128. {
  129. UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
  130. UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
  131. UINT32 indexResourceOffset = meshData.getResourceIndexOffset();
  132. UINT8* indices = nullptr;
  133. if(indexType == IndexBuffer::IT_16BIT)
  134. indices = (UINT8*)meshData.getIndices16();
  135. else
  136. indices = (UINT8*)meshData.getIndices32();
  137. UINT32 remainingNumIndices = (UINT32)std::max(0, (INT32)(mNumIndices - indexResourceOffset));
  138. UINT32 numIndicesToCopy = std::min(remainingNumIndices, meshData.getNumIndices());
  139. UINT32 indicesSize = numIndicesToCopy * idxElemSize;
  140. if(indicesSize > meshData.getIndexBufferSize())
  141. CM_EXCEPT(InvalidParametersException, "Provided buffer doesn't have enough space to store mesh indices.");
  142. idxData += indexResourceOffset * idxElemSize;
  143. memcpy(indices, idxData, numIndicesToCopy * idxElemSize);
  144. mIndexData->indexBuffer->unlock();
  145. }
  146. if(mVertexData)
  147. {
  148. auto vertexBuffers = mVertexData->getBuffers();
  149. UINT32 streamIdx = 0;
  150. for(auto iter = vertexBuffers.begin(); iter != vertexBuffers.end() ; ++iter)
  151. {
  152. if(streamIdx > meshData.getVertexDesc()->getMaxStreamIdx())
  153. continue;
  154. UINT32 vertexResourceOffset = meshData.getResourceVertexOffset();
  155. UINT32 remainingNumVertices = (UINT32)std::max(0, (INT32)(mNumVertices - vertexResourceOffset));
  156. UINT32 numVerticesToCopy = std::min(remainingNumVertices, meshData.getNumVertices());
  157. VertexBufferPtr vertexBuffer = iter->second;
  158. UINT32 bufferSize = vertexBuffer->getVertexSize() * numVerticesToCopy;
  159. UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY)) + vertexResourceOffset * meshData.getVertexDesc()->getVertexStride(streamIdx);
  160. if(bufferSize > meshData.getStreamSize(streamIdx))
  161. CM_EXCEPT(InvalidParametersException, "Provided buffer doesn't have enough space to store mesh vertices.");
  162. UINT8* dest = meshData.getStreamData(streamIdx);
  163. memcpy(dest, vertDataPtr, bufferSize);
  164. vertexBuffer->unlock();
  165. streamIdx++;
  166. }
  167. }
  168. }
  169. MeshDataPtr Mesh::allocateSubresourceBuffer(UINT32 subresourceIdx) const
  170. {
  171. IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
  172. if(mIndexData)
  173. indexType = mIndexData->indexBuffer->getType();
  174. MeshDataPtr meshData = cm_shared_ptr<MeshData>(mVertexData->vertexCount, mNumIndices, mVertexDesc, indexType);
  175. return meshData;
  176. }
  177. const AABox& Mesh::getBounds() const
  178. {
  179. // TODO - Retrieve bounds for entire mesh (need to calculate them during creation)
  180. return AABox::BOX_EMPTY;
  181. }
  182. const AABox& Mesh::getBounds(UINT32 submeshIdx) const
  183. {
  184. // TODO - Retrieve bounds a specific sub-mesh (need to calculate them during creation)
  185. return AABox::BOX_EMPTY;
  186. }
  187. std::shared_ptr<VertexData> Mesh::getVertexData() const
  188. {
  189. THROW_IF_NOT_CORE_THREAD;
  190. return mVertexData;
  191. }
  192. std::shared_ptr<IndexData> Mesh::getIndexData() const
  193. {
  194. THROW_IF_NOT_CORE_THREAD;
  195. return mIndexData;
  196. }
  197. void Mesh::clearSubMeshes()
  198. {
  199. THROW_IF_CORE_THREAD;
  200. mSubMeshes.clear();
  201. }
  202. void Mesh::addSubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp)
  203. {
  204. if((indexOffset + indexCount) >= mNumIndices)
  205. {
  206. LOGWRN("Provided sub-mesh references indexes out of range. Sub-mesh range: "
  207. + toString(indexOffset) + " .. " + toString(indexOffset + indexCount) + "." \
  208. "Valid range is: 0 .. " + toString(mNumIndices) + ". Ignoring command.");
  209. return;
  210. }
  211. mSubMeshes.push_back(SubMesh(indexOffset, indexCount, drawOp));
  212. }
  213. void Mesh::setSubMeshes(const Vector<SubMesh>::type& subMeshes)
  214. {
  215. THROW_IF_CORE_THREAD;
  216. for(auto& subMesh : subMeshes)
  217. {
  218. if((subMesh.indexOffset + subMesh.indexCount) >= mNumIndices)
  219. {
  220. LOGWRN("Provided sub-mesh references indexes out of range. Sub-mesh range: "
  221. + toString(subMesh.indexOffset) + " .. " + toString(subMesh.indexOffset + subMesh.indexCount) + "." \
  222. "Valid range is: 0 .. " + toString(mNumIndices) + ". Ignoring command.");
  223. return;
  224. }
  225. }
  226. mSubMeshes = subMeshes;
  227. }
  228. const SubMesh& Mesh::getSubMesh(UINT32 subMeshIdx) const
  229. {
  230. THROW_IF_CORE_THREAD;
  231. if(mSubMeshes.size() == 0 && subMeshIdx == 0)
  232. {
  233. return mDefaultSubMesh;
  234. }
  235. if(subMeshIdx < 0 || subMeshIdx >= mSubMeshes.size())
  236. {
  237. CM_EXCEPT(InvalidParametersException, "Invalid sub-mesh index ("
  238. + toString(subMeshIdx) + "). Number of sub-meshes available: " + toString((int)mSubMeshes.size()));
  239. }
  240. return mSubMeshes[subMeshIdx];
  241. }
  242. UINT32 Mesh::getNumSubMeshes() const
  243. {
  244. THROW_IF_CORE_THREAD;
  245. if(mSubMeshes.size() > 0)
  246. return (UINT32)mSubMeshes.size();
  247. else
  248. {
  249. if(mDefaultSubMesh.indexCount > 0)
  250. return 1;
  251. else
  252. return 0;
  253. }
  254. }
  255. void Mesh::initialize_internal()
  256. {
  257. THROW_IF_NOT_CORE_THREAD;
  258. mIndexData = std::shared_ptr<IndexData>(cm_new<IndexData, PoolAlloc>());
  259. mIndexData->indexCount = mNumIndices;
  260. mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
  261. mIndexType,
  262. mIndexData->indexCount,
  263. mBufferType == MeshBufferType::Dynamic ? GBU_DYNAMIC : GBU_STATIC);
  264. mVertexData = std::shared_ptr<VertexData>(cm_new<VertexData, PoolAlloc>());
  265. mVertexData->vertexCount = mNumVertices;
  266. mVertexData->vertexDeclaration = mVertexDesc->createDeclaration();
  267. for(UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
  268. {
  269. if(!mVertexDesc->hasStream(i))
  270. continue;
  271. VertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
  272. mVertexData->vertexDeclaration->getVertexSize(i),
  273. mVertexData->vertexCount,
  274. mBufferType == MeshBufferType::Dynamic ? GBU_DYNAMIC : GBU_STATIC);
  275. mVertexData->setBuffer(i, vertexBuffer);
  276. }
  277. // TODO Low priority - DX11 (and maybe OpenGL)? allow an optimization that allows you to set
  278. // buffer data upon buffer construction, instead of setting it in a second step like I do here
  279. if(mTempInitialMeshData != nullptr)
  280. {
  281. writeSubresource(0, *mTempInitialMeshData, mBufferType == MeshBufferType::Dynamic);
  282. mTempInitialMeshData = nullptr;
  283. }
  284. Resource::initialize_internal();
  285. }
  286. void Mesh::destroy_internal()
  287. {
  288. THROW_IF_NOT_CORE_THREAD;
  289. Resource::destroy_internal();
  290. }
  291. HMesh Mesh::dummy()
  292. {
  293. return MeshManager::instance().getDummyMesh();
  294. }
  295. /************************************************************************/
  296. /* SERIALIZATION */
  297. /************************************************************************/
  298. RTTITypeBase* Mesh::getRTTIStatic()
  299. {
  300. return MeshRTTI::instance();
  301. }
  302. RTTITypeBase* Mesh::getRTTI() const
  303. {
  304. return Mesh::getRTTIStatic();
  305. }
  306. /************************************************************************/
  307. /* STATICS */
  308. /************************************************************************/
  309. HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
  310. MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
  311. {
  312. MeshPtr meshPtr = MeshManager::instance().create(numVertices, numIndices, vertexDesc, bufferType, drawOp, indexType);
  313. return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
  314. }
  315. HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
  316. const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
  317. {
  318. MeshPtr meshPtr = MeshManager::instance().create(numVertices, numIndices, vertexDesc,
  319. initialMeshData, bufferType, drawOp, indexType);
  320. return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
  321. }
  322. HMesh Mesh::create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
  323. {
  324. MeshPtr meshPtr = MeshManager::instance().create(initialMeshData, bufferType, drawOp);
  325. return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
  326. }
  327. }