1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Math/BsMatrix4.h"
7#include "Math/BsVector3.h"
8#include "Math/BsQuaternion.h"
9#include "Reflection/BsRTTIType.h"
10#include "Scene/BsGameObjectManager.h"
11#include "Scene/BsGameObject.h"
12#include "Scene/BsComponent.h"
13#include "Scene/BsTransform.h"
14
15namespace bs
16{
17 class SceneInstance;
18
19 /** @addtogroup Scene
20 * @{
21 */
22
23 /** Possible modifiers that can be applied to a SceneObject. */
24 enum SceneObjectFlags
25 {
26 SOF_DontInstantiate = 0x01, /**< Object wont be in the main scene and its components won't receive updates. */
27 SOF_DontSave = 0x02, /**< Object will be skipped when saving the scene hierarchy or a prefab. */
28 SOF_Persistent = 0x04, /**< Object will remain in the scene even after scene clear, unless destroyed directly.
29 This only works with top-level objects. */
30 SOF_Internal = 0x08 /**< Provides a hint to external systems that his object is used by engine internals.
31 For example, those systems might not want to display those objects together with the
32 user created ones. */
33 };
34
35 /**
36 * An object in the scene graph. It has a transform object that allows it to be positioned, scaled and rotated. It can
37 * have other scene objects as children, and will have a scene object as a parent, in which case transform changes
38 * to the parent are reflected to the child scene objects (children are relative to the parent).
39 *
40 * Each scene object can have one or multiple Component%s attached to it, where the components inherit the scene
41 * object's transform, and receive updates about transform and hierarchy changes.
42 */
43 class BS_CORE_EXPORT SceneObject : public GameObject
44 {
45 /** Flags that signify which part of the SceneObject needs updating. */
46 enum DirtyFlags
47 {
48 LocalTfrmDirty = 0x01,
49 WorldTfrmDirty = 0x02
50 };
51
52 friend class SceneManager;
53 friend class Prefab;
54 friend class PrefabDiff;
55 friend class PrefabUtility;
56 public:
57 ~SceneObject();
58
59 /**
60 * Creates a new SceneObject with the specified name. Object will be placed in the top of the scene hierarchy.
61 *
62 * @param[in] name Name of the scene object.
63 * @param[in] flags Optional flags that control object behavior. See SceneObjectFlags.
64 */
65 static HSceneObject create(const String& name, UINT32 flags = 0);
66
67 /**
68 * Destroys this object and any of its held components.
69 *
70 * @param[in] immediate If true, the object will be deallocated and become unusable right away. Otherwise the
71 * deallocation will be delayed to the end of frame (preferred method).
72 */
73 void destroy(bool immediate = false);
74
75 /** Returns a handle to this object. */
76 HSceneObject getHandle() const { return mThisHandle; }
77
78 /**
79 * Returns the UUID of the prefab this object is linked to, if any.
80 *
81 * @param[in] onlyDirect If true, this method will return prefab link only for the root object of the prefab
82 * instance. If false the parent objects will be searched for the prefab ID.
83 */
84 UUID getPrefabLink(bool onlyDirect = false) const;
85
86 /**
87 * Returns the root object of the prefab instance that this object belongs to, if any. Returns null if the object
88 * is not part of a prefab instance.
89 */
90 HSceneObject getPrefabParent() const;
91
92 /**
93 * Breaks the link between this prefab instance and its prefab. Object will retain all current values but will no
94 * longer be influenced by modifications to its parent prefab.
95 */
96 void breakPrefabLink();
97
98 /** Checks if the scene object has a specific bit flag set. */
99 bool hasFlag(UINT32 flag) const;
100
101 public: // ***** INTERNAL ******
102 /** @name Internal
103 * @{
104 */
105
106 /** @copydoc GameObject::_setInstanceData */
107 void _setInstanceData(GameObjectInstanceDataPtr& other) override;
108
109 /**
110 * Register the scene object with the scene and activate all of its components.
111 *
112 * @param[in] prefabOnly If true, only objects within the current prefab will be instantiated. If false all child
113 * objects and components will.
114 */
115 void _instantiate(bool prefabOnly = false);
116
117 /**
118 * Clears the internally stored prefab diff. If this object is updated from prefab its instance specific changes
119 * will be lost.
120 */
121 void _clearPrefabDiff() { mPrefabDiff = nullptr; }
122
123 /**
124 * Returns the UUID of the prefab this object is linked to, if any. Unlike getPrefabLink() method this will not
125 * search parents, but instead return only the value assigned to this object.
126 */
127 const UUID& _getPrefabLinkUUID() const { return mPrefabLinkUUID; }
128
129 /**
130 * Allows you to change the prefab link UUID of this object. Normally this should be accompanied by reassigning the
131 * link IDs.
132 */
133 void _setPrefabLinkUUID(const UUID& UUID) { mPrefabLinkUUID = UUID; }
134
135 /**
136 * Returns a prefab diff object containing instance specific modifications of this object compared to its prefab
137 * reference, if any.
138 */
139 const SPtr<PrefabDiff>& _getPrefabDiff() const { return mPrefabDiff; }
140
141 /** Assigns a new prefab diff object. Caller must ensure the prefab diff was generated for this object. */
142 void _setPrefabDiff(const SPtr<PrefabDiff>& diff) { mPrefabDiff = diff; }
143
144 /** Recursively enables the provided set of flags on this object and all children. */
145 void _setFlags(UINT32 flags);
146
147 /** Recursively disables the provided set of flags on this object and all children. */
148 void _unsetFlags(UINT32 flags);
149
150 /** @} */
151
152 private:
153 SceneObject(const String& name, UINT32 flags);
154
155 /**
156 * Creates a new SceneObject instance, registers it with the game object manager, creates and returns a handle to
157 * the new object.
158 *
159 * @note
160 * When creating objects with DontInstantiate flag it is the callers responsibility to manually destroy the object,
161 * otherwise it will leak.
162 */
163 static HSceneObject createInternal(const String& name, UINT32 flags = 0);
164
165 /**
166 * Creates a new SceneObject instance from an existing pointer, registers it with the game object manager, creates
167 * and returns a handle to the object.
168 *
169 * @param[in] soPtr Pointer to the scene object register and return a handle to.
170 */
171 static HSceneObject createInternal(const SPtr<SceneObject>& soPtr);
172
173 /**
174 * Destroys this object and any of its held components.
175 *
176 * @param[in] handle Game object handle to this object.
177 * @param[in] immediate If true, the object will be deallocated and become unusable right away. Otherwise the
178 * deallocation will be delayed to the end of frame (preferred method).
179 *
180 * @note Unlike destroy(), does not remove the object from its parent.
181 */
182 void destroyInternal(GameObjectHandleBase& handle, bool immediate = false) override;
183
184 /** Checks is the scene object instantiated and visible in the scene. */
185 bool isInstantiated() const { return (mFlags & SOF_DontInstantiate) == 0; }
186
187 private:
188 HSceneObject mThisHandle;
189 UUID mPrefabLinkUUID;
190 SPtr<PrefabDiff> mPrefabDiff;
191 UINT32 mPrefabHash = 0;
192 UINT32 mFlags;
193
194 /************************************************************************/
195 /* Transform */
196 /************************************************************************/
197 public:
198 /** Gets the transform object representing object's position/rotation/scale in world space. */
199 const Transform& getTransform() const;
200
201 /** Gets the transform object representing object's position/rotation/scale relative to its parent. */
202 const Transform& getLocalTransform() const { return mLocalTfrm; }
203
204 /** Sets the local position of the object. */
205 void setPosition(const Vector3& position);
206
207 /** Sets the world position of the object. */
208 void setWorldPosition(const Vector3& position);
209
210 /** Sets the local rotation of the object. */
211 void setRotation(const Quaternion& rotation);
212
213 /** Sets the world rotation of the object. */
214 void setWorldRotation(const Quaternion& rotation);
215
216 /** Sets the local scale of the object. */
217 void setScale(const Vector3& scale);
218
219 /**
220 * Sets the world scale of the object.
221 *
222 * @note This will not work properly if this object or any of its parents have non-affine transform matrices.
223 */
224 void setWorldScale(const Vector3& scale);
225
226 /**
227 * Orients the object so it is looking at the provided @p location (world space) where @p up is used for
228 * determining the location of the object's Y axis.
229 */
230 void lookAt(const Vector3& location, const Vector3& up = Vector3::UNIT_Y);
231
232 /**
233 * Gets the objects world transform matrix.
234 *
235 * @note Performance warning: This might involve updating the transforms if the transform is dirty.
236 */
237 const Matrix4& getWorldMatrix() const;
238
239 /**
240 * Gets the objects inverse world transform matrix.
241 *
242 * @note Performance warning: This might involve updating the transforms if the transform is dirty.
243 */
244 Matrix4 getInvWorldMatrix() const;
245
246 /** Gets the objects local transform matrix. */
247 const Matrix4& getLocalMatrix() const;
248
249 /** Moves the object's position by the vector offset provided along world axes. */
250 void move(const Vector3& vec);
251
252 /** Moves the object's position by the vector offset provided along it's own axes (relative to orientation). */
253 void moveRelative(const Vector3& vec);
254
255 /**
256 * Rotates the game object so it's forward axis faces the provided direction.
257 *
258 * @param[in] forwardDir The forward direction to face, in world space.
259 *
260 * @note Local forward axis is considered to be negative Z.
261 */
262 void setForward(const Vector3& forwardDir);
263
264 /** Rotate the object around an arbitrary axis. */
265 void rotate(const Vector3& axis, const Radian& angle);
266
267 /** Rotate the object around an arbitrary axis using a Quaternion. */
268 void rotate(const Quaternion& q);
269
270 /**
271 * Rotates around local Z axis.
272 *
273 * @param[in] angle Angle to rotate by.
274 */
275 void roll(const Radian& angle);
276
277 /**
278 * Rotates around Y axis.
279 *
280 * @param[in] angle Angle to rotate by.
281 */
282 void yaw(const Radian& angle);
283
284 /**
285 * Rotates around X axis
286 *
287 * @param[in] angle Angle to rotate by.
288 */
289 void pitch(const Radian& angle);
290
291 /**
292 * Forces any dirty transform matrices on this object to be updated.
293 *
294 * @note
295 * Normally this is done internally when retrieving a transform, but sometimes it is useful to update transforms
296 * manually.
297 */
298 void updateTransformsIfDirty();
299
300 /**
301 * Returns a hash value that changes whenever a scene objects transform gets updated. It allows you to detect
302 * changes with the local or world transforms without directly comparing their values with some older state.
303 */
304 UINT32 getTransformHash() const { return mDirtyHash; }
305
306 private:
307 Transform mLocalTfrm;
308 mutable Transform mWorldTfrm;
309
310 mutable Matrix4 mCachedLocalTfrm = Matrix4::IDENTITY;
311 mutable Matrix4 mCachedWorldTfrm = Matrix4::IDENTITY;
312
313 mutable UINT32 mDirtyFlags = 0xFFFFFFFF;
314 mutable UINT32 mDirtyHash = 0;
315
316 /**
317 * Notifies components and child scene object that a transform has been changed.
318 *
319 * @param flags Specifies in what way was the transform changed.
320 */
321 void notifyTransformChanged(TransformChangedFlags flags) const;
322
323 /** Updates the local transform. Normally just reconstructs the transform matrix from the position/rotation/scale. */
324 void updateLocalTfrm() const;
325
326 /**
327 * Updates the world transform. Reconstructs the local transform matrix and multiplies it with any parent transforms.
328 *
329 * @note If parent transforms are dirty they will be updated.
330 */
331 void updateWorldTfrm() const;
332
333 /** Checks if cached local transform needs updating. */
334 bool isCachedLocalTfrmUpToDate() const { return (mDirtyFlags & DirtyFlags::LocalTfrmDirty) == 0; }
335
336 /** Checks if cached world transform needs updating. */
337 bool isCachedWorldTfrmUpToDate() const { return (mDirtyFlags & DirtyFlags::WorldTfrmDirty) == 0; }
338
339 /************************************************************************/
340 /* Hierarchy */
341 /************************************************************************/
342 public:
343 /**
344 * Changes the parent of this object. Also removes the object from the current parent, and assigns it to the new
345 * parent.
346 *
347 * @param[in] parent New parent.
348 * @param[in] keepWorldTransform Determines should the current transform be maintained even after the parent is
349 * changed (this means the local transform will be modified accordingly).
350 */
351 void setParent(const HSceneObject& parent, bool keepWorldTransform = true);
352
353 /**
354 * Gets the parent of this object.
355 *
356 * @return Parent object, or nullptr if this SceneObject is at root level.
357 */
358 HSceneObject getParent() const { return mParent; }
359
360 /**
361 * Gets a child of this item.
362 *
363 * @param[in] idx The zero based index of the child.
364 * @return SceneObject of the child.
365 */
366 HSceneObject getChild(UINT32 idx) const;
367
368 /**
369 * Find the index of the specified child. Don't persist this value as it may change whenever you add/remove children.
370 *
371 * @param[in] child The child to look for.
372 * @return The zero-based index of the found child, or -1 if no match was found.
373 */
374 int indexOfChild(const HSceneObject& child) const;
375
376 /** Gets the number of all child GameObjects. */
377 UINT32 getNumChildren() const { return (UINT32)mChildren.size(); }
378
379 /** Returns the scene this object is part of. Can be null if scene object hasn't been instantiated. */
380 const SPtr<SceneInstance>& getScene() const;
381
382 /**
383 * Searches the scene object hierarchy to find a child scene object using the provided path.
384 *
385 * @param[in] path Path to the property, where each element of the path is separated with "/" Path elements signify
386 * names of child scene objects (first one relative to this object).
387 */
388 HSceneObject findPath(const String& path) const;
389
390 /**
391 * Searches the child objects for an object matching the specified name.
392 *
393 * @param[in] name Name of the object to locate.
394 * @param[in] recursive If true all descendants of the scene object will be searched, otherwise only immediate
395 * children.
396 * @return First found scene object, or empty handle if none found.
397 */
398 HSceneObject findChild(const String& name, bool recursive = true);
399
400 /**
401 * Searches the child objects for objects matching the specified name.
402 *
403 * @param[in] name Name of the objects to locate.
404 * @param[in] recursive If true all descendants of the scene object will be searched, otherwise only immediate
405 * children.
406 * @return All scene objects matching the specified name.
407 */
408 Vector<HSceneObject> findChildren(const String& name, bool recursive = true);
409
410 /**
411 * Enables or disables this object. Disabled objects also implicitly disable all their child objects. No components
412 * on the disabled object are updated.
413 */
414 void setActive(bool active);
415
416 /**
417 * Returns whether or not an object is active.
418 *
419 * @param[in] self If true, the method will only check if this particular object was activated or deactivated
420 * directly via setActive. If false we we also check if any of the objects parents are inactive.
421 */
422 bool getActive(bool self = false) const;
423
424 /**
425 * Sets the mobility of a scene object. This is used primarily as a performance hint to engine systems. Objects
426 * with more restricted mobility will result in higher performance. Some mobility constraints will be enforced by
427 * the engine itself, while for others the caller must be sure not to break the promise he made when mobility was
428 * set. By default scene object's mobility is unrestricted.
429 */
430 void setMobility(ObjectMobility mobility);
431
432 /**
433 * Gets the mobility setting for this scene object. See setMobility();
434 */
435 ObjectMobility getMobility() const { return mMobility; }
436
437 /**
438 * Makes a deep copy of this object.
439 *
440 * @param[in] instantiate If false, the cloned hierarchy will just be a memory copy, but will not be present
441 * in the scene or otherwise active until instantiate() is called.
442 * @param[in] preserveUUIDs If false, each cloned game object will be assigned a brand new UUID. Otherwise
443 * the UUID of the original game objects will be preserved. Note that two instantiated
444 * scene objects should never have the same UUID, so if preserving UUID's make sure
445 * the original is destroyed before instantiating.
446 */
447 HSceneObject clone(bool instantiate = true, bool preserveUUIDs = false);
448
449 private:
450 SPtr<SceneInstance> mParentScene;
451 HSceneObject mParent;
452 Vector<HSceneObject> mChildren;
453 bool mActiveSelf = true;
454 bool mActiveHierarchy = true;
455 ObjectMobility mMobility = ObjectMobility::Movable;
456
457 /**
458 * Internal version of setParent() that allows you to set a null parent.
459 *
460 * @param[in] parent New parent.
461 * @param[in] keepWorldTransform Determines should the current transform be maintained even after the parent is
462 * changed (this means the local transform will be modified accordingly).
463 */
464 void _setParent(const HSceneObject& parent, bool keepWorldTransform = true);
465
466 /** Changes the owning scene of the scene object and all children. */
467 void setScene(const SPtr<SceneInstance>& scene);
468
469 /**
470 * Adds a child to the child array. This method doesn't check for null or duplicate values.
471 *
472 * @param[in] object New child.
473 */
474 void addChild(const HSceneObject& object);
475
476 /**
477 * Removes the child from the object.
478 *
479 * @param[in] object Child to remove.
480 */
481 void removeChild(const HSceneObject& object);
482
483 /** Changes the object active in hierarchy state, and triggers necessary events. */
484 void setActiveHierarchy(bool active, bool triggerEvents = true);
485
486 /************************************************************************/
487 /* Component */
488 /************************************************************************/
489 public:
490 /** Constructs a new component of the specified type and adds it to the internal component list. */
491 template<class T, class... Args>
492 GameObjectHandle<T> addComponent(Args &&... args)
493 {
494 static_assert((std::is_base_of<bs::Component, T>::value),
495 "Specified type is not a valid Component.");
496
497 SPtr<T> gameObject(new (bs_alloc<T>()) T(mThisHandle,
498 std::forward<Args>(args)...),
499 &bs_delete<T>, StdAlloc<T>());
500
501 const HComponent newComponent =
502 static_object_cast<Component>(GameObjectManager::instance().registerObject(gameObject));
503
504 addAndInitializeComponent(newComponent);
505 return static_object_cast<T>(newComponent);
506 }
507
508 /**
509 * Constructs a new component of the specified type id and adds it to the internal component list. Component must
510 * have a parameterless constructor.
511 */
512 HComponent addComponent(UINT32 typeId);
513
514 /**
515 * Searches for a component with the specific type and returns the first one it finds. Will also return components
516 * derived from the type.
517 *
518 * @tparam T Type of the component.
519 * @return Component if found, nullptr otherwise.
520 *
521 * @note
522 * Don't call this too often as it is relatively slow. It is more efficient to call it once and store the result
523 * for further use.
524 */
525 template <typename T>
526 GameObjectHandle<T> getComponent()
527 {
528 static_assert((std::is_base_of<bs::Component, T>::value),
529 "Specified type is not a valid Component.");
530
531 return static_object_cast<T>(getComponent(T::getRTTIStatic()));
532 }
533
534 /**
535 * Returns all components with the specific type. Will also return components derived from the type.
536 *
537 * @tparam typename T Type of the component.
538 * @return Array of found components.
539 *
540 * @note
541 * Don't call this too often as it is relatively slow. It is more efficient to call it once and store the result
542 * for further use.
543 */
544 template <typename T>
545 Vector<GameObjectHandle<T>> getComponents()
546 {
547 static_assert((std::is_base_of<bs::Component, T>::value),
548 "Specified type is not a valid Component.");
549
550 Vector<GameObjectHandle<T>> output;
551
552 for (auto entry : mComponents)
553 {
554 if (entry->getRTTI()->isDerivedFrom(T::getRTTIStatic()))
555 output.push_back(static_object_cast<T>(entry));
556 }
557
558 return output;
559 }
560
561 /**
562 * Checks if the current object contains the specified component or components derived from the provided type.
563 *
564 * @tparam typename T Type of the component.
565 * @return True if component exists on the object.
566 *
567 * @note Don't call this too often as it is relatively slow.
568 */
569 template <typename T>
570 bool hasComponent()
571 {
572 static_assert((std::is_base_of<bs::Component, T>::value),
573 "Specified type is not a valid Component.");
574
575 for (auto entry : mComponents)
576 {
577 if (entry->getRTTI()->isDerivedFrom(T::getRTTIStatic()))
578 return true;
579 }
580
581 return false;
582 }
583
584 /**
585 * Searches for a component with the specified type and returns the first one it finds. Will also return components
586 * derived from the type.
587 *
588 * @param[in] type RTTI information for the type.
589 * @return Component if found, nullptr otherwise.
590 *
591 * @note
592 * Don't call this too often as it is relatively slow. It is more efficient to call it once and store the result
593 * for further use.
594 */
595 HComponent getComponent(RTTITypeBase* type) const;
596
597 /**
598 * Removes the component from this object, and deallocates it.
599 *
600 * @param[in] component The component to destroy.
601 * @param[in] immediate If true, the component will be deallocated and become unusable right away. Otherwise
602 * the deallocation will be delayed to the end of frame (preferred method).
603 */
604 void destroyComponent(const HComponent component, bool immediate = false);
605
606 /**
607 * Removes the component from this object, and deallocates it.
608 *
609 * @param[in] component The component to destroy.
610 * @param[in] immediate If true, the component will be deallocated and become unusable right away. Otherwise
611 * the deallocation will be delayed to the end of frame (preferred method).
612 */
613 void destroyComponent(Component* component, bool immediate = false);
614
615 /** Returns all components on this object. */
616 const Vector<HComponent>& getComponents() const { return mComponents; }
617
618 /** Creates an empty component with the default constructor. Primarily used for RTTI purposes. */
619 template <typename T>
620 static SPtr<T> createEmptyComponent()
621 {
622 static_assert((std::is_base_of<bs::Component, T>::value), "Specified type is not a valid Component.");
623
624 T* rawPtr = new (bs_alloc<T>()) T();
625 SPtr<T> gameObject(rawPtr, &bs_delete<T>, StdAlloc<T>());
626 gameObject->mRTTIData = gameObject;
627
628 return gameObject;
629 }
630
631 public: // ***** INTERNAL ******
632 /** @name Internal
633 * @{
634 */
635
636 /** Returns a modifyable list of all components on this object. */
637 Vector<HComponent>& _getComponents() { return mComponents; }
638
639 /** @} */
640 private:
641 /** Adds the component to the internal component array. */
642 void addComponentInternal(const SPtr<Component>& component);
643
644 /** Adds the component to the internal component array, and initializes it. */
645 void addAndInitializeComponent(const HComponent& component);
646
647 /** Adds the component to the internal component array, and initializes it. */
648 void addAndInitializeComponent(const SPtr<Component>& component);
649
650 Vector<HComponent> mComponents;
651
652 /************************************************************************/
653 /* RTTI */
654 /************************************************************************/
655 public:
656 friend class GameObjectRTTI;
657 friend class SceneObjectRTTI;
658 static RTTITypeBase* getRTTIStatic();
659 RTTITypeBase* getRTTI() const override;
660 };
661
662 /** @} */
663}