diff --git a/ChangeLog.md b/ChangeLog.md index cb5e4d833..7242fbaf4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -95,6 +95,9 @@ Nazara Engine: - Fixed cubemaps seams with OpenGL - HandledObject movement constructor/assignement operator are now marked noexcept - ⚠️ PhysWorld2D callbacks OnPhysWorld2DPreStep and OnPhysWorld2DPostStep now takes a invStepCount depending on the number of step taken this update, fixing force application and other +- ⚠️ Refactored Mesh/SubMesh, allowing a submesh to be attached to multiple meshes, deprecating Create/Destroy methods +- SubMesh class now has a OnSubMeshInvalidateAABB signal, triggered when a new AABB is set to the submesh +- Mesh class now has a OnMeshInvalidateAABB signal, triggered when a mesh invalidates its AABB, which is also submesh updates its AABB Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp index d7ce4bb3d..1b5634eaf 100644 --- a/SDK/src/NDK/Systems/DebugSystem.cpp +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -300,9 +300,7 @@ namespace Ndk Nz::MeshRef mesh = Nz::Mesh::New(); mesh->CreateStatic(); - Nz::StaticMeshRef subMesh = Nz::StaticMesh::New(mesh); - subMesh->Create(vertexBuffer); - subMesh->SetIndexBuffer(indexBuffer); + Nz::StaticMeshRef subMesh = Nz::StaticMesh::New(vertexBuffer, indexBuffer); subMesh->SetPrimitiveMode(Nz::PrimitiveMode_LineList); subMesh->SetMaterialIndex(0); subMesh->GenerateAABB(); diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index 0848ee2fb..0ecd9eb3a 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -20,8 +20,12 @@ #include #include #include +#include +#include #include #include +#include +#include namespace Nz { @@ -56,7 +60,6 @@ namespace Nz class Mesh; struct Primitive; class PrimitiveList; - class Skeleton; class SubMesh; using MeshVertex = VertexStruct_XYZ_Normal_UV_Tangent; @@ -80,8 +83,10 @@ namespace Nz friend class Utility; public: - Mesh() = default; - ~Mesh(); + inline Mesh(); + Mesh(const Mesh&) = delete; + Mesh(Mesh&&) = delete; + inline ~Mesh(); void AddSubMesh(SubMesh* subMesh); void AddSubMesh(const String& identifier, SubMesh* subMesh); @@ -141,14 +146,34 @@ namespace Nz void Transform(const Matrix4f& matrix); + Mesh& operator=(const Mesh&) = delete; + Mesh& operator=(Mesh&&) = delete; + template static MeshRef New(Args&&... args); // Signals: NazaraSignal(OnMeshDestroy, const Mesh* /*mesh*/); + NazaraSignal(OnMeshInvalidateAABB, const Mesh* /*mesh*/); NazaraSignal(OnMeshRelease, const Mesh* /*mesh*/); private: - MeshImpl* m_impl = nullptr; + struct SubMeshData + { + SubMeshRef subMesh; + + NazaraSlot(SubMesh, OnSubMeshInvalidateAABB, onSubMeshInvalidated); + }; + + std::unordered_map m_subMeshMap; + std::vector m_materialData; + std::vector m_subMeshes; + AnimationType m_animationType; + mutable Boxf m_aabb; + Skeleton m_skeleton; // Only used by skeletal meshes + String m_animationPath; + mutable bool m_aabbUpdated; + bool m_isValid; + UInt32 m_jointCount; // Only used by skeletal meshes static bool Initialize(); static void Uninitialize(); diff --git a/include/Nazara/Utility/Mesh.inl b/include/Nazara/Utility/Mesh.inl index e63cb389f..5dbe349d0 100644 --- a/include/Nazara/Utility/Mesh.inl +++ b/include/Nazara/Utility/Mesh.inl @@ -2,11 +2,25 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { + Mesh::Mesh() : + m_materialData(1), + m_aabbUpdated(false) + { + } + + Mesh::~Mesh() + { + OnMeshRelease(this); + + Destroy(); + } + template MeshRef Mesh::New(Args&&... args) { diff --git a/include/Nazara/Utility/SkeletalMesh.hpp b/include/Nazara/Utility/SkeletalMesh.hpp index d1f652e85..ebba1cfb5 100644 --- a/include/Nazara/Utility/SkeletalMesh.hpp +++ b/include/Nazara/Utility/SkeletalMesh.hpp @@ -24,9 +24,14 @@ namespace Nz class NAZARA_UTILITY_API SkeletalMesh final : public SubMesh { public: + SkeletalMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer); + + NAZARA_DEPRECATED("SkeletalMesh constructor taking a mesh is deprecated, submeshes no longer require to be part of a single mesh") SkeletalMesh(const Mesh* parent); + ~SkeletalMesh(); + NAZARA_DEPRECATED("SkeletalMesh create/destroy functions are deprecated, please use constructor") bool Create(VertexBuffer* vertexBuffer); void Destroy(); @@ -51,8 +56,8 @@ namespace Nz private: Boxf m_aabb; - IndexBufferConstRef m_indexBuffer = nullptr; - VertexBufferRef m_vertexBuffer = nullptr; + IndexBufferConstRef m_indexBuffer; + VertexBufferRef m_vertexBuffer; }; } diff --git a/include/Nazara/Utility/StaticMesh.hpp b/include/Nazara/Utility/StaticMesh.hpp index 395713835..534157fb6 100644 --- a/include/Nazara/Utility/StaticMesh.hpp +++ b/include/Nazara/Utility/StaticMesh.hpp @@ -21,11 +21,16 @@ namespace Nz class NAZARA_UTILITY_API StaticMesh final : public SubMesh { public: + StaticMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer); + + NAZARA_DEPRECATED("StaticMesh constructor taking a mesh is deprecated, submeshes no longer require to be part of a single mesh") StaticMesh(const Mesh* parent); + ~StaticMesh(); void Center(); + NAZARA_DEPRECATED("StaticMesh create/destroy functions are deprecated, please use constructor") bool Create(VertexBuffer* vertexBuffer); void Destroy(); @@ -52,8 +57,8 @@ namespace Nz private: Boxf m_aabb; - IndexBufferConstRef m_indexBuffer = nullptr; - VertexBufferRef m_vertexBuffer = nullptr; + IndexBufferConstRef m_indexBuffer; + VertexBufferRef m_vertexBuffer; }; } diff --git a/include/Nazara/Utility/SubMesh.hpp b/include/Nazara/Utility/SubMesh.hpp index 54c948f89..cfbde074c 100644 --- a/include/Nazara/Utility/SubMesh.hpp +++ b/include/Nazara/Utility/SubMesh.hpp @@ -28,7 +28,13 @@ namespace Nz friend Mesh; public: + SubMesh(); + + NAZARA_DEPRECATED("Submesh constructor taking a mesh is deprecated, submeshes no longer require to be part of a single mesh") SubMesh(const Mesh* parent); + + SubMesh(const SubMesh&) = delete; + SubMesh(SubMesh&&) = delete; virtual ~SubMesh(); void GenerateNormals(); @@ -39,7 +45,6 @@ namespace Nz virtual AnimationType GetAnimationType() const = 0; virtual const IndexBuffer* GetIndexBuffer() const = 0; UInt32 GetMaterialIndex() const; - const Mesh* GetParent() const; PrimitiveMode GetPrimitiveMode() const; UInt32 GetTriangleCount() const; virtual UInt32 GetVertexCount() const = 0; @@ -49,12 +54,15 @@ namespace Nz void SetMaterialIndex(UInt32 matIndex); void SetPrimitiveMode(PrimitiveMode mode); + SubMesh& operator=(const SubMesh&) = delete; + SubMesh& operator=(SubMesh&&) = delete; + // Signals: + NazaraSignal(OnSubMeshInvalidateAABB, const SubMesh* /*subMesh*/); NazaraSignal(OnSubMeshRelease, const SubMesh* /*subMesh*/); protected: PrimitiveMode m_primitiveMode; - const Mesh* m_parent; UInt32 m_matIndex; }; } diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index 0dcd5fbcb..4320ae098 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -279,10 +279,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) vertexMapper.Unmap(); // Submesh - StaticMeshRef subMesh = StaticMesh::New(mesh); - subMesh->Create(vertexBuffer); - - subMesh->SetIndexBuffer(indexBuffer); + StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); subMesh->GenerateAABB(); subMesh->SetMaterialIndex(iMesh->mMaterialIndex); diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index 6758a2e1b..ac7d6e5d7 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -158,12 +158,7 @@ namespace Nz #endif VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, header.num_vertices, parameters.storage, parameters.vertexBufferFlags); - StaticMeshRef subMesh = StaticMesh::New(mesh); - if (!subMesh->Create(vertexBuffer)) - { - NazaraError("Failed to create SubMesh"); - return false; - } + StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); // Extracting vertices stream.SetCursorPos(header.offset_frames); diff --git a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp index d7104b9d0..84197e1c9 100644 --- a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp @@ -202,13 +202,9 @@ namespace Nz mesh->SetMaterialData(i, std::move(matData)); // Submesh - SkeletalMeshRef subMesh = SkeletalMesh::New(mesh); - subMesh->Create(vertexBuffer); - - subMesh->SetIndexBuffer(indexBuffer); + SkeletalMeshRef subMesh = SkeletalMesh::New(vertexBuffer, indexBuffer); subMesh->GenerateNormalsAndTangents(); subMesh->SetMaterialIndex(i); - subMesh->SetPrimitiveMode(PrimitiveMode_TriangleList); mesh->AddSubMesh(subMesh); @@ -255,6 +251,9 @@ namespace Nz } indexMapper.Unmap(); + if (parameters.optimizeIndexBuffers) + indexBuffer->Optimize(); + // Vertex buffer VertexBufferRef vertexBuffer = VertexBuffer::New(parameters.vertexDeclaration, UInt32(vertexCount), parameters.storage, parameters.vertexBufferFlags); @@ -287,13 +286,7 @@ namespace Nz vertexMapper.Unmap(); // Submesh - StaticMeshRef subMesh = StaticMesh::New(mesh); - subMesh->Create(vertexBuffer); - - if (parameters.optimizeIndexBuffers) - indexBuffer->Optimize(); - - subMesh->SetIndexBuffer(indexBuffer); + StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); subMesh->GenerateAABB(); subMesh->SetMaterialIndex(i); diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index 43e938bf4..ba8f90f73 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -311,20 +311,10 @@ namespace Nz vertexMapper.Unmap(); - StaticMeshRef subMesh = StaticMesh::New(mesh); - if (!subMesh->Create(vertexBuffer)) - { - NazaraError("Failed to create StaticMesh"); - continue; - } - - if (parameters.optimizeIndexBuffers) - indexBuffer->Optimize(); - + StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); subMesh->GenerateAABB(); - subMesh->SetIndexBuffer(indexBuffer); + subMesh->SetAABB(subMesh->GetAABB() * 0.5f); subMesh->SetMaterialIndex(meshes[i].material); - subMesh->SetPrimitiveMode(PrimitiveMode_TriangleList); // Ce que nous pouvons générer dépend des données à disposition (par exemple les tangentes nécessitent des coordonnées de texture) if (hasNormals && hasTexCoords) diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index 66ee817ff..015ee520d 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -56,62 +56,40 @@ namespace Nz return true; } - struct MeshImpl - { - MeshImpl() - { - materialData.resize(1); // One material by default - } - - std::unordered_map subMeshMap; - std::vector materialData; - std::vector subMeshes; - AnimationType animationType; - Boxf aabb; - Skeleton skeleton; // Only used by skeletal meshes - String animationPath; - bool aabbUpdated = false; - UInt32 jointCount; // Only used by skeletal meshes - }; - - Mesh::~Mesh() - { - OnMeshRelease(this); - - Destroy(); - } void Mesh::AddSubMesh(SubMesh* subMesh) { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); NazaraAssert(subMesh, "Invalid submesh"); - NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type"); + NazaraAssert(subMesh->GetAnimationType() == m_animationType, "Submesh animation type doesn't match mesh animation type"); - m_impl->subMeshes.emplace_back(subMesh); + m_subMeshes.emplace_back(); + SubMeshData& subMeshData = m_subMeshes.back(); + subMeshData.subMesh = subMesh; + subMeshData.onSubMeshInvalidated.Connect(subMesh->OnSubMeshInvalidateAABB, [this](const SubMesh* /*subMesh*/) { InvalidateAABB(); }); InvalidateAABB(); } void Mesh::AddSubMesh(const String& identifier, SubMesh* subMesh) { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); NazaraAssert(!identifier.IsEmpty(), "Identifier is empty"); - NazaraAssert(m_impl->subMeshMap.find(identifier) == m_impl->subMeshMap.end(), "SubMesh identifier \"" + identifier + "\" is already in use"); + NazaraAssert(m_subMeshMap.find(identifier) == m_subMeshMap.end(), "SubMesh identifier \"" + identifier + "\" is already in use"); NazaraAssert(subMesh, "Invalid submesh"); - NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type"); + NazaraAssert(subMesh->GetAnimationType() == m_animationType, "Submesh animation type doesn't match mesh animation type"); - std::size_t index = m_impl->subMeshes.size(); + std::size_t index = m_subMeshes.size(); - m_impl->subMeshes.emplace_back(subMesh); - m_impl->subMeshMap[identifier] = static_cast(index); + AddSubMesh(subMesh); - InvalidateAABB(); + m_subMeshMap[identifier] = static_cast(index); } SubMesh* Mesh::BuildSubMesh(const Primitive& primitive, const MeshParams& params) { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(m_impl->animationType == AnimationType_Static, "Submesh building only works for static meshes"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(m_animationType == AnimationType_Static, "Submesh building only works for static meshes"); NazaraAssert(params.IsValid(), "Invalid parameters"); NazaraAssert(params.vertexDeclaration->HasComponentOfType(VertexComponent_Position), "The vertex declaration doesn't have a Vector3 position component"); @@ -266,18 +244,11 @@ namespace Nz } } - StaticMeshRef subMesh = StaticMesh::New(this); - if (!subMesh->Create(vertexBuffer)) - { - NazaraError("Failed to create StaticMesh"); - return nullptr; - } - if (params.optimizeIndexBuffers) indexBuffer->Optimize(); + StaticMeshRef subMesh = StaticMesh::New(vertexBuffer, indexBuffer); subMesh->SetAABB(aabb); - subMesh->SetIndexBuffer(indexBuffer); AddSubMesh(subMesh); return subMesh; @@ -293,16 +264,15 @@ namespace Nz { Destroy(); - std::unique_ptr impl(new MeshImpl); - impl->animationType = AnimationType_Skeletal; - impl->jointCount = jointCount; - if (!impl->skeleton.Create(jointCount)) + m_animationType = AnimationType_Skeletal; + m_jointCount = jointCount; + if (!m_skeleton.Create(jointCount)) { NazaraError("Failed to create skeleton"); return false; } - m_impl = impl.release(); + m_isValid = true; return true; } @@ -311,236 +281,244 @@ namespace Nz { Destroy(); - m_impl = new MeshImpl; - m_impl->animationType = AnimationType_Static; + m_animationType = AnimationType_Static; + m_isValid = true; return true; } void Mesh::Destroy() { - if (m_impl) + if (m_isValid) { OnMeshDestroy(this); - delete m_impl; - m_impl = nullptr; + m_animationPath.Clear(); + m_materialData.clear(); + m_materialData.resize(1); + m_skeleton.Destroy(); + m_subMeshes.clear(); + m_subMeshMap.clear(); + + m_isValid = false; } } void Mesh::GenerateNormals() { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - for (SubMesh* subMesh : m_impl->subMeshes) - subMesh->GenerateNormals(); + for (SubMeshData& data : m_subMeshes) + data.subMesh->GenerateNormals(); } void Mesh::GenerateNormalsAndTangents() { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - for (SubMesh* subMesh : m_impl->subMeshes) - subMesh->GenerateNormalsAndTangents(); + for (SubMeshData& data : m_subMeshes) + data.subMesh->GenerateNormalsAndTangents(); } void Mesh::GenerateTangents() { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - for (SubMesh* subMesh : m_impl->subMeshes) - subMesh->GenerateTangents(); + for (SubMeshData& data : m_subMeshes) + data.subMesh->GenerateTangents(); } const Boxf& Mesh::GetAABB() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - if (!m_impl->aabbUpdated) + if (!m_aabbUpdated) { - std::size_t subMeshCount = m_impl->subMeshes.size(); + std::size_t subMeshCount = m_subMeshes.size(); if (subMeshCount > 0) { - m_impl->aabb.Set(m_impl->subMeshes[0]->GetAABB()); + m_aabb.Set(m_subMeshes.front().subMesh->GetAABB()); for (std::size_t i = 1; i < subMeshCount; ++i) - m_impl->aabb.ExtendTo(m_impl->subMeshes[i]->GetAABB()); + m_aabb.ExtendTo(m_subMeshes[i].subMesh->GetAABB()); } else - m_impl->aabb.MakeZero(); + m_aabb.MakeZero(); - m_impl->aabbUpdated = true; + m_aabbUpdated = true; } - return m_impl->aabb; + return m_aabb; } String Mesh::GetAnimation() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - return m_impl->animationPath; + return m_animationPath; } AnimationType Mesh::GetAnimationType() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - return m_impl->animationType; + return m_animationType; } UInt32 Mesh::GetJointCount() const { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(m_impl->animationType == AnimationType_Skeletal, "Mesh is not skeletal"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(m_animationType == AnimationType_Skeletal, "Mesh is not skeletal"); - return m_impl->jointCount; + return m_jointCount; } ParameterList& Mesh::GetMaterialData(UInt32 index) { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(index < m_impl->materialData.size(), "Material index out of range"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(index < m_materialData.size(), "Material index out of range"); - return m_impl->materialData[index]; + return m_materialData[index]; } const ParameterList& Mesh::GetMaterialData(UInt32 index) const { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(index < m_impl->materialData.size(), "Material index out of range"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(index < m_materialData.size(), "Material index out of range"); - return m_impl->materialData[index]; + return m_materialData[index]; } UInt32 Mesh::GetMaterialCount() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - return static_cast(m_impl->materialData.size()); + return static_cast(m_materialData.size()); } Skeleton* Mesh::GetSkeleton() { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(m_impl->animationType == AnimationType_Skeletal, "Mesh is not skeletal"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(m_animationType == AnimationType_Skeletal, "Mesh is not skeletal"); - return &m_impl->skeleton; + return &m_skeleton; } const Skeleton* Mesh::GetSkeleton() const { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(m_impl->animationType == AnimationType_Skeletal, "Mesh is not skeletal"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(m_animationType == AnimationType_Skeletal, "Mesh is not skeletal"); - return &m_impl->skeleton; + return &m_skeleton; } SubMesh* Mesh::GetSubMesh(const String& identifier) { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - auto it = m_impl->subMeshMap.find(identifier); - NazaraAssert(it != m_impl->subMeshMap.end(), "SubMesh " + identifier + " not found"); + auto it = m_subMeshMap.find(identifier); + NazaraAssert(it != m_subMeshMap.end(), "SubMesh " + identifier + " not found"); - return m_impl->subMeshes[it->second]; + return m_subMeshes[it->second].subMesh; } SubMesh* Mesh::GetSubMesh(UInt32 index) { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(index < m_impl->subMeshes.size(), "Submesh index out of range"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(index < m_subMeshes.size(), "Submesh index out of range"); - return m_impl->subMeshes[index]; + return m_subMeshes[index].subMesh; } const SubMesh* Mesh::GetSubMesh(const String& identifier) const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - auto it = m_impl->subMeshMap.find(identifier); - NazaraAssert(it != m_impl->subMeshMap.end(), "SubMesh " + identifier + " not found"); + auto it = m_subMeshMap.find(identifier); + NazaraAssert(it != m_subMeshMap.end(), "SubMesh " + identifier + " not found"); - return m_impl->subMeshes[it->second]; + return m_subMeshes[it->second].subMesh; } const SubMesh* Mesh::GetSubMesh(UInt32 index) const { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(index < m_impl->subMeshes.size(), "Submesh index out of range"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(index < m_subMeshes.size(), "Submesh index out of range"); - return m_impl->subMeshes[index]; + return m_subMeshes[index].subMesh; } UInt32 Mesh::GetSubMeshCount() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - return static_cast(m_impl->subMeshes.size()); + return static_cast(m_subMeshes.size()); } UInt32 Mesh::GetSubMeshIndex(const String& identifier) const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - auto it = m_impl->subMeshMap.find(identifier); - NazaraAssert(it != m_impl->subMeshMap.end(), "SubMesh " + identifier + " not found"); + auto it = m_subMeshMap.find(identifier); + NazaraAssert(it != m_subMeshMap.end(), "SubMesh " + identifier + " not found"); return it->second; } UInt32 Mesh::GetTriangleCount() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); UInt32 triangleCount = 0; - for (SubMesh* subMesh : m_impl->subMeshes) - triangleCount += subMesh->GetTriangleCount(); + for (const SubMeshData& data : m_subMeshes) + triangleCount += data.subMesh->GetTriangleCount(); return triangleCount; } UInt32 Mesh::GetVertexCount() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); UInt32 vertexCount = 0; - for (SubMesh* subMesh : m_impl->subMeshes) - vertexCount += subMesh->GetVertexCount(); + for (const SubMeshData& data : m_subMeshes) + vertexCount += data.subMesh->GetVertexCount(); return vertexCount; } void Mesh::InvalidateAABB() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - m_impl->aabbUpdated = false; + m_aabbUpdated = false; + + OnMeshInvalidateAABB(this); } bool Mesh::HasSubMesh(const String& identifier) const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - return m_impl->subMeshMap.find(identifier) != m_impl->subMeshMap.end(); + return m_subMeshMap.find(identifier) != m_subMeshMap.end(); } bool Mesh::HasSubMesh(UInt32 index) const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - return index < m_impl->subMeshes.size(); + return index < m_subMeshes.size(); } bool Mesh::IsAnimable() const { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - return m_impl->animationType != AnimationType_Static; + return m_animationType != AnimationType_Static; } bool Mesh::IsValid() const { - return m_impl != nullptr; + return m_isValid; } bool Mesh::LoadFromFile(const String& filePath, const MeshParams& params) @@ -560,20 +538,20 @@ namespace Nz void Mesh::Recenter() { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(m_impl->animationType == AnimationType_Static, "Mesh is not static"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(m_animationType == AnimationType_Static, "Mesh is not static"); // The center of our mesh is the center of our *global* AABB Vector3f center = GetAABB().GetCenter(); - for (SubMesh* subMesh : m_impl->subMeshes) + for (SubMeshData& data : m_subMeshes) { - StaticMesh* staticMesh = static_cast(subMesh); + StaticMesh& staticMesh = static_cast(*data.subMesh); - BufferMapper mapper(staticMesh->GetVertexBuffer(), BufferAccess_ReadWrite); + BufferMapper mapper(staticMesh.GetVertexBuffer(), BufferAccess_ReadWrite); MeshVertex* vertices = static_cast(mapper.GetPointer()); - UInt32 vertexCount = staticMesh->GetVertexCount(); + UInt32 vertexCount = staticMesh.GetVertexCount(); for (UInt32 i = 0; i < vertexCount; ++i) { vertices->position -= center; @@ -581,13 +559,11 @@ namespace Nz } // Our AABB doesn't change shape, only position - Boxf aabb = staticMesh->GetAABB(); + Boxf aabb = staticMesh.GetAABB(); aabb.Translate(-center); - staticMesh->SetAABB(aabb); + staticMesh.SetAABB(aabb); // This will invalidate our AABB } - - InvalidateAABB(); } void Mesh::RemoveSubMesh(const String& identifier) @@ -595,22 +571,22 @@ namespace Nz UInt32 index = GetSubMeshIndex(identifier); // On déplace l'itérateur du début d'une distance de x - auto it2 = m_impl->subMeshes.begin(); + auto it2 = m_subMeshes.begin(); std::advance(it2, index); - m_impl->subMeshes.erase(it2); + m_subMeshes.erase(it2); InvalidateAABB(); } void Mesh::RemoveSubMesh(UInt32 index) { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(index < m_impl->subMeshes.size(), "Submesh index out of range"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(index < m_subMeshes.size(), "Submesh index out of range"); // On déplace l'itérateur du début de x - auto it = m_impl->subMeshes.begin(); + auto it = m_subMeshes.begin(); std::advance(it, index); - m_impl->subMeshes.erase(it); + m_subMeshes.erase(it); InvalidateAABB(); } @@ -627,34 +603,34 @@ namespace Nz void Mesh::SetAnimation(const String& animationPath) { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); - m_impl->animationPath = animationPath; + m_animationPath = animationPath; } void Mesh::SetMaterialData(UInt32 matIndex, ParameterList data) { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(matIndex < m_impl->materialData.size(), "Material index out of range"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(matIndex < m_materialData.size(), "Material index out of range"); - m_impl->materialData[matIndex] = std::move(data); + m_materialData[matIndex] = std::move(data); } void Mesh::SetMaterialCount(UInt32 matCount) { - NazaraAssert(m_impl, "Mesh should be created first"); + NazaraAssert(m_isValid, "Mesh should be created first"); NazaraAssert(matCount > 0, "A mesh should have at least a material"); - m_impl->materialData.resize(matCount); + m_materialData.resize(matCount); #ifdef NAZARA_DEBUG - for (SubMesh* subMesh : m_impl->subMeshes) + for (SubMeshData& data : m_subMeshes) { - UInt32 matIndex = subMesh->GetMaterialIndex(); + UInt32 matIndex = data.subMesh->GetMaterialIndex(); if (matIndex >= matCount) { - subMesh->SetMaterialIndex(0); // To prevent a crash - NazaraWarning("SubMesh " + String::Pointer(subMesh) + " material index is over mesh new material count (" + String::Number(matIndex) + " >= " + String::Number(matCount) + "), setting it to first material"); + data.subMesh->SetMaterialIndex(0); // To prevent a crash + NazaraWarning("SubMesh " + String::Pointer(data.subMesh) + " material index is over mesh new material count (" + String::Number(matIndex) + " >= " + String::Number(matCount) + "), setting it to first material"); } } #endif @@ -662,19 +638,19 @@ namespace Nz void Mesh::Transform(const Matrix4f& matrix) { - NazaraAssert(m_impl, "Mesh should be created first"); - NazaraAssert(m_impl->animationType == AnimationType_Static, "Mesh is not static"); + NazaraAssert(m_isValid, "Mesh should be created first"); + NazaraAssert(m_animationType == AnimationType_Static, "Mesh is not static"); - for (SubMesh* subMesh : m_impl->subMeshes) + for (SubMeshData& data : m_subMeshes) { - StaticMesh* staticMesh = static_cast(subMesh); + StaticMesh& staticMesh = static_cast(*data.subMesh); - BufferMapper mapper(staticMesh->GetVertexBuffer(), BufferAccess_ReadWrite); + BufferMapper mapper(staticMesh.GetVertexBuffer(), BufferAccess_ReadWrite); MeshVertex* vertices = static_cast(mapper.GetPointer()); Boxf aabb(vertices->position.x, vertices->position.y, vertices->position.z, 0.f, 0.f, 0.f); - UInt32 vertexCount = staticMesh->GetVertexCount(); + UInt32 vertexCount = staticMesh.GetVertexCount(); for (UInt32 i = 0; i < vertexCount; ++i) { vertices->position = matrix.Transform(vertices->position); @@ -683,10 +659,8 @@ namespace Nz vertices++; } - staticMesh->SetAABB(aabb); + staticMesh.SetAABB(aabb); //< This will invalidate our AABB } - - InvalidateAABB(); } bool Mesh::Initialize() diff --git a/src/Nazara/Utility/SkeletalMesh.cpp b/src/Nazara/Utility/SkeletalMesh.cpp index 02550a4d6..e5a3a3268 100644 --- a/src/Nazara/Utility/SkeletalMesh.cpp +++ b/src/Nazara/Utility/SkeletalMesh.cpp @@ -8,8 +8,16 @@ namespace Nz { - SkeletalMesh::SkeletalMesh(const Mesh* parent) : - SubMesh(parent) + SkeletalMesh::SkeletalMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer) : + m_aabb(Nz::Boxf::Zero()), + m_indexBuffer(indexBuffer), + m_vertexBuffer(vertexBuffer) + { + NazaraAssert(m_vertexBuffer, "Invalid vertex buffer"); + } + + SkeletalMesh::SkeletalMesh(const Mesh* /*parent*/) : + m_aabb(Nz::Boxf::Zero()) { } @@ -90,6 +98,8 @@ namespace Nz void SkeletalMesh::SetAABB(const Boxf& aabb) { m_aabb = aabb; + + OnSubMeshInvalidateAABB(this); } void SkeletalMesh::SetIndexBuffer(const IndexBuffer* indexBuffer) diff --git a/src/Nazara/Utility/StaticMesh.cpp b/src/Nazara/Utility/StaticMesh.cpp index 7c7637481..b363736f7 100644 --- a/src/Nazara/Utility/StaticMesh.cpp +++ b/src/Nazara/Utility/StaticMesh.cpp @@ -10,8 +10,16 @@ namespace Nz { - StaticMesh::StaticMesh(const Mesh* parent) : - SubMesh(parent) + StaticMesh::StaticMesh(VertexBuffer* vertexBuffer, const IndexBuffer* indexBuffer) : + m_aabb(Nz::Boxf::Zero()), + m_indexBuffer(indexBuffer), + m_vertexBuffer(vertexBuffer) + { + NazaraAssert(m_vertexBuffer, "Invalid vertex buffer"); + } + + StaticMesh::StaticMesh(const Mesh* /*parent*/) : + m_aabb(Nz::Boxf::Zero()) { } @@ -69,7 +77,7 @@ namespace Nz { // On lock le buffer pour itérer sur toutes les positions et composer notre AABB VertexMapper mapper(m_vertexBuffer, BufferAccess_ReadOnly); - m_aabb = ComputeAABB(mapper.GetComponentPtr(VertexComponent_Position), m_vertexBuffer->GetVertexCount()); + SetAABB(ComputeAABB(mapper.GetComponentPtr(VertexComponent_Position), m_vertexBuffer->GetVertexCount())); return true; } @@ -117,10 +125,12 @@ namespace Nz void StaticMesh::SetAABB(const Boxf& aabb) { m_aabb = aabb; + + OnSubMeshInvalidateAABB(this); } void StaticMesh::SetIndexBuffer(const IndexBuffer* indexBuffer) { m_indexBuffer = indexBuffer; -} + } } diff --git a/src/Nazara/Utility/SubMesh.cpp b/src/Nazara/Utility/SubMesh.cpp index 44e601d22..0b7a95b31 100644 --- a/src/Nazara/Utility/SubMesh.cpp +++ b/src/Nazara/Utility/SubMesh.cpp @@ -12,14 +12,18 @@ namespace Nz { - SubMesh::SubMesh(const Mesh* parent) : - RefCounted(false), // Un SubMesh n'est pas persistant par défaut + SubMesh::SubMesh() : + RefCounted(false), // wut m_primitiveMode(PrimitiveMode_TriangleList), - m_parent(parent), m_matIndex(0) { } + SubMesh::SubMesh(const Mesh* /*parent*/) : + SubMesh() + { + } + SubMesh::~SubMesh() { OnSubMeshRelease(this); @@ -160,11 +164,6 @@ namespace Nz while (iterator.Advance()); } - const Mesh* SubMesh::GetParent() const - { - return m_parent; - } - PrimitiveMode SubMesh::GetPrimitiveMode() const { return m_primitiveMode;