Browse Source

Update the mesh resource

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
f280a12bae

+ 1 - 0
src/anki/collision/Obb.h

@@ -40,6 +40,7 @@ public:
 		, m_transposedRotation(rotation)
 		, m_extend(extend)
 	{
+		ANKI_ASSERT(m_center.w() == 0.0f && m_extend.w() == 0.0f);
 		m_transposedRotation.transposeRotationPart();
 	}
 

+ 1 - 0
src/anki/gr/Enums.h

@@ -327,6 +327,7 @@ enum class Format : U32
 	PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
 	PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
 };
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Format, inline)
 
 inline Bool formatIsDepthStencil(const Format fmt)
 {

+ 2 - 1
src/anki/resource/Common.h

@@ -49,7 +49,8 @@ enum class VertexAttributeLocation : U8
 	BONE_WEIGHTS,
 	BONE_INDICES,
 
-	COUNT
+	COUNT,
+	FIRST = POSITION,
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VertexAttributeLocation, inline)
 /// @}

+ 26 - 3
src/anki/resource/MeshLoader.cpp

@@ -46,6 +46,15 @@ Error MeshLoader::load(const ResourceFilename& filename)
 				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;
 		}
 
@@ -77,7 +86,11 @@ Error MeshLoader::load(const ResourceFilename& filename)
 			return Error::USER_DATA;
 		}
 
-		m_vertBufferCount = vertBufferCount;
+		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
@@ -87,7 +100,7 @@ Error MeshLoader::load(const ResourceFilename& filename)
 		totalSize += sizeof(MeshBinaryFile::SubMesh) * m_header.m_subMeshCount;
 		totalSize += getIndexBufferSize();
 
-		for(U i = 0; i < m_vertBufferCount; ++i)
+		for(U i = 0; i < header.m_vertexBufferCount; ++i)
 		{
 			totalSize += m_header.m_vertexBuffers[i].m_vertexStride * m_header.m_totalVertexCount;
 		}
@@ -193,6 +206,16 @@ Error MeshLoader::checkHeader() const
 		return Error::USER_DATA;
 	}
 
+	// AABB
+	for(U d = 0; d < 3; ++d)
+	{
+		if(h.m_aabbMin[i] >= h.m_aabbMax[i])
+		{
+			ANKI_RESOURCE_LOGE("Wrong bounding box");
+			return Error::USER_DATA;
+		}
+	}
+
 	return Error::NONE;
 }
 
@@ -218,7 +241,7 @@ Error MeshLoader::storeIndexBuffer(void* ptr, PtrSize size)
 Error MeshLoader::storeVertexBuffer(U32 bufferIdx, void* ptr, PtrSize size)
 {
 	ANKI_ASSERT(isLoaded());
-	ANKI_ASSERT(bufferIdx < m_vertBufferCount);
+	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);
 

+ 11 - 1
src/anki/resource/MeshLoader.h

@@ -49,6 +49,8 @@ public:
 	{
 		U32 m_firstIndex;
 		U32 m_indexCount;
+		Vec3 m_aabbMin; ///< Bounding box min.
+		Vec3 m_aabbMax; ///< Bounding box max.
 	};
 
 	struct Header
@@ -57,6 +59,7 @@ public:
 		Flag m_flags;
 
 		Array<VertexBuffer, U32(VertexAttributeLocation::COUNT)> m_vertexBuffers;
+		U32 m_vertexBufferCount;
 
 		Array<VertexAttribute, U32(VertexAttributeLocation::COUNT)> m_vertexAttributes;
 
@@ -65,6 +68,9 @@ public:
 		U32 m_totalIndexCount;
 		U32 m_totalVertexCount;
 		U32 m_subMeshCount;
+
+		Vec3 m_aabbMin; ///< Bounding box min.
+		Vec3 m_aabbMax; ///< Bounding box max.
 	};
 };
 
@@ -100,6 +106,11 @@ public:
 		return m_header.m_vertexAttributes[VertexAttributeLocation::BONE_INDICES].m_format != Format::NONE;
 	}
 
+	ConstWeakArray<MeshBinaryFile::SubMesh> getSubMeshes() const
+	{
+		return ConstWeakArray<MeshBinaryFile::SubMesh>(m_subMeshes);
+	}
+
 private:
 	ResourceManager* m_manager;
 	GenericMemoryPoolAllocator<U8> m_alloc;
