Procházet zdrojové kódy

Few more scene/gameobject related changes

Marko Pintera před 13 roky
rodič
revize
0c7f1425ac

+ 1 - 0
CamelotRenderer/CamelotRenderer.vcxproj

@@ -125,6 +125,7 @@
     <ClInclude Include="Include\CmRenderWindow.h" />
     <ClInclude Include="Include\CmRenderWindow.h" />
     <ClInclude Include="Include\CmResource.h" />
     <ClInclude Include="Include\CmResource.h" />
     <ClInclude Include="Include\CmResources.h" />
     <ClInclude Include="Include\CmResources.h" />
+    <ClInclude Include="Include\CmSceneManager.h" />
     <ClInclude Include="Include\CmSpecificImporter.h" />
     <ClInclude Include="Include\CmSpecificImporter.h" />
     <ClInclude Include="Include\CmTexture.h" />
     <ClInclude Include="Include\CmTexture.h" />
     <ClInclude Include="Include\CmTextureManager.h" />
     <ClInclude Include="Include\CmTextureManager.h" />

+ 3 - 0
CamelotRenderer/CamelotRenderer.vcxproj.filters

@@ -196,6 +196,9 @@
     <ClInclude Include="Include\CmComponent.h">
     <ClInclude Include="Include\CmComponent.h">
       <Filter>Header Files\Scene</Filter>
       <Filter>Header Files\Scene</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmSceneManager.h">
+      <Filter>Source Files\Scene</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CamelotRenderer.cpp">
     <ClCompile Include="Source\CamelotRenderer.cpp">

+ 11 - 5
CamelotRenderer/Include/CmGameObject.h

