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__GLTF__GLTF2_IMPORTER_H
17 #define CORE__GLTF__GLTF2_IMPORTER_H
18 
19 #include <atomic>
20 #include <condition_variable>
21 #include <mutex>
22 
23 #include <3d/gltf/gltf.h>
24 #include <3d/loaders/intf_scene_loader.h>
25 #include <3d/util/intf_mesh_builder.h>
26 #include <base/containers/string.h>
27 #include <base/containers/unique_ptr.h>
28 #include <base/containers/vector.h>
29 #include <core/ecs/entity_reference.h>
30 #include <core/ecs/intf_ecs.h>
31 #include <core/namespace.h>
32 #include <core/threading/intf_thread_pool.h>
33 
34 BASE_BEGIN_NAMESPACE()
35 template<class Key, class T>
36 class unordered_map;
37 BASE_END_NAMESPACE()
38 
39 CORE_BEGIN_NAMESPACE()
40 class IEngine;
41 class IImageLoaderManager;
42 class IPerformanceDataManager;
43 CORE_END_NAMESPACE()
44 
45 RENDER_BEGIN_NAMESPACE()
46 class IDevice;
47 class IGpuResourceManager;
48 class IRenderContext;
49 class IShaderManager;
50 RENDER_END_NAMESPACE()
51 
52 CORE3D_BEGIN_NAMESPACE()
53 class IGraphicsContext;
54 class IRenderHandleComponentManager;
55 class IMaterialComponentManager;
56 class IMeshComponentManager;
57 class INameComponentManager;
58 class IUriComponentManager;
59 class IAnimationInputComponentManager;
60 class IAnimationOutputComponentManager;
61 
62 namespace GLTF2 {
63 class Data;
64 struct Accessor;
65 struct AnimationTrack;
66 enum class ImportPhase {
67     BUFFERS = 0,
68     SAMPLERS,
69     IMAGES,
70     TEXTURES,
71     MATERIALS,
72     ANIMATION_SAMPLERS,
73     ANIMATIONS,
74     SKINS,
75     MESHES,
76     FINISHED
77 };
78 
79 // A class that executes GLTF load and import operation over multiple frames.
80 class GLTF2Importer final : public IGLTF2Importer {
81 public:
82     GLTF2Importer(CORE_NS::IEngine& engine, RENDER_NS::IRenderContext& renderContext, CORE_NS::IEcs& ecs);
83     GLTF2Importer(CORE_NS::IEngine& engine, RENDER_NS::IRenderContext& renderContext, CORE_NS::IEcs& ecs,
84         CORE_NS::IThreadPool& pool);
85     ~GLTF2Importer() override;
86 
87     void ImportGLTF(const IGLTFData& data, GltfResourceImportFlags flags) override;
88     void ImportGLTFAsync(const IGLTFData& data, GltfResourceImportFlags flags, Listener* listener) override;
89     bool Execute(uint32_t timeBudget) override;
90 
91     void Cancel() override;
92     bool IsCompleted() const override;
93 
94     const GLTFImportResult& GetResult() const override;
95 
96     const GltfMeshData& GetMeshData() const override;
97 
98     struct DefaultMaterialShaderData {
99         struct SingleShaderData {
100             CORE_NS::EntityReference shader;
101             CORE_NS::EntityReference gfxState;
102             CORE_NS::EntityReference gfxStateDoubleSided;
103         };
104         SingleShaderData opaque;
105         SingleShaderData blend;
106         SingleShaderData depth;
107     };
108 
109 protected:
110     void Destroy() override;
111 
112 private:
113     struct ImporterTask;
114     template<typename T>
115     struct GatheredDataTask;
116     template<typename Component>
117     struct ComponentTaskData;
118     struct AnimationTaskData;
119 
120     class ImportThreadTask;
121     class GatherThreadTask;
122 
123     void Prepare();
124     void PrepareBufferTasks();
125     void PrepareSamplerTasks();
126     void PrepareImageTasks();
127     void PrepareImageBasedLightTasks();
128     void PrepareMaterialTasks();
129     void PrepareAnimationTasks();
130     void PrepareSkinTasks();
131     void PrepareMeshTasks();
132     template<typename T>
133     GatheredDataTask<T>* PrepareAnimationInputTask(BASE_NS::unordered_map<GLTF2::Accessor*, GatheredDataTask<T>*>&,
134         const GLTF2::AnimationTrack&, IAnimationInputComponentManager*);
135     template<typename T>
136     GatheredDataTask<T>* PrepareAnimationOutputTask(BASE_NS::unordered_map<GLTF2::Accessor*, GatheredDataTask<T>*>&,
137         const GLTF2::AnimationTrack&, IAnimationOutputComponentManager*);
138     void QueueImage(size_t i, BASE_NS::string&& uri, BASE_NS::string&& name);
139 
140     void QueueTask(BASE_NS::unique_ptr<ImporterTask>&& task);
141     bool ProgressTask(ImporterTask& task);
142     void Gather(ImporterTask& task);
143     void Import(ImporterTask& task);
144     void CompleteTask(ImporterTask& task);
145 
146     void StartPhase(ImportPhase phase);
147     void HandleGatherTasks();
148     void HandleImportTasks();
149 
150     ImporterTask* FindTaskById(uint64_t id);
151 
152     ImportPhase phase_ { ImportPhase::BUFFERS };
153     BASE_NS::vector<BASE_NS::unique_ptr<ImporterTask>> tasks_;
154 
155     CORE_NS::IEngine& engine_;
156     RENDER_NS::IRenderContext& renderContext_;
157     RENDER_NS::IDevice& device_;
158     RENDER_NS::IGpuResourceManager& gpuResourceManager_;
159     CORE_NS::IEcs::Ptr ecs_;
160     IRenderHandleComponentManager& gpuHandleManager_;
161     IMaterialComponentManager& materialManager_;
162     IMeshComponentManager& meshManager_;
163     INameComponentManager& nameManager_;
164     IUriComponentManager& uriManager_;
165 
166     // assigned to material in import
167     DefaultMaterialShaderData dmShaderData_;
168 
169     const Data* data_ { nullptr };
170 
171     CORE_NS::IThreadPool::Ptr threadPool_;
172     CORE_NS::IDispatcherTaskQueue::Ptr mainThreadQueue_;
173     Listener* listener_ { nullptr };
174 
175     GltfResourceImportFlags flags_ { CORE_GLTF_IMPORT_RESOURCE_FLAG_BITS_ALL };
176     GLTFImportResult result_;
177 
178     std::mutex gatherTasksLock_;
179     std::condition_variable condition_;
180     BASE_NS::vector<uint64_t> finishedGatherTasks_;
181     BASE_NS::vector<CORE_NS::IThreadPool::IResult::Ptr> gatherTaskResults_;
182 
183     size_t pendingGatherTasks_ { 0 };
184     size_t pendingImportTasks_ { 0 };
185     size_t completedTasks_ { 0 };
186 
187     std::atomic_bool cancelled_ { false };
188 
189     BASE_NS::vector<IMeshBuilder::Ptr> meshBuilders_;
190     GltfMeshData meshData_;
191 };
192 
193 class Gltf2SceneImporter final : public ISceneImporter, IGLTF2Importer::Listener {
194 public:
195     Gltf2SceneImporter(CORE_NS::IEngine& engine, RENDER_NS::IRenderContext& renderContext, CORE_NS::IEcs& ecs);
196     Gltf2SceneImporter(CORE_NS::IEngine& engine, RENDER_NS::IRenderContext& renderContext, CORE_NS::IEcs& ecs,
197         CORE_NS::IThreadPool& pool);
198     ~Gltf2SceneImporter() = default;
199 
200     void ImportResources(const ISceneData::Ptr& data, ResourceImportFlags flags) override;
201     void ImportResources(
202         const ISceneData::Ptr& data, ResourceImportFlags flags, ISceneImporter::Listener* listener) override;
203     bool Execute(uint32_t timeBudget) override;
204     void Cancel() override;
205     bool IsCompleted() const override;
206     const Result& GetResult() const override;
207     const MeshData& GetMeshData() const override;
208     CORE_NS::Entity ImportScene(size_t sceneIndex) override;
209     CORE_NS::Entity ImportScene(size_t sceneIndex, SceneImportFlags flags) override;
210     CORE_NS::Entity ImportScene(size_t sceneIndex, CORE_NS::Entity parentEntity) override;
211     CORE_NS::Entity ImportScene(size_t sceneIndex, CORE_NS::Entity parentEntity, SceneImportFlags flags) override;
212 
213     // IInterface
214     const IInterface* GetInterface(const BASE_NS::Uid& uid) const override;
215     IInterface* GetInterface(const BASE_NS::Uid& uid) override;
216     void Ref() override;
217     void Unref() override;
218 
219     // IGLTF2Importer::Listener
220     void OnImportStarted() override;
221     void OnImportFinished() override;
222     void OnImportProgressed(size_t taskIndex, size_t taskCount) override;
223 
224 private:
225     CORE_NS::IEcs& ecs_;
226     IGraphicsContext* graphicsContext_ { nullptr };
227     GLTF2Importer::Ptr importer_;
228     ISceneData::Ptr data_;
229     uint32_t refcnt_ { 0 };
230     Result result_;
231     MeshData meshData_;
232     ISceneImporter::Listener* listener_ { nullptr };
233 };
234 } // namespace GLTF2
235 
236 CORE_NS::Entity ImportScene(RENDER_NS::IDevice& device, size_t sceneIndex, const GLTF2::Data& data,
237     const GLTFResourceData& gltfResourceData, CORE_NS::IEcs& ecs, CORE_NS::Entity rootEntity,
238     GltfSceneImportFlags flags);
239 CORE3D_END_NAMESPACE()
240 
241 #endif // CORE__GLTF__GLTF2_IMPORTER_H
242