Browse Source

SceneGraph: modifications to allow 2D implementation in future.

vectorfields
Vladimír Vondruš 14 years ago
parent
commit
810c06509a
  1. 129
      src/SceneGraph/Camera.cpp
  2. 133
      src/SceneGraph/Camera.h
  3. 4
      src/SceneGraph/Light.h
  4. 54
      src/SceneGraph/Object.cpp
  5. 127
      src/SceneGraph/Object.h
  6. 23
      src/SceneGraph/Scene.h
  7. 4
      src/SceneGraph/Test/CameraTest.cpp
  8. 44
      src/SceneGraph/Test/ObjectTest.cpp
  9. 6
      src/SceneGraph/Test/ObjectTest.h
  10. 10
      src/SceneGraph/Test/SceneTest.cpp

129
src/SceneGraph/Camera.cpp

@ -21,9 +21,72 @@ using namespace std;
namespace Magnum { namespace SceneGraph {
Camera::Camera(Object* parent): Object(parent), _aspectRatioPolicy(AspectRatioPolicy::Extend) {}
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
Matrix4 Camera<3>::fixAspectRatio(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2<GLsizei>& viewport) {
/* Don't divide by zero */
if(viewport.x() == 0 || viewport.y() == 0)
return Matrix4();
/* Extend on larger side = scale larger side down */
if(aspectRatioPolicy == AspectRatioPolicy::Extend)
return ((viewport.x() > viewport.y()) ?
Matrix4::scaling({GLfloat(viewport.y())/viewport.x(), 1, 1}) :
Matrix4::scaling({1, GLfloat(viewport.x())/viewport.y(), 1})
);
/* Clip on smaller side = scale smaller side up */
if(aspectRatioPolicy == AspectRatioPolicy::Clip)
return ((viewport.x() > viewport.y()) ?
Matrix4::scaling({1, GLfloat(viewport.x())/viewport.y(), 1}) :
Matrix4::scaling({GLfloat(viewport.y())/viewport.x(), 1, 1})
);
/* Don't preserve anything */
return Matrix4();
}
}
#endif
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::Camera(ObjectType* parent): ObjectType(parent), _aspectRatioPolicy(AspectRatioPolicy::Extend) {}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setViewport(const Math::Vector2<GLsizei>& size) {
Framebuffer::setViewport({0, 0}, size);
_viewport = size;
fixAspectRatio();
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::clean(const MatrixType& absoluteTransformation) {
ObjectType::clean(absoluteTransformation);
_cameraMatrix = absoluteTransformation.inverted();
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::draw() {
SceneType* s = this->scene();
CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", );
Framebuffer::clear();
/* Recursively draw child objects */
drawChildren(s, cameraMatrix());
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::drawChildren(ObjectType* object, const MatrixType& transformationMatrix) {
for(typename set<ObjectType*>::const_iterator it = object->children().begin(); it != object->children().end(); ++it) {
/* Transformation matrix for the object */
MatrixType matrix = transformationMatrix*(*it)->transformation();
/* Draw the object and its children */
(*it)->draw(matrix, static_cast<CameraType*>(this));
drawChildren(*it, matrix);
}
}
void Camera3D::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
_near = near;
_far = far;
@ -38,7 +101,7 @@ void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
fixAspectRatio();
}
void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
void Camera3D::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
_near = near;
_far = far;
@ -63,63 +126,7 @@ void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
fixAspectRatio();
}
void Camera::setViewport(const Math::Vector2<GLsizei>& size) {
Framebuffer::setViewport({0, 0}, size);
_viewport = size;
fixAspectRatio();
}
void Camera::clean(const Matrix4& absoluteTransformation) {
Object::clean(absoluteTransformation);
_cameraMatrix = absoluteTransformation.inverted();
}
void Camera::fixAspectRatio() {
/* Don't divide by zero */
if(_viewport.x() == 0 || _viewport.y() == 0) {
_projectionMatrix = rawProjectionMatrix;
return;
}
/* Extend on larger side = scale larger side down */
if(_aspectRatioPolicy == AspectRatioPolicy::Extend) {
_projectionMatrix = ((_viewport.x() > _viewport.y()) ?
Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1}) :
Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1})
)*rawProjectionMatrix;
/* Clip on smaller side = scale smaller side up */
} else if(_aspectRatioPolicy == AspectRatioPolicy::Clip) {
_projectionMatrix = ((_viewport.x() > _viewport.y()) ?
Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1}) :
Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1})
)*rawProjectionMatrix;
/* Don't preserve anything */
} else _projectionMatrix = rawProjectionMatrix;
}
void Camera::draw() {
Scene* s = scene();
CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", );
Framebuffer::clear();
/* Recursively draw child objects */
drawChildren(s, cameraMatrix());
}
void Camera::drawChildren(Object* object, const Matrix4& transformationMatrix) {
for(set<Object*>::const_iterator it = object->children().begin(); it != object->children().end(); ++it) {
/* Transformation matrix for the object */
Matrix4 matrix = transformationMatrix*(*it)->transformation();
/* Draw the object and its children */
(*it)->draw(matrix, this);
drawChildren(*it, matrix);
}
}
/* Explicitly instantiate the templates */
template class Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
}}