@@ -11,13 +11,19 @@ namespace CamelotEngine
 {
 {
 	class CM_EXPORT GameObject
 	class CM_EXPORT GameObject
 	{
 	{
+		friend class SceneManager;
 	public:
 	public:
-		GameObject(const String& name);
+		static GameObjectPtr create(const String& name);
 		~GameObject();
 		~GameObject();
 
 
 		void destroy();
 		void destroy();
+		bool isDestroyed() { return mIsDestroyed; }
 
 
 	private:
 	private:
+		GameObject(const String& name);
+		static GameObjectPtr createInternal(const String& name);
+
+		std::weak_ptr<GameObject> mThis;
 		bool mIsDestroyed;
 		bool mIsDestroyed;
 
 
 		/************************************************************************/
 		/************************************************************************/
@@ -73,7 +79,7 @@ namespace CamelotEngine
 		 *
 		 *
 		 * @return	Parent object, or nullptr if this GameObject is at root level.
 		 * @return	Parent object, or nullptr if this GameObject is at root level.
 		 */
 		 */
-		GameObjectPtr getParent() const { return mParent; }
+		GameObjectPtr getParent() const { return mParent.lock(); }
 
 
 		/**
 		/**
 		 * @brief	Gets a child of this item.
 		 * @brief	Gets a child of this item.
@@ -102,7 +108,7 @@ namespace CamelotEngine
 		int getNumChildren() const { return mChildren.size(); }
 		int getNumChildren() const { return mChildren.size(); }
 
 
 	private:
 	private:
-		GameObjectPtr mParent;
+		std::weak_ptr<GameObject> mParent;
 		vector<GameObjectPtr>::type mChildren;
 		vector<GameObjectPtr>::type mChildren;
 
 
 		/**
 		/**
@@ -110,7 +116,7 @@ namespace CamelotEngine
 		 *
 		 *
 		 * @param [in]	object	New child.
 		 * @param [in]	object	New child.
 		 */
 		 */
-		void addChild(GameObject* object);
+		void addChild(GameObjectPtr object);
 		
 		
 		/**
 		/**
 		 * @brief	Removes the child from the object. 
 		 * @brief	Removes the child from the object. 
@@ -119,7 +125,7 @@ namespace CamelotEngine
 		 * 					
 		 * 					
 		 * @throws INTERNAL_ERROR If the provided child isn't a child of the current object.
 		 * @throws INTERNAL_ERROR If the provided child isn't a child of the current object.
 		 */
 		 */
-		void removeChild(GameObject* object);
+		void removeChild(GameObjectPtr object);
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								Component	                     		*/
 		/* 								Component	                     		*/

+ 1 - 0
CamelotRenderer/Include/CmPrerequisites.h

@@ -105,6 +105,7 @@ namespace CamelotEngine {
 	// Scene
 	// Scene
 	class GameObject;
 	class GameObject;
 	class Component;
 	class Component;
+	class SceneManager;
 }
 }
 
 
 /* Shared pointer typedefs*/
 /* Shared pointer typedefs*/

+ 38 - 0
CamelotRenderer/Include/CmSceneManager.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmModule.h"
+
+namespace CamelotEngine
+{
+	/**
+	 * @brief	Manages all objects in the scene and provides various query methods
+	 * 			for finding objects you need. This is just the base class with basic
+	 * 			query functionality. You should override it with your own version that
+	 * 			implements a spatial data structure of your choice for faster queries.
+	 */
+	class CM_EXPORT SceneManager : public Module<SceneManager>
+	{
+	public:
+		SceneManager();
+		virtual ~SceneManager();
+
+		GameObjectPtr getRootNode() const { return mRootNode; }
+
+	private:
+		friend class GameObject;
+		GameObjectPtr mRootNode;
+
+		/**
+		 * @brief	Register a new node in the scene manager, on the top-most level of the hierarchy.
+		 * 			
+		 * @note	After you add a node in the scene manager, it takes ownership of its memory and is responsible for releasing it.
+		 * 			Do NOT add nodes that have already been added (i.e. if you just want to change their parent). Normally this method will only be called by GameObject.
+		 *
+		 * @param [in]	node	Node you wish to add. It's your responsibility not to add duplicate or null nodes. This method won't check.
+		 */
+		void registerNewGO(GameObjectPtr node);
+	};
+
+	CM_EXPORT SceneManager& gSceneManager();
+}

+ 5 - 0
CamelotRenderer/Source/CmApplication.cpp

@@ -12,6 +12,7 @@
 #include "CmHighLevelGpuProgramManager.h"
 #include "CmHighLevelGpuProgramManager.h"
 #include "CmDynLib.h"
 #include "CmDynLib.h"
 #include "CmDynLibManager.h"
 #include "CmDynLibManager.h"
+#include "CmSceneManager.h"
 #include "CmImporter.h"
 #include "CmImporter.h"
 #include "CmResources.h"
 #include "CmResources.h"
 
 
@@ -31,6 +32,8 @@ namespace CamelotEngine
 		RenderSystem* renderSystem = RenderSystemManager::getActive();
 		RenderSystem* renderSystem = RenderSystemManager::getActive();
 		renderSystem->_initialise(false, "Camelot Renderer");
 		renderSystem->_initialise(false, "Camelot Renderer");
 
 
+		SceneManager::startUp(new SceneManager());
+
 		mRenderWindow = renderSystem->_createRenderWindow("Camelot Renderer", 800, 600, false);
 		mRenderWindow = renderSystem->_createRenderWindow("Camelot Renderer", 800, 600, false);
 
 
 		//renderSystem->setAmbientLight(1.0f, 1.0f, 1.0f);
 		//renderSystem->setAmbientLight(1.0f, 1.0f, 1.0f);
@@ -155,6 +158,8 @@ namespace CamelotEngine
 
 
 	void Application::shutDown()
 	void Application::shutDown()
 	{
 	{
+		SceneManager::shutDown();
+
 		if(RenderSystemManager::getActive() != nullptr)
 		if(RenderSystemManager::getActive() != nullptr)
 			RenderSystemManager::getActive()->shutdown();
 			RenderSystemManager::getActive()->shutdown();
 
 

+ 48 - 23
CamelotRenderer/Source/CmGameObject.cpp

@@ -1,5 +1,6 @@
 #include "CmGameObject.h"
 #include "CmGameObject.h"
 #include "CmComponent.h"
 #include "CmComponent.h"
+#include "CmSceneManager.h"
 #include "CmException.h"
 #include "CmException.h"
 #include "CmDebug.h"
 #include "CmDebug.h"
 
 
@@ -10,7 +11,7 @@ namespace CamelotEngine
 		mCachedLocalTfrm(Matrix4::IDENTITY), mIsCachedLocalTfrmUpToDate(false),
 		mCachedLocalTfrm(Matrix4::IDENTITY), mIsCachedLocalTfrmUpToDate(false),
 		mCachedWorldTfrm(Matrix4::IDENTITY), mIsCachedWorldTfrmUpToDate(false),
 		mCachedWorldTfrm(Matrix4::IDENTITY), mIsCachedWorldTfrmUpToDate(false),
 		mCustomWorldTfrm(Matrix4::IDENTITY), mIsCustomTfrmModeActive(false),
 		mCustomWorldTfrm(Matrix4::IDENTITY), mIsCustomTfrmModeActive(false),
-		mParent(nullptr), mIsDestroyed(false)
+		mIsDestroyed(false)
 	{ }
 	{ }
 
 
 	GameObject::~GameObject()
 	GameObject::~GameObject()
@@ -19,13 +20,27 @@ namespace CamelotEngine
 			destroy();
 			destroy();
 	}
 	}
 
 
+	GameObjectPtr GameObject::create(const String& name)
+	{
+		GameObjectPtr newObject = createInternal(name);
+
+		gSceneManager().registerNewGO(newObject);
+
+		return newObject;
+	}
+
+	GameObjectPtr GameObject::createInternal(const String& name)
+	{
+		GameObjectPtr newObject = GameObjectPtr(new GameObject(name));
+		newObject->mThis = newObject;
+
+		return newObject;
+	}
+
 	void GameObject::destroy()
 	void GameObject::destroy()
 	{
 	{
 		mIsDestroyed = true;
 		mIsDestroyed = true;
 
 
-		if(mParent != nullptr)
-			mParent->removeChild(this);
-
 		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
 		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
 			(*iter)->destroy();
 			(*iter)->destroy();
 
 
@@ -35,6 +50,16 @@ namespace CamelotEngine
 			(*iter)->destroy();
 			(*iter)->destroy();
 
 
 		mComponents.clear();
 		mComponents.clear();
+
+		// 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.expired())
+		{
+			GameObjectPtr parentPtr = mParent.lock();
+
+			if(!parentPtr->isDestroyed())
+				parentPtr->removeChild(mThis.lock());
+		}
 	}
 	}
 
 
 	/************************************************************************/
 	/************************************************************************/
@@ -92,8 +117,8 @@ namespace CamelotEngine
 
 
 	void GameObject::updateWorldTfrm()
 	void GameObject::updateWorldTfrm()
 	{
 	{
-		if(mParent != nullptr)
-			mCachedWorldTfrm = getLocalTfrm() * mParent->getWorldTfrm();
+		if(!mParent.expired())
+			mCachedWorldTfrm = getLocalTfrm() * mParent.lock()->getWorldTfrm();
 		else
 		else
 			mCachedWorldTfrm = getLocalTfrm();
 			mCachedWorldTfrm = getLocalTfrm();
 
 
@@ -113,19 +138,19 @@ namespace CamelotEngine
 
 
 	void GameObject::setParent(GameObjectPtr parent)
 	void GameObject::setParent(GameObjectPtr parent)
 	{
 	{
-		if(parent == nullptr)
+		if(parent == nullptr || parent->isDestroyed())
 		{
 		{
 			CM_EXCEPT(InternalErrorException, 
 			CM_EXCEPT(InternalErrorException, 
-				"Parent is not allowed to be NULL.");
+				"Parent is not allowed to be NULL or destroyed.");
 		}
 		}
 
 
-		if(mParent != parent)
+		if(mParent.expired() || mParent.lock() != parent)
 		{
 		{
-			if(mParent != nullptr)
-				mParent->removeChild(this);
+			if(!mParent.expired())
+				mParent.lock()->removeChild(mThis.lock());
 
 
 			if(parent != nullptr)
 			if(parent != nullptr)
-				parent->addChild(this);
+				parent->addChild(mThis.lock());
 
 
 			mParent = parent;
 			mParent = parent;
 			markTfrmDirty();
 			markTfrmDirty();
@@ -154,22 +179,22 @@ namespace CamelotEngine
 		return -1;
 		return -1;
 	}
 	}
 
 
-	void GameObject::addChild(GameObject* object)
+	void GameObject::addChild(GameObjectPtr object)
 	{
 	{
-		//mChildren.push_back(object); // TODO - Not implemented. I'm not sure what's the best way to handle "this" ptr and smart ptrs
+		mChildren.push_back(object); 
 	}
 	}
 
 
-	void GameObject::removeChild(GameObject* object)
+	void GameObject::removeChild(GameObjectPtr object)
 	{
 	{
-		//auto result = find(mChildren.begin(), mChildren.end(), 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.");
-		//}
+		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.");
+		}
 	}
 	}
 
 
 	void GameObject::destroyComponent(ComponentPtr component)
 	void GameObject::destroyComponent(ComponentPtr component)

+ 27 - 0
CamelotRenderer/Source/CmSceneManager.cpp

@@ -0,0 +1,27 @@
+#include "CmSceneManager.h"
+#include "CmGameObject.h"
+
+namespace CamelotEngine
+{
+	SceneManager::SceneManager()
+	{
+		mRootNode = GameObject::createInternal("SceneRoot");
+	}
+
+	SceneManager::~SceneManager()
+	{
+		if(mRootNode != nullptr)
+			mRootNode->destroy();
+	}
+
+	void SceneManager::registerNewGO(GameObjectPtr node) 
+	{ 
+		if(mRootNode) // If root node is null, then this new node is the root node
+			node->setParent(mRootNode);
+	}
+
+	SceneManager& gSceneManager()
+	{
+		return SceneManager::instance();
+	}
+}