@@ -109,7 +120,6 @@ private:
 	MeshBinaryFile::Header m_header;
 
 	DynamicArray<MeshBinaryFile::SubMesh> m_subMeshes;
-	U32 m_vertBufferCount = 0;
 
 	U32 m_loadedChunk = 0; ///< Because the store methods need to be called in sequence.
 

+ 97 - 64
src/anki/resource/MeshResource.cpp

@@ -16,14 +16,12 @@ namespace anki
 class MeshResource::LoadContext
 {
 public:
-	ResourceManager* m_manager ANKI_DBG_NULLIFY;
+	MeshResource* m_mesh;
 	MeshLoader m_loader;
-	BufferPtr m_vertBuff;
-	BufferPtr m_indicesBuff;
 
-	LoadContext(ResourceManager* manager, GenericMemoryPoolAllocator<U8> alloc)
-		: m_manager(manager)
-		, m_loader(manager, alloc)
+	LoadContext(MeshResource* mesh, GenericMemoryPoolAllocator<U8> alloc)
+		: m_mesh(mesh)
+		, m_loader(&mesh->getManager(), alloc)
 	{
 	}
 };
@@ -34,14 +32,14 @@ class MeshResource::LoadTask : public AsyncLoaderTask
 public:
 	MeshResource::LoadContext m_ctx;
 
-	LoadTask(ResourceManager* manager)
-		: m_ctx(manager, manager->getAsyncLoader().getAllocator())
+	LoadTask(MeshResource* mesh)
+		: m_ctx(mesh, mesh->getManager().getAsyncLoader().getAllocator())
 	{
 	}
 
 	Error operator()(AsyncLoaderTaskContext& ctx) final
 	{
-		return MeshResource::load(m_ctx);
+		return m_ctx.m_mesh->loadAsync(m_ctx.m_loader);
 	}
 };
 
@@ -57,19 +55,19 @@ MeshResource::~MeshResource()
 
 Bool MeshResource::isCompatible(const MeshResource& other) const
 {
-	return hasBoneWeights() == other.hasBoneWeights() && getSubMeshesCount() == other.getSubMeshesCount()
-		   && m_texChannelsCount == other.m_texChannelsCount;
+	return hasBoneWeights() == other.hasBoneWeights() && getSubMeshCount() == other.getSubMeshCount()
+		   && m_texChannelCount == other.m_texChannelCount;
 }
 
 Error MeshResource::load(const ResourceFilename& filename, Bool async)
 {
 	LoadTask* task;
 	LoadContext* ctx;
-	LoadContext localCtx(&getManager(), getTempAllocator());
+	LoadContext localCtx(this, getTempAllocator());
 
 	if(async)
 	{
-		task = getManager().getAsyncLoader().newTask<LoadTask>(&getManager());
+		task = getManager().getAsyncLoader().newTask<LoadTask>(this);
 		ctx = &task->m_ctx;
 	}
 	else
@@ -78,74 +76,102 @@ Error MeshResource::load(const ResourceFilename& filename, Bool async)
 		ctx = &localCtx;
 	}
 
+	// Open file
 	MeshLoader& loader = ctx->m_loader;
 	ANKI_CHECK(loader.load(filename));
-
 	const MeshBinaryFile::Header& header = loader.getHeader();
-	m_indicesCount = header.m_totalIndexCount;
 
-	m_vertSize = loader.getVertexSize();
+	// Get submeshes
+	m_subMeshes.create(getAllocator(), header.m_subMeshCount);
+	for(U i = 0; i < m_subMeshes.getSize(); ++i)
+	{
+		m_subMeshes[i].m_firstIndex = loader.getSubMeshes()[i].m_firstIndex;
+		m_subMeshes[i].m_indexCount = loader.getSubMeshes()[i].m_indexCount;
 
-	PtrSize vertexSize = loader.getVertexSize();
-	m_obb.setFromPointCloud(
-		loader.getVertexData(), header.m_totalVerticesCount, vertexSize, loader.getVertexDataSize());
-	ANKI_ASSERT(m_indicesCount > 0);
-	ANKI_ASSERT(m_indicesCount % 3 == 0 && "Expecting triangles");
+		const Vec3 obbCenter = (loader.getSubMeshes()[i].m_aabbMax + loader.getSubMeshes()[i].m_aabbMin) / 2.0f;
+		const Vec3 obbExtend = loader.getSubMeshes()[i].m_aabbMax - obbCenter;
+		m_subMeshes[i].m_obb = Obb(obbCenter.xyz0(), Mat3x4::getIdentity(), obbExtend.xyz0());
+	}
 
