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 API_3D_GLTF_GLTF_H
17 #define API_3D_GLTF_GLTF_H
18 
19 #include <cstdint>
20 
21 #include <3d/ecs/components/mesh_component.h>
22 #include <3d/namespace.h>
23 #include <base/containers/array_view.h>
24 #include <base/containers/string.h>
25 #include <base/containers/string_view.h>
26 #include <base/containers/unique_ptr.h>
27 #include <base/containers/vector.h>
28 #include <core/ecs/entity_reference.h>
29 #include <render/device/pipeline_state_desc.h>
30 #include <render/resource_handle.h>
31 
32 CORE_BEGIN_NAMESPACE()
33 class IEcs;
34 class IThreadPool;
35 CORE_END_NAMESPACE()
36 
37 CORE3D_BEGIN_NAMESPACE()
38 /** \addtogroup group_gltf_gltf
39  *  @{
40  */
41 /** No scene explicitly defined in import options. */
42 const unsigned long CORE_GLTF_INVALID_INDEX = 0x7FFFFFFF;
43 
44 /** Interface to GLTF data. */
45 class IGLTFData {
46 public:
47     /** Populates buffers with binary data.
48      *  @return true if buffers were successfully loaded, otherwise false.
49      */
50     virtual bool LoadBuffers() = 0;
51 
52     /** Releases allocated data from buffers. */
53     virtual void ReleaseBuffers() = 0;
54 
55     /** Can be used to retrieve external file dependencies.
56      *  @return Array of file uris that describe required files that need to be available for this glTF file to
57      * successfully load.
58      */
59     virtual BASE_NS::vector<BASE_NS::string> GetExternalFileUris() = 0;
60 
61     /** Retrieve default scene index. */
62     virtual size_t GetDefaultSceneIndex() const = 0;
63 
64     /** Retrieve number of scenes in this glTF file.
65      *  @return Number of scenes available.
66      */
67     virtual size_t GetSceneCount() const = 0;
68 
69     /** Describes thumbnail image structure. */
70     struct ThumbnailImage {
71         /** Data extension, such as 'png'. */
72         BASE_NS::string extension;
73 
74         /** Image data buffer. */
75         BASE_NS::array_view<const uint8_t> data;
76     };
77 
78     /** Retrieve number of thumbnails in this glTF file.
79      *  @return Number of thumbnail images available.
80      */
81     virtual size_t GetThumbnailImageCount() const = 0;
82 
83     /** Retrieve thumbnail image data of given thumbnail.
84      *  @param thumbnailIndex Index of the requested thumbnail image.
85      *  @return A structure containing thumbnail image data.
86      */
87     virtual ThumbnailImage GetThumbnailImage(size_t thumbnailIndex) = 0;
88 
89     struct Deleter {
90         constexpr Deleter() noexcept = default;
operatorDeleter91         void operator()(IGLTFData* ptr) const
92         {
93             ptr->Destroy();
94         }
95     };
96     using Ptr = BASE_NS::unique_ptr<IGLTFData, Deleter>;
97 
98 protected:
99     IGLTFData() = default;
100     virtual ~IGLTFData() = default;
101     virtual void Destroy() = 0;
102 };
103 
104 /** Describes result of the loading operation. */
105 struct GLTFLoadResult {
106     GLTFLoadResult() = default;
GLTFLoadResultGLTFLoadResult107     explicit GLTFLoadResult(BASE_NS::string&& error) : success(false), error(error) {}
108 
109     /** Indicates, whether the loading operation is successful. */
110     bool success { true };
111 
112     /** In case of parsing error, contains the description of the error. */
113     BASE_NS::string error;
114 
115     /** Loaded data. */
116     IGLTFData::Ptr data;
117 };
118 
119 /** Access to imported GLTF resources. */
120 struct GLTFResourceData {
121     /** Imported samplers. */
122     BASE_NS::vector<CORE_NS::EntityReference> samplers;
123 
124     /** Imported images. */
125     BASE_NS::vector<CORE_NS::EntityReference> images;
126 
127     /** Imported textures. */
128     BASE_NS::vector<CORE_NS::EntityReference> textures;
129 
130     /** Imported materials. */
131     BASE_NS::vector<CORE_NS::EntityReference> materials;
132 
133     /** Imported geometry. */
134     BASE_NS::vector<CORE_NS::EntityReference> meshes;
135 
136     /** Imported skins. */
137     BASE_NS::vector<CORE_NS::EntityReference> skins;
138 
139     /** Imported animations. */
140     BASE_NS::vector<CORE_NS::EntityReference> animations;
141 
142     /** Imported IBL cubemaps. */
143     BASE_NS::vector<CORE_NS::EntityReference> specularRadianceCubemaps;
144 };
145 
146 /** Flags for resource import. */
147 enum GltfResourceImportFlagBits {
148     /** Sampler */
149     CORE_GLTF_IMPORT_RESOURCE_SAMPLER = 0x00000001,
150     /** Image */
151     CORE_GLTF_IMPORT_RESOURCE_IMAGE = 0x00000002,
152     /** Texture */
153     CORE_GLTF_IMPORT_RESOURCE_TEXTURE = 0x00000004,
154     /** Material */
155     CORE_GLTF_IMPORT_RESOURCE_MATERIAL = 0x00000008,
156     /** Mesh */
157     CORE_GLTF_IMPORT_RESOURCE_MESH = 0x00000010,
158     /** Skin */
159     CORE_GLTF_IMPORT_RESOURCE_SKIN = 0x00000020,
160     /** Animation */
161     CORE_GLTF_IMPORT_RESOURCE_ANIMATION = 0x00000040,
162     /** Skip resources that are not referenced and do not import them. */
163     CORE_GLTF_IMPORT_RESOURCE_SKIP_UNUSED = 0x00000080,
164     /** Keep mesh data for CPU access. Allowing CPU access increases memory usage. */
165     CORE_GLTF_IMPORT_RESOURCE_MESH_CPU_ACCESS = 0x00000100,
166     /** All flags bits */
167     CORE_GLTF_IMPORT_RESOURCE_FLAG_BITS_ALL = 0x7FFFFEFF
168 };
169 
170 /** Container for flags for resource import. */
171 using GltfResourceImportFlags = uint32_t;
172 
173 /** Flags for scene / ecs component import. */
174 enum GltfSceneImportFlagBits {
175     /** Scene, Deprecated value used for environment */
176     CORE_GLTF_IMPORT_COMPONENT_SCENE = 0x00000001,
177     /** Environment */
178     CORE_GLTF_IMPORT_COMPONENT_ENVIRONMENT = 0x00000001,
179     /** Mesh */
180     CORE_GLTF_IMPORT_COMPONENT_MESH = 0x00000002,
181     /** Camera */
182     CORE_GLTF_IMPORT_COMPONENT_CAMERA = 0x00000004,
183     /** Skin */
184     CORE_GLTF_IMPORT_COMPONENT_SKIN = 0x00000008,
185     /** Light */
186     CORE_GLTF_IMPORT_COMPONENT_LIGHT = 0x00000010,
187     /** Morph */
188     CORE_GLTF_IMPORT_COMPONENT_MORPH = 0x00000020,
189     /** All flag bits */
190     CORE_GLTF_IMPORT_COMPONENT_FLAG_BITS_ALL = 0x7FFFFFFF
191 };
192 
193 /** Container for Gltf scene import flag bits */
194 using GltfSceneImportFlags = uint32_t;
195 
196 /** Describes result of the import operation. */
197 struct GLTFImportResult {
198     /** Indicates, whether the import operation is successful. */
199     bool success { true };
200 
201     /** In case of import error, contains the description of the error. */
202     BASE_NS::string error;
203 
204     /** Imported data. */
205     GLTFResourceData data;
206 };
207 
208 struct GltfMeshData {
209     struct SubMesh {
210         uint32_t indices;
211         uint32_t vertices;
212         BASE_NS::array_view<const uint8_t> indexBuffer;
213         BASE_NS::array_view<const uint8_t> attributeBuffers[MeshComponent::Submesh::BUFFER_COUNT];
214     };
215     struct Mesh {
216         BASE_NS::vector<SubMesh> subMeshes;
217     };
218     /** Vertex input declaration used for formatting the data. */
219     RENDER_NS::VertexInputDeclarationData vertexInputDeclaration;
220     /** Data of each imported mesh. They are in the same order as in GLTFResourceData::meshes. */
221     BASE_NS::vector<Mesh> meshes;
222 };
223 
224 /** GLTF2 importer interface */
225 class IGLTF2Importer {
226 public:
227     /** Listener for import events. */
228     class Listener {
229     public:
230         virtual ~Listener() = default;
231 
232         /** On import started */
233         virtual void OnImportStarted() = 0;
234         /** On import finished */
235         virtual void OnImportFinished() = 0;
236         /** On import progressed */
237         virtual void OnImportProgressed(size_t taskIndex, size_t taskCount) = 0;
238     };
239 
240     /** Import GLTF2 data synchronously. The previous imported data will be discarded. */
241     virtual void ImportGLTF(const IGLTFData& data, GltfResourceImportFlags flags) = 0;
242 
243     /** Import GLTF2 data asynchronously, user is required to call Execute() from main thread until it returns true.
244      * The previous imported data will be discarded. */
245     virtual void ImportGLTFAsync(const IGLTFData& data, GltfResourceImportFlags flags, Listener* listener) = 0;
246 
247     /** Advances the import process, needs to be called from the main thread when performing asynchronous import.
248      *  @param timeBudget Time budget for resource import in microseconds, if 0 all available work will be executed
249      *  during this frame.
250      */
251     virtual bool Execute(uint32_t timeBudget) = 0;
252 
253     /** Cancel import operation, this does not discard imported data. */
254     virtual void Cancel() = 0;
255 
256     /** Returns true when import process is completed. */
257     virtual bool IsCompleted() const = 0;
258 
259     /** Returns imported data and success of the whole operation. The imported resources are reference counted and the
260      * importer holds references until a new import is started or the imported is destroyed. Therefore a copy of
261      * GLTFImportResult::GLTFResourceData (or selected EntityReferences) should be stored. */
262     virtual const GLTFImportResult& GetResult() const = 0;
263 
264     /** Returns CPU accessible mesh data. Data is available when CORE_GLTF_IMPORT_RESOURCE_MESH_CPU_ACCESS was included
265      * in import flags. Unless copied, the data is valid until a new import is started or the imported is destroyed. */
266     virtual const GltfMeshData& GetMeshData() const = 0;
267 
268     struct Deleter {
269         constexpr Deleter() noexcept = default;
operatorDeleter270         void operator()(IGLTF2Importer* ptr) const
271         {
272             ptr->Destroy();
273         }
274     };
275     using Ptr = BASE_NS::unique_ptr<IGLTF2Importer, Deleter>;
276 
277 protected:
278     IGLTF2Importer() = default;
279     virtual ~IGLTF2Importer() = default;
280     virtual void Destroy() = 0;
281 };
282 
283 class IGltf2 {
284 public:
285     /** Load GLTF data from URI.
286      *  @param uri URI pointing to the glTF data.
287      *  @return If the glTF data could be parsed GLTFLoadResult::success will be true and GLTFLoadResult::data is valid.
288      *  If parsing fails GLTFLoadResult::success will be false and GLTFLoadResult::error will give more details on the
289      *  failure.
290      */
291     virtual GLTFLoadResult LoadGLTF(BASE_NS::string_view uri) = 0;
292 
293     /** Load GLTF data from memory.
294      *  @param data Contents of a GLB or a glTF file with embedded data.
295      *  The memory should not be released until loading and importing have been completed.
296      *  @return If the glTF data could be parsed GLTFLoadResult::success will be true and GLTFLoadResult::data is valid.
297      * If parsing fails GLTFLoadResult::success will be false and GLTFLoadResult::error will give more details on the
298      * failure.
299      */
300     virtual GLTFLoadResult LoadGLTF(BASE_NS::array_view<uint8_t const> data) = 0;
301 
302     /** Save GLTF data to file.
303      *  @param ecs ECS instance from which data is exported as a glTF file.
304      *  @param uri URI pointing to the glTF file.
305      *  @return True if the data could be saved, false otherwise.
306      */
307     virtual bool SaveGLTF(CORE_NS::IEcs& ecs, BASE_NS::string_view uri) = 0;
308 
309     /** Create glTF file importer that builds 3D resources from glTF data.
310      *  The importer will create a thread pool where import task are executed.
311      *  @param ecs ECS that contains all required subsystems that are needed for resource creation.
312      *  @return glTF importer instance.
313      */
314     virtual IGLTF2Importer::Ptr CreateGLTF2Importer(CORE_NS::IEcs& ecs) = 0;
315 
316     /** Create glTF file importer that builds 3D resources from glTF data.
317      *  @param ecs ECS that contains all required subsystems that are needed for resource creation.
318      *  @param pool Importer will use the given thread pool instead of creating its own.
319      *  @return glTF importer instance.
320      */
321     virtual IGLTF2Importer::Ptr CreateGLTF2Importer(CORE_NS::IEcs& ecs, CORE_NS::IThreadPool& pool) = 0;
322 
323     /** Import glTF scene to Ecs using pre-imported glTF resources.
324      *  @param sceneIndex Index of scene to import.
325      *  @param gltfData Pre-loaded glTF data.
326      *  @param gltfImportData Structure that contains glTF resource handles related to imported glTF.
327      *  @param ecs Ecs structure that receives the imported entities and components.
328      *  @param rootEntity Root entity for imported data.
329      *  @param flags Import flags to filter out which components are imported.
330      *  @return Scene root entity.
331      */
332     virtual CORE_NS::Entity ImportGltfScene(size_t sceneIndex, const IGLTFData& gltfData,
333         const GLTFResourceData& gltfImportData, CORE_NS::IEcs& ecs, CORE_NS::Entity rootEntity = {},
334         GltfSceneImportFlags flags = CORE_GLTF_IMPORT_COMPONENT_FLAG_BITS_ALL) = 0;
335 
336 protected:
337     IGltf2() = default;
338     virtual ~IGltf2() = default;
339 };
340 /** @} */
341 CORE3D_END_NAMESPACE()
342 
343 #endif // API_3D_GLTF_GLTF_H
344