| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsSceneObject.h"
- #include "BsComponent.h"
- #include "BsCoreSceneManager.h"
- #include "BsException.h"
- #include "BsDebug.h"
- #include "BsSceneObjectRTTI.h"
- #include "BsMemorySerializer.h"
- #include "BsGameObjectManager.h"
- #include "BsPrefabUtility.h"
- #include "BsMatrix3.h"
- #include "BsCoreApplication.h"
- namespace BansheeEngine
- {
- SceneObject::SceneObject(const String& name, UINT32 flags)
- : GameObject(), mPrefabHash(0), mFlags(flags), mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY)
- , mScale(Vector3::ONE), mWorldPosition(Vector3::ZERO), mWorldRotation(Quaternion::IDENTITY)
- , mWorldScale(Vector3::ONE), mCachedLocalTfrm(Matrix4::IDENTITY), mCachedWorldTfrm(Matrix4::IDENTITY)
- , mDirtyFlags(0xFFFFFFFF), mDirtyHash(0), mActiveSelf(true), mActiveHierarchy(true)
- {
- setName(name);
- }
- SceneObject::~SceneObject()
- {
- if(!mThisHandle.isDestroyed())
- {
- LOGWRN("Object is being deleted without being destroyed first? " + mName);
- destroyInternal(mThisHandle, true);
- }
- }
- HSceneObject SceneObject::create(const String& name, UINT32 flags)
- {
- HSceneObject newObject = createInternal(name, flags);
- if (newObject->isInstantiated())
- gCoreSceneManager().registerNewSO(newObject);
- return newObject;
- }
- HSceneObject SceneObject::createInternal(const String& name, UINT32 flags)
- {
- SPtr<SceneObject> sceneObjectPtr = SPtr<SceneObject>(new (bs_alloc<SceneObject>()) SceneObject(name, flags),
- &bs_delete<SceneObject>, StdAlloc<SceneObject>());
-
- HSceneObject sceneObject = GameObjectManager::instance().registerObject(sceneObjectPtr);
- sceneObject->mThisHandle = sceneObject;
- return sceneObject;
- }
- HSceneObject SceneObject::createInternal(const SPtr<SceneObject>& soPtr, UINT64 originalId)
- {
- HSceneObject sceneObject = GameObjectManager::instance().registerObject(soPtr, originalId);
- sceneObject->mThisHandle = sceneObject;
- return sceneObject;
- }
- void SceneObject::destroy(bool immediate)
- {
- // Parent is our owner, so when his reference to us is removed, delete might be called.
- // So make sure this is the last thing we do.
- if(mParent != nullptr)
- {
- if(!mParent.isDestroyed())
- mParent->removeChild(mThisHandle);
- mParent = nullptr;
- }
- destroyInternal(mThisHandle, immediate);
- }
- void SceneObject::destroyInternal(GameObjectHandleBase& handle, bool immediate)
- {
- if (immediate)
- {
- for (auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
- (*iter)->destroyInternal(*iter, true);
- mChildren.clear();
- for (auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
- {
- HComponent component = *iter;
- component->_setIsDestroyed();
- if (isInstantiated())
- {
- if (getActive())
- component->onDisabled();
- component->onDestroyed();
- }
- component->destroyInternal(*iter, true);
- }
- mComponents.clear();
- GameObjectManager::instance().unregisterObject(handle);
- }
- else
- GameObjectManager::instance().queueForDestroy(handle);
- }
- void SceneObject::_setInstanceData(GameObjectInstanceDataPtr& other)
- {
- GameObject::_setInstanceData(other);
- // Instance data changed, so make sure to refresh the handles to reflect that
- SPtr<SceneObject> thisPtr = mThisHandle.getInternalPtr();
- mThisHandle._setHandleData(thisPtr);
- }
- String SceneObject::getPrefabLink() const
- {
- const SceneObject* curObj = this;
- while (curObj != nullptr)
- {
- if (!curObj->mPrefabLinkUUID.empty())
- return curObj->mPrefabLinkUUID;
- if (curObj->mParent != nullptr)
- curObj = curObj->mParent.get();
- else
- curObj = nullptr;
- }
- return "";
- }
- HSceneObject SceneObject::getPrefabParent() const
- {
- HSceneObject curObj = mThisHandle;
- while (curObj != nullptr)
- {
- if (!curObj->mPrefabLinkUUID.empty())
- return curObj;
- if (curObj->mParent != nullptr)
- curObj = curObj->mParent;
- else
- curObj = nullptr;
- }
- return curObj;
- }
- void SceneObject::breakPrefabLink()
- {
- SceneObject* rootObj = this;
- while (rootObj != nullptr)
- {
- if (!rootObj->mPrefabLinkUUID.empty())
- break;
- if (rootObj->mParent != nullptr)
- rootObj = rootObj->mParent.get();
- else
- rootObj = nullptr;
- }
- if (rootObj != nullptr)
- {
- rootObj->mPrefabLinkUUID = "";
- rootObj->mPrefabDiff = nullptr;
- PrefabUtility::clearPrefabIds(rootObj->getHandle(), true, false);
- }
- }
- bool SceneObject::hasFlag(UINT32 flag) const
- {
- return (mFlags & flag) != 0;
- }
- void SceneObject::setFlags(UINT32 flags)
- {
- mFlags |= flags;
- for (auto& child : mChildren)
- child->setFlags(flags);
- }
- void SceneObject::unsetFlags(UINT32 flags)
- {
- mFlags &= ~flags;
- for (auto& child : mChildren)
- child->unsetFlags(flags);
- }
- void SceneObject::_instantiate(bool prefabOnly)
- {
- std::function<void(SceneObject*)> instantiateRecursive = [&](SceneObject* obj)
- {
- obj->mFlags &= ~SOF_DontInstantiate;
- if (obj->mParent == nullptr)
- gCoreSceneManager().registerNewSO(obj->mThisHandle);
- for (auto& component : obj->mComponents)
- component->_instantiate();
- for (auto& child : obj->mChildren)
- {
- if(!prefabOnly || child->getPrefabLink().empty())
- instantiateRecursive(child.get());
- }
- };
- std::function<void(SceneObject*)> triggerEventsRecursive = [&](SceneObject* obj)
- {
- for (auto& component : obj->mComponents)
- {
- component->onInitialized();
- if (obj->getActive())
- component->onEnabled();
- }
- for (auto& child : obj->mChildren)
- {
- if (!prefabOnly || child->getPrefabLink().empty())
- triggerEventsRecursive(child.get());
- }
- };
- instantiateRecursive(this);
- triggerEventsRecursive(this);
- }
- /************************************************************************/
- /* Transform */
- /************************************************************************/
- void SceneObject::setPosition(const Vector3& position)
- {
- mPosition = position;
- notifyTransformChanged(TCF_Transform);
- }
- void SceneObject::setRotation(const Quaternion& rotation)
- {
- mRotation = rotation;
- notifyTransformChanged(TCF_Transform);
- }
- void SceneObject::setScale(const Vector3& scale)
- {
- mScale = scale;
- notifyTransformChanged(TCF_Transform);
- }
- void SceneObject::setWorldPosition(const Vector3& position)
- {
- if (mParent != nullptr)
- {
- Vector3 invScale = mParent->getWorldScale();
- if (invScale.x != 0) invScale.x = 1.0f / invScale.x;
- if (invScale.y != 0) invScale.y = 1.0f / invScale.y;
- if (invScale.z != 0) invScale.z = 1.0f / invScale.z;
- Quaternion invRotation = mParent->getWorldRotation().inverse();
- mPosition = invRotation.rotate(position - mParent->getWorldPosition()) * invScale;
- }
- else
- mPosition = position;
- notifyTransformChanged(TCF_Transform);
- }
- void SceneObject::setWorldRotation(const Quaternion& rotation)
- {
- if (mParent != nullptr)
- {
- Quaternion invRotation = mParent->getWorldRotation().inverse();
- mRotation = invRotation * rotation;
- }
- else
- mRotation = rotation;
- notifyTransformChanged(TCF_Transform);
- }
- void SceneObject::setWorldScale(const Vector3& scale)
- {
- if (mParent != nullptr)
- {
- Matrix3 rotScale;
- mParent->getWorldTfrm().extract3x3Matrix(rotScale);
- rotScale.inverse();
- Matrix3 scaleMat = Matrix3(Quaternion::IDENTITY, scale);
- scaleMat = rotScale * scaleMat;
- Quaternion rotation;
- Vector3 localScale;
- scaleMat.decomposition(rotation, localScale);
- mScale = localScale;
- }
- else
- mScale = scale;
- notifyTransformChanged(TCF_Transform);
- }
- const Vector3& SceneObject::getWorldPosition() const
- {
- if (!isCachedWorldTfrmUpToDate())
- updateWorldTfrm();
- return mWorldPosition;
- }
- const Quaternion& SceneObject::getWorldRotation() const
- {
- if (!isCachedWorldTfrmUpToDate())
- updateWorldTfrm();
- return mWorldRotation;
- }
- const Vector3& SceneObject::getWorldScale() const
- {
- if (!isCachedWorldTfrmUpToDate())
- updateWorldTfrm();
- return mWorldScale;
- }
- void SceneObject::lookAt(const Vector3& location, const Vector3& up)
- {
- Vector3 forward = location - getWorldPosition();
-
- Quaternion rotation = getWorldRotation();
- rotation.lookRotation(forward, up);
- setWorldRotation(rotation);
- }
- const Matrix4& SceneObject::getWorldTfrm() const
- {
- if (!isCachedWorldTfrmUpToDate())
- updateWorldTfrm();
- return mCachedWorldTfrm;
- }
- Matrix4 SceneObject::getInvWorldTfrm() const
- {
- if (!isCachedWorldTfrmUpToDate())
- updateWorldTfrm();
- Matrix4 worldToLocal = Matrix4::inverseTRS(mWorldPosition, mWorldRotation, mWorldScale);
- return worldToLocal;
- }
- const Matrix4& SceneObject::getLocalTfrm() const
- {
- if (!isCachedLocalTfrmUpToDate())
- updateLocalTfrm();
- return mCachedLocalTfrm;
- }
- void SceneObject::move(const Vector3& vec)
- {
- setPosition(mPosition + vec);
- }
- void SceneObject::moveRelative(const Vector3& vec)
- {
- // Transform the axes of the relative vector by camera's local axes
- Vector3 trans = mRotation.rotate(vec);
- setPosition(mPosition + trans);
- }
- void SceneObject::rotate(const Vector3& axis, const Radian& angle)
- {
- Quaternion q;
- q.fromAxisAngle(axis, angle);
- rotate(q);
- }
- void SceneObject::rotate(const Quaternion& q)
- {
- // Note the order of the mult, i.e. q comes after
- // Normalize the quat to avoid cumulative problems with precision
- Quaternion qnorm = q;
- qnorm.normalize();
- setRotation(qnorm * mRotation);
- }
- void SceneObject::roll(const Radian& angle)
- {
- // Rotate around local Z axis
- Vector3 zAxis = mRotation.rotate(Vector3::UNIT_Z);
- rotate(zAxis, angle);
- }
- void SceneObject::yaw(const Radian& angle)
- {
- Vector3 yAxis = mRotation.rotate(Vector3::UNIT_Y);
- rotate(yAxis, angle);
- }
- void SceneObject::pitch(const Radian& angle)
- {
- // Rotate around local X axis
- Vector3 xAxis = mRotation.rotate(Vector3::UNIT_X);
- rotate(xAxis, angle);
- }
- void SceneObject::setForward(const Vector3& forwardDir)
- {
- Quaternion currentRotation = getWorldRotation();
- currentRotation.lookRotation(forwardDir);
- setWorldRotation(currentRotation);
- }
- void SceneObject::updateTransformsIfDirty()
- {
- if (!isCachedLocalTfrmUpToDate())
- updateLocalTfrm();
- if (!isCachedWorldTfrmUpToDate())
- updateWorldTfrm();
- }
- void SceneObject::notifyTransformChanged(TransformChangedFlags flags) const
- {
- mDirtyFlags |= DirtyFlags::LocalTfrmDirty | DirtyFlags::WorldTfrmDirty;
- mDirtyHash++;
- for(auto& entry : mComponents)
- {
- if (entry->supportsNotify(flags))
- entry->onTransformChanged(flags);
- }
- for (auto& entry : mChildren)
- entry->notifyTransformChanged(flags);
- }
- void SceneObject::updateWorldTfrm() const
- {
- if(mParent != nullptr)
- {
- // Update orientation
- const Quaternion& parentOrientation = mParent->getWorldRotation();
- mWorldRotation = parentOrientation * mRotation;
- // Update scale
- const Vector3& parentScale = mParent->getWorldScale();
- // Scale own position by parent scale, just combine
- // as equivalent axes, no shearing
- mWorldScale = parentScale * mScale;
- // Change position vector based on parent's orientation & scale
- mWorldPosition = parentOrientation.rotate(parentScale * mPosition);
- // Add altered position vector to parents
- mWorldPosition += mParent->getWorldPosition();
- mCachedWorldTfrm.setTRS(mWorldPosition, mWorldRotation, mWorldScale);
- }
- else
- {
- mWorldRotation = mRotation;
- mWorldPosition = mPosition;
- mWorldScale = mScale;
- mCachedWorldTfrm = getLocalTfrm();
- }
- mDirtyFlags &= ~DirtyFlags::WorldTfrmDirty;
- }
- void SceneObject::updateLocalTfrm() const
- {
- mCachedLocalTfrm.setTRS(mPosition, mRotation, mScale);
- mDirtyFlags &= ~DirtyFlags::LocalTfrmDirty;
- }
- /************************************************************************/
- /* Hierarchy */
- /************************************************************************/
- void SceneObject::setParent(const HSceneObject& parent, bool keepWorldTransform)
- {
- if (parent.isDestroyed())
- return;
- #if BS_EDITOR_BUILD
- String originalPrefab = getPrefabLink();
- #endif
- _setParent(parent, keepWorldTransform);
- #if BS_EDITOR_BUILD
- if (gCoreApplication().isEditor())
- {
- String newPrefab = getPrefabLink();
- if (originalPrefab != newPrefab)
- PrefabUtility::clearPrefabIds(mThisHandle);
- }
- #endif
- }
- void SceneObject::_setParent(const HSceneObject& parent, bool keepWorldTransform)
- {
- if (mThisHandle == parent)
- return;
- if (mParent == nullptr || mParent != parent)
- {
- Vector3 worldPos;
- Quaternion worldRot;
- Vector3 worldScale;
- if (keepWorldTransform)
- {
- // Make sure the object keeps its world coordinates
- worldPos = getWorldPosition();
- worldRot = getWorldRotation();
- worldScale = getWorldScale();
- }
- if (mParent != nullptr)
- mParent->removeChild(mThisHandle);
- if (parent != nullptr)
- parent->addChild(mThisHandle);
- mParent = parent;
- if (keepWorldTransform)
- {
- setWorldPosition(worldPos);
- setWorldRotation(worldRot);
- setWorldScale(worldScale);
- }
- notifyTransformChanged((TransformChangedFlags)(TCF_Parent | TCF_Transform));
- }
- }
- HSceneObject SceneObject::getChild(UINT32 idx) const
- {
- if(idx >= mChildren.size())
- {
- BS_EXCEPT(InternalErrorException, "Child index out of range.");
- }
- return mChildren[idx];
- }
- int SceneObject::indexOfChild(const HSceneObject& child) const
- {
- for(int i = 0; i < (int)mChildren.size(); i++)
- {
- if(mChildren[i] == child)
- return i;
- }
- return -1;
- }
- void SceneObject::addChild(const HSceneObject& object)
- {
- mChildren.push_back(object);
- object->setFlags(mFlags);
- }
- void SceneObject::removeChild(const HSceneObject& object)
- {
- auto result = find(mChildren.begin(), mChildren.end(), object);
- if(result != mChildren.end())
- mChildren.erase(result);
- else
- {
- BS_EXCEPT(InternalErrorException,
- "Trying to remove a child but it's not a child of the transform.");
- }
- }
- HSceneObject SceneObject::findChild(const String& name, bool recursive)
- {
- for (auto& child : mChildren)
- {
- if (child->getName() == name)
- return child;
- }
- if (recursive)
- {
- for (auto& child : mChildren)
- {
- HSceneObject foundObject = child->findChild(name, true);
- if (foundObject != nullptr)
- return foundObject;
- }
- }
- return HSceneObject();
- }
- Vector<HSceneObject> SceneObject::findChildren(const String& name, bool recursive)
- {
- std::function<void(const HSceneObject&, Vector<HSceneObject>&)> findChildrenInternal =
- [&](const HSceneObject& so, Vector<HSceneObject>& output)
- {
- for (auto& child : so->mChildren)
- {
- if (child->getName() == name)
- output.push_back(child);
- }
- if (recursive)
- {
- for (auto& child : so->mChildren)
- findChildrenInternal(child, output);
- }
- };
- Vector<HSceneObject> output;
- findChildrenInternal(mThisHandle, output);
- return output;
- }
- void SceneObject::setActive(bool active)
- {
- mActiveSelf = active;
- setActiveHierarchy(active);
- }
- void SceneObject::setActiveHierarchy(bool active, bool triggerEvents)
- {
- bool activeHierarchy = active && mActiveSelf;
- if (mActiveHierarchy != activeHierarchy)
- {
- mActiveHierarchy = activeHierarchy;
- if (triggerEvents)
- {
- if (activeHierarchy)
- {
- for (auto& component : mComponents)
- component->onEnabled();
- }
- else
- {
- for (auto& component : mComponents)
- component->onDisabled();
- }
- }
- }
-
- for (auto child : mChildren)
- {
- child->setActiveHierarchy(mActiveHierarchy, triggerEvents);
- }
- }
- bool SceneObject::getActive(bool self)
- {
- if (self)
- return mActiveSelf;
- else
- return mActiveHierarchy;
- }
- HSceneObject SceneObject::clone(bool instantiate)
- {
- bool isInstantiated = !hasFlag(SOF_DontInstantiate);
- if (!instantiate)
- setFlags(SOF_DontInstantiate);
- else
- unsetFlags(SOF_DontInstantiate);
- UINT32 bufferSize = 0;
- MemorySerializer serializer;
- UINT8* buffer = serializer.encode(this, bufferSize, (void*(*)(UINT32))&bs_alloc);
- GameObjectManager::instance().setDeserializationMode(GODM_UseNewIds | GODM_RestoreExternal);
- SPtr<SceneObject> cloneObj = std::static_pointer_cast<SceneObject>(serializer.decode(buffer, bufferSize));
- bs_free(buffer);
- if(isInstantiated)
- unsetFlags(SOF_DontInstantiate);
- else
- setFlags(SOF_DontInstantiate);
- return cloneObj->mThisHandle;
- }
- HComponent SceneObject::getComponent(RTTITypeBase* type) const
- {
- for(auto& entry : mComponents)
- {
- if(entry->getRTTI()->isDerivedFrom(type))
- return entry;
- }
- return HComponent();
- }
- void SceneObject::destroyComponent(const HComponent component, bool immediate)
- {
- if(component == nullptr)
- {
- LOGDBG("Trying to remove a null component");
- return;
- }
- auto iter = std::find(mComponents.begin(), mComponents.end(), component);
- if(iter != mComponents.end())
- {
- (*iter)->_setIsDestroyed();
- if (isInstantiated())
- {
- if (getActive())
- component->onDisabled();
- (*iter)->onDestroyed();
- }
-
- (*iter)->destroyInternal(*iter, immediate);
- mComponents.erase(iter);
- }
- else
- LOGDBG("Trying to remove a component that doesn't exist on this SceneObject.");
- }
- void SceneObject::destroyComponent(Component* component, bool immediate)
- {
- auto iterFind = std::find_if(mComponents.begin(), mComponents.end(),
- [component](const HComponent& x)
- {
- if(x.isDestroyed())
- return false;
- return x._getHandleData()->mPtr->object.get() == component; }
- );
- if(iterFind != mComponents.end())
- {
- destroyComponent(*iterFind, immediate);
- }
- }
- void SceneObject::addComponentInternal(const SPtr<Component> component)
- {
- GameObjectHandle<Component> newComponent = GameObjectManager::instance().getObject(component->getInstanceId());
- newComponent->mParent = mThisHandle;
- newComponent->mThisHandle = newComponent;
- mComponents.push_back(newComponent);
- }
- RTTITypeBase* SceneObject::getRTTIStatic()
- {
- return SceneObjectRTTI::instance();
- }
- RTTITypeBase* SceneObject::getRTTI() const
- {
- return SceneObject::getRTTIStatic();
- }
- }
|