From 7fc31139e2f1cc03d7503e43b705cfbe64dbaaf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 13 Apr 2015 00:38:46 +0200 Subject: [PATCH] SceneGraph: added AbstractObject::addFeature(), Object::addChild(). --- doc/scenegraph.dox | 26 +++++++++++++---- src/Magnum/SceneGraph/AbstractObject.h | 10 +++++++ src/Magnum/SceneGraph/Object.h | 10 +++++++ src/Magnum/SceneGraph/Test/ObjectTest.cpp | 34 ++++++++++++++++++++++- 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/doc/scenegraph.dox b/doc/scenegraph.dox index be4d81f9a..aa0a316ea 100644 --- a/doc/scenegraph.dox +++ b/doc/scenegraph.dox @@ -136,14 +136,22 @@ observed through @ref SceneGraph::Object::parent() and @code Scene3D scene; -auto first = new Object3D(&scene); -auto second = new Object3D(first); +Object3D* first = new Object3D{&scene}; +Object3D* second = new Object3D{first}; @endcode The hierarchy takes care of memory management -- when an object is destroyed, all its children are destroyed too. See detailed explanation of @ref scenegraph-object-construction-order "construction and destruction order" -below for information about possible issues. +below for information about possible issues. To reflect the implicit memory +management in the code better, you can use @ref SceneGraph::Object::addChild() +instead of the naked `new` call in the code above: +@code +Scene3D scene; + +Object3D& first = scene.addChild(); +Object3D& second = first.addChild(); +@endcode @section scenegraph-features Object features @@ -177,8 +185,8 @@ feature to an object might look just like the following, as in some cases you don't even need to keep the pointer to it. List of object features is accessible through @ref SceneGraph::Object::features(). @code -Object3D* o; -new MyFeature{*o}; +Object3D& o; +new MyFeature{o, ...}; @endcode Some features are passive, some active. Passive features can be just added to @@ -211,7 +219,13 @@ feature list. Similarly to object hierarchy, when destroying object, all its features (both member and inherited) are destroyed. See detailed explanation of @ref scenegraph-feature-construction-order "construction and destruction order" -for information about possible issues. +for information about possible issues. Also, there is a +@ref SceneGraph::AbstractObject::addFeature() counterpart to +@ref SceneGraph::Object::addChild(): +@code +Object3D& o; +o.addFeature(...); +@endcode @subsection scenegraph-features-caching Transformation caching in features diff --git a/src/Magnum/SceneGraph/AbstractObject.h b/src/Magnum/SceneGraph/AbstractObject.h index 713607168..03c70ce12 100644 --- a/src/Magnum/SceneGraph/AbstractObject.h +++ b/src/Magnum/SceneGraph/AbstractObject.h @@ -147,6 +147,16 @@ template class AbstractObject CORRADE_DEPRECATED("use features().last() instead") const FeatureType* lastFeature() const { return features().last(); } #endif + /** + * @brief Add a feature + * + * Calling `object.addFeature(args...)` is equivalent to + * `new MyFeature{object, args...}`. + */ + template U& addFeature(Args... args) { + return *(new U{*this, std::forward(args)...}); + } + /** * @brief Scene * @return Scene or `nullptr`, if the object is not part of any scene. diff --git a/src/Magnum/SceneGraph/Object.h b/src/Magnum/SceneGraph/Object.h index 47d655701..01977015b 100644 --- a/src/Magnum/SceneGraph/Object.h +++ b/src/Magnum/SceneGraph/Object.h @@ -228,6 +228,16 @@ template class Object: public AbstractObject* lastChild() const { return children().last(); } #endif + /** + * @brief Add a child + * + * Calling `object.addChild(args...)` is equivalent to + * `new MyObject{args..., &object}`. + */ + template T& addChild(Args... args) { + return *(new T{std::forward(args)..., this}); + } + /** * @brief Set parent object * @return Reference to self (for method chaining) diff --git a/src/Magnum/SceneGraph/Test/ObjectTest.cpp b/src/Magnum/SceneGraph/Test/ObjectTest.cpp index 928b21718..4f03fe0a7 100644 --- a/src/Magnum/SceneGraph/Test/ObjectTest.cpp +++ b/src/Magnum/SceneGraph/Test/ObjectTest.cpp @@ -34,7 +34,10 @@ namespace Magnum { namespace SceneGraph { namespace Test { struct ObjectTest: TestSuite::Tester { explicit ObjectTest(); + void addFeature(); + void parenting(); + void addChild(); void scene(); void setParentKeepTransformation(); void absoluteTransformation(); @@ -68,7 +71,10 @@ class CachingObject: public Object3D, AbstractFeature3D { }; ObjectTest::ObjectTest() { - addTests({&ObjectTest::parenting, + addTests({&ObjectTest::addFeature, + + &ObjectTest::parenting, + &ObjectTest::addChild, &ObjectTest::scene, &ObjectTest::setParentKeepTransformation, &ObjectTest::absoluteTransformation, @@ -84,6 +90,19 @@ ObjectTest::ObjectTest() { &ObjectTest::rangeBasedForFeatures}); } +void ObjectTest::addFeature() { + class MyFeature: public AbstractFeature3D { + public: + explicit MyFeature(AbstractObject3D& object, Int, std::string&&): AbstractFeature3D{object} {} + }; + + Object3D o; + CORRADE_VERIFY(o.features().isEmpty()); + MyFeature& f = o.addFeature(0, "hello"); + CORRADE_VERIFY(!o.features().isEmpty()); + CORRADE_COMPARE(&f.object(), &o); +} + void ObjectTest::parenting() { Object3D root; @@ -114,6 +133,19 @@ void ObjectTest::parenting() { CORRADE_VERIFY(childOne->children().isEmpty()); } +void ObjectTest::addChild() { + class MyObject: public Object3D { + public: + explicit MyObject(Int, std::string&&, Object3D* parent = nullptr): Object3D{parent} {} + }; + + Object3D o; + CORRADE_VERIFY(o.children().isEmpty()); + MyObject& p = o.addChild(0, "hello"); + CORRADE_VERIFY(!o.children().isEmpty()); + CORRADE_COMPARE(p.parent(), &o); +} + void ObjectTest::scene() { Scene3D scene; CORRADE_VERIFY(scene.scene() == &scene);