-	// Set the non-VBO members
-	m_vertsCount = header.m_totalVerticesCount;
-	ANKI_ASSERT(m_vertsCount > 0);
+	// Index stuff
+	m_indexCount = header.m_totalIndexCount;
+	ANKI_ASSERT((m_indexCount % 3) == 0 && "Expecting triangles");
+	m_indexFormat = header.m_indicesFormat;
 
-	m_texChannelsCount = header.m_uvsChannelCount;
-	m_weights = loader.hasBoneInfo();
+	const PtrSize indexBuffSize = m_indexCount * ((m_indexFormat == Format::R32_UINT) ? 4 : 2);
 
-	// Allocate the buffers
-	GrManager& gr = getManager().getGrManager();
+	m_indexBuff = getManager().getGrManager().newBuffer(BufferInitInfo(indexBuffSize,
+		BufferUsageBit::INDEX | BufferUsageBit::BUFFER_UPLOAD_DESTINATION | BufferUsageBit::FILL,
+		BufferMapAccessBit::NONE,
+		"MeshIdx"));
+
+	// Vertex stuff
+	m_vertCount = header.m_totalVertexCount;
+	m_vertBufferInfos.create(getAllocator(), header.m_vertexBufferCount);
 
-	m_vertBuff = gr.newBuffer(BufferInitInfo(loader.getVertexDataSize(),
+	PtrSize totalVertexBuffSize = 0;
+	for(U i = 0; i < header.m_vertexBufferCount; ++i)
+	{
+		m_vertBufferInfos[i].m_offset = getAlignedRoundUp(VERTEX_BUFFER_ALIGNMENT, totalVertexBuffSize);
+		m_vertBufferInfos[i].m_stride = header.m_vertexBuffers[i].m_vertexStride;
+
+		totalVertexBuffSize = m_vertBufferInfos[i].m_offset + m_vertCount;
+	}
+
+	m_vertBuff = getManager().getGrManager().newBuffer(BufferInitInfo(totalVertexBuffSize,
 		BufferUsageBit::VERTEX | BufferUsageBit::BUFFER_UPLOAD_DESTINATION | BufferUsageBit::FILL,
 		BufferMapAccessBit::NONE,
 		"MeshVert"));
 
-	m_indicesBuff = gr.newBuffer(BufferInitInfo(loader.getIndexDataSize(),
-		BufferUsageBit::INDEX | BufferUsageBit::BUFFER_UPLOAD_DESTINATION | BufferUsageBit::FILL,
-		BufferMapAccessBit::NONE,
-		"MeshIdx"));
+	m_texChannelCount = !!header.m_vertexAttributes[VertexAttributeLocation::UV2].m_format ? 2 : 1;
 
-	// Clear them
+	for(VertexAttributeLocation attrib = VertexAttributeLocation::FIRST; attrib < VertexAttributeLocation::COUNT;
+		++attrib)
+	{
+		AttribInfo& out = m_attribs[attrib];
+		const MeshBinaryFile::VertexAttribute& in = header.m_vertexAttributes[attrib];
+
+		out.m_fmt = in.m_format;
+		out.m_relativeOffset = in.m_relativeOffset;
+		out.m_buffIdx = in.m_bufferBinding;
+		ANKI_ASSERT(in.m_scale == 1.0f && "Not supported ATM");
+	}
+
+	// Other
+	const Vec3 obbCenter = (header.m_aabbMax + header.m_aabbMin) / 2.0f;
+	const Vec3 obbExtend = header.m_aabbMax - obbCenter;
+	m_obb = Obb(obbCenter.xyz0(), Mat3x4::getIdentity(), obbExtend.xyz0());
+
+	// Clear the buffers
 	CommandBufferInitInfo cmdbinit;
 	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH;
-	CommandBufferPtr cmdb = gr.newCommandBuffer(cmdbinit);
+	CommandBufferPtr cmdb = getManager().getGrManager().newCommandBuffer(cmdbinit);
 
 	cmdb->fillBuffer(m_vertBuff, 0, MAX_PTR_SIZE, 0);
-	cmdb->fillBuffer(m_indicesBuff, 0, MAX_PTR_SIZE, 0);
+	cmdb->fillBuffer(m_indexBuff, 0, MAX_PTR_SIZE, 0);
 
 	cmdb->setBufferBarrier(m_vertBuff, BufferUsageBit::FILL, BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE);
-	cmdb->setBufferBarrier(m_indicesBuff, BufferUsageBit::FILL, BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);
+	cmdb->setBufferBarrier(m_indexBuff, BufferUsageBit::FILL, BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);
 
 	cmdb->flush();
 
 	// Submit the loading task
-	ctx->m_vertBuff = m_vertBuff;
-	ctx->m_indicesBuff = m_indicesBuff;
-
 	if(async)
 	{
 		getManager().getAsyncLoader().submitTask(task);
 	}
 	else
 	{
-		ANKI_CHECK(load(*ctx));
+		ANKI_CHECK(loadAsync(loader));
 	}
 
 	return Error::NONE;
 }
 
-Error MeshResource::load(LoadContext& ctx)
+Error MeshResource::loadAsync(MeshLoader& loader) const
 {
-	GrManager& gr = ctx.m_manager->getGrManager();
-	TransferGpuAllocator& transferAlloc = ctx.m_manager->getTransferGpuAllocator();
-	const MeshLoader& loader = ctx.m_loader;
+	GrManager& gr = getManager().getGrManager();
+	TransferGpuAllocator& transferAlloc = getManager().getTransferGpuAllocator();
 	Array<TransferGpuAllocatorHandle, 2> handles;
 
 	CommandBufferInitInfo cmdbinit;
@@ -154,43 +180,50 @@ Error MeshResource::load(LoadContext& ctx)
 
 	// Set barriers
 	cmdb->setBufferBarrier(
-		ctx.m_vertBuff, BufferUsageBit::VERTEX, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, 0, MAX_PTR_SIZE);
+		m_vertBuff, BufferUsageBit::VERTEX, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, 0, MAX_PTR_SIZE);
 	cmdb->setBufferBarrier(
-		ctx.m_indicesBuff, BufferUsageBit::INDEX, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, 0, MAX_PTR_SIZE);
+		m_indexBuff, BufferUsageBit::INDEX, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, 0, MAX_PTR_SIZE);
 
