1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef CORE_UTIL_MESH_BUILDER_H
17 #define CORE_UTIL_MESH_BUILDER_H
18 
19 #include <3d/util/intf_mesh_builder.h>
20 #include <base/util/formats.h>
21 #include <core/namespace.h>
22 #include <render/resource_handle.h>
23 
24 #include "gltf/gltf2_util.h"
25 
26 RENDER_BEGIN_NAMESPACE()
27 class IRenderContext;
28 RENDER_END_NAMESPACE()
29 
CORE3D_BEGIN_NAMESPACE()30 CORE3D_BEGIN_NAMESPACE()
31 class MeshBuilder final : public IMeshBuilder {
32 public:
33     MeshBuilder(RENDER_NS::IRenderContext& renderContext);
34 
35     ~MeshBuilder() override = default;
36 
37     void Initialize(const RENDER_NS::VertexInputDeclarationView& vertexInputDeclaration, size_t submeshCount) override;
38 
39     void AddSubmesh(const MeshBuilder::Submesh& submesh) override;
40 
41     const Submesh& GetSubmesh(size_t index) const override;
42 
43     void Allocate() override;
44 
45     void SetVertexData(size_t submeshIndex, const DataBuffer& positions, const DataBuffer& normals,
46         const DataBuffer& texcoords0, const DataBuffer& texcoords1, const DataBuffer& tangents,
47         const DataBuffer& colors) override;
48 
49     void SetIndexData(size_t submeshIndex, const DataBuffer& indices) override;
50 
51     void SetJointData(size_t submeshIndex, const DataBuffer& jointData, const DataBuffer& weightData,
52         const DataBuffer& vertexPositions) override;
53 
54     void SetMorphTargetData(size_t submeshIndex, const DataBuffer& basePositions, const DataBuffer& baseNormals,
55         const DataBuffer& baseTangents, const DataBuffer& targetPositions, const DataBuffer& targetNormals,
56         const DataBuffer& targetTangents) override;
57 
58     void SetAABB(size_t submeshIndex, const BASE_NS::Math::Vec3& min, const BASE_NS::Math::Vec3& max) override;
59     void CalculateAABB(size_t submeshIndex, const DataBuffer& positions) override;
60 
61     BASE_NS::array_view<const uint8_t> GetVertexData() const override;
62     BASE_NS::array_view<const uint8_t> GetIndexData() const override;
63     BASE_NS::array_view<const uint8_t> GetJointData() const override;
64     BASE_NS::array_view<const uint8_t> GetMorphTargetData() const override;
65 
66     BASE_NS::array_view<const float> GetJointBoundsData() const override;
67 
68     BASE_NS::array_view<const MeshComponent::Submesh> GetSubmeshes() const override;
69 
70     uint32_t GetVertexCount() const override;
71     uint32_t GetIndexCount() const override;
72 
73     void CreateGpuResources() override;
74     void CreateGpuResources(const GpuBufferCreateInfo& createInfo) override;
75 
76     CORE_NS::Entity CreateMesh(CORE_NS::IEcs& ecs) const override;
77 
78     // IInterface
79     const IInterface* GetInterface(const BASE_NS::Uid& uid) const override;
80     IInterface* GetInterface(const BASE_NS::Uid& uid) override;
81 
82     void Ref() override;
83     void Unref() override;
84 
85     struct BufferHandles {
86         RENDER_NS::RenderHandleReference vertexBuffer;
87         RENDER_NS::RenderHandleReference jointBuffer;
88         RENDER_NS::RenderHandleReference indexBuffer;
89         RENDER_NS::RenderHandleReference morphBuffer;
90     };
91 
92     struct BufferEntities {
93         CORE_NS::EntityReference vertexBuffer;
94         CORE_NS::EntityReference jointBuffer;
95         CORE_NS::EntityReference indexBuffer;
96         CORE_NS::EntityReference morphBuffer;
97     };
98 
99     // Morph target descriptor
100     struct MorphTargetDesc {
101         // Offset to morph target data from submesh's morphTargetOffset.
102         uint32_t offset { 0 };
103         // Byte size of morph target data.
104         uint32_t byteSize { 0 };
105     };
106 
107     // Extend submesh info with offset-data.
108     struct SubmeshExt {
109         MeshBuilder::Submesh info;
110 
111         // Automatically calculated by builder.
112         BASE_NS::vector<uint32_t> vertexBindingByteSize;
113         BASE_NS::vector<uint32_t> vertexBindingOffset;
114         BASE_NS::vector<MorphTargetDesc> morphTargets;
115         uint32_t jointBufferOffset = 0;
116         uint32_t indexBufferOffset = 0;
117         uint32_t morphTargetBufferOffset = 0;
118         uint32_t morphTargetBufferSize = 0;
119         bool hasNormals = false;
120         bool hasUv0 = false;
121         bool hasTangents = false;
122         int32_t positionOffset = -1;
123         uint32_t positionSize = 0;
124         int32_t normalOffset = -1;
125         uint32_t normalSize = 0;
126         int32_t uvOffset = -1;
127         uint32_t uvSize = 0;
128         int32_t tangentsOffset = -1;
129         uint32_t tangentSize = 0;
130         int32_t indexOffset = -1;
131         uint32_t indexSize = 0;
132     };
133 
134 private:
135     BufferEntities CreateBuffers(CORE_NS::IEcs& ecs) const;
136     void GenerateMissingAttributes() const;
137 
138     struct BufferSizesInBytes {
139         size_t indexBuffer;
140         size_t jointBuffer;
141         size_t morphVertexData;
142     };
143 
144     BufferSizesInBytes CalculateSizes();
145 
146     static void GatherDeltasP(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
147         uint32_t targetSize, const DataBuffer& targetPositions);
148     static void GatherDeltasPN(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
149         uint32_t targetSize, const DataBuffer& targetPositions, const DataBuffer& targetNormals);
150     static void GatherDeltasPT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
151         uint32_t targetSize, const DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetTangents);
152     static void GatherDeltasPNT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
153         uint32_t targetSize, const DataBuffer& targetPositions, const DataBuffer& targetNormals,
154         const DataBuffer& targetTangents);
155 
156     void CalculateJointBounds(
157         const DataBuffer& jointData, const DataBuffer& weightData, const DataBuffer& vertexPositions);
158 
159     bool WriteData(const DataBuffer& data, const SubmeshExt& submesh, uint32_t attributeLocation, uint32_t& byteOffset,
160         uint32_t& byteSize, uint8_t* dst) const;
161 
162     RENDER_NS::IRenderContext& renderContext_;
163     RENDER_NS::VertexInputDeclarationView vertexInputDeclaration_;
164 
165     mutable BASE_NS::vector<SubmeshExt> submeshInfos_;
166     mutable BASE_NS::vector<MeshComponent::Submesh> submeshes_;
167 
168     uint32_t vertexCount_ = 0;
169     uint32_t indexCount_ = 0;
170 
171     size_t vertexDataSize_ = 0;
172     size_t indexDataSize_ = 0;
173     size_t jointDataSize_ = 0;
174     size_t targetDataSize_ = 0;
175     BufferHandles bufferHandles_;
176     RENDER_NS::RenderHandleReference stagingBuffer_;
177     uint8_t* stagingPtr_ = nullptr;
178 
179     struct Bounds {
180         BASE_NS::Math::Vec3 min;
181         BASE_NS::Math::Vec3 max;
182     };
183     // Bounds for each joint is 6 floats (3 min & 3 max).
184     static_assert(sizeof(Bounds) == (sizeof(float) * 6));
185     BASE_NS::vector<Bounds> jointBoundsData_;
186 
187     mutable BASE_NS::vector<uint8_t> vertexData_;
188     BASE_NS::vector<uint8_t> indexData_;
189     uint32_t refCount_ = 0;
190 };
191 CORE3D_END_NAMESPACE()
192 
193 #endif // CORE_UTIL_MESH_BUILDER_H
194