|
|
@@ -0,0 +1,154 @@
|
|
|
+#include "CmGameObject.h"
|
|
|
+#include "CmException.h"
|
|
|
+
|
|
|
+namespace CamelotEngine
|
|
|
+{
|
|
|
+ GameObject::GameObject(const String& name)
|
|
|
+ :mName(name), mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY), mScale(Vector3::ZERO),
|
|
|
+ mCachedLocalTfrm(Matrix4::IDENTITY), mIsCachedLocalTfrmUpToDate(false),
|
|
|
+ mCachedWorldTfrm(Matrix4::IDENTITY), mIsCachedWorldTfrmUpToDate(false),
|
|
|
+ mCustomWorldTfrm(Matrix4::IDENTITY), mIsCustomTfrmModeActive(false),
|
|
|
+ mParent(nullptr)
|
|
|
+ { }
|
|
|
+
|
|
|
+ GameObject::~GameObject()
|
|
|
+ {
|
|
|
+ if(mParent != nullptr)
|
|
|
+ mParent->removeChild(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ /************************************************************************/
|
|
|
+ /* Transform */
|
|
|
+ /************************************************************************/
|
|
|
+
|
|
|
+ void GameObject::setPosition(const Vector3& position)
|
|
|
+ {
|
|
|
+ mPosition = position;
|
|
|
+ markTfrmDirty();
|
|
|
+ }
|
|
|
+
|
|
|
+ void GameObject::setRotation(const Quaternion& rotation)
|
|
|
+ {
|
|
|
+ mRotation = rotation;
|
|
|
+ markTfrmDirty();
|
|
|
+ }
|
|
|
+
|
|
|
+ void GameObject::setScale(const Vector3& scale)
|
|
|
+ {
|
|
|
+ mScale = scale;
|
|
|
+ markTfrmDirty();
|
|
|
+ }
|
|
|
+
|
|
|
+ const Matrix4& GameObject::getWorldTfrm()
|
|
|
+ {
|
|
|
+ if(!mIsCachedWorldTfrmUpToDate)
|
|
|
+ updateWorldTfrm();
|
|
|
+
|
|
|
+ return mCachedWorldTfrm;
|
|
|
+ }
|
|
|
+
|
|
|
+ const Matrix4& GameObject::getLocalTfrm()
|
|
|
+ {
|
|
|
+ if(!mIsCachedLocalTfrmUpToDate) // TODO - Low priority - This unnecessarily updates world transform as well
|
|
|
+ updateLocalTfrm();
|
|
|
+
|
|
|
+ return mCachedLocalTfrm;
|
|
|
+ }
|
|
|
+
|
|
|
+ void GameObject::markTfrmDirty()
|
|
|
+ {
|
|
|
+ mIsCachedLocalTfrmUpToDate = false;
|
|
|
+
|
|
|
+ if(mIsCachedWorldTfrmUpToDate) // If it's already marked as dirty, no point is recursing the hierarchy again
|
|
|
+ {
|
|
|
+ mIsCachedWorldTfrmUpToDate = false;
|
|
|
+
|
|
|
+ for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
|
|
|
+ {
|
|
|
+ (*iter)->markTfrmDirty();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void GameObject::updateWorldTfrm()
|
|
|
+ {
|
|
|
+ if(mParent != nullptr)
|
|
|
+ mCachedWorldTfrm = getLocalTfrm() * mParent->getWorldTfrm();
|
|
|
+ else
|
|
|
+ mCachedWorldTfrm = getLocalTfrm();
|
|
|
+
|
|
|
+ mIsCachedWorldTfrmUpToDate = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ void GameObject::updateLocalTfrm()
|
|
|
+ {
|
|
|
+ mCachedLocalTfrm.makeTransform(mPosition, mScale, mRotation);
|
|
|
+
|
|
|
+ mIsCachedLocalTfrmUpToDate = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /************************************************************************/
|
|
|
+ /* Hierarchy */
|
|
|
+ /************************************************************************/
|
|
|
+
|
|
|
+ void GameObject::setParent(GameObject* parent)
|
|
|
+ {
|
|
|
+ if(parent == nullptr)
|
|
|
+ {
|
|
|
+ CM_EXCEPT(InternalErrorException,
|
|
|
+ "Parent is not allowed to be NULL.");
|
|
|
+ }
|
|
|
+
|
|
|
+ if(mParent != parent)
|
|
|
+ {
|
|
|
+ if(mParent != nullptr)
|
|
|
+ mParent->removeChild(this);
|
|
|
+
|
|
|
+ if(parent != nullptr)
|
|
|
+ parent->addChild(this);
|
|
|
+
|
|
|
+ mParent = parent;
|
|
|
+ markTfrmDirty();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ GameObject* GameObject::getChild(unsigned int idx) const
|
|
|
+ {
|
|
|
+ if(idx < 0 || idx >= mChildren.size())
|
|
|
+ {
|
|
|
+ CM_EXCEPT(InternalErrorException,
|
|
|
+ "Child index out of range.");
|
|
|
+ }
|
|
|
+
|
|
|
+ return mChildren[idx];
|
|
|
+ }
|
|
|
+
|
|
|
+ int GameObject::indexOfChild(const GameObject* child) const
|
|
|
+ {
|
|
|
+ for(int i = 0; i < (int)mChildren.size(); i++)
|
|
|
+ {
|
|
|
+ if(mChildren[i] == child)
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ void GameObject::addChild(GameObject* object)
|
|
|
+ {
|
|
|
+ mChildren.push_back(object);
|
|
|
+ }
|
|
|
+
|
|
|
+ void GameObject::removeChild(GameObject* object)
|
|
|
+ {
|
|
|
+ auto result = find(mChildren.begin(), mChildren.end(), object);
|
|
|
+
|
|
|
+ if(result != mChildren.end())
|
|
|
+ mChildren.erase(result);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ CM_EXCEPT(InternalErrorException,
|
|
|
+ "Trying to remove a child but it's not a child of the transform.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|