/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

namespace Magnum { namespace SceneGraph {
/** @page scenegraph Using scene graph
@brief Overview of scene management capabilities.

-   Previous page: @ref plugins
-   Next page: @ref shapes

%Scene graph provides way to hiearchically manage your objects, their
transformation, physics interaction, animation and rendering. The library is
contained in @ref SceneGraph namespace, see its documentation for more
information about building and usage with CMake.

@tableofcontents

There are naturally many possible feature combinations (2D vs. 3D, different
transformation representations, animated vs. static, object can have collision
shape, participate in physics events, have forward vs. deferred rendering...)
and to make everything possible without combinatiorial explosion and allow the
users to provide their own features, scene graph in %Magnum is composed of
three main components:

 - objects, providing parent/children hierarchy
 - transformations, implementing particular transformation type
 - features, providing rendering capabilities, collision detection, physics
   etc.

@note Fully contained applications with initial scene graph setup are available
    in `scenegraph2D` and `scenegraph3D` branches of
    [Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository.

@section scenegraph-transformation Transformations

Transformation handles object position, rotation etc. and its basic property
is dimension count (2D or 3D) and underlying floating-point type.

@note All classes in @ref SceneGraph are templated on underlying type. However,
    in most cases @ref Magnum::Float "Float" is used and thus nearly all
    classes have convenience aliases so you don't have to explicitly specify
    it.

%Scene graph has implementation of transformations in both 2D and 3D, using
either matrices or combination of position and rotation. Each implementation
has its own advantages and disadvantages -- for example when using matrices
you can have nearly arbitrary transformations, but composing transformations
and computing their inverse is costly operation. On the other hand quaternions
won't allow you to scale or shear objects, but are more memory efficient than
matrices.

It's also possible to implement your own transformation class for specific
needs, see source of other transformation classes for more information.

@section scenegraph-hierarchy Scene hierarchy

%Scene hierarchy is skeleton part of scene graph. In the root there is
@ref Scene and its children are @ref Object instances. The hierarchy has some
transformation type, identical for all objects (because for example having part
of the tree in 2D and part in 3D just wouldn't make sense). Common usage is to
typedef %Scene and %Object with desired transformation type to save unnecessary
typing later:
@code
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D> Scene3D;
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;
@endcode

Then you can start building the hierarchy by *parenting* one object to another.
Parent object can be either passed in constructor or using @ref Object::setParent().
%Scene is always root object, so it naturally cannot have parent object.
@code
Scene3D scene;

auto first = new Object3D(&scene);
auto second = new Object3D(first);
@endcode

%Object children can be accessed using @ref Object::firstChild() and
@ref Object::lastChild(), then you can traverse siblings (objects with the same
parent) with @ref Object::previousSibling() and @ref Object::nextSibling(). For
example all children of an object can be traversed the following way:
@code
Object3D* o;
for(Object3D* child = o->firstChild(); child; child = child->nextSibling()) {
    // ...
}
@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"
for information about possible issues.

The object is derived from the transformation you specified earlier in the
`typedef`, so you can directly transform the objects using methods of given
transformation implementation. %Scene, as a root object, cannot have any
transformation. For convenience you can use method chaining:
@code
auto next = new Object3D;
next->setParent(another)
    .translate(Vector3::yAxis(3.0f))
    .rotateY(35.0_degf);
@endcode

@section scenegraph-features Object features

The object itself handles only parent/child relationship and transformation.
To make the object renderable, animatable, add collision shape to it etc., you
have to add a *feature* to it.

Each feature takes reference to holder object in constructor, so adding a
feature to an object might look just like this, as in some cases you don't even
need to keep the pointer to it:
@code
Object3D* o;
new MyFeature(o);
@endcode

Features of an object can be accessed using @ref Object::firstFeature() and
@ref Object::lastFeature(), then you can traverse the features using
@ref AbstractFeature::previousFeature() and @ref AbstractFeature::nextFeature(),
similarly to traversing object children:
@code
Object3D* o;
for(Object3D::FeatureType feature = o->firstFeature(); feature; feature = feature->nextFeature()) {
    // ...
}
@endcode

Some features are passive, some active. Passive features can be just added to
an object like above, without any additional work (for example collision shape).
Active features require the user to implement some virtual function (for
example to draw the object on screen or perform animation step). To make things
convenient, features can be added directly to object itself using multiple
inheritance, so you can conveniently add all the active features you want and
implement needed functions in your own @ref Object subclass without having to
subclass each feature individually (and making the code overly verbose).
Simplified example:
@code
class Bomb: public Object3D, SceneGraph::Drawable3D, SceneGraph::Animable3D {
    public:
        Bomb(Object3D* parent): Object3D(parent), SceneGraph::Drawable3D(*this), SceneGraph::Animable3D(*this) {}

    protected:
        // drawing implementation for Drawable feature
        void draw(...) override;

        // animation step for Animable feature
        void animationStep(...) override;
};
@endcode

From the outside there is no difference between features added "at runtime" and
features added using multiple inheritance, they can be both accessed from
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.

@section scenegraph-caching Transformation caching

Some features need to operate with absolute transformations and their
inversions - for example camera needs its inverse transformation to render the
scene, collision detection needs to know about positions of surrounding
objects etc. To avoid computing the transformations from scratch every time,
the feature can cache them.

The cached data stay until the object is marked as dirty - that is by changing
transformation, changing parent or explicitly calling @ref Object::setDirty().
If the object is marked as dirty, all its children are marked as dirty too and
@ref AbstractFeature::markDirty() is called on every feature. Calling
@ref Object::setClean() cleans the dirty object and all its dirty parents.
The function goes through all object features and calls @ref AbstractFeature::clean()
or @ref AbstractFeature::cleanInverted() depending on which caching is enabled
on given feature. If the object is already clean, @ref Object::setClean() does
nothing.

Most probably you will need caching in @ref Object itself -- which doesn't
support it on its own -- however you can take advantage of multiple inheritance
and implement it using @ref AbstractFeature. In order to have caching, you must
enable it first, because by default the caching is disabled. You can enable it
using @ref AbstractFeature::setCachedTransformations() and then implement
corresponding cleaning function(s):
@code
class CachingObject: public Object3D, SceneGraph::AbstractFeature3D {
    public:
        CachingObject(Object3D* parent): SceneGraph::AbstractFeature3D(*this) {
            setCachedTransformations(SceneGraph::CachedTransformation::Absolute);
        }

    protected:
        void clean(const Matrix4& absoluteTransformation) override {
            absolutePosition = absoluteTransformation.translation();
        }

    private:
        Vector3 absolutePosition;
};
@endcode

When you need to use the cached value, you can explicitly request the cleanup
by calling @ref Object::setClean(). @ref Camera3D "Camera", for example, calls
it automatically before it starts rendering, as it needs its own inverse
transformation to properly draw the objects.

See @ref SceneGraph-AbstractFeature-subclassing-caching for more information.

@section scenegraph-construction-order Construction and destruction order

There aren't any limitations and usage trade-offs of what you can and can't do
when working with objects and features, but there are two issues which you
should be aware of:

@subsection scenegraph-object-construction-order Object hierarchy

When objects are created on the heap (the preferred way, using `new`), they
can be constructed in any order and they will be destroyed when their parent
is destroyed. When creating them on the stack, however, they will be destroyed
when they go out of scope. Normally, the natural order of creation is not a
problem:
@code
{
    Scene3D scene;
    Object3D object(&scene);
}
@endcode
The object is created last, so it will be destroyed first, removing itself
from `scene`'s children list, causing no problems when destroying `scene`
object later. However, if their order is swapped, it will cause problems:
@code
{
    Object3D object;
    Scene3D scene;

    object.setParent(&scene);
} // crash!
@endcode
The scene will be destroyed first, deleting all its children, which is wrong,
because `object` is created on stack. If this doesn't already crash, the
`object` destructor is called (again), making things even worse.

@subsection scenegraph-feature-construction-order Member and inherited features

When destroying the object, all its features are destroyed. For features added
as member it's no issue, features added using multiple inheritance must be
inherited after the %Object class:
@code
class MyObject: public Object3D, MyFeature {
    public:
        MyObject(Object3D* parent): Object3D(parent), MyFeature(*this) {}
};
@endcode
When constructing MyObject, Object3D constructor is called first and then
MyFeature constructor adds itself to Object3D's list of features. When
destroying MyObject, its destructor is called and then the destructors of
ancestor classes -- first MyFeature destructor, which will remove itself from
Object3D's list, then Object3D destructor.

However, if we would inherit MyFeature first, it will cause problems:
@code
class MyObject: MyFeature, public Object3D {
    public:
        MyObject(Object3D* parent): MyFeature(*this), Object3D(parent) {} // crash!
};
@endcode
MyFeature tries to add itself to feature list in not-yet-constructed Object3D,
causing undefined behavior. Then, if this doesn't already crash, Object3D is
created, creating empty feature list, making the feature invisible.

If we would construct them in swapped order (if it is even possible), it
wouldn't help either:
@code
class MyObject: MyFeature, public Object3D {
    public:
        MyObject(Object3D* parent): Object3D(parent), MyFeature(*this) {}

        // crash on destruction!
};
@endcode
On destruction, Object3D destructor is called first, deleting MyFeature,
which is wrong, because MyFeature is in the same object. After that (if the
program didn't already crash) destructor of MyFeature is called (again).

-   Previous page: @ref plugins
-   Next page: @ref shapes
*/
}}