-	// Write vert buff
+	// Write index buffer
 	{
-		ANKI_CHECK(transferAlloc.allocate(loader.getVertexDataSize(), handles[0]));
-		void* data = handles[0].getMappedMemory();
+		ANKI_CHECK(transferAlloc.allocate(m_indexBuff->getSize(), handles[1]));
+		void* data = handles[1].getMappedMemory();
 		ANKI_ASSERT(data);
 
-		memcpy(data, loader.getVertexData(), loader.getVertexDataSize());
+		ANKI_CHECK(loader.storeIndexBuffer(data, m_indexBuff->getSize()));
 
-		cmdb->copyBufferToBuffer(
-			handles[0].getBuffer(), handles[0].getOffset(), ctx.m_vertBuff, 0, handles[0].getRange());
+		cmdb->copyBufferToBuffer(handles[1].getBuffer(), handles[1].getOffset(), m_indexBuff, 0, handles[1].getRange());
 	}
 
-	// Create index buffer
+	// Write vert buff
 	{
-		ANKI_CHECK(transferAlloc.allocate(loader.getIndexDataSize(), handles[1]));
-		void* data = handles[1].getMappedMemory();
+		ANKI_CHECK(transferAlloc.allocate(m_vertBuff->getSize(), handles[0]));
+		U8* data = static_cast<U8*>(handles[0].getMappedMemory());
 		ANKI_ASSERT(data);
 
-		memcpy(data, loader.getIndexData(), loader.getIndexDataSize());
+		// Load to staging
+		PtrSize offset = 0;
+		for(U i = 0; i < m_vertBufferInfos.getSize(); ++i)
+		{
+			alignRoundUp(VERTEX_BUFFER_ALIGNMENT, offset);
+			ANKI_CHECK(loader.storeVertexBuffer(i, data + offset, m_vertBufferInfos[i].m_stride * m_vertCount));
 
-		cmdb->copyBufferToBuffer(
-			handles[1].getBuffer(), handles[1].getOffset(), ctx.m_indicesBuff, 0, handles[1].getRange());
+			offset += m_vertBufferInfos[i].m_stride * m_vertCount;
+		}
+
+		ANKI_ASSERT(offset == m_vertBuff->getSize());
+
+		// Copy
+		cmdb->copyBufferToBuffer(handles[0].getBuffer(), handles[0].getOffset(), m_vertBuff, 0, handles[0].getRange());
 	}
 
 	// Set barriers
 	cmdb->setBufferBarrier(
-		ctx.m_vertBuff, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE);
+		m_vertBuff, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE);
 	cmdb->setBufferBarrier(
-		ctx.m_indicesBuff, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);
-
-	ctx.m_vertBuff.reset(nullptr);
-	ctx.m_indicesBuff.reset(nullptr);
+		m_indexBuff, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);
 
