From c38a1993dba07a61668a3d9eeae321706b76b5eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 31 Dec 2010 15:57:52 +0100 Subject: [PATCH] More robust object parenting. --- src/Object.cpp | 16 ++++++++++++---- src/Object.h | 6 +++++- src/Scene.h | 3 ++- src/Test/CMakeLists.txt | 1 + src/Test/ObjectTest.cpp | 8 ++++++++ src/Test/SceneTest.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/Test/SceneTest.h | 33 +++++++++++++++++++++++++++++++++ 7 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/Test/SceneTest.cpp create mode 100644 src/Test/SceneTest.h diff --git a/src/Object.cpp b/src/Object.cpp index 2dee248b5..eb948d854 100644 --- a/src/Object.cpp +++ b/src/Object.cpp @@ -22,15 +22,23 @@ namespace Magnum { void Object::setParent(Object* parent) { if(_parent == parent) return; - /* Remove the object from old parent children list */ - if(_parent != 0) - _parent->_children.erase(this); - /* Set new parent and add the object to new parent children list */ if(parent != 0) { + + /* Only Fry can be his own grandfather */ + Object* p = parent; + while(p != 0 && p->parent() != p) { + if(p == this) return; + p = p->parent(); + } + parent->_children.insert(this); } + /* Remove the object from old parent children list */ + if(_parent != 0) + _parent->_children.erase(this); + _parent = parent; } diff --git a/src/Object.h b/src/Object.h index 3dec16f00..489a5b749 100644 --- a/src/Object.h +++ b/src/Object.h @@ -25,6 +25,8 @@ namespace Magnum { +class Scene; + /** * @brief Base for all positioned objects * @@ -34,6 +36,8 @@ namespace Magnum { class Object { DISABLE_COPY(Object) + friend class Scene; + public: /** * @brief Constructor @@ -60,7 +64,7 @@ class Object { inline const std::set& children() const { return _children; } /** @brief Set parent object */ - void setParent(Object* parent); + virtual void setParent(Object* parent); /** @brief Transformation matrix */ inline Matrix4 transformation() const { return _transformation; } diff --git a/src/Scene.h b/src/Scene.h index 372d3da8c..0c832347d 100644 --- a/src/Scene.h +++ b/src/Scene.h @@ -26,7 +26,7 @@ namespace Magnum { /** @brief Scene */ class Scene: public Object { private: - Object::setParent; + virtual void setParent(Object* parent) {} Object::setTransformation; public: @@ -39,6 +39,7 @@ class Scene: public Object { /** @brief Constructor */ inline Scene(): Object(0), _features(0), _camera(0) { + _parent = this; setClearColor(0.1f, 0.1f, 0.1f, 1.0f); } diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 919f63675..f42e0fa06 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -1,2 +1,3 @@ magnum_add_test(ObjectTest ObjectTest.h ObjectTest.cpp Magnum) magnum_add_test(CameraTest CameraTest.h CameraTest.cpp Magnum) +magnum_add_test(SceneTest SceneTest.h SceneTest.cpp Magnum) diff --git a/src/Test/ObjectTest.cpp b/src/Test/ObjectTest.cpp index 3a13d2b63..12f02dca3 100644 --- a/src/Test/ObjectTest.cpp +++ b/src/Test/ObjectTest.cpp @@ -30,6 +30,14 @@ void ObjectTest::parenting() { QVERIFY(childOne->parent() == &root); QVERIFY(root.children().size() == 2); + /* A object cannot be parent of itself */ + childOne->setParent(childOne); + QVERIFY(childOne->parent() == &root); + + /* In fact, cyclic dependencies are not allowed at all */ + root.setParent(childTwo); + QVERIFY(root.parent() == 0); + /* Reparent to another */ childTwo->setParent(childOne); QVERIFY(root.children().size() == 1 && *root.children().begin() == childOne); diff --git a/src/Test/SceneTest.cpp b/src/Test/SceneTest.cpp new file mode 100644 index 000000000..6f031bbf6 --- /dev/null +++ b/src/Test/SceneTest.cpp @@ -0,0 +1,38 @@ +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "SceneTest.h" + +#include + +#include "Scene.h" + +QTEST_APPLESS_MAIN(Magnum::Test::SceneTest) + +namespace Magnum { namespace Test { + +void SceneTest::parent() { + Scene scene; + + QVERIFY(scene.parent() == &scene); + + /* Scene parent cannot be changed */ + Object* scenePointer = &scene; + Object* object = new Object; + scenePointer->setParent(object); + QVERIFY(scene.parent() == &scene); +} + +}} diff --git a/src/Test/SceneTest.h b/src/Test/SceneTest.h new file mode 100644 index 000000000..3c3a50e9a --- /dev/null +++ b/src/Test/SceneTest.h @@ -0,0 +1,33 @@ +#ifndef Magnum_Test_SceneTest_h +#define Magnum_Test_SceneTest_h +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include + +#include "Object.h" + +namespace Magnum { namespace Test { + +class SceneTest: public QObject { + Q_OBJECT + + private slots: + void parent(); +}; + +}} + +#endif