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 #ifndef SCENEPLUGIN_INTF_NODE_H 16 #define SCENEPLUGIN_INTF_NODE_H 17 18 #include <scene_plugin/namespace.h> 19 20 #include <base/containers/vector.h> 21 22 #include <meta/api/animation/animation.h> 23 #include <meta/api/make_callback.h> 24 #include <meta/base/types.h> 25 #include <meta/interface/intf_container.h> 26 #include <meta/interface/property/property.h> 27 28 SCENE_BEGIN_NAMESPACE() 29 30 REGISTER_INTERFACE(IPendingRequest, "59856b13-8674-48f0-9b34-9b1093472958") 31 template<typename T> 32 class IPendingRequest : public CORE_NS::IInterface { 33 META_INTERFACE(CORE_NS::IInterface, IPendingRequest, InterfaceId::IPendingRequest) 34 public: 35 META_EVENT(META_NS::IOnChanged, OnReady) 36 virtual const BASE_NS::vector<T>& GetResults() const = 0; 37 }; 38 39 using IPickingResult = IPendingRequest<BASE_NS::Math::Vec3>; 40 41 class IMesh; 42 class IScene; 43 class IMultiMeshProxy; 44 45 enum class NodeState { DETACHED = 0, ATTACHED = 1 }; 46 47 // Implemented by SCENE_NS::ClassId::Camera, SCENE_NS::ClassId::Light, SCENE_NS::ClassId::Model 48 REGISTER_INTERFACE(INode, "e9770092-67fe-42ad-8703-a9be44250841") 49 class INode : public META_NS::INamed { 50 META_INTERFACE(META_NS::INamed, INode, InterfaceId::INode) 51 public: 52 /** 53 * @brief Path of this object on 3D scene (mirrored to META_NS::IContainer, also), 54 * @return property pointer 55 */ 56 META_READONLY_PROPERTY(BASE_NS::string, Path) 57 58 /** 59 * @brief If the node was created from a prefab, the uri is stored here, empty otherwise 60 * @return property pointer 61 */ 62 63 /** 64 * @brief Transform of the node Position 65 * @return property pointer 66 */ 67 META_PROPERTY(BASE_NS::Math::Vec3, Position) 68 69 /** 70 * @brief Transform of the node Scale 71 * @return property pointer 72 */ 73 META_PROPERTY(BASE_NS::Math::Vec3, Scale) 74 75 /** 76 * @brief Transform of the node Rotation 77 * @return property pointer 78 */ 79 META_PROPERTY(BASE_NS::Math::Quat, Rotation) 80 81 /** 82 * @brief Enable node in 3D scene. 83 * @return property pointer 84 */ 85 META_PROPERTY(bool, Visible) 86 87 /** 88 * @brief Bitmask that controls if the node are rendered. ICamera::LayerMask defines the 89 * bits that need to be active, while nodes may have different combinations of bits 90 * @return property pointer 91 */ 92 META_PROPERTY(uint64_t, LayerMask) 93 94 enum NodeStatus { 95 /** Instance exists, but the properties are not set even locally*/ 96 NODE_STATUS_UNINITIALIZED = 0, 97 /** The local properties are set*/ 98 NODE_STATUS_CONNECTING = 1, 99 /** The node is bound to 3D scene*/ 100 NODE_STATUS_CONNECTED = 2, 101 /** The respective 3D element was not found 102 * Node properties are preserved but not proxied to 3D scene */ 103 NODE_STATUS_DISCONNECTED = 3, 104 /** The node and all its children are bound to 3D scene*/ 105 NODE_STATUS_FULLY_CONNECTED = 4 106 }; 107 /** 108 * @brief Node status. 109 * @return property pointer 110 */ 111 META_READONLY_PROPERTY(uint8_t, Status) 112 113 /** 114 * @brief Nodes local matrix on 3D scene. 115 * @return Pointer to the property. 116 */ 117 META_PROPERTY(BASE_NS::Math::Mat4X4, LocalMatrix) 118 119 /** 120 * @brief The mesh attached to node, if any. 121 * @return Pointer to the property. 122 */ 123 META_PROPERTY(BASE_NS::shared_ptr<IMesh>, Mesh) 124 125 /** 126 * @brief Event that is invoked when the backing resources for the node have been loaded 127 * @return Reference to the event. 128 */ 129 META_EVENT(META_NS::IOnChanged, OnLoaded) 130 131 /** 132 * @brief Event that is invoked when all the children of this node have been bound to 3d scene 133 * @return Reference to the event. 134 */ 135 META_EVENT(META_NS::IOnChanged, OnBound) 136 137 /** 138 * @brief Deprecated, use Mesh() property. Set the given mesh to this node. 139 * @param the mesh to set. 140 */ 141 virtual void SetMesh(BASE_NS::shared_ptr<IMesh> mesh) = 0; 142 143 /** 144 * @brief Deprecated, use Mesh() property. Returns a mesh from the scene. 145 * @returns always an instance, even the engine node does not no have mesh attached. 146 */ 147 virtual BASE_NS::shared_ptr<IMesh> GetMesh() const = 0; 148 149 virtual BASE_NS::shared_ptr<IMultiMeshProxy> CreateMeshProxy(size_t count, BASE_NS::shared_ptr<IMesh> mesh) = 0; 150 virtual void SetMultiMeshProxy(BASE_NS::shared_ptr<IMultiMeshProxy> multimesh) = 0; 151 virtual BASE_NS::shared_ptr<IMultiMeshProxy> GetMultiMeshProxy() const = 0; 152 153 /** 154 * @brief Set node parent on the container, reflected to 3D scene. 155 * @param node Node to parent. 156 * @param parent New parent of the node. 157 * @return true on success. 158 */ SetParent(const INode::Ptr & node,const META_NS::IObject::Ptr & parent)159 static bool SetParent(const INode::Ptr& node, const META_NS::IObject::Ptr& parent) 160 { 161 if (auto container = interface_pointer_cast<META_NS::IContainer>(parent); node && container) { 162 return container->Add(node); 163 } 164 return false; 165 } 166 167 // ToDo: Should perhaps be a property 168 enum BuildBehavior { 169 // Do not build children automatically 170 NODE_BUILD_CHILDREN_NO_BUILD = 0, 171 // Build children gradually asynchronously 172 NODE_BUILD_CHILDREN_GRADUAL = 1, 173 // Build all node descendants on one go 174 NODE_BUILD_CHILDREN_ALL = 2, 175 // Build only direct descendants. 176 // (does not recurse in to children of children, to access them you need to call buildchildren on the children first.) 177 NODE_BUILD_ONLY_DIRECT_CHILDREN = 3 178 }; 179 /** 180 * @brief Instantiate children nodes, i.e. mirror all immediate children from 3D system. 181 * @param options controls if the node builds also descendants of immediate children. 182 * @return True if scene is ready to process possible children. 183 */ 184 virtual bool BuildChildren(BuildBehavior options) = 0; 185 186 /** @brief Get the scene attached to this node. 187 */ 188 virtual BASE_NS::shared_ptr<IScene> GetScene() const = 0; 189 190 /** 191 * @brief Add handler for OnLoaded event 192 * @param callback 193 * @return reference to this instance. 194 */ 195 template<class Callback> OnLoaded(Callback && callback)196 auto& OnLoaded(Callback&& callback) 197 { 198 OnLoaded()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>(callback)); 199 return *this; 200 } 201 202 /** 203 * @brief Run a callback once object is loaded. if object has been already loaded, runs the callback synchronously. 204 * Keeps the instance alive using strong ref if callback attaches one and removes the reference on callback. 205 * @param callback 206 * @return true if object is already loaded. 207 */ 208 template<class Callback> OnLoadedSingleShot(Callback && callback)209 bool OnLoadedSingleShot(Callback&& callback) 210 { 211 if (auto status = META_NS::GetValue(Status()); 212 (status == NODE_STATUS_FULLY_CONNECTED || status == NODE_STATUS_CONNECTED)) { 213 callback(); 214 return true; 215 } 216 auto token = OnLoaded()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>(callback)); 217 OnLoaded()->AddHandler( 218 META_NS::MakeCallback<META_NS::IOnChanged>([token, this]() { OnLoaded()->RemoveHandler(token); })); 219 return false; 220 } 221 222 /** 223 * @brief Like above, the function makes a strong assumption that either the callback 224 * contains a strong pointer to the object itself, or lifetime is otherwise guaranteed. 225 * ToDo: should make that more explicit 226 * @param self pointer to this instance 227 * @param callback that runs either immediately if the object is ready or later if the construction of node or its 228 * children is not finished 229 * @return true if object is already fully loaded. 230 */ 231 template<class Callback> OnReady(Callback && callback)232 bool OnReady(Callback&& callback) 233 { 234 if (META_NS::GetValue(Status()) == NODE_STATUS_FULLY_CONNECTED) { 235 callback(); 236 return true; 237 } 238 239 auto token = OnBound()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>(callback)); 240 OnBound()->AddHandler( 241 META_NS::MakeCallback<META_NS::IOnChanged>([token, this]() { OnBound()->RemoveHandler(token); })); 242 return false; 243 } 244 245 /** 246 * @brief Calculates the global matrix based on node hierarchy and local matrices. 247 * The local matrix reflects values from transform component, so there can be 248 * some delay reading back values set using local transformations. 249 * @return Global matrix of Node transformations. 250 */ 251 virtual BASE_NS::Math::Mat4X4 GetGlobalTransform() const = 0; 252 253 /** 254 * @brief Calculates the parents global matrix based on node hierarchy and local matrices 255 * and subtracts that from the given matrix to store it as local matrix. 256 * @param matrix Global matrix of Node transformations. 257 */ 258 virtual void SetGlobalTransform(const BASE_NS::Math::Mat4X4& matrix) = 0; 259 260 virtual void AttachToHierarchy() = 0; 261 262 virtual void DetachFromHierarchy() = 0; 263 264 virtual NodeState GetAttachedState() const = 0; 265 266 /** 267 * Calculates a world space AABB for this node and optionally all of it's children recursively. Uses the world 268 * matrix component for the calculations i.e. the values are only valid after the ECS has updated all the systems 269 * that manipulate the world matrix. 270 */ 271 virtual IPickingResult::Ptr GetWorldMatrixComponentAABB(bool isRecursive) const = 0; 272 273 /** 274 * Calculates a world space AABB for this node and optionally all of it's children recursively. Uses only the 275 * transform component for the calculations. This way the call will also give valid results even when the ECS has 276 * not been updated. Does not take skinning or animations into account. 277 */ 278 virtual IPickingResult::Ptr GetTransformComponentAABB(bool isRecursive) const = 0; 279 }; 280 281 struct NodeDistance { 282 INode::Ptr node; 283 float distance; 284 }; 285 286 using IRayCastResult = IPendingRequest<NodeDistance>; 287 288 SCENE_END_NAMESPACE() 289 290 META_TYPE(SCENE_NS::INode::WeakPtr); 291 META_TYPE(SCENE_NS::INode::Ptr); 292 293 #endif // SCENEPLUGIN_INTF_NODE_H 294