MeshBinaryLoader.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Resource/MeshBinaryLoader.h>
  6. #include <AnKi/Resource/ResourceManager.h>
  7. namespace anki {
  8. MeshBinaryLoader::MeshBinaryLoader(ResourceManager* manager)
  9. : MeshBinaryLoader(manager, manager->getTempAllocator())
  10. {
  11. }
  12. MeshBinaryLoader::~MeshBinaryLoader()
  13. {
  14. m_subMeshes.destroy(m_alloc);
  15. }
  16. Error MeshBinaryLoader::load(const ResourceFilename& filename)
  17. {
  18. auto& alloc = m_alloc;
  19. // Load header
  20. ANKI_CHECK(m_manager->getFilesystem().openFile(filename, m_file));
  21. ANKI_CHECK(m_file->read(&m_header, sizeof(m_header)));
  22. ANKI_CHECK(checkHeader());
  23. // Read submesh info
  24. {
  25. m_subMeshes.create(alloc, m_header.m_subMeshCount);
  26. ANKI_CHECK(m_file->read(&m_subMeshes[0], m_subMeshes.getSizeInBytes()));
  27. // Checks
  28. const U32 indicesPerFace = !!(m_header.m_flags & MeshBinaryFlag::QUAD) ? 4 : 3;
  29. U idxSum = 0;
  30. for(U32 i = 0; i < m_subMeshes.getSize(); i++)
  31. {
  32. const MeshBinarySubMesh& sm = m_subMeshes[i];
  33. if(sm.m_firstIndex != idxSum || (sm.m_indexCount % indicesPerFace) != 0)
  34. {
  35. ANKI_RESOURCE_LOGE("Incorrect sub mesh info");
  36. return Error::USER_DATA;
  37. }
  38. for(U d = 0; d < 3; ++d)
  39. {
  40. if(sm.m_aabbMin[i] >= sm.m_aabbMax[i])
  41. {
  42. ANKI_RESOURCE_LOGE("Wrong bounding box");
  43. return Error::USER_DATA;
  44. }
  45. }
  46. idxSum += sm.m_indexCount;
  47. }
  48. if(idxSum != m_header.m_totalIndexCount)
  49. {
  50. ANKI_RESOURCE_LOGE("Incorrect sub mesh info");
  51. return Error::USER_DATA;
  52. }
  53. }
  54. return Error::NONE;
  55. }
  56. Error MeshBinaryLoader::checkFormat(VertexAttributeId type, ConstWeakArray<Format> supportedFormats,
  57. U32 vertexBufferIdx, U32 relativeOffset) const
  58. {
  59. const MeshBinaryVertexAttribute& attrib = m_header.m_vertexAttributes[type];
  60. // Check format
  61. Bool found = false;
  62. for(Format fmt : supportedFormats)
  63. {
  64. if(fmt == attrib.m_format)
  65. {
  66. found = true;
  67. break;
  68. }
  69. }
  70. if(!found)
  71. {
  72. ANKI_RESOURCE_LOGE("Vertex attribute %u has unsupported format %u", U32(type),
  73. U32(m_header.m_vertexAttributes[type].m_format));
  74. return Error::USER_DATA;
  75. }
  76. if(!attrib.m_format)
  77. {
  78. // Attrib is not in use, no more checks
  79. return Error::NONE;
  80. }
  81. if(attrib.m_bufferBinding != vertexBufferIdx)
  82. {
  83. ANKI_RESOURCE_LOGE("Vertex attribute %u should belong to the %u vertex buffer", U32(type), vertexBufferIdx);
  84. return Error::USER_DATA;
  85. }
  86. if(attrib.m_relativeOffset != relativeOffset)
  87. {
  88. ANKI_RESOURCE_LOGE("Vertex attribute %u should have relative vertex offset equal to %u", U32(type),
  89. relativeOffset);
  90. return Error::USER_DATA;
  91. }
  92. // Scale should be 1.0 for now
  93. if(attrib.m_scale != 1.0f)
  94. {
  95. ANKI_RESOURCE_LOGE("Vertex attribute %u should have 1.0 scale", U32(type));
  96. return Error::USER_DATA;
  97. }
  98. return Error::NONE;
  99. }
  100. Error MeshBinaryLoader::checkHeader() const
  101. {
  102. const MeshBinaryHeader& h = m_header;
  103. // Header
  104. if(memcmp(&h.m_magic[0], MESH_MAGIC, 8) != 0)
  105. {
  106. ANKI_RESOURCE_LOGE("Wrong magic word");
  107. return Error::USER_DATA;
  108. }
  109. // Flags
  110. if((h.m_flags & ~MeshBinaryFlag::ALL) != MeshBinaryFlag::NONE)
  111. {
  112. ANKI_RESOURCE_LOGE("Wrong header flags");
  113. return Error::USER_DATA;
  114. }
  115. // Attributes
  116. ANKI_CHECK(checkFormat(VertexAttributeId::POSITION, Array<Format, 1>{{Format::R32G32B32_SFLOAT}}, 0, 0));
  117. ANKI_CHECK(checkFormat(VertexAttributeId::NORMAL, Array<Format, 1>{{Format::A2B10G10R10_SNORM_PACK32}}, 1, 0));
  118. ANKI_CHECK(checkFormat(VertexAttributeId::TANGENT, Array<Format, 1>{{Format::A2B10G10R10_SNORM_PACK32}}, 1, 4));
  119. ANKI_CHECK(checkFormat(VertexAttributeId::UV0, Array<Format, 1>{{Format::R32G32_SFLOAT}}, 1, 8));
  120. ANKI_CHECK(checkFormat(VertexAttributeId::UV1, Array<Format, 1>{{Format::NONE}}, 1, 0));
  121. ANKI_CHECK(
  122. checkFormat(VertexAttributeId::BONE_INDICES, Array<Format, 2>{{Format::NONE, Format::R8G8B8A8_UINT}}, 2, 0));
  123. ANKI_CHECK(
  124. checkFormat(VertexAttributeId::BONE_WEIGHTS, Array<Format, 2>{{Format::NONE, Format::R8G8B8A8_UNORM}}, 2, 4));
  125. // Vertex buffers
  126. if(m_header.m_vertexBufferCount != 2 + U32(hasBoneInfo()))
  127. {
  128. ANKI_RESOURCE_LOGE("Wrong number of vertex buffers");
  129. return Error::USER_DATA;
  130. }
  131. if(m_header.m_vertexBuffers[0].m_vertexStride != sizeof(Vec3) || m_header.m_vertexBuffers[1].m_vertexStride != 16
  132. || (hasBoneInfo() && m_header.m_vertexBuffers[2].m_vertexStride != 8))
  133. {
  134. ANKI_RESOURCE_LOGE("Some of the vertex buffers have incorrect vertex stride");
  135. return Error::USER_DATA;
  136. }
  137. // Indices format
  138. if(h.m_indexType != IndexType::U16)
  139. {
  140. ANKI_RESOURCE_LOGE("Wrong format for indices");
  141. return Error::USER_DATA;
  142. }
  143. // m_totalIndexCount
  144. const U indicesPerFace = !!(h.m_flags & MeshBinaryFlag::QUAD) ? 4 : 3;
  145. if(h.m_totalIndexCount == 0 || (h.m_totalIndexCount % indicesPerFace) != 0)
  146. {
  147. ANKI_RESOURCE_LOGE("Wrong index count");
  148. return Error::USER_DATA;
  149. }
  150. // m_totalVertexCount
  151. if(h.m_totalVertexCount == 0)
  152. {
  153. ANKI_RESOURCE_LOGE("Wrong vertex count");
  154. return Error::USER_DATA;
  155. }
  156. // m_subMeshCount
  157. if(h.m_subMeshCount == 0)
  158. {
  159. ANKI_RESOURCE_LOGE("Wrong submesh count");
  160. return Error::USER_DATA;
  161. }
  162. // AABB
  163. for(U d = 0; d < 3; ++d)
  164. {
  165. if(h.m_aabbMin[d] >= h.m_aabbMax[d])
  166. {
  167. ANKI_RESOURCE_LOGE("Wrong bounding box");
  168. return Error::USER_DATA;
  169. }
  170. }
  171. // Check the file size
  172. PtrSize totalSize = sizeof(m_header);
  173. totalSize += sizeof(MeshBinarySubMesh) * m_header.m_subMeshCount;
  174. totalSize += getAlignedIndexBufferSize();
  175. for(U32 i = 0; i < m_header.m_vertexBufferCount; ++i)
  176. {
  177. totalSize += getAlignedVertexBufferSize(i);
  178. }
  179. if(totalSize != m_file->getSize())
  180. {
  181. ANKI_RESOURCE_LOGE("Unexpected file size");
  182. return Error::USER_DATA;
  183. }
  184. return Error::NONE;
  185. }
  186. Error MeshBinaryLoader::storeIndexBuffer(void* ptr, PtrSize size)
  187. {
  188. ANKI_ASSERT(ptr);
  189. ANKI_ASSERT(isLoaded());
  190. ANKI_ASSERT(size == getIndexBufferSize());
  191. const PtrSize seek = sizeof(m_header) + m_subMeshes.getSizeInBytes();
  192. ANKI_CHECK(m_file->seek(seek, FileSeekOrigin::BEGINNING));
  193. ANKI_CHECK(m_file->read(ptr, size));
  194. return Error::NONE;
  195. }
  196. Error MeshBinaryLoader::storeVertexBuffer(U32 bufferIdx, void* ptr, PtrSize size)
  197. {
  198. ANKI_ASSERT(ptr);
  199. ANKI_ASSERT(isLoaded());
  200. ANKI_ASSERT(bufferIdx < m_header.m_vertexBufferCount);
  201. ANKI_ASSERT(size == getVertexBufferSize(bufferIdx));
  202. PtrSize seek = sizeof(m_header) + m_subMeshes.getSizeInBytes() + getAlignedIndexBufferSize();
  203. for(U32 i = 0; i < bufferIdx; ++i)
  204. {
  205. seek += getAlignedVertexBufferSize(i);
  206. }
  207. ANKI_CHECK(m_file->seek(seek, FileSeekOrigin::BEGINNING));
  208. ANKI_CHECK(m_file->read(ptr, size));
  209. return Error::NONE;
  210. }
  211. Error MeshBinaryLoader::storeIndicesAndPosition(DynamicArrayAuto<U32>& indices, DynamicArrayAuto<Vec3>& positions)
  212. {
  213. ANKI_ASSERT(isLoaded());
  214. // Store indices
  215. {
  216. indices.resize(m_header.m_totalIndexCount);
  217. // Store to staging buff
  218. DynamicArrayAuto<U8, PtrSize> staging(m_alloc);
  219. staging.create(getIndexBufferSize());
  220. ANKI_CHECK(storeIndexBuffer(&staging[0], staging.getSizeInBytes()));
  221. // Copy from staging
  222. ANKI_ASSERT(m_header.m_indexType == IndexType::U16);
  223. for(U32 i = 0; i < m_header.m_totalIndexCount; ++i)
  224. {
  225. indices[i] = *reinterpret_cast<U16*>(&staging[PtrSize(i) * 2]);
  226. }
  227. }
  228. // Store positions
  229. {
  230. positions.resize(m_header.m_totalVertexCount);
  231. const MeshBinaryVertexAttribute& attrib = m_header.m_vertexAttributes[VertexAttributeId::POSITION];
  232. ANKI_ASSERT(attrib.m_format == Format::R32G32B32_SFLOAT);
  233. ANKI_CHECK(storeVertexBuffer(attrib.m_bufferBinding, &positions[0], positions.getSizeInBytes()));
  234. }
  235. return Error::NONE;
  236. }
  237. } // end namespace anki