| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- // Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <anki/resource/MeshLoader.h>
- #include <anki/resource/ResourceManager.h>
- #include <anki/resource/ResourceFilesystem.h>
- namespace anki
- {
- MeshLoader::MeshLoader(ResourceManager* manager)
- : MeshLoader(manager, manager->getTempAllocator())
- {
- }
- MeshLoader::~MeshLoader()
- {
- m_subMeshes.destroy(m_alloc);
- }
- Error MeshLoader::load(const ResourceFilename& filename)
- {
- auto& alloc = m_alloc;
- // Load header
- ANKI_CHECK(m_manager->getFilesystem().openFile(filename, m_file));
- ANKI_CHECK(m_file->read(&m_header, sizeof(m_header)));
- ANKI_CHECK(checkHeader());
- // Read submesh info
- {
- m_subMeshes.create(alloc, m_header.m_subMeshCount);
- ANKI_CHECK(m_file->read(&m_subMeshes[0], m_subMeshes.getSizeInBytes()));
- // Checks
- const U32 indicesPerFace = !!(m_header.m_flags & MeshBinaryFile::Flag::QUAD) ? 4 : 3;
- U idxSum = 0;
- for(U i = 0; i < m_subMeshes.getSize(); i++)
- {
- const MeshBinaryFile::SubMesh& sm = m_subMeshes[0];
- if(sm.m_firstIndex != idxSum || (sm.m_indexCount % indicesPerFace) != 0)
- {
- ANKI_RESOURCE_LOGE("Incorrect sub mesh info");
- return Error::USER_DATA;
- }
- for(U d = 0; d < 3; ++d)
- {
- if(sm.m_aabbMin[i] >= sm.m_aabbMax[i])
- {
- ANKI_RESOURCE_LOGE("Wrong bounding box");
- return Error::USER_DATA;
- }
- }
- idxSum += sm.m_indexCount;
- }
- if(idxSum != m_header.m_totalIndexCount)
- {
- ANKI_RESOURCE_LOGE("Incorrect sub mesh info");
- return Error::USER_DATA;
- }
- }
- // Read vert buffer info
- {
- U32 vertBufferMask = 0;
- U32 vertBufferCount = 0;
- for(const MeshBinaryFile::VertexAttribute& attrib : m_header.m_vertexAttributes)
- {
- if(attrib.m_format == Format::NONE)
- {
- continue;
- }
- vertBufferCount = max(attrib.m_bufferBinding + 1, vertBufferCount);
- vertBufferMask |= 1 << attrib.m_bufferBinding;
- }
- if(U(__builtin_popcount(vertBufferMask)) != vertBufferCount)
- {
- ANKI_RESOURCE_LOGE("Problem in vertex buffers");
- return Error::USER_DATA;
- }
- if(vertBufferCount != m_header.m_vertexBufferCount)
- {
- ANKI_RESOURCE_LOGE("Wrong vertex buffer count in the header");
- return Error::USER_DATA;
- }
- }
- // Count and check the file size
- {
- U32 totalSize = sizeof(m_header);
- totalSize += sizeof(MeshBinaryFile::SubMesh) * m_header.m_subMeshCount;
- totalSize += getIndexBufferSize();
- for(U i = 0; i < m_header.m_vertexBufferCount; ++i)
- {
- totalSize += m_header.m_vertexBuffers[i].m_vertexStride * m_header.m_totalVertexCount;
- }
- if(totalSize != m_file->getSize())
- {
- ANKI_RESOURCE_LOGE("Unexpected file size");
- return Error::USER_DATA;
- }
- }
- return Error::NONE;
- }
- Error MeshLoader::checkFormat(VertexAttributeLocation type, ConstWeakArray<Format> supportedFormats) const
- {
- const MeshBinaryFile::VertexAttribute& attrib = m_header.m_vertexAttributes[type];
- // Check format
- Bool found = false;
- for(Format fmt : supportedFormats)
- {
- if(fmt == attrib.m_format)
- {
- found = true;
- break;
- }
- }
- if(!found)
- {
- ANKI_RESOURCE_LOGE(
- "Vertex attribute %u has unsupported format %u", U(type), U(m_header.m_vertexAttributes[type].m_format));
- return Error::USER_DATA;
- }
- if(!attrib.m_format)
- {
- // Attrib is not in use, no more checks
- return Error::NONE;
- }
- // Scale should be 1.0 for now
- if(attrib.m_scale != 1.0f)
- {
- ANKI_RESOURCE_LOGE("Vertex attribute %u should have 1.0 scale", U(type));
- return Error::USER_DATA;
- }
- return Error::NONE;
- }
- Error MeshLoader::checkHeader() const
- {
- const MeshBinaryFile::Header& h = m_header;
- // Header
- if(memcmp(&h.m_magic[0], MeshBinaryFile::MAGIC, 8) != 0)
- {
- ANKI_RESOURCE_LOGE("Wrong magic word");
- return Error::USER_DATA;
- }
- // Flags
- if((h.m_flags & ~MeshBinaryFile::Flag::ALL) != MeshBinaryFile::Flag::NONE)
- {
- ANKI_RESOURCE_LOGE("Wrong header flags");
- return Error::USER_DATA;
- }
- // Attributes
- ANKI_CHECK(checkFormat(
- VertexAttributeLocation::POSITION, Array<Format, 2>{{Format::R16G16B16A16_SFLOAT, Format::R32G32B32_SFLOAT}}));
- ANKI_CHECK(checkFormat(VertexAttributeLocation::NORMAL, Array<Format, 1>{{Format::A2B10G10R10_SNORM_PACK32}}));
- ANKI_CHECK(checkFormat(VertexAttributeLocation::TANGENT, Array<Format, 1>{{Format::A2B10G10R10_SNORM_PACK32}}));
- ANKI_CHECK(
- checkFormat(VertexAttributeLocation::UV, Array<Format, 2>{{Format::R16G16_UNORM, Format::R16G16_SFLOAT}}));
- ANKI_CHECK(checkFormat(
- VertexAttributeLocation::BONE_INDICES, Array<Format, 2>{{Format::NONE, Format::R16G16B16A16_UINT}}));
- ANKI_CHECK(
- checkFormat(VertexAttributeLocation::BONE_WEIGHTS, Array<Format, 2>{{Format::NONE, Format::R8G8B8A8_UNORM}}));
- // Indices format
- if(h.m_indexType != IndexType::U16 && h.m_indexType != IndexType::U32)
- {
- ANKI_RESOURCE_LOGE("Wrong format for indices");
- return Error::USER_DATA;
- }
- // m_totalIndexCount
- const U indicesPerFace = !!(h.m_flags & MeshBinaryFile::Flag::QUAD) ? 4 : 3;
- if(h.m_totalIndexCount == 0 || (h.m_totalIndexCount % indicesPerFace) != 0)
- {
- ANKI_RESOURCE_LOGE("Wrong index count");
- return Error::USER_DATA;
- }
- // m_totalVertexCount
- if(h.m_totalVertexCount == 0)
- {
- ANKI_RESOURCE_LOGE("Wrong vertex count");
- return Error::USER_DATA;
- }
- // m_subMeshCount
- if(h.m_subMeshCount == 0)
- {
- ANKI_RESOURCE_LOGE("Wrong submesh count");
- return Error::USER_DATA;
- }
- // AABB
- for(U d = 0; d < 3; ++d)
- {
- if(h.m_aabbMin[d] >= h.m_aabbMax[d])
- {
- ANKI_RESOURCE_LOGE("Wrong bounding box");
- return Error::USER_DATA;
- }
- }
- return Error::NONE;
- }
- Error MeshLoader::storeIndexBuffer(void* ptr, PtrSize size)
- {
- ANKI_ASSERT(isLoaded());
- ANKI_ASSERT(size == getIndexBufferSize());
- ANKI_ASSERT(m_loadedChunk == 0);
- if(ptr)
- {
- ANKI_CHECK(m_file->read(ptr, size));
- }
- else
- {
- ANKI_CHECK(m_file->seek(size, ResourceFile::SeekOrigin::CURRENT));
- }
- ++m_loadedChunk;
- return Error::NONE;
- }
- Error MeshLoader::storeVertexBuffer(U32 bufferIdx, void* ptr, PtrSize size)
- {
- ANKI_ASSERT(isLoaded());
- ANKI_ASSERT(bufferIdx < m_header.m_vertexBufferCount);
- ANKI_ASSERT(size == m_header.m_vertexBuffers[bufferIdx].m_vertexStride * m_header.m_totalVertexCount);
- ANKI_ASSERT(m_loadedChunk == bufferIdx + 1);
- if(ptr)
- {
- ANKI_CHECK(m_file->read(ptr, size));
- }
- else
- {
- ANKI_CHECK(m_file->seek(size, ResourceFile::SeekOrigin::CURRENT));
- }
- ++m_loadedChunk;
- return Error::NONE;
- }
- Error MeshLoader::storeIndicesAndPosition(DynamicArrayAuto<U32>& indices, DynamicArrayAuto<Vec3>& positions)
- {
- // Store indices
- {
- indices.resize(m_header.m_totalIndexCount);
- // Create staging buff
- const PtrSize idxBufferSize = getIndexBufferSize();
- DynamicArrayAuto<U8> staging(m_alloc);
- staging.create(idxBufferSize);
- // Store to staging buff
- ANKI_CHECK(storeIndexBuffer(&staging[0], staging.getSizeInBytes()));
- // Copy
- for(U i = 0; i < m_header.m_totalIndexCount; ++i)
- {
- if(m_header.m_indexType == IndexType::U32)
- {
- indices[i] = *reinterpret_cast<U32*>(&staging[i * 4]);
- }
- else
- {
- indices[i] = *reinterpret_cast<U16*>(&staging[i * 2]);
- }
- }
- }
- // Store positions
- {
- positions.resize(m_header.m_totalVertexCount);
- const MeshBinaryFile::VertexAttribute& attrib = m_header.m_vertexAttributes[VertexAttributeLocation::POSITION];
- const MeshBinaryFile::VertexBuffer& buffInfo = m_header.m_vertexBuffers[attrib.m_bufferBinding];
- // Create staging buff
- const PtrSize vertBuffSize = m_header.m_totalVertexCount * buffInfo.m_vertexStride;
- DynamicArrayAuto<U8> staging(m_alloc);
- staging.create(vertBuffSize);
- // Store to staging buff
- ANKI_CHECK(storeVertexBuffer(attrib.m_bufferBinding, &staging[0], staging.getSizeInBytes()));
- // Copy
- for(U i = 0; i < m_header.m_totalVertexCount; ++i)
- {
- Vec3 vert(0.0f);
- if(attrib.m_format == Format::R32G32B32_SFLOAT)
- {
- vert = *reinterpret_cast<Vec3*>(&staging[i * buffInfo.m_vertexStride + attrib.m_relativeOffset]);
- }
- else if(attrib.m_format == Format::R16G16B16A16_SFLOAT)
- {
- F16* f16 = reinterpret_cast<F16*>(&staging[i * buffInfo.m_vertexStride + attrib.m_relativeOffset]);
- vert[0] = f16[0].toF32();
- vert[1] = f16[1].toF32();
- vert[2] = f16[2].toF32();
- }
- else
- {
- ANKI_ASSERT(0);
- }
- positions[i] = vert;
- }
- }
- return Error::NONE;
- }
- } // end namespace anki
|