Browse Source

Transform & transform updates

Marko Pintera 13 years ago
parent
commit
783ead2ce7

+ 2 - 0
CamelotRenderer/CamelotRenderer.vcxproj

@@ -134,6 +134,7 @@
     <ClInclude Include="Include\CmViewport.h" />
     <ClInclude Include="Include\CmWindowEventUtilities.h" />
     <ClInclude Include="Include\CmResourceST.h" />
+    <ClInclude Include="Include\CmGameObject.h" />
     <ClInclude Include="Include\stdafx.h" />
     <ClInclude Include="Include\targetver.h" />
   </ItemGroup>
@@ -170,6 +171,7 @@
     <ClCompile Include="Source\CmVertexIndexData.cpp" />
     <ClCompile Include="Source\CmViewport.cpp" />
     <ClCompile Include="Source\CmWindowEventUtilities.cpp" />
+    <ClCompile Include="Source\CmGameObject.cpp" />
     <ClCompile Include="Source\stdafx.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 12 - 0
CamelotRenderer/CamelotRenderer.vcxproj.filters

@@ -52,6 +52,12 @@
     <Filter Include="Source Files\Cg">
       <UniqueIdentifier>{eeb7d0ea-f842-4f3c-b462-135af2eff493}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\Scene">
+      <UniqueIdentifier>{327fbccb-fd0d-4fb1-af08-5d00cd7d56a7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Scene">
+      <UniqueIdentifier>{2211ce11-e426-4aad-a5e6-73727d44bb98}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <Text Include="TODO.txt" />
@@ -184,6 +190,9 @@
     <ClInclude Include="Include\CmCgProgramFactory.h">
       <Filter>Header Files\Cg</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmGameObject.h">
+      <Filter>Header Files\Scene</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CamelotRenderer.cpp">
@@ -285,5 +294,8 @@
     <ClCompile Include="Source\CmCgProgramFactory.cpp">
       <Filter>Source Files\Cg</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmGameObject.cpp">
+      <Filter>Source Files\Scene</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 117 - 0
CamelotRenderer/Include/CmGameObject.h

@@ -0,0 +1,117 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmMatrix4.h"
+#include "CmVector3.h"
+#include "CmQuaternion.h"
+
+namespace CamelotEngine
+{
+	class CM_EXPORT GameObject
+	{
+	public:
+		GameObject(const String& name);
+		~GameObject();
+
+		/************************************************************************/
+		/* 								Transform	                     		*/
+		/************************************************************************/
+	public:
+		void setPosition(const Vector3& position);
+		Vector3 getPosition() const { return mPosition; }
+
+		void setRotation(const Quaternion& rotation);
+		Quaternion getRotation() const { return mRotation; }
+
+		void setScale(const Vector3& scale);
+		Vector3 getScale() const { return mScale; }
+
+		const Matrix4& getWorldTfrm();
+		const Matrix4& getLocalTfrm();
+
+	private:
+		String mName;
+
+		Vector3 mPosition;
+		Quaternion mRotation;
+		Vector3 mScale;
+
+		Matrix4 mCachedLocalTfrm;
+		bool mIsCachedLocalTfrmUpToDate;
+
+		Matrix4 mCachedWorldTfrm;
+		bool mIsCachedWorldTfrmUpToDate;
+
+		Matrix4 mCustomWorldTfrm; // TODO
+		bool mIsCustomTfrmModeActive; // TODO
+
+		void markTfrmDirty();
+		void updateLocalTfrm();
+		void updateWorldTfrm();
+
+		/************************************************************************/
+		/* 								Hierarchy	                     		*/
+		/************************************************************************/
+	public:
+		/**
+		 * @brief	Changes the parent of this object. Also removes the object from the current parent,
+		 * 			and assigns it to the new parent.
+		 *
+		 * @param [in]	parent	New parent.
+		 */
+		void setParent(GameObject* parent);
+
+		/**
+		 * @brief	Gets the parent of this object.
+		 *
+		 * @return	Parent object, or nullptr if this GameObject is at root level.
+		 */
+		GameObject* getParent() const { return mParent; }
+
+		/**
+		 * @brief	Gets a child of this item.
+		 *
+		 * @param	idx	The zero based index of the child.
+		 *
+		 * @return	GameObject of the child.
+		 * 			
+		 * @throws ERR_INVALIDPARAMS If the index is out of range.
+		 */
+		GameObject* getChild(unsigned int idx) const;
+
+		/**
+		 * @brief	Find the index of the specified child. Don't persist this value as
+		 * 			it may change whenever you add/remove children.
+		 *
+		 * @param	child	The child to look for.
+		 *
+		 * @return	The zero-based index of the found child, or -1 if no match was found.
+		 */
+		int indexOfChild(const GameObject* child) const;
+
+		/**
+		 * @brief	Gets the number of all child GameObjects.
+		 */
+		int getNumChildren() const { return mChildren.size(); }
+
+	private:
+		GameObject* mParent;
+		vector<GameObject*>::type mChildren;
+
+		/**
+		 * @brief	Adds a child to the child array. This method doesn't check for null or duplicate values.
+		 *
+		 * @param [in]	object	New child.
+		 */
+		void addChild(GameObject* object);
+		
+		/**
+		 * @brief	Removes the child from the object. 
+		 *
+		 * @param [in]	object	Child to remove.
+		 * 					
+		 * @throws INTERNAL_ERROR If the provided child isn't a child of the current object.
+		 */
+		void removeChild(GameObject* object);
+	};
+}

+ 154 - 0
CamelotRenderer/Source/CmGameObject.cpp

@@ -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.");
+		}
+	}
+}