/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #pragma once #include #include #include #include #include #include #include "MeshBuilderVertexAttributeLayers.h" #include "MeshBuilderSubMesh.h" #include "MeshBuilderSkinningInfo.h" namespace AZ::MeshBuilder { /* * Small usage tutorial: * * For all your vertex data types (position, normal, uvs etc) * AddLayer( layer ); * * For all polygons inside a mesh you want to export * BeginPolygon( polyMaterialIndex ) * For all added layers you added to the mesh * layer->SetCurrentVertexValue( ) * AddPolygonVertex( originalVertexNr ) * EndPolygon() * * OptimizeTriangleList() */ class MeshBuilder { friend class MeshBuilderSubMesh; public: AZ_CLASS_ALLOCATOR_DECL explicit MeshBuilder(size_t numOrgVerts, bool optimizeDuplicates = true); explicit MeshBuilder(size_t numOrgVerts, size_t maxBonesPerSubMesh, size_t maxSubMeshVertices, bool optimizeDuplicates = true); template AZStd::enable_if_t, LayerType*> AddLayer(Args&&... args) { if constexpr (AZStd::is_same_v>, AZStd::unique_ptr>) { // If the thing we were passed is already a unique_ptr, just move it in m_layers.emplace_back(AZStd::move(args)...); } else { m_layers.emplace_back(AZStd::make_unique(AZStd::forward(args)...)); } return static_cast(m_layers.back().get()); } void BeginPolygon(size_t materialIndex); // begin a poly void AddPolygonVertex(size_t orgVertexNr); // add a vertex to it (do this n-times, for an n-gon) void EndPolygon(); // end the polygon, after adding all polygon vertices size_t CalcNumIndices() const; // calculate the number of indices in the mesh size_t CalcNumVertices() const; // calculate the number of vertices in the mesh size_t GetNumOrgVerts() const { return m_numOrgVerts; } void SetSkinningInfo(AZStd::unique_ptr skinningInfo); const MeshBuilderSkinningInfo* GetSkinningInfo() const { return m_skinningInfo.get(); } MeshBuilderSkinningInfo* GetSkinningInfo() { return m_skinningInfo.get(); } size_t GetMaxBonesPerSubMesh() const { return m_maxBonesPerSubMesh; } size_t GetMaxVerticesPerSubMesh() const { return m_maxSubMeshVertices; } void SetMaxBonesPerSubMesh(size_t maxBones) { m_maxBonesPerSubMesh = maxBones; } size_t GetNumLayers() const { return m_layers.size(); } size_t GetNumSubMeshes() const { return m_subMeshes.size(); } const MeshBuilderSubMesh* GetSubMesh(size_t index) const { return m_subMeshes[index].get(); } const MeshBuilderVertexAttributeLayer* GetLayer(size_t index) const { return m_layers[index].get(); } size_t GetNumPolygons() const { return m_polyVertexCounts.size(); } struct SubMeshVertex { size_t m_realVertexNr; size_t m_dupeNr; MeshBuilderSubMesh* m_subMesh; }; size_t FindRealVertexNr(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) const; void SetRealVertexNrForSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr, size_t realVertexNr); const SubMeshVertex* FindSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) const; size_t CalcNumVertexDuplicates(const MeshBuilderSubMesh* subMesh, size_t orgVtx) const; void GenerateSubMeshVertexOrders(); void AddSubMeshVertex(size_t orgVtx, SubMeshVertex&& vtx); size_t GetNumSubMeshVertices(size_t orgVtx) const; const SubMeshVertex& GetSubMeshVertex(size_t orgVtx, size_t index) const { return m_vertices[orgVtx][index]; } private: static constexpr inline int s_defaultMaxBonesPerSubMesh = 512; static constexpr inline int s_defaultMaxSubMeshVertices = 65535; AZStd::vector> m_subMeshes; AZStd::vector> m_layers; AZStd::vector> m_vertices; AZStd::vector m_polyJointList; AZStd::unique_ptr m_skinningInfo{}; AZStd::vector m_polyIndices; AZStd::vector m_polyOrgVertexNumbers; AZStd::vector m_polyVertexCounts; size_t m_materialIndex = 0; size_t m_maxBonesPerSubMesh = s_defaultMaxBonesPerSubMesh; size_t m_maxSubMeshVertices = s_defaultMaxSubMeshVertices; size_t m_numOrgVerts = 0; bool m_optimizeDuplicates = true; const MeshBuilderVertexLookup FindMatchingDuplicate(size_t orgVertexNr) const; const MeshBuilderVertexLookup AddVertex(size_t orgVertexNr); const MeshBuilderVertexLookup FindVertexIndex(size_t orgVertexNr) const; const MeshBuilderSubMesh* FindSubMeshForPolygon(const AZStd::vector& orgVertexNumbers, size_t materialIndex) const; MeshBuilderSubMesh* FindSubMeshForPolygon(const AZStd::vector& orgVertexNumbers, size_t materialIndex) { return const_cast(static_cast(this)->FindSubMeshForPolygon(orgVertexNumbers, materialIndex)); } SubMeshVertex* FindSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) { return const_cast(static_cast(this)->FindSubMeshVertex(subMesh, orgVtx, dupeNr)); } void ExtractBonesForPolygon(const AZStd::vector& orgVertexNumbers, AZStd::vector& outPolyJointList) const; void AddPolygon(const AZStd::vector& indices, const AZStd::vector& orgVertexNumbers, size_t materialIndex); }; } // namespace AZ::MeshBuilder