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