Browse Source

SceneGraph rework, part 7: Drawable and Camera features.

* Camera is now templated also on underlying floating-point type.
 * Drawable objects can be split into groups (e.g. for separated
   rendering of transparent objects)
 * Added (long time missing) test for draw() function.
pull/7/head
Vladimír Vondruš 14 years ago
parent
commit
bef497c46a
  1. 14
      src/SceneGraph/CMakeLists.txt
  2. 115
      src/SceneGraph/Camera.cpp
  3. 215
      src/SceneGraph/Camera.h
  4. 145
      src/SceneGraph/Camera.hpp
  5. 192
      src/SceneGraph/Drawable.h
  6. 1
      src/SceneGraph/Test/CMakeLists.txt
  7. 89
      src/SceneGraph/Test/CameraTest.cpp
  8. 1
      src/SceneGraph/Test/CameraTest.h

14
src/SceneGraph/CMakeLists.txt

@ -1,4 +1,5 @@
set(MagnumSceneGraph_SRCS )
set(MagnumSceneGraph_SRCS
Camera.cpp)
set(MagnumSceneGraph_HEADERS
AbstractFeature.h
AbstractGroupedFeature.h
@ -8,6 +9,9 @@ set(MagnumSceneGraph_HEADERS
AbstractTranslationRotation3D.h
AbstractTranslationRotationScaling2D.h
AbstractTranslationRotationScaling3D.h
Camera.h
Camera.hpp
Drawable.h
MatrixTransformation2D.h
MatrixTransformation3D.h
Object.h
@ -15,7 +19,7 @@ set(MagnumSceneGraph_HEADERS
Scene.h
magnumSceneGraphVisibility.h)
# add_library(MagnumSceneGraphObjects OBJECT ${MagnumSceneGraph_SRCS})
add_library(MagnumSceneGraphObjects OBJECT ${MagnumSceneGraph_SRCS})
# Files compiled with different flags for main library and unit test library
set(MagnumSceneGraph_GracefulAssert_SRCS
@ -24,11 +28,11 @@ set(MagnumSceneGraph_GracefulAssert_SRCS
# Set shared library flags for the objects, as they will be part of shared lib
# TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well
# set_target_properties(MagnumSceneGraphObjects PROPERTIES COMPILE_FLAGS "-DMagnumSceneGraphObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
set_target_properties(MagnumSceneGraphObjects PROPERTIES COMPILE_FLAGS "-DMagnumSceneGraphObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
# SceneGraph library
add_library(MagnumSceneGraph SHARED
# $<TARGET_OBJECTS:MagnumSceneGraphObjects>
$<TARGET_OBJECTS:MagnumSceneGraphObjects>
${MagnumSceneGraph_GracefulAssert_SRCS})
target_link_libraries(MagnumSceneGraph Magnum)
@ -40,7 +44,7 @@ if(BUILD_TESTS)
# Library with graceful assert for testing
add_library(MagnumSceneGraphTestLib SHARED
# $<TARGET_OBJECTS:MagnumSceneGraphObjects>
$<TARGET_OBJECTS:MagnumSceneGraphObjects>
${MagnumSceneGraph_GracefulAssert_SRCS})
set_target_properties(MagnumSceneGraphTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
target_link_libraries(MagnumSceneGraphTestLib Magnum)

115
src/SceneGraph/Camera.cpp

@ -14,121 +14,16 @@
*/
#include "Camera.h"
#include "Scene.h"
using namespace std;
#include "Camera.hpp"
namespace Magnum { namespace SceneGraph {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<class MatrixType> MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Vector2& projectionScale, const Math::Vector2<GLsizei>& viewport) {
/* Don't divide by zero / don't preserve anything */
if(projectionScale.x() == 0 || projectionScale.y() == 0 || viewport.x() == 0 || viewport.y() == 0 || aspectRatioPolicy == AspectRatioPolicy::NotPreserved)
return MatrixType();
Vector2 relativeAspectRatio = Vector2::from(viewport)*projectionScale;
/* Extend on larger side = scale larger side down
Clip on smaller side = scale smaller side up */
return Camera<MatrixType::Size-1>::aspectRatioScale(
(relativeAspectRatio.x() > relativeAspectRatio.y()) == (aspectRatioPolicy == AspectRatioPolicy::Extend) ?
Vector2(relativeAspectRatio.y()/relativeAspectRatio.x(), 1.0f) :
Vector2(1.0f, relativeAspectRatio.x()/relativeAspectRatio.y()));
}
/* Explicitly instantiate the templates */
template Matrix3 aspectRatioFix<Matrix3>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
template Matrix4 aspectRatioFix<Matrix4>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
}
template class SCENEGRAPH_EXPORT AbstractCamera<2, GLfloat>;
template class SCENEGRAPH_EXPORT AbstractCamera<3, GLfloat>;
template class SCENEGRAPH_EXPORT Camera2D<GLfloat>;
template class SCENEGRAPH_EXPORT Camera3D<GLfloat>;
#endif
template<std::uint8_t dimensions> AbstractCamera<dimensions>::AbstractCamera(typename AbstractObject<dimensions>::ObjectType* parent): AbstractObject<dimensions>::ObjectType(parent), _aspectRatioPolicy(AspectRatioPolicy::NotPreserved) {}
template<std::uint8_t dimensions> typename AbstractObject<dimensions>::CameraType* AbstractCamera<dimensions>::setAspectRatioPolicy(AspectRatioPolicy policy) {
_aspectRatioPolicy = policy;
fixAspectRatio();
return static_cast<typename AbstractObject<dimensions>::CameraType*>(this);
}
template<std::uint8_t dimensions> void AbstractCamera<dimensions>::setViewport(const Math::Vector2<GLsizei>& size) {
_viewport = size;
fixAspectRatio();
}
template<std::uint8_t dimensions> void AbstractCamera<dimensions>::clean(const typename DimensionTraits<dimensions, GLfloat>::MatrixType& absoluteTransformation) {
AbstractObject<dimensions>::ObjectType::clean(absoluteTransformation);
_cameraMatrix = absoluteTransformation.inverted();
}
template<std::uint8_t dimensions> void AbstractCamera<dimensions>::draw() {
typename AbstractObject<dimensions>::SceneType* s = this->scene();
CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", );
/* Recursively draw child objects */
drawChildren(s, cameraMatrix());
}
template<std::uint8_t dimensions> void AbstractCamera<dimensions>::drawChildren(typename AbstractObject<dimensions>::ObjectType* object, const typename DimensionTraits<dimensions, GLfloat>::MatrixType& transformationMatrix) {
for(typename AbstractObject<dimensions>::ObjectType* i = object->firstChild(); i; i = i->nextSibling()) {
/* Transformation matrix for the object */
typename DimensionTraits<dimensions, GLfloat>::MatrixType matrix = transformationMatrix*i->transformation();
/* Draw the object and its children */
i->draw(matrix, static_cast<typename AbstractObject<dimensions>::CameraType*>(this));
drawChildren(i, matrix);
}
}
Camera2D* Camera2D::setProjection(const Vector2& size) {
/* Scale the volume down so it fits in (-1, 1) in all directions */
rawProjectionMatrix = Matrix3::scaling(2.0f/size);
fixAspectRatio();
return this;
}
Camera3D* Camera3D::setOrthographic(const Vector2& size, GLfloat near, GLfloat far) {
_near = near;
_far = far;
Vector2 xyScale = 2.0f/size;
GLfloat zScale = 2.0f/(near-far);
rawProjectionMatrix = Matrix4(
xyScale.x(), 0.0f, 0.0f, 0.0f,
0.0f, xyScale.y(), 0.0f, 0.0f,
0.0f, 0.0f, zScale, 0.0f,
0.0f, 0.0f, near*zScale-1, 1.0f
);
fixAspectRatio();
return this;
}
Camera3D* Camera3D::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
_near = near;
_far = far;
GLfloat xyScale = 1.0f/tan(fov/2); /* == near/size */
GLfloat zScale = 1.0f/(near-far);
rawProjectionMatrix = Matrix4(
xyScale, 0.0f, 0.0f, 0.0f,
0.0f, xyScale, 0.0f, 0.0f,
0.0f, 0.0f, (far+near)*zScale, -1.0f,
0.0f, 0.0f, (2*far*near)*zScale, 0.0f
);
fixAspectRatio();
return this;
}
/* Explicitly instantiate the templates */
template class AbstractCamera<2>;
template class AbstractCamera<3>;
}}

215
src/SceneGraph/Camera.h

@ -16,10 +16,14 @@
*/
/** @file
* @brief Class Magnum::SceneGraph::AbstractCamera, Magnum::SceneGraph::Camera2D, Magnum::SceneGraph::Camera3D
* @brief Class Magnum::SceneGraph::AbstractCamera, Magnum::SceneGraph::Camera2D, Magnum::SceneGraph::Camera3D, alias Magnum::SceneGraph::AbstractCamera2D, Magnum::SceneGraph::AbstractCamera3D
*/
#include "Object.h"
#include "Math/Matrix3.h"
#include "Math/Matrix4.h"
#include "AbstractFeature.h"
#include "magnumSceneGraphVisibility.h"
#ifdef WIN32 /* I so HATE windows.h */
#undef near
@ -28,6 +32,14 @@
namespace Magnum { namespace SceneGraph {
template<std::uint8_t, class> class Drawable;
template<std::uint8_t, class, class> class FeatureGroup;
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<std::uint8_t dimensions, class T = GLfloat> using DrawableGroup = FeatureGroup<dimensions, Drawable<dimensions, T>, T>;
#else
template<std::uint8_t, class> class DrawableGroup;
#endif
/** @todo Export implementation symbols only for tests */
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -36,18 +48,28 @@ namespace Implementation {
NotPreserved, Extend, Clip
};
template<class MatrixType> MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Vector2& projectionScale, const Math::Vector2<GLsizei>& viewport);
/* These templates are instantiated in source file */
extern template SCENEGRAPH_EXPORT Matrix3 aspectRatioFix<Matrix3>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
extern template SCENEGRAPH_EXPORT Matrix4 aspectRatioFix<Matrix4>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
template<std::uint8_t dimensions, class T> typename DimensionTraits<dimensions, T>::MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2<T>& projectionScale, const Math::Vector2<GLsizei>& viewport);
}
#endif
/**
@brief %Camera object
*/
template<std::uint8_t dimensions> class SCENEGRAPH_EXPORT AbstractCamera: public AbstractObject<dimensions>::ObjectType {
@brief Base for cameras
See Drawable documentation for more information.
@section AbstractCamera-explicit-specializations Explicit template specializations
The following specialization are explicitly compiled into SceneGraph library.
For other specializations you have to use Camera.hpp implementation file to
avoid linker errors. See @ref compilation-speedup-hpp for more information.
- @ref AbstractCamera "AbstractCamera<2>"
- @ref AbstractCamera "AbstractCamera<3>"
@see Camera2D, Camera3D, Drawable, DrawableGroup, AbstractCamera2D,
AbstractCamera3D
*/
template<std::uint8_t dimensions, class T = GLfloat> class SCENEGRAPH_EXPORT AbstractCamera: public AbstractFeature<dimensions, T> {
public:
/**
* @brief Aspect ratio policy
@ -64,8 +86,13 @@ template<std::uint8_t dimensions> class SCENEGRAPH_EXPORT AbstractCamera: public
};
#endif
/** @copydoc AbstractObject::AbstractObject() */
AbstractCamera(typename AbstractObject<dimensions>::ObjectType* parent = nullptr);
/**
* @brief Constructor
* @param object Object holding the camera
*/
inline AbstractCamera(AbstractObject<dimensions, T>* object): AbstractFeature<dimensions, T>(object), _aspectRatioPolicy(AspectRatioPolicy::NotPreserved) {
AbstractFeature<dimensions, T>::setCachedTransformations(AbstractFeature<dimensions, T>::CachedTransformation::InvertedAbsolute);
}
virtual ~AbstractCamera() = 0;
@ -76,7 +103,7 @@ template<std::uint8_t dimensions> class SCENEGRAPH_EXPORT AbstractCamera: public
* @brief Set aspect ratio policy
* @return Pointer to self (for method chaining)
*/
typename AbstractObject<dimensions>::CameraType* setAspectRatioPolicy(AspectRatioPolicy policy);
AbstractCamera<dimensions, T>* setAspectRatioPolicy(AspectRatioPolicy policy);
/**
* @brief Camera matrix
@ -84,8 +111,8 @@ template<std::uint8_t dimensions> class SCENEGRAPH_EXPORT AbstractCamera: public
* Camera matrix describes world position relative to the camera and is
* applied as first.
*/
inline typename DimensionTraits<dimensions, GLfloat>::MatrixType cameraMatrix() {
this->setClean();
inline typename DimensionTraits<dimensions, T>::MatrixType cameraMatrix() {
AbstractFeature<dimensions, T>::object()->setClean();
return _cameraMatrix;
}
@ -96,7 +123,7 @@ template<std::uint8_t dimensions> class SCENEGRAPH_EXPORT AbstractCamera: public
* as last.
* @see projectionSize()
*/
inline typename DimensionTraits<dimensions, GLfloat>::MatrixType projectionMatrix() const { return _projectionMatrix; }
inline typename DimensionTraits<dimensions, T>::MatrixType projectionMatrix() const { return _projectionMatrix; }
/**
* @brief Size of (near) XY plane in current projection
@ -104,8 +131,8 @@ template<std::uint8_t dimensions> class SCENEGRAPH_EXPORT AbstractCamera: public
* Returns size of near XY plane computed from projection matrix.
* @see projectionMatrix()
*/
inline Vector2 projectionSize() const {
return {2.0f/_projectionMatrix[0].x(), 2.0f/_projectionMatrix[1].y()};
inline Math::Vector2<T> projectionSize() const {
return {T(2.0)/_projectionMatrix[0].x(), T(2.0)/_projectionMatrix[1].y()};
}
/** @brief Viewport size */
@ -121,79 +148,95 @@ template<std::uint8_t dimensions> class SCENEGRAPH_EXPORT AbstractCamera: public
virtual void setViewport(const Math::Vector2<GLsizei>& size);
/**
* @brief Draw the scene
* @brief Draw
*
* Draws the scene using drawChildren().
* Draws given group of drawables.
*/
virtual void draw();
using AbstractObject<dimensions>::ObjectType::draw; /* Don't hide Object's draw() */
virtual void draw(DrawableGroup<dimensions, T>& group);
protected:
/**
* Recalculates camera matrix.
*/
void clean(const typename DimensionTraits<dimensions, GLfloat>::MatrixType& absoluteTransformation);
/**
* @brief Draw object children
*
* Recursively draws all children of the object.
*/
void drawChildren(typename AbstractObject<dimensions>::ObjectType* object, const typename DimensionTraits<dimensions, GLfloat>::MatrixType& transformationMatrix);
/** Recalculates camera matrix */
inline void cleanInverted(const typename DimensionTraits<dimensions, T>::MatrixType& invertedAbsoluteTransformation) override {
_cameraMatrix = invertedAbsoluteTransformation;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
inline void fixAspectRatio() {
_projectionMatrix = Implementation::aspectRatioFix<typename DimensionTraits<dimensions, GLfloat>::MatrixType>(_aspectRatioPolicy, {rawProjectionMatrix[0].x(), rawProjectionMatrix[1].y()}, _viewport)*rawProjectionMatrix;
_projectionMatrix = Implementation::aspectRatioFix<dimensions, T>(_aspectRatioPolicy, {rawProjectionMatrix[0].x(), rawProjectionMatrix[1].y()}, _viewport)*rawProjectionMatrix;
}
typename DimensionTraits<dimensions, GLfloat>::MatrixType rawProjectionMatrix;
typename DimensionTraits<dimensions, T>::MatrixType rawProjectionMatrix;
AspectRatioPolicy _aspectRatioPolicy;
#endif
private:
typename DimensionTraits<dimensions, GLfloat>::MatrixType _projectionMatrix;
typename DimensionTraits<dimensions, GLfloat>::MatrixType _cameraMatrix;
typename DimensionTraits<dimensions, T>::MatrixType _projectionMatrix;
typename DimensionTraits<dimensions, T>::MatrixType _cameraMatrix;
Math::Vector2<GLsizei> _viewport;
};
template<std::uint8_t dimensions> inline AbstractCamera<dimensions>::~AbstractCamera() {}
template<std::uint8_t dimensions, class T> inline AbstractCamera<dimensions, T>::~AbstractCamera() {}
/**
@brief Base for two-dimensional cameras
Convenience alternative to <tt>%AbstractCamera<2, T></tt>. See AbstractCamera
for more information.
@note Not available on GCC < 4.7. Use <tt>%AbstractCamera<2, T></tt> instead.
@see AbstractCamera3D
@todoc Remove workaround when Doxygen supports alias template
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<std::uint8_t dimensions> class Camera {};
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using AbstractCamera2D = AbstractCamera<2, T>;
#endif
#else
typedef AbstractCamera<2, T = GLfloat> AbstractCamera2D;
#endif
template<> class Camera<2> {
public:
inline constexpr static Matrix3 aspectRatioScale(const Vector2& scale) {
return Matrix3::scaling({scale.x(), scale.y()});
}
};
template<> class Camera<3> {
public:
inline constexpr static Matrix4 aspectRatioScale(const Vector2& scale) {
return Matrix4::scaling({scale.x(), scale.y(), 1.0f});
}
};
}
/**
@brief Base for three-dimensional cameras
Convenience alternative to <tt>%AbstractCamera<3, T></tt>. See AbstractCamera
for more information.
@note Not available on GCC < 4.7. Use <tt>%AbstractCamera<3, T></tt> instead.
@see AbstractCamera2D
@todoc Remove workaround when Doxygen supports alias template
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using AbstractCamera3D = AbstractCamera<3, T>;
#endif
#else
typedef AbstractCamera<3, T = GLfloat> AbstractCamera3D;
#endif
/**
@brief %Camera for two-dimensional scenes
@brief Camera for two-dimensional scenes
See Drawable documentation for more information.
@section Object-explicit-specializations Explicit template specializations
@see Camera3D
The following specialization are explicitly compiled into SceneGraph library.
For other specializations you have to use Camera.hpp implementation file to
avoid linker errors. See @ref compilation-speedup-hpp for more information.
- @ref Camera2D "Camera2D<GLfloat>"
@see Camera3D, Drawable, DrawableGroup
*/
class SCENEGRAPH_EXPORT Camera2D: public AbstractCamera<2> {
template<class T = GLfloat> class SCENEGRAPH_EXPORT Camera2D: public AbstractCamera<2, T> {
public:
/**
* @brief Constructor
* @param parent Parent object
* @param object %Object holding this feature
*
* Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions).
* @see setOrthographic()
*/
inline Camera2D(Object2D* parent = nullptr): AbstractCamera<2>(parent) {}
inline Camera2D(AbstractObject<2, T>* object): AbstractCamera<2, T>(object) {}
/**
* @brief Set projection
@ -203,24 +246,42 @@ class SCENEGRAPH_EXPORT Camera2D: public AbstractCamera<2> {
* The area of given size will be scaled down to range @f$ [-1; 1] @f$
* on all directions.
*/
Camera2D* setProjection(const Vector2& size);
Camera2D<T>* setProjection(const Math::Vector2<T>& size);
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline Camera2D<T>* setAspectRatioPolicy(typename AbstractCamera<2, T>::AspectRatioPolicy policy) {
AbstractCamera<2, T>::setAspectRatioPolicy(policy);
return this;
}
#endif
};
/**
@brief %Camera for three-dimensional scenes
@brief Camera for three-dimensional scenes
See Drawable documentation for more information.
@section Object-explicit-specializations Explicit template specializations
The following specialization are explicitly compiled into SceneGraph library.
For other specializations you have to use Camera.hpp implementation file to
avoid linker errors. See @ref compilation-speedup-hpp for more information.
- @ref Camera3D "Camera3D<GLfloat>"
@see Camera2D
@see Camera2D, Drawable, DrawableGroup
*/
class SCENEGRAPH_EXPORT Camera3D: public AbstractCamera<3> {
template<class T = GLfloat> class SCENEGRAPH_EXPORT Camera3D: public AbstractCamera<3, T> {
public:
/**
* @brief Constructor
* @param parent Parent object
* @param object %Object holding this feature
*
* Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions).
* @see setOrthographic(), setPerspective()
*/
inline Camera3D(Object3D* parent = nullptr): AbstractCamera<3>(parent), _near(0.0f), _far(0.0f) {}
inline Camera3D(AbstractObject<3, T>* object): AbstractCamera<3, T>(object), _near(0.0f), _far(0.0f) {}
/**
* @brief Set orthographic projection
@ -232,7 +293,7 @@ class SCENEGRAPH_EXPORT Camera3D: public AbstractCamera<3> {
* The volume of given size will be scaled down to range @f$ [-1; 1] @f$
* on all directions.
*/
Camera3D* setOrthographic(const Vector2& size, GLfloat near, GLfloat far);
Camera3D<T>* setOrthographic(const Math::Vector2<T>& size, T near, T far);
/**
* @brief Set perspective projection
@ -243,18 +304,32 @@ class SCENEGRAPH_EXPORT Camera3D: public AbstractCamera<3> {
*
* @todo Aspect ratio
*/
Camera3D* setPerspective(GLfloat fov, GLfloat near, GLfloat far);
Camera3D<T>* setPerspective(T fov, T near, T far);
/** @brief Near clipping plane */
inline GLfloat near() const { return _near; }
inline T near() const { return _near; }
/** @brief Far clipping plane */
inline GLfloat far() const { return _far; }
inline T far() const { return _far; }
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline Camera3D<T>* setAspectRatioPolicy(typename AbstractCamera<3, T>::AspectRatioPolicy policy) {
AbstractCamera<3, T>::setAspectRatioPolicy(policy);
return this;
}
#endif
private:
GLfloat _near, _far;
T _near, _far;
};
/* Make implementers' life easier */
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using DrawableGroup2D = DrawableGroup<2, T>;
template<class T = GLfloat> using DrawableGroup3D = DrawableGroup<3, T>;
#endif
}}
#endif

145
src/SceneGraph/Camera.hpp

@ -0,0 +1,145 @@
#ifndef Magnum_SceneGraph_Camera_hpp
#define Magnum_SceneGraph_Camera_hpp
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief @ref compilation-speedup-hpp "Template implementation" for Camera.h
*/
#include "Camera.h"
#include <algorithm>
#include "Drawable.h"
#include "Scene.h"
using namespace std;
namespace Magnum { namespace SceneGraph {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<std::uint8_t dimensions, class T> class Camera {};
template<class T> class Camera<2, T> {
public:
inline constexpr static Math::Matrix3<T> aspectRatioScale(const Math::Vector2<T>& scale) {
return Math::Matrix3<T>::scaling({scale.x(), scale.y()});
}
};
template<class T> class Camera<3, T> {
public:
inline constexpr static Math::Matrix4<T> aspectRatioScale(const Math::Vector2<T>& scale) {
return Math::Matrix4<T>::scaling({scale.x(), scale.y(), 1.0f});
}
};
template<std::uint8_t dimensions, class T> typename DimensionTraits<dimensions, T>::MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Math::Vector2<T>& projectionScale, const Math::Vector2<GLsizei>& viewport) {
/* Don't divide by zero / don't preserve anything */
if(projectionScale.x() == 0 || projectionScale.y() == 0 || viewport.x() == 0 || viewport.y() == 0 || aspectRatioPolicy == AspectRatioPolicy::NotPreserved)
return {};
Math::Vector2<T> relativeAspectRatio = Math::Vector2<T>::from(viewport)*projectionScale;
/* Extend on larger side = scale larger side down
Clip on smaller side = scale smaller side up */
return Camera<dimensions, T>::aspectRatioScale(
(relativeAspectRatio.x() > relativeAspectRatio.y()) == (aspectRatioPolicy == AspectRatioPolicy::Extend) ?
Vector2(relativeAspectRatio.y()/relativeAspectRatio.x(), T(1.0)) :
Vector2(T(1.0), relativeAspectRatio.x()/relativeAspectRatio.y()));
}
}
#endif
template<std::uint8_t dimensions, class T> AbstractCamera<dimensions, T>* AbstractCamera<dimensions, T>::setAspectRatioPolicy(AspectRatioPolicy policy) {
_aspectRatioPolicy = policy;
fixAspectRatio();
return this;
}
template<std::uint8_t dimensions, class T> void AbstractCamera<dimensions, T>::setViewport(const Math::Vector2<GLsizei>& size) {
_viewport = size;
fixAspectRatio();
}
template<std::uint8_t dimensions, class T> void AbstractCamera<dimensions, T>::draw(DrawableGroup<dimensions, T>& group) {
AbstractObject<dimensions, T>* scene = AbstractFeature<dimensions, T>::object()->sceneObject();
CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", );
/* Compute camera matrix */
AbstractFeature<dimensions, T>::object()->setClean();
/* Compute transformations of all objects in the group relative to the camera */
std::vector<AbstractObject<dimensions, T>*> objects(group.size());
for(std::size_t i = 0; i != group.size(); ++i)
objects[i] = group[i]->object();
std::vector<typename DimensionTraits<dimensions, T>::MatrixType> transformations =
scene->transformationMatrices(objects, _cameraMatrix);
/* Perform the drawing */
for(std::size_t i = 0; i != transformations.size(); ++i)
group[i]->draw(transformations[i], this);
}
template<class T> Camera2D<T>* Camera2D<T>::setProjection(const Math::Vector2<T>& size) {
/* Scale the volume down so it fits in (-1, 1) in all directions */
AbstractCamera<2, T>::rawProjectionMatrix = Math::Matrix3<T>::scaling(2.0f/size);
AbstractCamera<2, T>::fixAspectRatio();
return this;
}
template<class T> Camera3D<T>* Camera3D<T>::setOrthographic(const Math::Vector2<T>& size, T near, T far) {
_near = near;
_far = far;
Math::Vector2<T> xyScale = T(2.0)/size;
T zScale = T(2.0)/(near-far);
AbstractCamera<3, T>::rawProjectionMatrix = Math::Matrix4<T>(
xyScale.x(), T(0.0), T(0.0), T(0.0),
T(0.0), xyScale.y(), T(0.0), T(0.0),
T(0.0), T(0.0), zScale, T(0.0),
T(0.0), T(0.0), near*zScale-1, T(1.0)
);
AbstractCamera<3, T>::fixAspectRatio();
return this;
}
template<class T> Camera3D<T>* Camera3D<T>::setPerspective(T fov, T near, T far) {
_near = near;
_far = far;
T xyScale = T(1.0)/tan(fov/2); /* == near/size */
T zScale = T(1.0)/(near-far);
AbstractCamera<3, T>::rawProjectionMatrix = Matrix4(
xyScale, T(0.0), T(0.0), T(0.0),
T(0.0), xyScale, T(0.0), T(0.0),
T(0.0), T(0.0), (far+near)*zScale, T(-1.0),
T(0.0), T(0.0), (2*far*near)*zScale, T(0.0)
);
AbstractCamera<3, T>::fixAspectRatio();
return this;
}
}}
#endif

192
src/SceneGraph/Drawable.h

@ -0,0 +1,192 @@
#ifndef Magnum_SceneGraph_Drawable_h
#define Magnum_SceneGraph_Drawable_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief Class Magnum::SceneGraph::Drawable, Magnum::SceneGraph::DrawableGroup, alias Magnum::SceneGraph::Drawable2D, Magnum::SceneGraph::Drawable3D, Magnum::SceneGraph::DrawableGroup2D, Magnum::SceneGraph::DrawableGroup3D
*/
#include "AbstractGroupedFeature.h"
namespace Magnum { namespace SceneGraph {
template<std::uint8_t, class> class AbstractCamera;
template<std::uint8_t, class> class Drawable;
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<std::uint8_t dimensions, class T = GLfloat> using DrawableGroup = FeatureGroup<dimensions, Drawable<dimensions, T>, T>;
#else
template<std::uint8_t, class> class DrawableGroup;
#endif
/**
@brief %Drawable
Adds drawing function to object. Each %Drawable is part of some DrawableGroup
and the whole group is drawn with particular camera using AbstractCamera::draw().
@section Drawable-usage Usage
First thing is add Drawable feature to some object and implement draw(). You
can do it conveniently using multiple inheritance (see @ref scenegraph-features
for introduction). Example:
@code
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D<>> Object3D;
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D<>> Scene3D;
class DrawableObject: public Object3D, SceneGraph::Drawable3D<> {
public:
DrawableObject(Object* parent, SceneGraph::DrawableGroup3D<>* group): Object3D(parent), SceneGraph::Drawable3D<>(this, group) {
// ...
}
void draw(const Matrix4& transformationMatrix, AbstractCamera3D<>* camera) override {
// ...
}
}
@endcode
Then you add these objects to your scene and some drawable group and transform
them as you like:
@code
Scene3D scene;
SceneGraph::DrawableGroup3D<> group;
(new DrawableObject(&scene, &group))
->translate(Vector3::yAxis(-0.3f))
->rotateX(deg(30.0f));
(new AnotherDrawableObject(&scene, &group))
->translate(Vector3::zAxis(0.5f));
// ...
@endcode
The last thing you need is Camera attached to some object (thus using its
transformation) and with it you can perform drawing in your draw event:
@code
Camera3D<> camera(&cameraObject);
void MyApplication::drawEvent() {
camera.draw(&group);
}
@endcode
@see Drawable2D, Drawable3D, DrawableGroup2D, DrawableGroup3D
*/
template<std::uint8_t dimensions, class T = GLfloat> class Drawable: public AbstractGroupedFeature<dimensions, Drawable<dimensions, T>, T> {
public:
/** @copydoc AbstractGroupedFeature::AbstractGroupedFeature() */
inline Drawable(AbstractObject<dimensions, T>* object, DrawableGroup<dimensions, T>* group = nullptr): AbstractGroupedFeature<dimensions, Drawable<dimensions, T>, T>(object, group) {}
/**
* @brief Draw the object using given camera
* @param transformationMatrix %Object transformation relative
* to camera
* @param camera Camera
*
* Projection matrix can be retrieved from AbstractCamera::projectionMatrix().
*/
virtual void draw(const typename DimensionTraits<dimensions, T>::MatrixType& transformationMatrix, AbstractCamera<dimensions, T>* camera) = 0;
};
/**
@brief Two-dimensional drawable
Convenience alternative to <tt>%Drawable<2, T></tt>. See Drawable for more
information.
@note Not available on GCC < 4.7. Use <tt>%Drawable<2, T></tt> instead.
@see Drawable3D
@todoc Remove workaround when Doxygen supports alias template
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using Drawable2D = Drawable<2, T>;
#endif
#else
typedef Drawable<2, T = GLfloat> Drawable2D;
#endif
/**
@brief Three-dimensional drawable
Convenience alternative to <tt>%Drawable<3, T></tt>. See Drawable for more
information.
@note Not available on GCC < 4.7. Use <tt>%Drawable<3, T></tt> instead.
@see Drawable2D
@todoc Remove workaround when Doxygen supports alias template
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using Drawable3D = Drawable<3, T>;
#endif
#else
typedef Drawable<3, T = GLfloat> Drawable3D;
#endif
/**
@brief Group of drawables
See Drawable for more information.
@see DrawableGroup2D, DrawableGroup3D
@todoc Remove workaround when Doxygen supports alias template
*/
#if !defined(MAGNUM_GCC46_COMPATIBILITY) && !defined(DOXYGEN_GENERATING_OUTPUT)
template<std::uint8_t dimensions, class T = GLfloat> using DrawableGroup = FeatureGroup<dimensions, Drawable<dimensions, T>, T>;
#else
template<std::uint8_t dimensions, class T = GLfloat> class DrawableGroup: public FeatureGroup<dimensions, Drawable<dimensions, T>, T> {};
#endif
/**
@brief Group of two-dimensional drawables
Convenience alternative to <tt>%DrawableGroup<2, T></tt>. See Drawable for
more information.
@note Not available on GCC < 4.7. Use <tt>%Drawable<2, T></tt> instead.
@see DrawableGroup3D
@todoc Remove workaround when Doxygen supports alias template
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using DrawableGroup2D = DrawableGroup<2, T>;
#endif
#else
typedef DrawableGroup<2, T = GLfloat> DrawableGroup2D;
#endif
/**
@brief Group of three-dimensional drawables
Convenience alternative to <tt>%DrawableGroup<3, T></tt>. See Drawable for
more information.
@note Not available on GCC < 4.7. Use <tt>%Drawable<3, T></tt> instead.
@see DrawableGroup2D
@todoc Remove workaround when Doxygen supports alias template
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using DrawableGroup3D = DrawableGroup<3, T>;
#endif
#else
typedef DrawableGroup<3, T = GLfloat> DrawableGroup3D;
#endif
/* Make implementers' life easier */
#ifndef MAGNUM_GCC46_COMPATIBILITY
template<class T = GLfloat> using AbstractCamera2D = AbstractCamera<2, T>;
template<class T = GLfloat> using AbstractCamera3D = AbstractCamera<3, T>;
#endif
}}
#endif

1
src/SceneGraph/Test/CMakeLists.txt

@ -1,2 +1,3 @@
corrade_add_test2(SceneGraphObjectTest ObjectTest.cpp LIBRARIES MagnumSceneGraphTestLib)
corrade_add_test2(SceneGraphCameraTest CameraTest.cpp LIBRARIES MagnumSceneGraph)
corrade_add_test2(SceneGraphSceneTest SceneTest.cpp LIBRARIES MagnumSceneGraph)

89
src/SceneGraph/Test/CameraTest.cpp

@ -17,11 +17,21 @@
#include "Math/Constants.h"
#include "SceneGraph/Camera.h"
#include "SceneGraph/Camera.hpp" /* only for aspectRatioFix(), so it doesn't have to be exported */
#include "SceneGraph/Drawable.h"
#include "SceneGraph/MatrixTransformation2D.h"
#include "SceneGraph/MatrixTransformation3D.h"
CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::CameraTest)
namespace Magnum { namespace SceneGraph { namespace Test {
typedef SceneGraph::Object<SceneGraph::MatrixTransformation2D<>> Object2D;
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D<>> Object3D;
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D<>> Scene3D;
typedef SceneGraph::Camera2D<> Camera2D;
typedef SceneGraph::Camera3D<> Camera3D;
CameraTest::CameraTest() {
addTests(&CameraTest::fixAspectRatio,
&CameraTest::defaultProjection2D,
@ -29,7 +39,8 @@ CameraTest::CameraTest() {
&CameraTest::projection2D,
&CameraTest::orthographic,
&CameraTest::perspective,
&CameraTest::projectionSizeViewport);
&CameraTest::projectionSizeViewport,
&CameraTest::draw);
}
void CameraTest::fixAspectRatio() {
@ -41,54 +52,57 @@ void CameraTest::fixAspectRatio() {
Vector2 projectionScaleZeroX(0.0f, 0.5f);
Math::Vector2<GLsizei> sizeZeroY(400, 0);
Math::Vector2<GLsizei> sizeZeroX(0, 300);
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Clip, projectionScaleZeroX, size), Matrix4());
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Clip, projectionScaleZeroY, size), Matrix4());
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Clip, projectionScale, sizeZeroY), Matrix4());
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Extend, projectionScale, sizeZeroX), Matrix4());
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Clip, projectionScaleZeroX, size)), Matrix4());
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Clip, projectionScaleZeroY, size)), Matrix4());
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Clip, projectionScale, sizeZeroY)), Matrix4());
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Extend, projectionScale, sizeZeroX)), Matrix4());
/* Not preserved */
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::NotPreserved, projectionScale, size), Matrix4());
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::NotPreserved, projectionScale, size)), Matrix4());
/* Clip */
Matrix4 expectedClip(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 4.0f/3.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Clip, Vector2(0.5f), size), expectedClip);
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Clip, Vector2(0.5f), size)), expectedClip);
Matrix4 expectedClipRectangle(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Clip, projectionScale, size), expectedClipRectangle);
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Clip, projectionScale, size)), expectedClipRectangle);
/* Extend */
Matrix4 expectedExtend(3.0f/4.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Extend, Vector2(0.5f), size), expectedExtend);
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Extend, Vector2(0.5f), size)), expectedExtend);
Matrix4 expectedExtendRectangle(0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
CORRADE_COMPARE(Implementation::aspectRatioFix<Matrix4>(Implementation::AspectRatioPolicy::Extend, projectionScale, size), expectedExtendRectangle);
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(Implementation::AspectRatioPolicy::Extend, projectionScale, size)), expectedExtendRectangle);
}
void CameraTest::defaultProjection2D() {
Camera2D camera;
Object2D o;
Camera2D camera(&o);
CORRADE_COMPARE(camera.projectionMatrix(), Matrix3());
CORRADE_COMPARE(camera.projectionSize(), Vector2(2.0f));
}
void CameraTest::defaultProjection3D() {
Camera3D camera;
Object3D o;
Camera3D camera(&o);
CORRADE_COMPARE(camera.projectionMatrix(), Matrix4());
CORRADE_COMPARE(camera.projectionSize(), Vector2(2.0f));
}
void CameraTest::projection2D() {
Vector2 projectionSize(4.0f, 3.0f);
Camera2D camera;
Object2D o;
Camera2D camera(&o);
camera.setProjection(projectionSize);
Matrix3 a(2.0f/4.0f, 0.0f, 0.0f,
@ -101,7 +115,8 @@ void CameraTest::projection2D() {
void CameraTest::orthographic() {
Vector2 projectionSize(5);
Camera3D camera;
Object3D o;
Camera3D camera(&o);
camera.setOrthographic(projectionSize, 1, 9);
Matrix4 a(0.4f, 0.0f, 0.0f, 0.0f,
@ -125,7 +140,8 @@ void CameraTest::orthographic() {
}
void CameraTest::perspective() {
Camera3D camera;
Object3D o;
Camera3D camera(&o);
camera.setPerspective(deg(27.0f), 32.0f, 100);
Matrix4 a(4.1652994f, 0.0f, 0.0f, 0.0f,
@ -138,7 +154,8 @@ void CameraTest::perspective() {
}
void CameraTest::projectionSizeViewport() {
Camera3D camera;
Object3D o;
Camera3D camera(&o);
camera.setViewport({200, 300});
CORRADE_COMPARE(camera.projectionSize(), Vector2(2.0f, 2.0f));
@ -149,4 +166,44 @@ void CameraTest::projectionSizeViewport() {
CORRADE_COMPARE(camera.projectionSize(), Vector2(4.0f/3.0f, 2.0f));
}
void CameraTest::draw() {
class Drawable: public SceneGraph::Drawable<3> {
public:
inline Drawable(AbstractObject<3>* object, DrawableGroup<3>* group, Matrix4& result): SceneGraph::Drawable<3>(object, group), result(result) {}
protected:
void draw(const Matrix4& transformationMatrix, AbstractCamera<3>*) {
result = transformationMatrix;
}
private:
Matrix4& result;
};
DrawableGroup<3> group;
Scene3D scene;
Object3D first(&scene);
Matrix4 firstTransformation;
first.scale(Vector3(5.0f));
new Drawable(&first, &group, firstTransformation);
Object3D second(&scene);
Matrix4 secondTransformation;
second.translate(Vector3::yAxis(3.0f));
new Drawable(&second, &group, secondTransformation);
Object3D third(&second);
Matrix4 thirdTransformation;
third.translate(Vector3::zAxis(-1.5f));
new Drawable(&third, &group, thirdTransformation);
Camera3D camera(&third);
camera.draw(group);
CORRADE_COMPARE(firstTransformation, Matrix4::translation({0.0f, -3.0f, 1.5f})*Matrix4::scaling(Vector3(5.0f)));
CORRADE_COMPARE(secondTransformation, Matrix4::translation(Vector3::zAxis(1.5f)));
CORRADE_COMPARE(thirdTransformation, Matrix4());
}
}}}

1
src/SceneGraph/Test/CameraTest.h

@ -30,6 +30,7 @@ class CameraTest: public Corrade::TestSuite::Tester<CameraTest> {
void orthographic();
void perspective();
void projectionSizeViewport();
void draw();
};
}}}

Loading…
Cancel
Save