MeshBinaryLoader.cpp 7.5 KB

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