Browse Source

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.
vectorfields
Vladimír Vondruš 14 years ago
parent
commit
58abfdeeee
  1. 8
      src/SceneGraph/Camera.cpp
  2. 42
      src/SceneGraph/Object.cpp
  3. 30
      src/SceneGraph/Object.h
  4. 11
      src/SceneGraph/Test/ObjectTest.cpp
  5. 4
      src/SceneGraph/Test/SceneTest.cpp

8
src/SceneGraph/Camera.cpp

@ -72,13 +72,13 @@ template<class MatrixType, class VectorType, class ObjectType, class SceneType,
} }
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::drawChildren(ObjectType* object, const MatrixType& transformationMatrix) { template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::drawChildren(ObjectType* object, const MatrixType& transformationMatrix) {
for(typename set<ObjectType*>::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 */ /* Transformation matrix for the object */
MatrixType matrix = transformationMatrix*(*it)->transformation(); MatrixType matrix = transformationMatrix*i->transformation();
/* Draw the object and its children */ /* Draw the object and its children */
(*it)->draw(matrix, static_cast<CameraType*>(this)); i->draw(matrix, static_cast<CameraType*>(this));
drawChildren(*it, matrix); drawChildren(i, matrix);
} }
} }

42
src/SceneGraph/Object.cpp

