Browse Source

SceneGraph: added AbstractObject::addFeature(), Object::addChild().

pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
7fc31139e2
  1. 26
      doc/scenegraph.dox
  2. 10
      src/Magnum/SceneGraph/AbstractObject.h
  3. 10
      src/Magnum/SceneGraph/Object.h
  4. 34
      src/Magnum/SceneGraph/Test/ObjectTest.cpp

26
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>();
Object3D& second = first.addChild<Object3D>();
@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<MyFeature>(...);
@endcode
@subsection scenegraph-features-caching Transformation caching in features

10
src/Magnum/SceneGraph/AbstractObject.h

@ -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.

10
src/Magnum/SceneGraph/Object.h

@ -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)

34
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<MyFeature>(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<MyObject>(0, "hello");
CORRADE_VERIFY(!o.children().isEmpty());
CORRADE_COMPARE(p.parent(), &o);
}
void ObjectTest::scene() {
Scene3D scene;
CORRADE_VERIFY(scene.scene() == &scene);

Loading…
Cancel
Save