+	// Finalize
 	FencePtr fence;
 	cmdb->flush(&fence);
 

+ 52 - 19
src/anki/resource/MeshResource.h

@@ -34,29 +34,30 @@ public:
 	/// Load from a mesh file
 	ANKI_USE_RESULT Error load(const ResourceFilename& filename, Bool async);
 
+	/// Get the complete bounding box.
 	const Obb& getBoundingShape() const
 	{
 		return m_obb;
 	}
 
 	/// Get submesh info.
-	void getSubMeshInfo(U subMeshId, U32& indexOffset, U32& indexCount, Obb* obb) const
+	void getSubMeshInfo(U subMeshId, U32& firstIndex, U32& indexCount, Obb* obb) const
 	{
 		const SubMesh& sm = m_subMeshes[subMeshId];
-		indexOffset = sm.m_indicesOffset;
-		indexCount = sm.m_indicesCount;
+		firstIndex = sm.m_firstIndex;
+		indexCount = sm.m_indexCount;
 		if(obb)
 		{
 			*obb = sm.m_obb;
 		}
 	}
 
-	/// If returns zero then the mesh is a single uniform mesh
 	U32 getSubMeshCount() const
 	{
 		return m_subMeshes.getSize();
 	}
 
+	/// Get all info around vertex indices.
 	void getIndexBufferInfo(BufferPtr& buff, U32& buffOffset, U32& indexCount, Format& indexFormat) const
 	{
 		buff = m_indexBuff;
@@ -65,41 +66,59 @@ public:
 		indexFormat = m_indexFormat;
 	}
 
+	/// Get the number of logical vertex buffers.
 	U32 getVertexBufferCount() const
 	{
-		return m_vertBuffCount;
+		return m_vertBufferInfos.getSize();
 	}
 
-	void getVertexBufferInfo(U32 buffIdx, BufferPtr& buff, U32& offset, U32& stride) const
+	/// Get vertex buffer info.
+	void getVertexBufferInfo(const U32 buffIdx, BufferPtr& buff, U32& offset, U32& stride) const
 	{
 		buff = m_vertBuff;
-		// TODO
+		offset = m_vertBufferInfos[buffIdx].m_offset;
+		stride = m_vertBufferInfos[buffIdx].m_stride;
 	}
 
-	void getVerteAttributeInfo(VertexAttributeLocation attrib, U32& bufferIdx, Format& format, U32& relativeOffset)
+	/// Get attribute info. You need to check if the attribute is preset first (isVertexAttributePresent)
+	void getVerteAttributeInfo(
+		const VertexAttributeLocation attrib, U32& bufferIdx, Format& format, U32& relativeOffset) const
 	{
-		// TODO
+		ANKI_ASSERT(!!m_attribs[attrib].m_fmt);
+		bufferIdx = m_attribs[attrib].m_buffIdx;
+		format = m_attribs[attrib].m_fmt;
+		relativeOffset = m_attribs[attrib].m_relativeOffset;
 	}
 
-	U32 getTextureChannelsCount() const
+	/// Check if a vertex attribute is present.
+	Bool isVertexAttributePresent(const VertexAttributeLocation attrib) const
 	{
-		return m_texChannelsCount;
+		return !!m_attribs[attrib].m_fmt;
 	}
 
+	/// Get the number of texture coordinates channels.
+	U32 getTextureChannelCount() const
+	{
+		return m_texChannelCount;
+	}
+
+	/// Return true if it has bone weights.
 	Bool hasBoneWeights() const
 	{
-		return m_weights;
+		return isVertexAttributePresent(VertexAttributeLocation::BONE_WEIGHTS);
 	}
 
 protected:
 	class LoadTask;
 	class LoadContext;
 
-	/// Per sub mesh data
+	static constexpr U VERTEX_BUFFER_ALIGNMENT = 64;
+
+	/// Sub-mesh data
 	struct SubMesh
 	{
-		U32 m_indicesCount;
-		U32 m_indicesOffset;
+		U32 m_firstIndex;
+		U32 m_indexCount;
 		Obb m_obb;
 	};
 	DynamicArray<SubMesh> m_subMeshes;
