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#include "Scene/BsSceneObject.h"
4#include "Scene/BsComponent.h"
5#include "Scene/BsSceneManager.h"
6#include "Error/BsException.h"
7#include "Debug/BsDebug.h"
8#include "Private/RTTI/BsSceneObjectRTTI.h"
9#include "Serialization/BsMemorySerializer.h"
10#include "Scene/BsGameObjectManager.h"
11#include "Scene/BsPrefabUtility.h"
12#include "Math/BsMatrix3.h"
13#include "BsCoreApplication.h"
14
15namespace bs
16{
17 SceneObject::SceneObject(const String& name, UINT32 flags)
18 : GameObject(), mFlags(flags)
19 {
20 setName(name);
21 }
22
23 SceneObject::~SceneObject()
24 {
25 if(!mThisHandle.isDestroyed())
26 {
27 LOGWRN("Object is being deleted without being destroyed first? " + mName);
28 destroyInternal(mThisHandle, true);
29 }
30 }
31
32 HSceneObject SceneObject::create(const String& name, UINT32 flags)
33 {
34 HSceneObject newObject = createInternal(name, flags);
35
36 if (newObject->isInstantiated())
37 gSceneManager().registerNewSO(newObject);
38
39 return newObject;
40 }
41
42 HSceneObject SceneObject::createInternal(const String& name, UINT32 flags)
43 {
44 SPtr<SceneObject> sceneObjectPtr = SPtr<SceneObject>(new (bs_alloc<SceneObject>()) SceneObject(name, flags),
45 &bs_delete<SceneObject>, StdAlloc<SceneObject>());
46 sceneObjectPtr->mUUID = UUIDGenerator::generateRandom();
47
48 HSceneObject sceneObject = static_object_cast<SceneObject>(
49 GameObjectManager::instance().registerObject(sceneObjectPtr));
50 sceneObject->mThisHandle = sceneObject;
51
52 return sceneObject;
53 }
54
55 HSceneObject SceneObject::createInternal(const SPtr<SceneObject>& soPtr)
56 {
57 HSceneObject sceneObject = static_object_cast<SceneObject>(
58 GameObjectManager::instance().registerObject(soPtr));
59 sceneObject->mThisHandle = sceneObject;
60
61 return sceneObject;
62 }
63
64 void SceneObject::destroy(bool immediate)
65 {
66 // Parent is our owner, so when his reference to us is removed, delete might be called.
67 // So make sure this is the last thing we do.
68 if(mParent != nullptr)
69 {
70 if(!mParent.isDestroyed())
71 mParent->removeChild(mThisHandle);
72
73 mParent = nullptr;
74 }
75
76 destroyInternal(mThisHandle, immediate);
77 }
78
79 void SceneObject::destroyInternal(GameObjectHandleBase& handle, bool immediate)
80 {
81 if (immediate)
82 {
83 for (auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
84 (*iter)->destroyInternal(*iter, true);
85
86 mChildren.clear();
87
88 // It's important to remove the elements from the array as soon as they're destroyed, as OnDestroy callbacks
89 // for components might query the SO's components, and we want to only return live ones
90 while (!mComponents.empty())
91 {
92 HComponent component = mComponents.back();
93 component->_setIsDestroyed();
94
95 if (isInstantiated())
96 gSceneManager()._notifyComponentDestroyed(component, immediate);
97
98 component->destroyInternal(component, true);
99 mComponents.erase(mComponents.end() - 1);
100 }
101
102 GameObjectManager::instance().unregisterObject(handle);
103 }
104 else
105 GameObjectManager::instance().queueForDestroy(handle);
106 }
107
108 void SceneObject::_setInstanceData(GameObjectInstanceDataPtr& other)
109 {
110 GameObject::_setInstanceData(other);
111
112 // Instance data changed, so make sure to refresh the handles to reflect that
113 SPtr<SceneObject> thisPtr = mThisHandle.getInternalPtr();
114 mThisHandle._setHandleData(thisPtr);
115 }
116
117 UUID SceneObject::getPrefabLink(bool onlyDirect) const
118 {
119 const SceneObject* curObj = this;
120
121 while (curObj != nullptr)
122 {
123 if (!curObj->mPrefabLinkUUID.empty())
124 return curObj->mPrefabLinkUUID;
125
126 if (curObj->mParent != nullptr && !onlyDirect)
127 curObj = curObj->mParent.get();
128 else
129 curObj = nullptr;
130 }
131
132 return UUID::EMPTY;
133 }
134
135 HSceneObject SceneObject::getPrefabParent() const
136 {
137 HSceneObject curObj = mThisHandle;
138
139 while (curObj != nullptr)
140 {
141 if (!curObj->mPrefabLinkUUID.empty())
142 return curObj;
143
144 if (curObj->mParent != nullptr)
145 curObj = curObj->mParent;
146 else
147 curObj = nullptr;
148 }
149
150 return curObj;
151 }
152
153 void SceneObject::breakPrefabLink()
154 {
155 SceneObject* rootObj = this;
156
157 while (rootObj != nullptr)
158 {
159 if (!rootObj->mPrefabLinkUUID.empty())
160 break;
161
162 if (rootObj->mParent != nullptr)
163 rootObj = rootObj->mParent.get();
164 else
165 rootObj = nullptr;
166 }
167
168 if (rootObj != nullptr)
169 {
170 rootObj->mPrefabLinkUUID = UUID::EMPTY;
171 rootObj->mPrefabDiff = nullptr;
172 PrefabUtility::clearPrefabIds(rootObj->getHandle(), true, false);
173 }
174 }
175
176 bool SceneObject::hasFlag(UINT32 flag) const
177 {
178 return (mFlags & flag) != 0;
179 }
180
181 void SceneObject::_setFlags(UINT32 flags)
182 {
183 mFlags |= flags;
184
185 for (auto& child : mChildren)
186 child->_setFlags(flags);
187 }
188
189 void SceneObject::_unsetFlags(UINT32 flags)
190 {
191 mFlags &= ~flags;
192
193 for (auto& child : mChildren)
194 child->_unsetFlags(flags);
195 }
196
197 void SceneObject::_instantiate(bool prefabOnly)
198 {
199 std::function<void(SceneObject*)> instantiateRecursive = [&](SceneObject* obj)
200 {
201 obj->mFlags &= ~SOF_DontInstantiate;
202
203 if (obj->mParent == nullptr)
204 gSceneManager().registerNewSO(obj->mThisHandle);
205
206 for (auto& component : obj->mComponents)
207 component->_instantiate();
208
209 for (auto& child : obj->mChildren)
210 {
211 if(!prefabOnly || child->mPrefabLinkUUID.empty())
212 instantiateRecursive(child.get());
213 }
214 };
215
216 std::function<void(SceneObject*)> triggerEventsRecursive = [&](SceneObject* obj)
217 {
218 for (auto& component : obj->mComponents)
219 gSceneManager()._notifyComponentCreated(component, obj->getActive());
220
221 for (auto& child : obj->mChildren)
222 {
223 if (!prefabOnly || child->mPrefabLinkUUID.empty())
224 triggerEventsRecursive(child.get());
225 }
226 };
227
228 instantiateRecursive(this);
229 triggerEventsRecursive(this);
230 }
231
232 /************************************************************************/
233 /* Transform */
234 /************************************************************************/
235
236 void SceneObject::setPosition(const Vector3& position)
237 {
238 if (mMobility == ObjectMobility::Movable)
239 {
240 mLocalTfrm.setPosition(position);
241 notifyTransformChanged(TCF_Transform);
242 }
243 }
244
245 void SceneObject::setRotation(const Quaternion& rotation)
246 {
247 if (mMobility == ObjectMobility::Movable)
248 {
249 mLocalTfrm.setRotation(rotation);
250 notifyTransformChanged(TCF_Transform);
251 }
252 }
253
254 void SceneObject::setScale(const Vector3& scale)
255 {
256 if (mMobility == ObjectMobility::Movable)
257 {
258 mLocalTfrm.setScale(scale);
259 notifyTransformChanged(TCF_Transform);
260 }
261 }
262
263 void SceneObject::setWorldPosition(const Vector3& position)
264 {
265 if(mMobility != ObjectMobility::Movable)
266 return;
267
268 if (mParent != nullptr)
269 mLocalTfrm.setWorldPosition(position, mParent->getTransform());
270 else
271 mLocalTfrm.setPosition(position);
272
273 notifyTransformChanged(TCF_Transform);
274 }
275
276 void SceneObject::setWorldRotation(const Quaternion& rotation)
277 {
278 if (mMobility != ObjectMobility::Movable)
279 return;
280
281 if (mParent != nullptr)
282 mLocalTfrm.setWorldRotation(rotation, mParent->getTransform());
283 else
284 mLocalTfrm.setRotation(rotation);
285
286 notifyTransformChanged(TCF_Transform);
287 }
288
289 void SceneObject::setWorldScale(const Vector3& scale)
290 {
291 if (mMobility != ObjectMobility::Movable)
292 return;
293
294 if (mParent != nullptr)
295 mLocalTfrm.setWorldScale(scale, mParent->getTransform());
296 else
297 mLocalTfrm.setScale(scale);
298
299 notifyTransformChanged(TCF_Transform);
300 }
301
302 const Transform& SceneObject::getTransform() const
303 {
304 if (!isCachedWorldTfrmUpToDate())
305 updateWorldTfrm();
306
307 return mWorldTfrm;
308 }
309
310 void SceneObject::lookAt(const Vector3& location, const Vector3& up)
311 {
312 const Transform& worldTfrm = getTransform();
313
314 Vector3 forward = location - worldTfrm.getPosition();
315
316 Quaternion rotation = worldTfrm.getRotation();
317 rotation.lookRotation(forward, up);
318 setWorldRotation(rotation);
319 }
320
321 const Matrix4& SceneObject::getWorldMatrix() const
322 {
323 if (!isCachedWorldTfrmUpToDate())
324 updateWorldTfrm();
325
326 return mCachedWorldTfrm;
327 }
328
329 Matrix4 SceneObject::getInvWorldMatrix() const
330 {
331 if (!isCachedWorldTfrmUpToDate())
332 updateWorldTfrm();
333
334 Matrix4 worldToLocal = mWorldTfrm.getInvMatrix();
335 return worldToLocal;
336 }
337
338 const Matrix4& SceneObject::getLocalMatrix() const
339 {
340 if (!isCachedLocalTfrmUpToDate())
341 updateLocalTfrm();
342
343 return mCachedLocalTfrm;
344 }
345
346 void SceneObject::move(const Vector3& vec)
347 {
348 if (mMobility == ObjectMobility::Movable)
349 {
350 mLocalTfrm.move(vec);
351 notifyTransformChanged(TCF_Transform);
352 }
353 }
354
355 void SceneObject::moveRelative(const Vector3& vec)
356 {
357 if (mMobility == ObjectMobility::Movable)
358 {
359 mLocalTfrm.moveRelative(vec);
360 notifyTransformChanged(TCF_Transform);
361 }
362 }
363
364 void SceneObject::rotate(const Vector3& axis, const Radian& angle)
365 {
366 if (mMobility == ObjectMobility::Movable)
367 {
368 mLocalTfrm.rotate(axis, angle);
369 notifyTransformChanged(TCF_Transform);
370 }
371 }
372
373 void SceneObject::rotate(const Quaternion& q)
374 {
375 if (mMobility == ObjectMobility::Movable)
376 {
377 mLocalTfrm.rotate(q);
378 notifyTransformChanged(TCF_Transform);
379 }
380 }
381
382 void SceneObject::roll(const Radian& angle)
383 {
384 if (mMobility == ObjectMobility::Movable)
385 {
386 mLocalTfrm.roll(angle);
387 notifyTransformChanged(TCF_Transform);
388 }
389 }
390
391 void SceneObject::yaw(const Radian& angle)
392 {
393 if (mMobility == ObjectMobility::Movable)
394 {
395 mLocalTfrm.yaw(angle);
396 notifyTransformChanged(TCF_Transform);
397 }
398 }
399
400 void SceneObject::pitch(const Radian& angle)
401 {
402 if (mMobility == ObjectMobility::Movable)
403 {
404 mLocalTfrm.pitch(angle);
405 notifyTransformChanged(TCF_Transform);
406 }
407 }
408
409 void SceneObject::setForward(const Vector3& forwardDir)
410 {
411 const Transform& worldTfrm = getTransform();
412
413 Quaternion currentRotation = worldTfrm.getRotation();
414 currentRotation.lookRotation(forwardDir);
415 setWorldRotation(currentRotation);
416 }
417
418 void SceneObject::updateTransformsIfDirty()
419 {
420 if (!isCachedLocalTfrmUpToDate())
421 updateLocalTfrm();
422
423 if (!isCachedWorldTfrmUpToDate())
424 updateWorldTfrm();
425 }
426
427 void SceneObject::notifyTransformChanged(TransformChangedFlags flags) const
428 {
429 // If object is immovable, don't send transform changed events nor mark the transform dirty
430 TransformChangedFlags componentFlags = flags;
431 if (mMobility != ObjectMobility::Movable)
432 componentFlags = (TransformChangedFlags)(componentFlags & ~TCF_Transform);
433 else
434 {
435 mDirtyFlags |= DirtyFlags::LocalTfrmDirty | DirtyFlags::WorldTfrmDirty;
436 mDirtyHash++;
437 }
438
439 // Only send component flags if we haven't removed them all
440 if (componentFlags != 0)
441 {
442 for (auto& entry : mComponents)
443 {
444 if (entry->supportsNotify(flags))
445 {
446 bool alwaysRun = entry->hasFlag(ComponentFlag::AlwaysRun);
447 if (alwaysRun || gSceneManager().isRunning())
448 entry->onTransformChanged(componentFlags);
449 }
450 }
451 }
452
453 // Mobility flag is only relevant for this scene object
454 flags = (TransformChangedFlags)(flags & ~TCF_Mobility);
455 if (flags != 0)
456 {
457 for (auto& entry : mChildren)
458 entry->notifyTransformChanged(flags);
459 }
460 }
461
462 void SceneObject::updateWorldTfrm() const
463 {
464 mWorldTfrm = mLocalTfrm;
465
466 // Don't allow movement from parent when not movable
467 if (mParent != nullptr && mMobility == ObjectMobility::Movable)
468 {
469 mWorldTfrm.makeWorld(mParent->getTransform());
470
471 mCachedWorldTfrm = mWorldTfrm.getMatrix();
472 }
473 else
474 {
475 mCachedWorldTfrm = getLocalMatrix();
476 }
477
478 mDirtyFlags &= ~DirtyFlags::WorldTfrmDirty;
479 }
480
481 void SceneObject::updateLocalTfrm() const
482 {
483 mCachedLocalTfrm = mLocalTfrm.getMatrix();
484 mDirtyFlags &= ~DirtyFlags::LocalTfrmDirty;
485 }
486
487 /************************************************************************/
488 /* Hierarchy */
489 /************************************************************************/
490
491 void SceneObject::setParent(const HSceneObject& parent, bool keepWorldTransform)
492 {
493 if (parent.isDestroyed())
494 return;
495
496#if BS_IS_BANSHEE3D
497 UUID originalPrefab = getPrefabLink();
498#endif
499
500 if (mMobility != ObjectMobility::Movable)
501 keepWorldTransform = true;
502
503 _setParent(parent, keepWorldTransform);
504
505#if BS_IS_BANSHEE3D
506 if (gCoreApplication().isEditor())
507 {
508 UUID newPrefab = getPrefabLink();
509 if (originalPrefab != newPrefab)
510 PrefabUtility::clearPrefabIds(mThisHandle);
511 }
512#endif
513 }
514
515 void SceneObject::_setParent(const HSceneObject& parent, bool keepWorldTransform)
516 {
517 if (mThisHandle == parent)
518 return;
519
520 if (mParent == nullptr || mParent != parent)
521 {
522 Transform worldTfrm;
523
524 // Make sure the object keeps its world coordinates
525 if (keepWorldTransform)
526 worldTfrm = getTransform();
527
528 if (mParent != nullptr)
529 mParent->removeChild(mThisHandle);
530
531 if (parent != nullptr)
532 {
533 parent->addChild(mThisHandle);
534 setScene(parent->mParentScene);
535 }
536 else
537 setScene(nullptr);
538
539 mParent = parent;
540
541 if (keepWorldTransform)
542 {
543 mLocalTfrm = worldTfrm;
544
545 if (mParent != nullptr)
546 mLocalTfrm.makeLocal(mParent->getTransform());
547 }
548
549 bool isInstantiated = (mFlags & SOF_DontInstantiate) == 0;
550 if(isInstantiated)
551 notifyTransformChanged((TransformChangedFlags)(TCF_Parent | TCF_Transform));
552 }
553 }
554
555 const SPtr<SceneInstance>& SceneObject::getScene() const
556 {
557 if(mParentScene)
558 return mParentScene;
559
560 LOGWRN("Attempting to access a scene of a SceneObject with no scene, returning main scene instead.");
561 return gSceneManager().getMainScene();
562
563 }
564
565 void SceneObject::setScene(const SPtr<SceneInstance>& scene)
566 {
567 if(mParentScene == scene)
568 return;
569
570 mParentScene = scene;
571
572 for(auto& child : mChildren)
573 child->setScene(scene);
574 }
575
576 HSceneObject SceneObject::getChild(UINT32 idx) const
577 {
578 if(idx >= mChildren.size())
579 {
580 BS_EXCEPT(InternalErrorException, "Child index out of range.");
581 }
582
583 return mChildren[idx];
584 }
585
586 int SceneObject::indexOfChild(const HSceneObject& child) const
587 {
588 for(int i = 0; i < (int)mChildren.size(); i++)
589 {
590 if(mChildren[i] == child)
591 return i;
592 }
593
594 return -1;
595 }
596
597 void SceneObject::addChild(const HSceneObject& object)
598 {
599 mChildren.push_back(object);
600
601 object->_setFlags(mFlags);
602 }
603
604 void SceneObject::removeChild(const HSceneObject& object)
605 {
606 auto result = find(mChildren.begin(), mChildren.end(), object);
607
608 if(result != mChildren.end())
609 mChildren.erase(result);
610 else
611 {
612 BS_EXCEPT(InternalErrorException,
613 "Trying to remove a child but it's not a child of the transform.");
614 }
615 }
616
617 HSceneObject SceneObject::findPath(const String& path) const
618 {
619 if (path.empty())
620 return HSceneObject();
621
622 String trimmedPath = path;
623 StringUtil::trim(trimmedPath, "/");
624
625 Vector<String> entries = StringUtil::split(trimmedPath, "/");
626
627 // Find scene object referenced by the path
628 HSceneObject so = getHandle();
629 UINT32 pathIdx = 0;
630 for (; pathIdx < (UINT32)entries.size(); pathIdx++)
631 {
632 String entry = entries[pathIdx];
633
634 if (entry.empty())
635 continue;
636
637 // This character signifies not-a-scene-object. This is allowed to support
638 // paths used by the scripting system (which can point to properties of
639 // components on scene objects).
640 if (entry[0] != '!')
641 break;
642
643 String childName = entry.substr(1, entry.size() - 1);
644 so = so->findChild(childName);
645
646 if (so == nullptr)
647 break;
648 }
649
650 return so;
651 }
652
653 HSceneObject SceneObject::findChild(const String& name, bool recursive)
654 {
655 for (auto& child : mChildren)
656 {
657 if (child->getName() == name)
658 return child;
659 }
660
661 if (recursive)
662 {
663 for (auto& child : mChildren)
664 {
665 HSceneObject foundObject = child->findChild(name, true);
666 if (foundObject != nullptr)
667 return foundObject;
668 }
669 }
670
671 return HSceneObject();
672 }
673
674 Vector<HSceneObject> SceneObject::findChildren(const String& name, bool recursive)
675 {
676 std::function<void(const HSceneObject&, Vector<HSceneObject>&)> findChildrenInternal =
677 [&](const HSceneObject& so, Vector<HSceneObject>& output)
678 {
679 for (auto& child : so->mChildren)
680 {
681 if (child->getName() == name)
682 output.push_back(child);
683 }
684
685 if (recursive)
686 {
687 for (auto& child : so->mChildren)
688 findChildrenInternal(child, output);
689 }
690 };
691
692 Vector<HSceneObject> output;
693 findChildrenInternal(mThisHandle, output);
694
695 return output;
696 }
697
698 void SceneObject::setActive(bool active)
699 {
700 mActiveSelf = active;
701 setActiveHierarchy(active);
702 }
703
704 void SceneObject::setActiveHierarchy(bool active, bool triggerEvents)
705 {
706 bool activeHierarchy = active && mActiveSelf;
707
708 if (mActiveHierarchy != activeHierarchy)
709 {
710 mActiveHierarchy = activeHierarchy;
711
712 if (triggerEvents)
713 {
714 if (activeHierarchy)
715 {
716 for (auto& component : mComponents)
717 gSceneManager()._notifyComponentActivated(component, triggerEvents);
718 }
719 else
720 {
721 for (auto& component : mComponents)
722 gSceneManager()._notifyComponentDeactivated(component, triggerEvents);
723 }
724 }
725 }
726
727 for (auto child : mChildren)
728 {
729 child->setActiveHierarchy(mActiveHierarchy, triggerEvents);
730 }
731 }
732
733 bool SceneObject::getActive(bool self) const
734 {
735 if (self)
736 return mActiveSelf;
737 else
738 return mActiveHierarchy;
739 }
740
741 void SceneObject::setMobility(ObjectMobility mobility)
742 {
743 if(mMobility != mobility)
744 {
745 mMobility = mobility;
746
747 // If mobility changed to movable, update both the mobility flag and transform, otherwise just mobility
748 if (mMobility == ObjectMobility::Movable)
749 notifyTransformChanged((TransformChangedFlags)(TCF_Transform | TCF_Mobility));
750 else
751 notifyTransformChanged(TCF_Mobility);
752 }
753 }
754
755 HSceneObject SceneObject::clone(bool instantiate, bool preserveUUIDs)
756 {
757 const bool isInstantiated = !hasFlag(SOF_DontInstantiate);
758
759 if (!instantiate)
760 _setFlags(SOF_DontInstantiate);
761 else
762 _unsetFlags(SOF_DontInstantiate);
763
764 UINT32 bufferSize = 0;
765
766 MemorySerializer serializer;
767 UINT8* buffer = serializer.encode(this, bufferSize, (void*(*)(size_t))&bs_alloc);
768
769 int flags = GODM_RestoreExternal | GODM_UseNewIds;
770 if(!preserveUUIDs)
771 flags |= GODM_UseNewUUID;
772
773 CoreSerializationContext serzContext;
774 serzContext.goState = bs_shared_ptr_new<GameObjectDeserializationState>(flags);
775
776 SPtr<SceneObject> cloneObj = std::static_pointer_cast<SceneObject>(
777 serializer.decode(buffer, bufferSize, &serzContext));
778 bs_free(buffer);
779
780 if(isInstantiated)
781 _unsetFlags(SOF_DontInstantiate);
782 else
783 _setFlags(SOF_DontInstantiate);
784
785 return cloneObj->mThisHandle;
786 }
787
788 HComponent SceneObject::getComponent(RTTITypeBase* type) const
789 {
790 if(type != Component::getRTTIStatic())
791 {
792 for (auto& entry : mComponents)
793 {
794 if (entry->getRTTI()->isDerivedFrom(type))
795 return entry;
796 }
797 }
798
799 return HComponent();
800 }
801
802 void SceneObject::destroyComponent(const HComponent component, bool immediate)
803 {
804 if(component == nullptr)
805 {
806 LOGDBG("Trying to remove a null component");
807 return;
808 }
809
810 auto iter = std::find(mComponents.begin(), mComponents.end(), component);
811
812 if(iter != mComponents.end())
813 {
814 (*iter)->_setIsDestroyed();
815
816 if (isInstantiated())
817 gSceneManager()._notifyComponentDestroyed(*iter, immediate);
818
819 (*iter)->destroyInternal(*iter, immediate);
820 mComponents.erase(iter);
821 }
822 else
823 LOGDBG("Trying to remove a component that doesn't exist on this SceneObject.");
824 }
825
826 void SceneObject::destroyComponent(Component* component, bool immediate)
827 {
828 auto iterFind = std::find_if(mComponents.begin(), mComponents.end(),
829 [component](const HComponent& x)
830 {
831 if(x.isDestroyed())
832 return false;
833
834 return x._getHandleData()->mPtr->object.get() == component; }
835 );
836
837 if(iterFind != mComponents.end())
838 {
839 destroyComponent(*iterFind, immediate);
840 }
841 }
842
843 HComponent SceneObject::addComponent(UINT32 typeId)
844 {
845 SPtr<IReflectable> newObj = rtti_create(typeId);
846
847 if(!rtti_is_subclass<Component>(newObj.get()))
848 {
849 LOGERR("Specified type is not a valid Component.");
850 return HComponent();
851 }
852
853 SPtr<Component> componentPtr = std::static_pointer_cast<Component>(newObj);
854
855 // Clean up the self-reference assigned by the RTTI system
856 componentPtr->mRTTIData = nullptr;
857
858 HComponent newComponent = static_object_cast<Component>(GameObjectManager::instance().registerObject(componentPtr));
859 newComponent->mParent = mThisHandle;
860
861 addAndInitializeComponent(newComponent);
862 return newComponent;
863 }
864
865 void SceneObject::addComponentInternal(const SPtr<Component>& component)
866 {
867 HComponent newComponent = static_object_cast<Component>(
868 GameObjectManager::instance().getObject(component->getInstanceId()));
869 newComponent->mParent = mThisHandle;
870 newComponent->mThisHandle = newComponent;
871
872 mComponents.push_back(newComponent);
873 }
874
875 void SceneObject::addAndInitializeComponent(const HComponent& component)
876 {
877 component->mThisHandle = component;
878
879 if(component->mUUID.empty())
880 component->mUUID = UUIDGenerator::generateRandom();
881
882 mComponents.push_back(component);
883
884 if (isInstantiated())
885 {
886 component->_instantiate();
887
888 gSceneManager()._notifyComponentCreated(component, getActive());
889 }
890 }
891
892 void SceneObject::addAndInitializeComponent(const SPtr<Component>& component)
893 {
894 HComponent newComponent = static_object_cast<Component>(
895 GameObjectManager::instance().getObject(component->getInstanceId()));
896 newComponent->mParent = mThisHandle;
897
898 addAndInitializeComponent(newComponent);
899 }
900
901 RTTITypeBase* SceneObject::getRTTIStatic()
902 {
903 return SceneObjectRTTI::instance();
904 }
905
906 RTTITypeBase* SceneObject::getRTTI() const
907 {
908 return SceneObject::getRTTIStatic();
909 }
910}
911