@ -27,28 +27,23 @@ namespace Magnum { namespace SceneGraph {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setParent(ObjectType* parent) { template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setParent(ObjectType* parent) {
/* Skip if nothing to do or this is scene */ /* Skip if nothing to do or this is scene */
if(_parent == parent || isScene()) return static_cast<ObjectType*>(this); if(this->parent() == parent || isScene()) return static_cast<ObjectType*>(this);
/* Add the object to children list of new parent */ /* Only Fry can be his own grandfather */
if(parent != nullptr) { ObjectType* p = parent;
while(p) {
/* Only Fry can be his own grandfather */ /** @todo Assert for this */
ObjectType* p = parent; if(p == this) return static_cast<ObjectType*>(this);
while(p != nullptr) { p = p->parent();
/** @todo Assert for this */
if(p == this) return static_cast<ObjectType*>(this);
p = p->parent();
}
parent->_children.insert(static_cast<ObjectType*>(this));
} }
/* Remove the object from old parent children list */ /* Remove the object from old parent children list */
if(_parent != nullptr) if(this->parent())
_parent->_children.erase(static_cast<ObjectType*>(this)); this->parent()->cut(static_cast<ObjectType*>(this));
/* Set new parent */ /* Add the object to list of new parent */
_parent = parent; if(parent)
parent->insert(static_cast<ObjectType*>(this));
setDirty(); setDirty();
return static_cast<ObjectType*>(this); return static_cast<ObjectType*>(this);
@ -82,15 +77,6 @@ template<class MatrixType, class VectorType, class ObjectType, class SceneType,
return t; return t;
} }
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::~Object() {
/* Remove the object from parent's children */
setParent(nullptr);
/* Delete all children */
while(!_children.empty())
delete *_children.begin();
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> SceneType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::scene() { template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> SceneType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::scene() {
/* Goes up the family tree until it finds object which is parent of itself /* Goes up the family tree until it finds object which is parent of itself
(that's the scene) */ (that's the scene) */
@ -120,8 +106,8 @@ template<class MatrixType, class VectorType, class ObjectType, class SceneType,
dirty = true; dirty = true;
/* Make all children dirty */ /* Make all children dirty */
for(typename set<ObjectType*>::iterator it = _children.begin(); it != _children.end(); ++it) for(ObjectType* i = firstChild(); i; i = i->nextSibling())
(*it)->setDirty(); i->setDirty();
} }
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setClean() { template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setClean() {

30
src/SceneGraph/Object.h

@ -19,7 +19,7 @@
* @brief Class Magnum::SceneGraph::Object * @brief Class Magnum::SceneGraph::Object
*/ */
#include <set> #include <Containers/DoubleLinkedList.h>
#include "Magnum.h" #include "Magnum.h"
@ -43,7 +43,7 @@ namespace Magnum { namespace SceneGraph {
* @todo Transform transformation when changing parent, so the object stays in * @todo Transform transformation when changing parent, so the object stays in
* place. * place.
*/ */
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Object { template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Object: public Corrade::Containers::DoubleLinkedList<ObjectType>, public Corrade::Containers::DoubleLinkedListItem<ObjectType, ObjectType> {
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
Object(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete; Object(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete;
Object(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete; Object(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete;
@ -58,7 +58,7 @@ template<class MatrixType, class VectorType, class ObjectType, class SceneType,
* *
* Sets all transformations to their default values. * Sets all transformations to their default values.
*/ */
inline Object(ObjectType* parent = nullptr): _parent(nullptr), dirty(true) { inline Object(ObjectType* parent = nullptr): dirty(true) {
setParent(parent); setParent(parent);
} }
@ -68,7 +68,7 @@ template<class MatrixType, class VectorType, class ObjectType, class SceneType,
* Removes itself from parent's children list and destroys all own * Removes itself from parent's children list and destroys all own
* children. * children.
*/ */
virtual ~Object(); virtual inline ~Object() {}
/** @{ @name Scene hierarchy */ /** @{ @name Scene hierarchy */
@ -81,11 +81,23 @@ template<class MatrixType, class VectorType, class ObjectType, class SceneType,
*/ */
SceneType* scene(); SceneType* scene();
/** @brief Parent object */ /** @brief Parent object or `nullptr`, if this is root object */
inline ObjectType* parent() { return _parent; } inline ObjectType* parent() { return Corrade::Containers::DoubleLinkedListItem<ObjectType, ObjectType>::list(); }
/** @brief Child objects */ /** @brief Previous sibling object or `nullptr`, if this is first object */
inline const std::set<ObjectType*>& children() { return _children; } inline ObjectType* previousSibling() { return Corrade::Containers::DoubleLinkedListItem<ObjectType, ObjectType>::previous(); }
/** @brief Next sibling object or `nullptr`, if this is last object */
inline ObjectType* nextSibling() { return Corrade::Containers::DoubleLinkedListItem<ObjectType, ObjectType>::next(); }
/** @brief Whether this object has children */
inline bool hasChildren() const { return !Corrade::Containers::DoubleLinkedList<ObjectType>::isEmpty(); }
/** @brief First child object or `nullptr`, if this object has no children */
inline ObjectType* firstChild() { return Corrade::Containers::DoubleLinkedList<ObjectType>::first(); }
/** @brief Last child object or `nullptr`, if this object has no children */
inline ObjectType* lastChild() { return Corrade::Containers::DoubleLinkedList<ObjectType>::last(); }
/** @brief Set parent object */ /** @brief Set parent object */
ObjectType* setParent(ObjectType* parent); ObjectType* setParent(ObjectType* parent);
@ -230,8 +242,6 @@ template<class MatrixType, class VectorType, class ObjectType, class SceneType,
/*@}*/ /*@}*/
private: private:
ObjectType* _parent;
std::set<ObjectType*> _children;
MatrixType _transformation; MatrixType _transformation;
bool dirty; bool dirty;
}; };

11
src/SceneGraph/Test/ObjectTest.cpp

@ -41,7 +41,10 @@ void ObjectTest::parenting() {
Object3D* childTwo = new Object3D(&root); Object3D* childTwo = new Object3D(&root);
CORRADE_VERIFY(childOne->parent() == &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 */ /* A object cannot be parent of itself */
childOne->setParent(childOne); childOne->setParent(childOne);
@ -53,12 +56,12 @@ void ObjectTest::parenting() {
/* Reparent to another */ /* Reparent to another */
childTwo->setParent(childOne); childTwo->setParent(childOne);
CORRADE_VERIFY(root.children().size() == 1 && *root.children().begin() == childOne); CORRADE_VERIFY(root.firstChild() == childOne && root.firstChild()->nextSibling() == nullptr);
CORRADE_VERIFY(childOne->children().size() == 1 && *childOne->children().begin() == childTwo); CORRADE_VERIFY(childOne->firstChild() == childTwo && childOne->firstChild()->nextSibling() == nullptr);
/* Delete child */ /* Delete child */
delete childTwo; delete childTwo;
CORRADE_VERIFY(childOne->children().empty()); CORRADE_VERIFY(!childOne->hasChildren());
} }
void ObjectTest::transformation() { void ObjectTest::transformation() {

4
src/SceneGraph/Test/SceneTest.cpp

@ -43,8 +43,8 @@ void SceneTest::parent() {
Object3D object; Object3D object;
scenePointer->setParent(&object); scenePointer->setParent(&object);
CORRADE_VERIFY(scene.parent() == nullptr); CORRADE_VERIFY(scene.parent() == nullptr);
CORRADE_VERIFY(scene.children().empty()); CORRADE_VERIFY(!scene.hasChildren());
CORRADE_VERIFY(object.children().empty()); CORRADE_VERIFY(!object.hasChildren());
} }
}}} }}}

Loading…
Cancel
Save