@@ -111,15 +130,29 @@ protected:
 
 	// Vertex stuff
 	U32 m_vertCount = 0;
+
+	struct VertBuffInfo
+	{
+		U32 m_offset; ///< Offset from the base of m_vertBuff.
+		U32 m_stride;
+	};
+	DynamicArray<VertBuffInfo> m_vertBufferInfos;
+
+	struct AttribInfo
+	{
+		Format m_fmt = Format::NONE;
+		U32 m_relativeOffset = 0;
+		U8 m_buffIdx = 0;
+	};
+	Array<AttribInfo, U(VertexAttributeLocation::COUNT)> m_attribs;
+
 	BufferPtr m_vertBuff;
-	U8 m_vertBuffCount = 0;
-	U8 m_texChannelsCount = 0;
+	U8 m_texChannelCount = 0;
 
 	// Other
 	Obb m_obb;
-	Bool8 m_weights = false;
 
-	static ANKI_USE_RESULT Error load(LoadContext& ctx);
+	ANKI_USE_RESULT Error loadAsync(MeshLoader& loader) const;
 };
 /// @}
 

+ 14 - 3
tools/scene/ExporterMesh.cpp

@@ -73,6 +73,7 @@ void Exporter::exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform, unsi
 
 	float maxPositionDistance = 0.0; // Distance of positions from zero
 	float maxUvDistance = -FLT_MAX, minUvDistance = FLT_MAX;
+	anki::Vec3 aabbMin(anki::MAX_F32), aabbMax(anki::MIN_F32);
 
 	{
 		const aiMatrix3x3 normalMat = (transform) ? aiMatrix3x3(*transform) : aiMatrix3x3();
@@ -111,9 +112,12 @@ void Exporter::exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform, unsi
 			positions[i * 3 + 0] = pos.x;
 			positions[i * 3 + 1] = pos.y;
 			positions[i * 3 + 2] = pos.z;
-			maxPositionDistance = std::max<float>(maxPositionDistance, fabs(pos.x));
-			maxPositionDistance = std::max<float>(maxPositionDistance, fabs(pos.y));
-			maxPositionDistance = std::max<float>(maxPositionDistance, fabs(pos.z));
+			for(int d = 0; d < 3; ++d)
+			{
+				maxPositionDistance = std::max<float>(maxPositionDistance, fabs(pos[d]));
+				aabbMin[i] = std::min(aabbMin[i], pos[d]);
+				aabbMax[i] = std::max(aabbMax[i], pos[d]);
+			}
 
 			ntVerts[i].m_n[0] = n.x;
 			ntVerts[i].m_n[1] = n.y;
@@ -229,6 +233,8 @@ void Exporter::exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform, unsi
 
 	// Arange the attributes into vert buffers
 	{
+		header.m_vertexBufferCount = 2;
+
 		// First buff has positions
 		const auto& posa = header.m_vertexAttributes[anki::MeshBinaryFile::VertexAttributeType::POSITION];
 		if(posa.m_format == anki::Format::R32G32B32_SFLOAT)
@@ -247,6 +253,7 @@ void Exporter::exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform, unsi
 		if(hasBoneWeights)
 		{
 			header.m_vertexBuffers[2].m_vertexStride = sizeof(WeightVertex);
+			++header.m_vertexBufferCount;
 		}
 	}
 
@@ -258,6 +265,8 @@ void Exporter::exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform, unsi
 		header.m_totalIndexCount = mesh.mNumFaces * vertCountPerFace;
 		header.m_totalVertexCount = mesh.mNumVertices;
 		header.m_subMeshCount = 1;
+		header.m_aabbMin = aabbMin;
+		header.m_aabbMax = aabbMax;
 	}
 
 	// Open file
@@ -272,6 +281,8 @@ void Exporter::exportMesh(const aiMesh& mesh, const aiMatrix4x4* transform, unsi
 		anki::MeshBinaryFile::SubMesh smesh;
 		smesh.m_firstIndex = 0;
 		smesh.m_indexCount = header.m_totalIndexCount;
+		smesh.m_aabbMin = aabbMin;
+		smesh.m_aabbMax = aabbMax;
 
 		file.write(reinterpret_cast<char*>(&smesh), sizeof(smesh));
 	}