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_LOADERS_ISCENE_LOADER_H
17 #define API_3D_LOADERS_ISCENE_LOADER_H
18 
19 #include <3d/ecs/components/mesh_component.h>
20 #include <3d/namespace.h>
21 #include <base/containers/array_view.h>
22 #include <base/containers/refcnt_ptr.h>
23 #include <base/containers/string.h>
24 #include <base/containers/string_view.h>
25 #include <base/containers/vector.h>
26 #include <core/ecs/entity.h>
27 #include <core/ecs/entity_reference.h>
28 #include <core/plugin/intf_interface.h>
29 
30 CORE_BEGIN_NAMESPACE()
31 class IEcs;
32 class IThreadPool;
33 CORE_END_NAMESPACE()
34 
35 CORE3D_BEGIN_NAMESPACE()
36 /** No scene explicitly defined in import options. */
37 const unsigned long CORE_SCENE_INVALID_INDEX = 0x7FFFFFFF;
38 
39 class ISceneData : public CORE_NS::IInterface {
40 public:
41     static constexpr auto UID = BASE_NS::Uid { "eb6381c1-36a3-4709-8031-c37c1b9cd76e" };
42     using Ptr = BASE_NS::refcnt_ptr<ISceneData>;
43 
44     /** Retrieve default scene index. */
45     virtual size_t GetDefaultSceneIndex() const = 0;
46 
47     /** Retrieve number of scenes in this scene file.
48      *  @return Number of scenes available.
49      */
50     virtual size_t GetSceneCount() const = 0;
51 
52 protected:
53     ISceneData() = default;
54     virtual ~ISceneData() = default;
55 };
56 
57 /** Access to imported resources. */
58 struct ResourceData {
59     /** Imported samplers. */
60     BASE_NS::vector<CORE_NS::EntityReference> samplers;
61 
62     /** Imported images. */
63     BASE_NS::vector<CORE_NS::EntityReference> images;
64 
65     /** Imported textures. */
66     BASE_NS::vector<CORE_NS::EntityReference> textures;
67 
68     /** Imported materials. */
69     BASE_NS::vector<CORE_NS::EntityReference> materials;
70 
71     /** Imported geometry. */
72     BASE_NS::vector<CORE_NS::EntityReference> meshes;
73 
74     /** Imported skins. */
75     BASE_NS::vector<CORE_NS::EntityReference> skins;
76 
77     /** Imported animations. */
78     BASE_NS::vector<CORE_NS::EntityReference> animations;
79 
80     /** Imported IBL cubemaps. */
81     BASE_NS::vector<CORE_NS::EntityReference> specularRadianceCubemaps;
82 };
83 
84 /** Flags for resource import. */
85 enum ResourceImportFlagBits {
86     /** Sampler */
87     CORE_IMPORT_RESOURCE_SAMPLER = 0x00000001,
88     /** Image */
89     CORE_IMPORT_RESOURCE_IMAGE = 0x00000002,
90     /** Texture */
91     CORE_IMPORT_RESOURCE_TEXTURE = 0x00000004,
92     /** Material */
93     CORE_IMPORT_RESOURCE_MATERIAL = 0x00000008,
94     /** Mesh */
95     CORE_IMPORT_RESOURCE_MESH = 0x00000010,
96     /** Skin */
97     CORE_IMPORT_RESOURCE_SKIN = 0x00000020,
98     /** Animation */
99     CORE_IMPORT_RESOURCE_ANIMATION = 0x00000040,
100     /** Skip resources that are not referenced and do not import them. */
101     CORE_IMPORT_RESOURCE_SKIP_UNUSED = 0x00000080,
102     /** Keep mesh data for CPU access. Allowing CPU access increases memory usage. */
103     CORE_IMPORT_RESOURCE_MESH_CPU_ACCESS = 0x00000100,
104     /** All flags bits */
105     CORE_IMPORT_RESOURCE_FLAG_BITS_ALL = 0x7FFFFEFF
106 };
107 
108 /** Container for flags for resource import. */
109 using ResourceImportFlags = uint32_t;
110 
111 /** Flags for scene / ecs component import. */
112 enum SceneImportFlagBits {
113     /** Environment */
114     CORE_IMPORT_COMPONENT_ENVIRONMENT = 0x00000001,
115     /** Mesh */
116     CORE_IMPORT_COMPONENT_MESH = 0x00000002,
117     /** Camera */
118     CORE_IMPORT_COMPONENT_CAMERA = 0x00000004,
119     /** Skin */
120     CORE_IMPORT_COMPONENT_SKIN = 0x00000008,
121     /** Light */
122     CORE_IMPORT_COMPONENT_LIGHT = 0x00000010,
123     /** Morph */
124     CORE_IMPORT_COMPONENT_MORPH = 0x00000020,
125     /** All flag bits */
126     CORE_IMPORT_COMPONENT_FLAG_BITS_ALL = 0x7FFFFFFF
127 };
128 
129 /** Container for  scene import flag bits */
130 using SceneImportFlags = uint32_t;
131 
132 struct MeshData {
133     struct SubMesh {
134         uint32_t indices;
135         uint32_t vertices;
136         BASE_NS::array_view<const uint8_t> indexBuffer;
137         BASE_NS::array_view<const uint8_t> attributeBuffers[MeshComponent::Submesh::BUFFER_COUNT];
138     };
139     struct Mesh {
140         BASE_NS::vector<SubMesh> subMeshes;
141     };
142     /** Vertex input declaration used for formatting the data. */
143     RENDER_NS::VertexInputDeclarationData vertexInputDeclaration;
144     /** Data of each imported mesh. They are in the same order as in ResourceData::meshes. */
145     BASE_NS::vector<Mesh> meshes;
146 };
147 
148 class ISceneImporter : public CORE_NS::IInterface {
149 public:
150     static constexpr auto UID = BASE_NS::Uid { "6dd26fca-9ef1-40f1-ba67-1bbcc1740885" };
151 
152     using Ptr = BASE_NS::refcnt_ptr<ISceneImporter>;
153 
154     struct Result {
155         /** Indicates, whether the import operation is successful. */
156         int32_t error { 0 };
157 
158         /** In case of import error, contains the description of the error. */
159         BASE_NS::string message;
160 
161         /** Imported resources. */
162         ResourceData data;
163     };
164 
165     /** Listener for import events. */
166     class Listener {
167     public:
168         virtual ~Listener() = default;
169 
170         /** On import started */
171         virtual void OnImportStarted() = 0;
172         /** On import progressed */
173         virtual void OnImportProgressed(size_t taskIndex, size_t taskCount) = 0;
174         /** On import finished */
175         virtual void OnImportFinished() = 0;
176     };
177 
178     /** Import resources synchronously. The previous imported data will be discarded.
179      * @param data Scene data returned by the loader.
180      * @param flags Flags for scene / ecs component import.
181      */
182     virtual void ImportResources(const ISceneData::Ptr& data, ResourceImportFlags flags) = 0;
183 
184     /** Import resource data asynchronously. The previous imported data will be discarded. Import will mostly happen in
185      * a threadpool, but any access to the ECS must be done synchronized. Typically the user calls Execute() from the
186      * rendering thread each frame.
187      * @param data Scene data returned by the loader.
188      * @param flags Flags for scene / ecs component import.
189      * @param listener Listener which receives updates of the imports progress.
190      */
191     virtual void ImportResources(const ISceneData::Ptr& data, ResourceImportFlags flags, Listener* listener) = 0;
192 
193     /** Advances the import process when performing asynchronous import. Needs to be called synchronized with other ECS
194      * usage.
195      *  @param timeBudget Time budget for resource import in microseconds, if 0 all available work will be executed
196      *  during this frame.
197      * @return True if the import was compled.
198      */
199     virtual bool Execute(uint32_t timeBudget) = 0;
200 
201     /** Cancel import operation, this does not discard imported data. */
202     virtual void Cancel() = 0;
203 
204     /** Returns true when import process is completed. */
205     virtual bool IsCompleted() const = 0;
206 
207     /** Returns imported data and success of the whole operation. The imported resources are reference counted and the
208      * importer holds references until a new import is started or the imported is destroyed. Therefore a copy of
209      * ImportResult::ResourceData (or selected EntityReferences) should be stored. */
210     virtual const Result& GetResult() const = 0;
211 
212     /** Returns CPU accessible mesh data. Data is available when CORE_IMPORT_RESOURCE_MESH_CPU_ACCESS was included
213      * in import flags. Unless copied, the data is valid until a new import is started or the imported is destroyed. */
214     virtual const MeshData& GetMeshData() const = 0;
215 
216     /** Import scene to ECS using pre-imported resources.
217      *  @param sceneIndex Index of scene to import.
218      *  @return Scene root entity.
219      */
220     virtual CORE_NS::Entity ImportScene(size_t sceneIndex) = 0;
221 
222     /** Import scene to ECS using pre-imported resources.
223      *  @param sceneIndex Index of scene to import.
224      *  @param flags Import flags to filter out which components are imported.
225      *  @return Scene root entity.
226      */
227     virtual CORE_NS::Entity ImportScene(size_t sceneIndex, SceneImportFlags flags) = 0;
228 
229     /** Import scene to ECS using pre-imported resources.
230      *  @param sceneIndex Index of scene to import.
231      *  @param parentEntity Scene will be added as a child of the parent entity.
232      *  @return Scene root entity.
233      */
234     virtual CORE_NS::Entity ImportScene(size_t sceneIndex, CORE_NS::Entity parentEntity) = 0;
235 
236     /** Import scene to ECS using pre-imported resources.
237      *  @param sceneIndex Index of scene to import.
238      *  @param parentEntity Scene will be added as a child of the parent entity.
239      *  @param flags Import flags to filter out which components are imported.
240      *  @return Scene root entity.
241      */
242     virtual CORE_NS::Entity ImportScene(size_t sceneIndex, CORE_NS::Entity parentEntity, SceneImportFlags flags) = 0;
243 
244 protected:
245 };
246 
247 class ISceneLoader : public CORE_NS::IInterface {
248 public:
249     static constexpr auto UID = BASE_NS::Uid { "61997694-aa64-4753-9d01-17d18aad4822" };
250 
251     using Ptr = BASE_NS::refcnt_ptr<ISceneLoader>;
252 
253     struct Result {
254         /** Indicates, whether the loading was successful. */
255         int32_t error { 0 };
256 
257         /** In case of an error, contains the description of the error. */
258         BASE_NS::string message;
259 
260         /** Loaded data. */
261         ISceneData::Ptr data;
262     };
263 
264     /** Load scene data from URI.
265      * @param uri URI pointing to the scene data.
266      * @return If the scene data could be parsed LoadResult::result will be zero and LoadResult::data is valid. If
267      * parsing fails LoadResult::result will be a non-zero, loader specific error code and LoadResult::error will give
268      * more details on the failure.
269      */
270     virtual Result Load(BASE_NS::string_view uri) = 0;
271 
272     /** Create an importer that builds 3D resources and scenes from loaded scene data.
273      *  The importer will create a thread pool where import task are executed.
274      * @param ecs ECS that contains all required subsystems that are needed for resource creation.
275      * @return Scene importer instance.
276      */
277     virtual ISceneImporter::Ptr CreateSceneImporter(CORE_NS::IEcs& ecs) = 0;
278 
279     /** Create an importer that builds 3D resources and scenes from loaded scene data.
280      * @param ecs ECS that contains all required subsystems that are needed for resource creation.
281      * @param pool Importer will use the given thread pool instead of creating its own.
282      * @return Scene importer instance.
283      */
284     virtual ISceneImporter::Ptr CreateSceneImporter(CORE_NS::IEcs& ecs, CORE_NS::IThreadPool& pool) = 0;
285 
286     /** Returns a list of extensions the loader supports.
287      * @return List of supported file extensions.
288      */
289     virtual BASE_NS::array_view<const BASE_NS::string_view> GetSupportedExtensions() const = 0;
290 
291 protected:
292     ISceneLoader() = default;
293     virtual ~ISceneLoader() = default;
294 };
295 CORE3D_END_NAMESPACE()
296 #endif // API_3D_LOADERS_ISCENE_LOADER_H