Browse Source

Creating base class for scene objects

Panagiotis Christopoulos Charitos 12 years ago
parent
commit
5b97723b55

+ 2 - 10
include/anki/scene/SceneNode.h

@@ -3,6 +3,7 @@
 
 #include "anki/scene/Property.h"
 #include "anki/scene/Common.h"
+#include "anki/scene/SceneObject.h"
 #include <string>
 
 namespace anki {
@@ -21,7 +22,7 @@ class RigidBody;
 /// @{
 
 /// Interface class backbone of scene
-class SceneNode: public PropertyMap
+class SceneNode: public SceneObject, public PropertyMap
 {
 public:
 	/// @name Constructors/Destructor
@@ -44,15 +45,6 @@ public:
 	{
 		return name.c_str();
 	}
-
-	SceneGraph& getSceneGraph()
-	{
-		return *scene;
-	}
-
-	SceneAllocator<U8> getSceneAllocator() const;
-
-	SceneAllocator<U8> getSceneFrameAllocator() const;
 	/// @}
 
 	/// @name Accessors of components

+ 50 - 0
include/anki/scene/SceneObject.h

@@ -0,0 +1,50 @@
+#ifndef ANKI_SCENE_SCENE_OBJECT_H
+#define ANKI_SCENE_SCENE_OBJECT_H
+
+#include "anki/scene/Common.h"
+#include "anki/util/Object.h"
+
+namespace anki {
+
+// Forward
+class SceneGraph;
+
+/// The SceneObject deleter
+template<typename T, typename Alloc>
+struct SceneObjectDeleter
+{
+	void operator()(T* x)
+	{
+		Alloc alloc = x->getSceneAllocator();
+
+		alloc.destroy(x);
+		alloc.deallocate(x, 1);
+	}
+};
+
+/// The base of all scene related objects
+class SceneObject: public Object<SceneObject, SceneAllocator<SceneObject>,
+	SceneObjectDeleter<SceneObject, SceneAllocator<SceneObject>>>
+{
+public:
+	typedef Object<SceneObject, SceneAllocator<SceneObject>,
+		SceneObjectDeleter<SceneObject, SceneAllocator<SceneObject>>> Base;
+
+	SceneObject(SceneObject* parent, SceneGraph* scene);
+
+	SceneAllocator<U8> getSceneAllocator() const;
+
+	SceneAllocator<U8> getSceneFrameAllocator() const;
+
+	SceneGraph& getSceneGraph()
+	{
+		return *scene;
+	}
+
+public:
+	SceneGraph* scene;
+};
+
+} // end namespace anki
+
+#endif

+ 39 - 55
include/anki/util/Object.h

@@ -15,8 +15,19 @@ namespace anki {
 /// @addtogroup patterns
 /// @{
 
+/// The default object deleter. It does nothing
+template<typename T>
+struct ObjectDeleter
+{
+	void operator()(T*)
+	{
+		// Do nothing
+	}
+};
+
 /// A hierarchical object
-template<typename T, typename Alloc = Allocator<T>>
+template<typename T, typename Alloc = Allocator<T>,
+	typename Deleter = ObjectDeleter<T>>
 class Object: public NonCopyable
 {
 public:
@@ -24,8 +35,9 @@ public:
 	typedef Vector<Value*, Alloc> Container;
 
 	/// Calls addChild if parent is not nullptr
-	Object(Value* parent_, const Alloc& alloc = Alloc())
-		: parent(nullptr), childs(alloc)
+	Object(Value* parent_, const Alloc& alloc = Alloc(),
+		const Deleter& del = Deleter())
+		: parent(nullptr), children(alloc), deleter(del)
 	{
 		if(parent_ != nullptr)
 		{
@@ -41,10 +53,14 @@ public:
 			parent->removeChild(getSelf());
 		}
 
+		Alloc alloc = children.get_allocator();
+
 		// Remove all children (fast version)
-		for(Value* child : childs)
+		for(Value* child : children)
 		{
 			child->parent = nullptr;
+
+			deleter(child);
 		}
 	}
 
@@ -61,24 +77,29 @@ public:
 
 	typename Container::const_iterator getChildrenBegin() const
 	{
-		return childs.begin();
+		return children.begin();
 	}
 	typename Container::iterator getChildrenBegin()
 	{
-		return childs.begin();
+		return children.begin();
 	}
 	typename Container::const_iterator getChildrenEnd() const
 	{
-		return childs.end();
+		return children.end();
 	}
 	typename Container::iterator getChildrenEnd()
 	{
-		return childs.end();
+		return children.end();
 	}
 
 	PtrSize getChildrenSize() const
 	{
-		return childs.size();
+		return children.size();
+	}
+
+	Alloc getAllocator() const
+	{
+		return children.get_allocator();
 	}
 	/// @}
 
@@ -88,12 +109,12 @@ public:
 		ANKI_ASSERT(child != nullptr && "Null arg");
 		ANKI_ASSERT(child != getSelf() && "Cannot put itself");
 		ANKI_ASSERT(child->parent == nullptr && "Child already has parent");
-		ANKI_ASSERT(child->findChild(getSelf()) == child->childs.end() 
+		ANKI_ASSERT(child->findChild(getSelf()) == child->children.end()
 			&& "Cyclic add");
-		ANKI_ASSERT(findChild(child) == childs.end() && "Already a child");
+		ANKI_ASSERT(findChild(child) == children.end() && "Already a child");
 
 		child->parent = getSelf();
-		childs.push_back(child);
+		children.push_back(child);
 	}
 
 	/// Remove a child
@@ -104,9 +125,9 @@ public:
 
 		typename Container::iterator it = findChild(child);
 
-		ANKI_ASSERT(it != childs.end() && "Child not found");
+		ANKI_ASSERT(it != children.end() && "Child not found");
 
-		childs.erase(it);
+		children.erase(it);
 		child->parent = nullptr;
 	}
 
@@ -116,7 +137,7 @@ public:
 	{
 		vis(*getSelf());
 
-		for(Value* c : childs)
+		for(Value* c : children)
 		{
 			c->visitTreeDepth(vis);
 		}
@@ -124,7 +145,8 @@ public:
 
 private:
 	Value* parent; ///< May be nullptr
-	Container childs;
+	Container children;
+	Deleter deleter;
 
 	/// Cast the Object to the given type
 	Value* getSelf()
@@ -136,49 +158,11 @@ private:
 	typename Container::iterator findChild(Value* child)
 	{
 		typename Container::iterator it =
-			std::find(childs.begin(), childs.end(), child);
+			std::find(children.begin(), children.end(), child);
 		return it;
 	}
 };
 
-/// XXX
-template<typename T, typename Alloc = Allocator<T>>
-class CleanupObject: public Object<T, Alloc>
-{
-public:
-	typedef T Value;
-	typedef Object<Value, Alloc> Base;
-
-	/// @see Object::Object
-	CleanupObject(Value* parent_, const Alloc& alloc = Alloc())
-		: Base(parent_, alloc)
-	{}
-
-	virtual ~CleanupObject()
-	{
-		if(Base::parent != nullptr)
-		{
-			Base::parent->removeChild(Base::getSelf());
-			Base::parent = nullptr;
-		}
-
-		Alloc alloc = Base::childs.get_allocator();
-
-		// Delete all children
-		for(Value* child : Base::childs)
-		{
-			// Set parent to null to prevent the child from removing itself
-			child->parent = nullptr;
-
-			// Destroy
-			alloc.destroy(child);
-			alloc.deallocate(child, 1);
-		}
-
-		Base::childs.clear();
-	}
-};
-
 /// @}
 /// @}
 

+ 1 - 15
src/scene/SceneNode.cpp

@@ -8,7 +8,7 @@ namespace anki {
 
 //==============================================================================
 SceneNode::SceneNode(const char* name_, SceneGraph* scene_)
-	: scene(scene_), name(name_, scene_->getAllocator())
+	: SceneObject(nullptr, scene_), name(name_, scene_->getAllocator())
 {
 	name.shrink_to_fit(); // Do that first
 	scene->registerNode(this);
@@ -28,20 +28,6 @@ SceneNode::~SceneNode()
 	}
 }
 
-//==============================================================================
-SceneAllocator<U8> SceneNode::getSceneAllocator() const
-{
-	ANKI_ASSERT(scene);
-	return scene->getAllocator();
-}
-
-//==============================================================================
-SceneAllocator<U8> SceneNode::getSceneFrameAllocator() const
-{
-	ANKI_ASSERT(scene);
-	return scene->getFrameAllocator();
-}
-
 //==============================================================================
 U32 SceneNode::getLastUpdateFrame()
 {

+ 25 - 0
src/scene/SceneObject.cpp

@@ -0,0 +1,25 @@
+#include "anki/scene/SceneObject.h"
+#include "anki/scene/SceneGraph.h"
+
+namespace anki {
+
+//==============================================================================
+SceneObject::SceneObject(SceneObject* parent, SceneGraph* scene_)
+	: Base(parent, scene_->getAllocator()), scene(scene_)
+{}
+
+//==============================================================================
+SceneAllocator<U8> SceneObject::getSceneAllocator() const
+{
+	ANKI_ASSERT(scene);
+	return scene->getAllocator();
+}
+
+//==============================================================================
+SceneAllocator<U8> SceneObject::getSceneFrameAllocator() const
+{
+	ANKI_ASSERT(scene);
+	return scene->getFrameAllocator();
+}
+
+} // end namespace anki

+ 80 - 0
tests/util/Object.cpp

@@ -0,0 +1,80 @@
+#include "tests/framework/Framework.h"
+#include "anki/util/Object.h"
+
+using namespace anki;
+
+template<typename T, typename Alloc>
+struct Deleter
+{
+	void operator()(T* x)
+	{
+		std::cout << __PRETTY_FUNCTION__ << std::endl;
+
+		Alloc alloc = x->getAllocator();
+
+		alloc.destroy(x);
+		alloc.deallocate(x, 1);
+	}
+};
+
+struct Foo2: public Object<Foo2, Allocator<Foo2>,
+	Deleter<Foo2, Allocator<Foo2>>>
+{
+	typedef Object<Foo2, Allocator<Foo2>,
+		Deleter<Foo2, Allocator<Foo2>>> Base;
+
+	int x = 666;
+	static int constructorCallCount;
+	static int destructorCallCount;
+
+	Foo2(Foo2* parent)
+		: Base(parent)
+	{
+		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		++constructorCallCount;
+	}
+
+	~Foo2()
+	{
+		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		++destructorCallCount;
+	}
+
+	Foo2& operator=(const Foo2& b)
+	{
+		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		x = b.x;
+		return *this;
+	}
+
+	Foo2& operator=(Foo2&& b)
+	{
+		std::cout << __PRETTY_FUNCTION__ << std::endl;
+		x = b.x;
+		b.x = 0;
+		return *this;
+	}
+
+	static void reset()
+	{
+		destructorCallCount = constructorCallCount = 0;
+	}
+};
+
+int Foo2::constructorCallCount = 0;
+int Foo2::destructorCallCount = 0;
+
+ANKI_TEST(Object, Test)
+{
+
+	Foo2* a = new Foo2(nullptr);
+
+	Foo2* b = new Foo2(a);
+	Foo2* c = new Foo2(b);
+
+	(void)c;
+
+	delete a;
+}
+
+