133
src/SceneGraph/Camera.h

@ -28,31 +28,38 @@
namespace Magnum { namespace SceneGraph {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
enum class AspectRatioPolicy {
NotPreserved, Extend, Clip
};
template<size_t dimensions> class Camera {};
}
#endif
/**
@brief %Camera object
*/
class SCENEGRAPH_EXPORT Camera: public Object {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Camera: public ObjectType {
public:
/**
* @brief Aspect ratio policy
*
* @see aspectRatioPolicy(), setAspectRatioPolicy()
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
typedef Implementation::AspectRatioPolicy AspectRatioPolicy;
#else
enum class AspectRatioPolicy {
NotPreserved, /**< Don't preserve aspect ratio */
Extend, /**< Extend on larger side of view */
Clip /**< Clip on smaller side of view */
};
#endif
/**
* @brief Constructor
* @param parent Parent object
*
* Sets orthographic projection to the default OpenGL cube (range
* @f$ [-1; 1] @f$ in all directions).
* @see setOrthographic(), setPerspective()
*/
Camera(Object* parent = nullptr);
/** @copydoc Object::Object */
Camera(ObjectType* parent = nullptr);
/** @brief Aspect ratio policy */
inline AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; }
@ -60,39 +67,14 @@ class SCENEGRAPH_EXPORT Camera: public Object {
/** @brief Set aspect ratio policy */
void setAspectRatioPolicy(AspectRatioPolicy policy) { _aspectRatioPolicy = policy; }
/**
* @brief Set orthographic projection
* @param size Size of (square) view
* @param near Near clipping plane
* @param far Far clipping plane
*
* The volume of given size will be scaled down to range
* @f$ [-1; 1] @f$ on all directions.
*/
void setOrthographic(GLfloat size, GLfloat near, GLfloat far);
/**
* @brief Set perspective projection
* @param fov Field of view angle
* @param near Near clipping plane
* @param far Far clipping plane
*/
void setPerspective(GLfloat fov, GLfloat near, GLfloat far);
/** @brief Near clipping plane */
inline GLfloat near() const { return _near; }
/** @brief Far clipping plane */
inline GLfloat far() const { return _far; }
/**
* @brief Camera matrix
*
* Camera matrix describes world position relative to the camera and is
* applied as first.
*/
inline Matrix4 cameraMatrix() {
setClean();
inline MatrixType cameraMatrix() {
this->setClean();
return _cameraMatrix;
}
@ -102,7 +84,7 @@ class SCENEGRAPH_EXPORT Camera: public Object {
* Projection matrix handles e.g. perspective distortion and is applied
* as last.
*/
inline Matrix4 projectionMatrix() const { return _projectionMatrix; }
inline MatrixType projectionMatrix() const { return _projectionMatrix; }
/** @brief Viewport size */
inline Math::Vector2<GLsizei> viewport() const { return _viewport; }
@ -124,31 +106,88 @@ class SCENEGRAPH_EXPORT Camera: public Object {
*/
virtual void draw();
using Object::draw; /* Don't hide Object's draw() */
using ObjectType::draw; /* Don't hide Object's draw() */
protected:
/**
* Recalculates camera matrix.
*/
void clean(const Matrix4& absoluteTransformation);
void clean(const MatrixType& absoluteTransformation);
/**
* @brief Draw object children
*
* Recursively draws all children of the object.
*/
void drawChildren(Object* object, const Matrix4& transformationMatrix);
void drawChildren(ObjectType* object, const MatrixType& transformationMatrix);
#ifndef DOXYGEN_GENERATING_OUTPUT
inline void fixAspectRatio() {
_projectionMatrix = Implementation::Camera<VectorType::Size>::fixAspectRatio(_aspectRatioPolicy, _viewport)*rawProjectionMatrix;
}
MatrixType rawProjectionMatrix;
AspectRatioPolicy _aspectRatioPolicy;
#endif
private:
Matrix4 rawProjectionMatrix;
Matrix4 _projectionMatrix;
Matrix4 _cameraMatrix;
GLfloat _near, _far;
MatrixType _projectionMatrix;
MatrixType _cameraMatrix;
Math::Vector2<GLsizei> _viewport;
AspectRatioPolicy _aspectRatioPolicy;
};
#ifndef DOXYGEN_GENERATING_OUTPUT
/* These templates are instantiated in source file */
extern template class SCENEGRAPH_EXPORT Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
namespace Implementation {
template<> class Camera<3> {
public:
static Matrix4 fixAspectRatio(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2<GLsizei>& viewport);
};
}
#endif
/** @brief %Camera for three-dimensional scenes */
class SCENEGRAPH_EXPORT Camera3D: public Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D> {
public:
/**
* @brief Constructor
* @param parent Parent object
*
* Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions).
* @see setOrthographic(), setPerspective()
*/
inline Camera3D(Object3D* parent = nullptr): Camera(parent), _near(0.0), _far(0.0) {}
/**
* @brief Set orthographic projection
* @param size Size of (square) view
* @param near Near clipping plane
* @param far Far clipping plane
*
* The volume of given size will be scaled down to range @f$ [-1; 1] @f$
* on all directions.
*/
void setOrthographic(GLfloat size, GLfloat near, GLfloat far);
/**
* @brief Set perspective projection
* @param fov Field of view angle
* @param near Near clipping plane
* @param far Far clipping plane
*/
void setPerspective(GLfloat fov, GLfloat near, GLfloat far);
SCENEGRAPH_LOCAL void fixAspectRatio();
/** @brief Near clipping plane */
inline GLfloat near() const { return _near; }
/** @brief Far clipping plane */
inline GLfloat far() const { return _far; }
private:
GLfloat _near, _far;
};
}}

4
src/SceneGraph/Light.h

@ -28,13 +28,13 @@ namespace Magnum { namespace SceneGraph {
*
* Provides cached light position.
*/
class SCENEGRAPH_EXPORT Light: public Object {
class SCENEGRAPH_EXPORT Light: public Object3D {
public:
/**
* @brief Constructor
* @param parent Parent object
*/
inline Light(Object* parent = nullptr): Object(parent) {}
inline Light(Object3D* parent = nullptr): Object3D(parent) {}
/**
* @brief Light position relative to root object (scene)

54
src/SceneGraph/Object.cpp

@ -21,44 +21,45 @@
#include "Camera.h"
using namespace std;
using namespace Magnum::Math;
namespace Magnum { namespace SceneGraph {
Object* Object::setParent(Object* parent) {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setParent(ObjectType* parent) {
/* Skip if nothing to do or this is scene */
if(_parent == parent || _parent == this) return this;
if(_parent == parent || _parent == this) return static_cast<ObjectType*>(this);
/* Add the object to children list of new parent */
if(parent != nullptr) {
/* Only Fry can be his own grandfather */
Object* p = parent;
ObjectType* p = parent;
while(p != nullptr && p->parent() != p) {
if(p == this) return this;
if(p == this) return static_cast<ObjectType*>(this);
p = p->parent();
}
parent->_children.insert(this);
parent->_children.insert(static_cast<ObjectType*>(this));
}
/* Remove the object from old parent children list */
if(_parent != nullptr)
_parent->_children.erase(this);
_parent->_children.erase(static_cast<ObjectType*>(this));
/* Set new parent */
_parent = parent;
setDirty();
return this;
return static_cast<ObjectType*>(this);
}
Matrix4 Object::absoluteTransformation(Camera* camera) {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> MatrixType Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::absoluteTransformation(CameraType* camera) {
/* Shortcut for absolute transformation of camera relative to itself */
if(camera == this) return Matrix4();
if(camera == this) return MatrixType();
Matrix4 t = _transformation;
MatrixType t = _transformation;
Object* p = parent();
ObjectType* p = parent();
while(p != nullptr) {
t = p->transformation()*t;
@ -80,7 +81,7 @@ Matrix4 Object::absoluteTransformation(Camera* camera) {
return t;
}
Object::~Object() {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::~Object() {
/* Remove the object from parent's children */
setParent(nullptr);
@ -89,44 +90,44 @@ Object::~Object() {
delete *_children.begin();
}
Scene* Object::scene() {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> SceneType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::scene() {
/* Goes up the family tree until it finds object which is parent of itself
(that's the scene) */
Object* p = parent();
ObjectType* p = parent();
while(p != nullptr) {
if(p->parent() == p) return static_cast<Scene*>(p);
if(p->parent() == p) return static_cast<SceneType*>(p);
p = p->parent();
}
return nullptr;
}
Object* Object::setTransformation(const Matrix4& transformation) {
if(_parent == this) return this;
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setTransformation(const MatrixType& transformation) {
if(_parent == this) return static_cast<ObjectType*>(this);
_transformation = transformation;
setDirty();
return this;
return static_cast<ObjectType*>(this);
}
void Object::setDirty() {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setDirty() {
/* The object (and all its children) are already dirty, nothing to do */
if(dirty) return;
dirty = true;
/* Make all children dirty */
for(set<Object*>::iterator it = _children.begin(); it != _children.end(); ++it)
for(typename set<ObjectType*>::iterator it = _children.begin(); it != _children.end(); ++it)
(*it)->setDirty();
}
void Object::setClean() {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setClean() {
/* The object (and all its parents) are already clean, nothing to do */
if(!dirty) return;
/* Collect all parents */
stack<Object*> objects;
Object* p = this;
stack<ObjectType*> objects;
ObjectType* p = static_cast<ObjectType*>(this);
for(;;) {
objects.push(p);
@ -138,9 +139,9 @@ void Object::setClean() {
}
/* Call setClean(const Matrix4&) for every parent and also this object */
Object* o = objects.top();
ObjectType* o = objects.top();
objects.pop();
Matrix4 absoluteTransformation = o->absoluteTransformation();
MatrixType absoluteTransformation = o->absoluteTransformation();
o->clean(absoluteTransformation);
while(!objects.empty()) {
o = objects.top();
@ -150,4 +151,7 @@ void Object::setClean() {
}
}
/* Explicitly instantiate the templates */
template class Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
}}

127
src/SceneGraph/Object.h

@ -27,8 +27,7 @@
namespace Magnum { namespace SceneGraph {
class Scene;
class Camera;
template<class MatrixType, class VectorType, class ObjectType, class CameraType> class Scene;
/**
@todo User-specified Object implementation:
@ -46,13 +45,15 @@ class Camera;
* @todo Transform transformation when changing parent, so the object stays in
* place.
*/
class SCENEGRAPH_EXPORT Object {
Object(const Object& other) = delete;
Object(Object&& other) = delete;
Object& operator=(const Object& other) = delete;
Object& operator=(Object&& other) = delete;
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Object {
#ifndef DOXYGEN_GENERATING_OUTPUT
Object(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete;
Object(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete;
Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& operator=(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete;
Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& operator=(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete;
#endif
friend class Scene;
friend class Scene<MatrixType, VectorType, ObjectType, CameraType>;
public:
/**
@ -61,7 +62,7 @@ class SCENEGRAPH_EXPORT Object {
*
* Sets all transformations to their default values.
*/
inline Object(Object* parent = nullptr): _parent(nullptr), dirty(true) {
inline Object(ObjectType* parent = nullptr): _parent(nullptr), dirty(true) {
setParent(parent);
}
@ -79,16 +80,16 @@ class SCENEGRAPH_EXPORT Object {
* @brief %Scene
* @return If the object is not assigned to any scene, returns nullptr.
*/
Scene* scene();
SceneType* scene();
/** @brief Parent object */
inline Object* parent() { return _parent; }
inline ObjectType* parent() { return _parent; }
/** @brief Child objects */
inline const std::set<Object*>& children() { return _children; }
inline const std::set<ObjectType*>& children() { return _children; }
/** @brief Set parent object */
Object* setParent(Object* parent);
ObjectType* setParent(ObjectType* parent);
/*@}*/
@ -108,7 +109,7 @@ class SCENEGRAPH_EXPORT Object {
};
/** @brief Transformation */
inline Matrix4 transformation() const {
inline MatrixType transformation() const {
return _transformation;
}
@ -123,50 +124,20 @@ class SCENEGRAPH_EXPORT Object {
* objects every time it is asked, unless this function is
* reimplemented in a different way.
*/
virtual Matrix4 absoluteTransformation(Camera* camera = nullptr);
virtual MatrixType absoluteTransformation(CameraType* camera = nullptr);
/** @brief Set transformation */
Object* setTransformation(const Matrix4& transformation);
ObjectType* setTransformation(const MatrixType& transformation);
/**
* @brief Multiply transformation
* @param transformation Transformation
* @param type Transformation type
*/
inline Object* multiplyTransformation(const Matrix4& transformation, Transformation type = Transformation::Global) {
inline ObjectType* multiplyTransformation(const MatrixType& transformation, Transformation type = Transformation::Global) {
setTransformation(type == Transformation::Global ?
transformation*_transformation : _transformation*transformation);
return this;
}
/**
* @brief Translate object
*
* Same as calling multiplyTransformation() with Matrix4::translation().
*/
inline Object* translate(Vector3 vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::translation(vec), type);
return this;
}
/**
* @brief Scale object
*
* Same as calling multiplyTransformation() with Matrix4::scaling().
*/
inline Object* scale(Vector3 vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::scaling(vec), type);
return this;
}
/**
* @brief Rotate object
*
* Same as calling multiplyTransformation() with Matrix4::rotation().
*/
inline Object* rotate(GLfloat angle, Vector3 vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::rotation(angle, vec), type);
return this;
return static_cast<ObjectType*>(this);
}
/*@}*/
@ -180,7 +151,7 @@ class SCENEGRAPH_EXPORT Object {
*
* Default implementation does nothing.
*/
virtual void draw(const Matrix4& transformationMatrix, Camera* camera);
virtual void draw(const MatrixType& transformationMatrix, CameraType* camera);
/** @{ @name Caching helpers
*
@ -255,20 +226,66 @@ class SCENEGRAPH_EXPORT Object {
* }
* @endcode
*/
virtual void clean(const Matrix4& absoluteTransformation);
virtual void clean(const MatrixType& absoluteTransformation);
/*@}*/
private:
Object* _parent;
std::set<Object*> _children;
Matrix4 _transformation;
ObjectType* _parent;
std::set<ObjectType*> _children;
MatrixType _transformation;
bool dirty;
};
/* Implementations for inline functions with unused parameters */
inline void Object::draw(const Matrix4&, Camera*) {}
inline void Object::clean(const Matrix4&) { dirty = false; }
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> inline void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::draw(const MatrixType&, CameraType*) {}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> inline void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::clean(const MatrixType&) { dirty = false; }
class Camera3D;
class Object3D;
typedef Scene<Matrix4, Vector3, Object3D, Camera3D> Scene3D;
#ifndef DOXYGEN_GENERATING_OUTPUT
/* These templates are instantiated in source file */
extern template class SCENEGRAPH_EXPORT Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
#endif
/** @brief Three-dimensional object */
class SCENEGRAPH_EXPORT Object3D: public Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D> {
public:
/** @copydoc Object::Object */
inline Object3D(Object3D* parent = nullptr): Object(parent) {}
/**
* @brief Translate object
*
* Same as calling multiplyTransformation() with Matrix4::translation().
*/
inline Object3D* translate(const Vector3& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::translation(vec), type);
return this;
}
/**
* @brief Scale object
*
* Same as calling multiplyTransformation() with Matrix4::scaling().
*/
inline Object3D* scale(const Vector3& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::scaling(vec), type);
return this;
}
/**
* @brief Rotate object
*
* Same as calling multiplyTransformation() with Matrix4::rotation().
*/
inline Object3D* rotate(GLfloat angle, const Vector3& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::rotation(angle, vec), type);
return this;
}
};
}}

23
src/SceneGraph/Scene.h

@ -24,22 +24,27 @@
namespace Magnum { namespace SceneGraph {
/** @brief %Scene */
class SCENEGRAPH_EXPORT Scene: public Object {
template<class MatrixType, class VectorType, class ObjectType, class CameraType> class SCENEGRAPH_EXPORT Scene: public ObjectType {
public:
/** @brief Constructor */
inline Scene() { _parent = this; }
inline Scene() { this->_parent = this; }
void setParent(Object* parent) = delete;
void setTransformation(const Matrix4& transformation) = delete;
void multiplyTransformation(const Matrix4& transformation, Transformation type = Transformation::Global) = delete;
void translate(Vector3 vec, Transformation type = Transformation::Global) = delete;
void scale(Vector3 vec, Transformation type = Transformation::Global) = delete;
void rotate(GLfloat angle, Vector3 vec, Transformation type = Transformation::Global) = delete;
#ifndef DOXYGEN_GENERATING_OUTPUT
void setParent(ObjectType* parent) = delete;
void setTransformation(const MatrixType& transformation) = delete;
void multiplyTransformation(const MatrixType& transformation, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
void translate(const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
void scale(const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
void rotate(GLfloat angle, const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
#endif
private:
inline void draw(const Magnum::Matrix4&, Camera*) {}
inline void draw(const MatrixType&, CameraType*) {}
};
/** @brief Three-dimensional scene */
typedef Scene<Matrix4, Vector3, Object3D, Camera3D> Scene3D;
}}
#endif

4
src/SceneGraph/Test/CameraTest.cpp

@ -27,7 +27,7 @@ CameraTest::CameraTest() {
}
void CameraTest::orthographic() {
Camera camera;
Camera3D camera;
camera.setOrthographic(5, 1, 9);
Matrix4 a(0.4f, 0.0f, 0.0f, 0.0f,
@ -39,7 +39,7 @@ void CameraTest::orthographic() {
}
void CameraTest::perspective() {
Camera camera;
Camera3D camera;
camera.setPerspective(deg(27.0f), 32.0f, 100);
Matrix4 a(4.1652994f, 0.0f, 0.0f, 0.0f,

44
src/SceneGraph/Test/ObjectTest.cpp

@ -35,10 +35,10 @@ ObjectTest::ObjectTest() {
}
void ObjectTest::parenting() {
Object root;
Object3D root;
Object* childOne = new Object(&root);
Object* childTwo = new Object(&root);
Object3D* childOne = new Object3D(&root);
Object3D* childTwo = new Object3D(&root);
CORRADE_VERIFY(childOne->parent() == &root);
CORRADE_COMPARE(root.children().size(), 2);
@ -62,8 +62,8 @@ void ObjectTest::parenting() {
}
void ObjectTest::transformation() {
Object o;
Object o2;
Object3D o;
Object3D o2;
o.setTransformation(Matrix4::translation(Vector3::xAxis(1.0f)));
o2.translate(Vector3::xAxis(1.0f));
@ -74,8 +74,8 @@ void ObjectTest::transformation() {
Matrix4::translation(Vector3::xAxis(1.0f)));
CORRADE_COMPARE(o2.transformation(), o.transformation());
o.multiplyTransformation(Matrix4::scaling(Vector3(2.0f)), Object::Transformation::Local);
o2.scale(Vector3(2.0f), Object::Transformation::Local);
o.multiplyTransformation(Matrix4::scaling(Vector3(2.0f)), Object3D::Transformation::Local);
o2.scale(Vector3(2.0f), Object3D::Transformation::Local);
CORRADE_COMPARE(o.transformation(), Matrix4::rotation(deg(35.0f), Vector3::zAxis())*
Matrix4::translation(Vector3::xAxis(1.0f))*
Matrix4::scaling(Vector3(2.0f)));
@ -86,56 +86,56 @@ void ObjectTest::absoluteTransformationWrongCamera() {
stringstream ss;
Error::setOutput(&ss);
Scene s;
Object o(&s);
Scene3D s;
Object3D o(&s);
o.translate(Vector3::yAxis());
Camera c;
Camera3D c;
CORRADE_COMPARE(o.absoluteTransformation(&c), Matrix4::translation(Vector3::yAxis()));
CORRADE_COMPARE(ss.str(), "Object::absoluteTransformation(): the camera is not part of the same scene as object!\n");
ss.str("");
Object o2;
Object3D o2;
o2.translate(Vector3::xAxis());
CORRADE_COMPARE(o2.absoluteTransformation(&c), Matrix4::translation(Vector3::xAxis()));
CORRADE_COMPARE(ss.str(), "Object::absoluteTransformation(): the object is not part of camera scene!\n");
}
void ObjectTest::absoluteTransformation() {
Scene s;
Camera c(&s);
Scene3D s;
Camera3D c(&s);
c.translate(Vector3::zAxis(2.0f));
CORRADE_COMPARE(s.absoluteTransformation(), Matrix4());
CORRADE_COMPARE(c.absoluteTransformation(&c), Matrix4());
Object o(&s);
Object3D o(&s);
o.scale(Vector3(2.0f));
Object o2(&o);
Object3D o2(&o);
o.rotate(deg(90.0f), Vector3::yAxis());
CORRADE_COMPARE(o2.absoluteTransformation(),
Matrix4::scaling(Vector3(2.0f))*Matrix4::rotation(deg(90.0f), Vector3::yAxis()));
CORRADE_COMPARE(o2.absoluteTransformation(&c),
(Matrix4::translation(Vector3::zAxis(2.0f)).inverted())*Matrix4::scaling(Vector3(2.0f))*Matrix4::rotation(deg(90.0f), Vector3::yAxis()));
Object o3;
Object3D o3;
o3.translate({1.0f, 2.0f, 3.0f});
CORRADE_COMPARE(o3.absoluteTransformation(), Matrix4::translation({1.0f, 2.0f, 3.0f}));
}
void ObjectTest::scene() {
Scene scene;
Scene3D scene;
Object* childOne = new Object(&scene);
Object* childTwo = new Object(childOne);
Object3D* childOne = new Object3D(&scene);
Object3D* childTwo = new Object3D(childOne);
Object orphan;
Object* childOfOrphan = new Object(&orphan);
Object3D orphan;
Object3D* childOfOrphan = new Object3D(&orphan);
CORRADE_VERIFY(childTwo->scene() == &scene);
CORRADE_VERIFY(childOfOrphan->scene() == nullptr);
}
void ObjectTest::dirty() {
Scene scene;
Scene3D scene;
CleaningObject* childOne = new CleaningObject(&scene);
childOne->scale(Vector3(2.0f));

6
src/SceneGraph/Test/ObjectTest.h

@ -33,12 +33,12 @@ class ObjectTest: public Corrade::TestSuite::Tester<ObjectTest> {
void dirty();
private:
class CleaningObject: public Object {
class CleaningObject: public Object3D {
public:
CleaningObject(Object* parent = nullptr): Object(parent) {}
CleaningObject(Object3D* parent = nullptr): Object3D(parent) {}
inline void clean(const Matrix4& absoluteTransformation) {
Object::clean(absoluteTransformation);
Object3D::clean(absoluteTransformation);
cleanedAbsoluteTransformation = absoluteTransformation;
}

10
src/SceneGraph/Test/SceneTest.cpp

@ -27,21 +27,21 @@ SceneTest::SceneTest() {
}
void SceneTest::transformation() {
Scene scene;
Scene3D scene;
Object* scenePointer = &scene;
Object3D* scenePointer = &scene;
scenePointer->setTransformation(Matrix4::translation({1.0f, 1.0f, 1.0f}));
CORRADE_COMPARE(scene.transformation(), Matrix4());
}
void SceneTest::parent() {
Scene scene;
Scene3D scene;
CORRADE_VERIFY(scene.parent() == &scene);
/* Scene parent cannot be changed */
Object* scenePointer = &scene;
Object object;
Object3D* scenePointer = &scene;
Object3D object;
scenePointer->setParent(&object);
CORRADE_VERIFY(scene.parent() == &scene);
CORRADE_VERIFY(scene.children().empty());

Loading…
Cancel
Save