• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SCENE_API_SCENE_H
17 #define SCENE_API_SCENE_H
18 
19 #include <scene/api/node.h>
20 #include <scene/api/resource.h>
21 #include <scene/ext/intf_internal_scene.h>
22 #include <scene/interface/intf_application_context.h>
23 #include <scene/interface/intf_image.h>
24 #include <scene/interface/intf_light.h>
25 #include <scene/interface/intf_mesh.h>
26 #include <scene/interface/intf_node_import.h>
27 #include <scene/interface/intf_scene.h>
28 #include <scene/interface/intf_scene_manager.h>
29 #include <scene/interface/resource/intf_render_resource_manager.h>
30 
31 #include <meta/api/animation.h>
32 #include <meta/api/iteration.h>
33 
34 SCENE_BEGIN_NAMESPACE()
35 
36 class Scene;
37 
38 #define SCENE_RESOURCE_FACTORY_CREATE_NODE(NodeName, NodeType, ClassId) \
39     template<const AsyncCallType& CallType = Sync>                      \
40     auto Create##NodeName(BASE_NS::string_view path)                    \
41     {                                                                   \
42         return CallCreateNode<NodeType, CallType>(path, ClassId);       \
43     }
44 
45 /**
46  * @brief The SceneResourceParameters class defines generic parameters for resource creation.
47  */
48 struct SceneResourceParameters {
49     SceneResourceParameters() = default;
SceneResourceParametersSceneResourceParameters50     SceneResourceParameters(BASE_NS::string_view path) : path(path) {}
SceneResourceParametersSceneResourceParameters51     SceneResourceParameters(const char* path) : path(path) {}
52     /// Path to load the resource from. Depending on resource type this parameter may be ignored.
53     BASE_NS::string path;
54 };
55 
56 /**
57  * @brief The MaterialResourceParameters class defines Material creation specific parameters.
58  */
59 struct MaterialResourceParameters : public SceneResourceParameters {
60     /// Type of the material
61     MaterialType type { MaterialType::METALLIC_ROUGHNESS };
62 };
63 
64 /**
65  * @brief The TextResourceParameters class defines Text3D node creation specific parameters.
66  */
67 struct TextResourceParameters : public SceneResourceParameters {
68     /// The text string to show
69     BASE_NS::string text;
70     /// Font to use
71     BASE_NS::string font;
72     /// Height of the rasterized 2d texture.
73     float fontSize {};
74     /// Text color in SRGB RGBA.
75     BASE_NS::Math::Vec4 color;
76 };
77 
78 /**
79  * @brief RenderContextResourceFactory can be used to instantiate new RenderContext specific resources (shared between
80  *        all scenes using the same RenderContext).
81  */
82 class RenderContextResourceFactory {
83 public:
84     RenderContextResourceFactory() = delete;
RenderContextResourceFactory(const IScene::Ptr & scene)85     RenderContextResourceFactory(const IScene::Ptr& scene) : scene_(scene) {};
86     virtual ~RenderContextResourceFactory() = default;
META_DEFAULT_COPY_MOVE(RenderContextResourceFactory)87     META_DEFAULT_COPY_MOVE(RenderContextResourceFactory)
88     operator bool() const noexcept
89     {
90         return scene_.lock() != nullptr;
91     }
92     /// Creates a new environment with given parameters.
CreateEnvironment(const SceneResourceParameters & params)93     META_API_ASYNC auto CreateEnvironment(const SceneResourceParameters& params)
94     {
95         return CallCreateResource<Environment, CallType>(params, ClassId::Environment);
96     }
97     /// Creates a new material with given parameters.
CreateMaterial(const MaterialResourceParameters & params)98     META_API_ASYNC auto CreateMaterial(const MaterialResourceParameters& params)
99     {
100         auto f = CallScene([&](auto& scene) {
101             return scene.CreateObject(ClassId::Material).Then([params](const META_NS::IObject::Ptr& object) {
102                 auto material = interface_pointer_cast<IMaterial>(object);
103                 if (material) {
104                     SetValue(material->Type(), params.type);
105                 }
106                 return material;
107             });
108         });
109         return Internal::UnwrapFuture<CallType, Material>(BASE_NS::move(f));
110     }
111     /// Creates a new mesh with given parameters.
CreateMesh(const SceneResourceParameters & params)112     META_API_ASYNC auto CreateMesh(const SceneResourceParameters& params)
113     {
114         return CallCreateResource<Mesh, CallType>(params, ClassId::Mesh);
115     }
116     /// Creates a new shader with given parameters.
CreateShader(const SceneResourceParameters & params)117     META_API_ASYNC auto CreateShader(const SceneResourceParameters& params)
118     {
119         auto f = CallScene([&](auto& scene) {
120             return scene.template CreateObject<IRenderResourceManager>(ClassId::RenderResourceManager)
121                 .Then([params](const IRenderResourceManager::Ptr& manager) {
122                     return manager ? manager->LoadShader(params.path).GetResult() : IShader::Ptr {};
123                 });
124         });
125         return Internal::UnwrapFuture<CallType, Shader>(BASE_NS::move(f));
126     }
127     /// Creates a new image with given parameters.
CreateImage(const SceneResourceParameters & params)128     META_API_ASYNC auto CreateImage(const SceneResourceParameters& params)
129     {
130         auto f = CallScene([&](auto& scene) {
131             return scene.template CreateObject<IRenderResourceManager>(ClassId::RenderResourceManager)
132                 .Then([params](const IRenderResourceManager::Ptr& manager) {
133                     return manager ? manager->LoadImage(params.path).GetResult() : IImage::Ptr {};
134                 });
135         });
136         return Internal::UnwrapFuture<CallType, Image>(BASE_NS::move(f));
137     }
138 
139 protected:
140     template<class Type, const META_NS::AsyncCallType& CallType>
CallCreateResource(const SceneResourceParameters & params,META_NS::ObjectId id)141     auto CallCreateResource(const SceneResourceParameters& params, META_NS::ObjectId id)
142     {
143         auto f = CallScene([&](auto& scene) { return scene.CreateObject(id); });
144         return Internal::UnwrapFuture<CallType, Type>(BASE_NS::move(f));
145     }
146     template<typename Fn>
CallScene(Fn && fn)147     auto CallScene(Fn&& fn) const
148     {
149         auto scene = scene_.lock();
150         return scene ? fn(*scene) : decltype(fn(*scene)) {};
151     }
152 
153 private:
154     IScene::WeakPtr scene_;
155 };
156 
157 /**
158  * @brief SceneResourceFactory can be used to instantiate new Scene specific resources (unique to each Scene instance).
159  */
160 class SceneResourceFactory : public RenderContextResourceFactory {
161 public:
162     SceneResourceFactory() = delete;
SceneResourceFactory(const IScene::Ptr & scene)163     SceneResourceFactory(const IScene::Ptr& scene) : RenderContextResourceFactory(scene) {};
164     virtual ~SceneResourceFactory() = default;
META_DEFAULT_COPY_MOVE(SceneResourceFactory)165     META_DEFAULT_COPY_MOVE(SceneResourceFactory)
166     /// Creates a new empty node with given parameters.
167     META_API_ASYNC auto CreateNode(const SceneResourceParameters& params)
168     {
169         return CallCreateNode<Node, CallType>(params, ClassId::Node);
170     }
171     /// Creates a new geometry node with given parameters.
CreateGeometryNode(const SceneResourceParameters & params,const IMesh::Ptr & mesh)172     META_API_ASYNC auto CreateGeometryNode(const SceneResourceParameters& params, const IMesh::Ptr& mesh)
173     {
174         auto f = CallScene([&](auto& scene) {
175             return scene.template CreateNode<IMeshAccess>(params.path, ClassId::MeshNode)
176                 .Then([mesh](const IMeshAccess::Ptr& node) {
177                     bool set = !mesh || node->SetMesh(mesh).GetResult();
178                     return set ? interface_pointer_cast<INode>(node) : nullptr;
179                 });
180         });
181         return Internal::UnwrapFuture<CallType, Geometry>(BASE_NS::move(f));
182     }
183     /// Creates a new camera node with given parameters.
CreateCameraNode(const SceneResourceParameters & params)184     META_API_ASYNC auto CreateCameraNode(const SceneResourceParameters& params)
185     {
186         return CallCreateNode<Camera, CallType>(params, ClassId::CameraNode);
187     }
188     /// Creates a new light node with given parameters.
CreateLightNode(const SceneResourceParameters & params)189     META_API_ASYNC auto CreateLightNode(const SceneResourceParameters& params)
190     {
191         return CallCreateNode<Light, CallType>(params, ClassId::LightNode);
192     }
193     /// Creates a new text node with given parameters.
CreateTextNode(const TextResourceParameters & params)194     META_API_ASYNC auto CreateTextNode(const TextResourceParameters& params)
195     {
196         return CallCreateNode<Text3D, CallType>(params, ClassId::TextNode);
197     }
198 
199 private:
200     template<class Type, const META_NS::AsyncCallType& CallType>
CallCreateNode(const SceneResourceParameters & params,META_NS::ObjectId id)201     auto CallCreateNode(const SceneResourceParameters& params, META_NS::ObjectId id)
202     {
203         auto f = CallScene([&](auto& scene) { return scene.CreateNode(params.path, id); });
204         return Internal::UnwrapFuture<CallType, Type>(BASE_NS::move(f));
205     }
206 };
207 
208 /**
209  * @brief The Component class is a wrapper for IComponent::Ptr.
210  *        Components can be queried from Nodes by calling Scene.GetComponent() or created
211  *        at runtime by calling Scene.CreateComponent().
212  * @note  The Component's metadata contains all of the component specific properties.
213  */
214 class Component : public META_NS::Object {
215 public:
META_INTERFACE_OBJECT(Component,META_NS::Object,IComponent)216     META_INTERFACE_OBJECT(Component, META_NS::Object, IComponent)
217 
218     /**
219      * @brief Returns a component property with given name.
220      * @param name Name of the component property to return.
221      */
222     template<typename Type>
223     auto GetProperty(BASE_NS::string_view name) const
224     {
225         auto meta = META_NS::Metadata(*this);
226         auto p = meta.GetProperty<Type>(name);
227         // Could also be "ComponentName.PropertyName"
228         return p ? p : meta.GetProperty<Type>(GetName() + "." + name);
229     }
230     /**
231      * @brief Returns a component array property with given name.
232      * @note  Equivalent to calling component.GetProperty<BASE_NS::vector<Type>>(name)
233      * @param name Name of the component property to return.
234      */
235     template<typename Type>
GetArrayProperty(BASE_NS::string_view name)236     auto GetArrayProperty(BASE_NS::string_view name) const
237     {
238         return GetProperty<BASE_NS::vector<Type>>(name);
239     }
240 
241 private:
InitializeComponent()242     auto& InitializeComponent()
243     {
244         META_INTERFACE_OBJECT_CALL_PTR(PopulateAllProperties());
245         return *this;
246     }
247     friend class Scene;
248 };
249 
250 /// Wrapper for scene objects which implement SCENE_NS::IScene.
251 class Scene : public META_NS::Object {
252 public:
META_INTERFACE_OBJECT(Scene,META_NS::Object,IScene)253     META_INTERFACE_OBJECT(Scene, META_NS::Object, IScene)
254     /// Initialize a Scene object from a Node.
255     explicit Scene(const Node& node) : META_NS::Object(node.GetScene()) {}
256     /**
257      * @brief Load a Scene from a file.
258      * @param uri The uri to load the scene from.
259      * @return A valid Scene object if loading was successful, an invalid object otherwise.
260      */
Load(BASE_NS::string_view uri)261     META_API_ASYNC static auto Load(BASE_NS::string_view uri)
262     {
263         Future<IScene::Ptr> f;
264         // Use default application context for loading
265         if (const auto ctx = GetDefaultApplicationContext()) {
266             if (const auto sm = ctx->GetSceneManager()) {
267                 f = sm->CreateScene(uri);
268             }
269         }
270         return Internal::UnwrapFuture<CallType, Scene>(BASE_NS::move(f));
271     }
272     /// Returns a resource factory for creating resources associated with this scene.
GetResourceFactory()273     auto GetResourceFactory()
274     {
275         return SceneResourceFactory(GetPtr<IScene>());
276     }
277     /// @see IScene::GetRootNode
GetRootNode()278     META_API_ASYNC auto GetRootNode() const
279     {
280         return META_INTERFACE_OBJECT_ASYNC_CALL_PTR(Node, GetRootNode());
281     }
282     /// @see IScene::FindNode
283     META_API_ASYNC auto GetNode(BASE_NS::string_view path, META_NS::ObjectId id = {}) const
284     {
285         return META_INTERFACE_OBJECT_ASYNC_CALL_PTR(Node, FindNode(path, id));
286     }
287     /**
288      * @brief Removes the node (and its children) from the scene.
289      * @see IScene::RemoveNode
290      * @param node The node to remove. The Node object is unitinialized as a result of this call.
291      */
RemoveNode(Node & node)292     META_API_ASYNC auto RemoveNode(Node& node)
293     {
294         auto ret = META_INTERFACE_OBJECT_ASYNC_CALL_PTR(bool, RemoveNode(node.GetPtr<INode>()));
295         node.Release();
296         return ret;
297     }
298     /// @see IScene::GetCaemras
GetCameras()299     META_API_ASYNC auto GetCameras() const
300     {
301         return META_INTERFACE_OBJECT_ASYNC_CALL_PTR(META_NS::Internal::ArrayCast<Camera>, GetCameras());
302     }
303     /// @see IScene::GetAnimations
GetAnimations()304     META_API_ASYNC auto GetAnimations() const
305     {
306         return META_INTERFACE_OBJECT_ASYNC_CALL_PTR(META_NS::Internal::ArrayCast<META_NS::Animation>, GetAnimations());
307     }
308     /// @see IScene::SetRenderMode
SetRenderMode(RenderMode mode)309     META_API_ASYNC auto SetRenderMode(RenderMode mode)
310     {
311         return META_INTERFACE_OBJECT_ASYNC_CALL_PTR(bool, SetRenderMode(BASE_NS::move(mode)));
312     }
313     /// @see IScene::GetRenderMode
GetRenderMode()314     META_API_ASYNC auto GetRenderMode() const
315     {
316         return META_INTERFACE_OBJECT_ASYNC_CALL_PTR(bool, GetRenderMode());
317     }
318     /**
319      * @brief Returns an underlying ECS component from a Node with given name.
320      * @param node The Node to query from.
321      * @param name The component name to query.
322      * @return a Component with given name, if one exists in the target Node.
323      */
GetComponent(const Node & node,BASE_NS::string_view name)324     auto GetComponent(const Node& node, BASE_NS::string_view name) const
325     {
326         auto component = Component(META_INTERFACE_OBJECT_CALL_PTR(GetComponent(node, name)));
327         component.InitializeComponent();
328         return component;
329     }
330     /**
331      * @brief Creates an underlying ECS component with given component manager name to the given node.
332      * @note If there is already a component with given name associated with the node, the existing component instance
333      *       is returned.
334      * @param node The node to create the component to.
335      * @param name Name of the ECS component manager to instantiate. E.g. "CameraComponent" would create a camera
336      *        component and associate it with the node.
337      * @return The component with given component manager name.
338      */
CreateComponent(const Node & node,BASE_NS::string_view name)339     META_API_ASYNC auto CreateComponent(const Node& node, BASE_NS::string_view name) const
340     {
341         auto f = META_INTERFACE_OBJECT_CALL_PTR(CreateComponent(node, name)).Then([](const IComponent::Ptr& component) {
342             if (component) {
343                 component->PopulateAllProperties();
344             }
345             return component;
346         });
347         return Internal::UnwrapFuture<CallType, Component>(BASE_NS::move(f));
348     }
349     /**
350      * @brief Imports a Scene into this scene under given node.
351      * @param scene The scene to import.
352      * @param node The node under which the scene should be imported. If null, the imported node is placed under root
353      *        node of this scene.
354      * @param name The name which should be given to the root node of the imported scene, placed as a child of node.
355      */
ImportScene(const IScene::Ptr & scene,const INode::Ptr & node,BASE_NS::string_view name)356     META_API_ASYNC auto ImportScene(const IScene::Ptr& scene, const INode::Ptr& node, BASE_NS::string_view name)
357     {
358         Future<INode::Ptr> f;
359         if (auto import = interface_cast<INodeImport>(node)) {
360             f = import->ImportChildScene(scene, name);
361         } else {
362             f = GetRootNode<META_NS::Async>().Then([scene, name = BASE_NS::string(name)](const INode::Ptr& root) {
363                 auto import = interface_cast<INodeImport>(root);
364                 return import ? import->ImportChildScene(scene, name).GetResult() : nullptr;
365             });
366         }
367         return Internal::UnwrapFuture<CallType, Node>(BASE_NS::move(f));
368     }
369     /**
370      * @brief Imports a Scene from a resource into this scene under given node.
371      * @param uri Uri of the scene resource to import (.gltf or .scene)
372      * @param node The node under which the scene should be imported. If null, the imported node is placed under root
373      *        node of this scene.
374      * @param name The name which should be given to the root node of the imported scene, placed as a child of node.
375      */
ImportScene(BASE_NS::string_view uri,const INode::Ptr & node,BASE_NS::string_view name)376     META_API_ASYNC auto ImportScene(BASE_NS::string_view uri, const INode::Ptr& node, BASE_NS::string_view name)
377     {
378         Future<INode::Ptr> f;
379         if (auto import = interface_cast<INodeImport>(node)) {
380             f = import->ImportChildScene(uri, name);
381         } else {
382             f = GetRootNode<META_NS::Async>().Then(
383                 [uri = BASE_NS::string(uri), name = BASE_NS::string(name)](const INode::Ptr& root) {
384                     auto import = interface_cast<INodeImport>(root);
385                     return import ? import->ImportChildScene(uri, name).GetResult() : nullptr;
386                 });
387         }
388         return Internal::UnwrapFuture<CallType, Node>(BASE_NS::move(f));
389     }
390     /**
391      * @brief Finds the first occurrence of a node with given name in the scene.
392      * @note  If the full path is known, it is more efficient to call Scene::GetNode
393      * @param name Name of the node to find.
394      * @param traversalType Can be used to control how the scene is traversed, or to limit finding only immediate
395      *        children by specifying TraversalType::NO_HIERARCHY.
396      * @return The first node matching the parameters or an invalid node in case of failure.
397      */
398     META_API_ASYNC auto FindNode(
399         BASE_NS::string_view name, META_NS::TraversalType traversalType = META_NS::TraversalType::FULL_HIERARCHY) const
400     {
401         auto f = META_INTERFACE_OBJECT_CALL_PTR(GetRootNode())
402                      .Then([name = BASE_NS::string(name), traversalType](const INode::Ptr& node) -> INode::Ptr {
403                          return Node(Internal::FindNode(node, name, traversalType));
404                      });
405         return Internal::UnwrapFuture<CallType, Node>(BASE_NS::move(f));
406     }
407     /**
408      * @brief Finds an animation from the scene.
409      * @param name Name of the animation to find.
410      * @return The animation with given name or an invalid object in case of failure.
411      */
FindAnimation(BASE_NS::string_view name)412     META_API_ASYNC auto FindAnimation(BASE_NS::string_view name)
413     {
414         auto f =
415             META_INTERFACE_OBJECT_CALL_PTR(GetAnimations())
416                 .Then([name = BASE_NS::string(name)](
417                           const BASE_NS::vector<META_NS::IAnimation::Ptr>& animations) -> META_NS::IAnimation::Ptr {
418                     return Internal::FindFromContainer<META_NS::IAnimation>(animations, name);
419                 });
420         return Internal::UnwrapFuture<CallType, META_NS::Animation>(BASE_NS::move(f));
421     }
422 };
423 
424 SCENE_END_NAMESPACE()
425 
426 #endif // SCENE_API_SCENE_H
427