From 58abfdeeeef74b371d7c88073aca98c42721e580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 17 Aug 2012 22:08:40 +0200 Subject: [PATCH] SceneGraph: Using linked list from Corrade instead of std::set. Resulting (debug) executables are ~100 kB smaller, all operations which were previously logarithmic are now done in constant time and the whole implementation is a lot simpler. --- src/SceneGraph/Camera.cpp | 8 +++--- src/SceneGraph/Object.cpp | 42 ++++++++++-------------------- src/SceneGraph/Object.h | 30 ++++++++++++++------- src/SceneGraph/Test/ObjectTest.cpp | 11 +++++--- src/SceneGraph/Test/SceneTest.cpp | 4 +-- 5 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/SceneGraph/Camera.cpp b/src/SceneGraph/Camera.cpp index 46db61799..6f1101bcf 100644 --- a/src/SceneGraph/Camera.cpp +++ b/src/SceneGraph/Camera.cpp @@ -72,13 +72,13 @@ template void Camera::drawChildren(ObjectType* object, const MatrixType& transformationMatrix) { - for(typename set::const_iterator it = object->children().begin(); it != object->children().end(); ++it) { + for(ObjectType* i = object->firstChild(); i; i = i->nextSibling()) { /* Transformation matrix for the object */ - MatrixType matrix = transformationMatrix*(*it)->transformation(); + MatrixType matrix = transformationMatrix*i->transformation(); /* Draw the object and its children */ - (*it)->draw(matrix, static_cast(this)); - drawChildren(*it, matrix); + i->draw(matrix, static_cast(this)); + drawChildren(i, matrix); } } diff --git a/src/SceneGraph/Object.cpp b/src/SceneGraph/Object.cpp index c3831644b..f3de86b1c 100644 --- a/src/SceneGraph/Object.cpp +++ b/src/SceneGraph/Object.cpp @@ -27,28 +27,23 @@ namespace Magnum { namespace SceneGraph { template ObjectType* Object::setParent(ObjectType* parent) { /* Skip if nothing to do or this is scene */ - if(_parent == parent || isScene()) return static_cast(this); + if(this->parent() == parent || isScene()) return static_cast(this); - /* Add the object to children list of new parent */ - if(parent != nullptr) { - - /* Only Fry can be his own grandfather */ - ObjectType* p = parent; - while(p != nullptr) { - /** @todo Assert for this */ - if(p == this) return static_cast(this); - p = p->parent(); - } - - parent->_children.insert(static_cast(this)); + /* Only Fry can be his own grandfather */ + ObjectType* p = parent; + while(p) { + /** @todo Assert for this */ + if(p == this) return static_cast(this); + p = p->parent(); } /* Remove the object from old parent children list */ - if(_parent != nullptr) - _parent->_children.erase(static_cast(this)); + if(this->parent()) + this->parent()->cut(static_cast(this)); - /* Set new parent */ - _parent = parent; + /* Add the object to list of new parent */ + if(parent) + parent->insert(static_cast(this)); setDirty(); return static_cast(this); @@ -82,15 +77,6 @@ template Object::~Object() { - /* Remove the object from parent's children */ - setParent(nullptr); - - /* Delete all children */ - while(!_children.empty()) - delete *_children.begin(); -} - template SceneType* Object::scene() { /* Goes up the family tree until it finds object which is parent of itself (that's the scene) */ @@ -120,8 +106,8 @@ template::iterator it = _children.begin(); it != _children.end(); ++it) - (*it)->setDirty(); + for(ObjectType* i = firstChild(); i; i = i->nextSibling()) + i->setDirty(); } template void Object::setClean() { diff --git a/src/SceneGraph/Object.h b/src/SceneGraph/Object.h index 6a1ccd02d..de69e990a 100644 --- a/src/SceneGraph/Object.h +++ b/src/SceneGraph/Object.h @@ -19,7 +19,7 @@ * @brief Class Magnum::SceneGraph::Object */ -#include +#include #include "Magnum.h" @@ -43,7 +43,7 @@ namespace Magnum { namespace SceneGraph { * @todo Transform transformation when changing parent, so the object stays in * place. */ -template class SCENEGRAPH_EXPORT Object { +template class SCENEGRAPH_EXPORT Object: public Corrade::Containers::DoubleLinkedList, public Corrade::Containers::DoubleLinkedListItem { #ifndef DOXYGEN_GENERATING_OUTPUT Object(const Object& other) = delete; Object(Object&& other) = delete; @@ -58,7 +58,7 @@ template::list(); } - /** @brief Child objects */ - inline const std::set& children() { return _children; } + /** @brief Previous sibling object or `nullptr`, if this is first object */ + inline ObjectType* previousSibling() { return Corrade::Containers::DoubleLinkedListItem::previous(); } + + /** @brief Next sibling object or `nullptr`, if this is last object */ + inline ObjectType* nextSibling() { return Corrade::Containers::DoubleLinkedListItem::next(); } + + /** @brief Whether this object has children */ + inline bool hasChildren() const { return !Corrade::Containers::DoubleLinkedList::isEmpty(); } + + /** @brief First child object or `nullptr`, if this object has no children */ + inline ObjectType* firstChild() { return Corrade::Containers::DoubleLinkedList::first(); } + + /** @brief Last child object or `nullptr`, if this object has no children */ + inline ObjectType* lastChild() { return Corrade::Containers::DoubleLinkedList::last(); } /** @brief Set parent object */ ObjectType* setParent(ObjectType* parent); @@ -230,8 +242,6 @@ template _children; MatrixType _transformation; bool dirty; }; diff --git a/src/SceneGraph/Test/ObjectTest.cpp b/src/SceneGraph/Test/ObjectTest.cpp index 06248e097..77f5a7afa 100644 --- a/src/SceneGraph/Test/ObjectTest.cpp +++ b/src/SceneGraph/Test/ObjectTest.cpp @@ -41,7 +41,10 @@ void ObjectTest::parenting() { Object3D* childTwo = new Object3D(&root); CORRADE_VERIFY(childOne->parent() == &root); - CORRADE_COMPARE(root.children().size(), 2); + CORRADE_VERIFY(childTwo->parent() == &root); + CORRADE_VERIFY(root.firstChild() == childOne); + CORRADE_VERIFY(root.lastChild() == childTwo); + CORRADE_VERIFY(root.firstChild()->nextSibling() == root.lastChild()); /* A object cannot be parent of itself */ childOne->setParent(childOne); @@ -53,12 +56,12 @@ void ObjectTest::parenting() { /* Reparent to another */ childTwo->setParent(childOne); - CORRADE_VERIFY(root.children().size() == 1 && *root.children().begin() == childOne); - CORRADE_VERIFY(childOne->children().size() == 1 && *childOne->children().begin() == childTwo); + CORRADE_VERIFY(root.firstChild() == childOne && root.firstChild()->nextSibling() == nullptr); + CORRADE_VERIFY(childOne->firstChild() == childTwo && childOne->firstChild()->nextSibling() == nullptr); /* Delete child */ delete childTwo; - CORRADE_VERIFY(childOne->children().empty()); + CORRADE_VERIFY(!childOne->hasChildren()); } void ObjectTest::transformation() { diff --git a/src/SceneGraph/Test/SceneTest.cpp b/src/SceneGraph/Test/SceneTest.cpp index a3f859aa6..65bff5daa 100644 --- a/src/SceneGraph/Test/SceneTest.cpp +++ b/src/SceneGraph/Test/SceneTest.cpp @@ -43,8 +43,8 @@ void SceneTest::parent() { Object3D object; scenePointer->setParent(&object); CORRADE_VERIFY(scene.parent() == nullptr); - CORRADE_VERIFY(scene.children().empty()); - CORRADE_VERIFY(object.children().empty()); + CORRADE_VERIFY(!scene.hasChildren()); + CORRADE_VERIFY(!object.hasChildren()); } }}}