Skip to content

Commit

Permalink
SceneGraph: added AbstractObject::addFeature(), Object::addChild().
Browse files Browse the repository at this point in the history
  • Loading branch information
mosra committed Apr 12, 2015
1 parent e9d02a5 commit 7fc3113
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
26 changes: 20 additions & 6 deletions doc/scenegraph.dox
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Object3D& second = first.addChild<Object3D>();
@endcode

@section scenegraph-features Object features

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<MyFeature>(...);
@endcode

@subsection scenegraph-features-caching Transformation caching in features

Expand Down
10 changes: 10 additions & 0 deletions src/Magnum/SceneGraph/AbstractObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,16 @@ template<UnsignedInt dimensions, class T> class AbstractObject
CORRADE_DEPRECATED("use features().last() instead") const FeatureType* lastFeature() const { return features().last(); }
#endif

/**
* @brief Add a feature
*
* Calling `object.addFeature<MyFeature>(args...)` is equivalent to
* `new MyFeature{object, args...}`.
*/
template<class U, class ...Args> U& addFeature(Args... args) {
return *(new U{*this, std::forward<Args>(args)...});
}

/**
* @brief Scene
* @return Scene or `nullptr`, if the object is not part of any scene.
Expand Down
10 changes: 10 additions & 0 deletions src/Magnum/SceneGraph/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ template<class Transformation> class Object: public AbstractObject<Transformatio
CORRADE_DEPRECATED("use children().last()") const Object<Transformation>* lastChild() const { return children().last(); }
#endif

/**
* @brief Add a child
*
* Calling `object.addChild<MyObject>(args...)` is equivalent to
* `new MyObject{args..., &object}`.
*/
template<class T, class ...Args> T& addChild(Args... args) {
return *(new T{std::forward<Args>(args)..., this});
}

/**
* @brief Set parent object
* @return Reference to self (for method chaining)
Expand Down
34 changes: 33 additions & 1 deletion src/Magnum/SceneGraph/Test/ObjectTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand All @@ -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<MyFeature>(0, "hello");
CORRADE_VERIFY(!o.features().isEmpty());
CORRADE_COMPARE(&f.object(), &o);
}

void ObjectTest::parenting() {
Object3D root;

Expand Down Expand Up @@ -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<MyObject>(0, "hello");
CORRADE_VERIFY(!o.children().isEmpty());
CORRADE_COMPARE(p.parent(), &o);
}

void ObjectTest::scene() {
Scene3D scene;
CORRADE_VERIFY(scene.scene() == &scene);
Expand Down

0 comments on commit 7fc3113

Please sign in to comment.