Browse Source

Removed "active camera" from Scene.

It was overengineered and unnecessarily complicated. Now the camera is
specified only in Scene::draw(), which eliminates all the needs for
recalculating absolute object transformations on each camera
transformation change. Absolute object transformation is now computed
relative to root object or relative to camera object passed as
parameter. Because of that it is now also possible to draw the scene
using multiple cameras at once.
vectorfields
Vladimír Vondruš 14 years ago
parent
commit
0945c50aa6
  1. 39
      src/Camera.cpp
  2. 22
      src/Camera.h
  3. 2
      src/Light.cpp
  4. 2
      src/Light.h
  5. 11
      src/Object.cpp
  6. 28
      src/Object.h
  7. 34
      src/Scene.cpp
  8. 29
      src/Scene.h
  9. 20
      src/Test/CameraTest.cpp
  10. 1
      src/Test/CameraTest.h
  11. 14
      src/Test/ObjectTest.cpp

39
src/Camera.cpp

@ -18,27 +18,10 @@
namespace Magnum {
Camera::Camera(Object* parent): Object(parent), _active(nullptr), _aspectRatioPolicy(Extend) {
Camera::Camera(Object* parent): Object(parent), _aspectRatioPolicy(Extend) {
setOrthographic(2, 1, 1000);
}
void Camera::setActive(Scene* _scene) {
if(_scene == _active || scene() != _scene) return;
Scene* oldActive = _active;
/* Set camera active in new scene */
_active = _scene;
if(_active) _active->setCamera(this);
/* Remove the camera from current active scene, if the camera is still
active there */
if(oldActive && oldActive->camera() == this) oldActive->setCamera(nullptr);
/* Clean the path to scene */
setClean();
}
void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
_near = near;
_far = far;
@ -88,28 +71,10 @@ void Camera::setViewport(const Math::Vector2<unsigned int>& size) {
void Camera::setClean() {
if(!isDirty()) return;
_cameraMatrix = transformation(true).inverse();
_cameraMatrix = absoluteTransformation().inverse();
Object::setClean();
}
void Camera::setDirty() {
Object::setDirty();
/* Camera is active */
if(_active) {
Scene* currentScene = scene();
/* Camera is not part of the scene anymore, remove it from there */
if(!currentScene) _active->setCamera(nullptr);
/* Otherwise set the scene dirty */
else _active->setDirty();
/* Clean up the path to scene immediately */
setClean();
}
}
void Camera::fixAspectRatio() {
/* Don't divide by zero */
if(_viewport.x() == 0 || _viewport.y() == 0) {

22
src/Camera.h

@ -50,20 +50,6 @@ class MAGNUM_EXPORT Camera: public Object {
*/
Camera(Object* parent = nullptr);
/**
* @brief Scene in which the camera is active
* @return If the camera is not active anywhere, returns nullptr.
*/
inline Scene* active() const { return _active; }
/**
* @brief Make camera active in given scene
*
* If passed nullptr as @c scene and this camera is active in an scene,
* the camera will be removed from that scene.
*/
void setActive(Scene* scene);
/** @brief Aspect ratio policy */
AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; }
@ -135,19 +121,11 @@ class MAGNUM_EXPORT Camera: public Object {
*/
virtual void setClean();
/**
* If the camera was active before and is still active, calls
* setDirty() on the scene, if is not part of the scene anymore, calls
* setCamera(nullptr) on the scene.
*/
virtual void setDirty();
private:
Matrix4 rawProjectionMatrix;
Matrix4 _projectionMatrix;
Matrix4 _cameraMatrix;
GLfloat _near, _far;
Scene* _active;
Math::Vector2<unsigned int> _viewport;
AspectRatioPolicy _aspectRatioPolicy;

2
src/Light.cpp

@ -19,7 +19,7 @@ namespace Magnum {
void Light::setClean() {
if(!isDirty()) return;
_position = transformation(true).at(3).xyz();
_position = absoluteTransformation().at(3).xyz();
Object::setClean();
}

2
src/Light.h

@ -37,7 +37,7 @@ class Light: public Object {
inline Light(Object* parent = nullptr): Object(parent) {}
/**
* @brief Light position relative to the camera
* @brief Light position relative to root object (scene)
*/
inline Vector3 position() {
setClean();

11
src/Object.cpp

@ -45,19 +45,20 @@ void Object::setParent(Object* parent) {
setDirty();
}
Matrix4 Object::transformation(bool absolute) {
if(!absolute) return _transformation;
Matrix4 Object::absoluteTransformation(Camera* camera) {
Matrix4 t = _transformation;
/* Shortcut for absolute transformation of camera relative to itself */
if(camera == this) return Matrix4();
Object* p = parent();
while(p != nullptr) {
t = p->transformation()*t;
/* We got to the scene, multiply with camera matrix */
if(p->parent() == p) {
Camera* camera = static_cast<Scene*>(p)->camera();
if(camera && camera != this) t = camera->cameraMatrix()*t;
if(camera && camera->scene() == scene())
t = camera->cameraMatrix()*t;
break;
}

28
src/Object.h

@ -26,6 +26,7 @@
namespace Magnum {
class Scene;
class Camera;
/**
* @brief Base for all positioned objects
@ -78,14 +79,21 @@ class MAGNUM_EXPORT Object {
/**
* @brief Transformation matrix
*
* If the object is part of an scene and @c absolute is set to true,
* returns absolute transformation matrix (thus relative to actual
* camera), if the object is not part of an scene, returns
* transformation matrix composed of all matrices of parent objects.
* If @c absolute is set to false, returns transformation matrix
* relative to parent.
* @return Transformation matrix relative to parent.
*/
virtual Matrix4 transformation(bool absolute = false);
inline Matrix4 transformation() const {
return _transformation;
}
/**
* @brief Absolute transformation matrix
*
* If both this object and the camera is part of the same scene,
* returns absolute transformation matrix (relative to the camera).
* Otherwise returns transformation matrix relative to root object
* (in most cases this object's scene).
*/
virtual Matrix4 absoluteTransformation(Camera* camera = nullptr);
/** @brief Set transformation matrix */
inline void setTransformation(const Matrix4& transformation) {
@ -209,10 +217,14 @@ class MAGNUM_EXPORT Object {
/**
* @brief Draw object
* @param transformationMatrix %Matrix specifying object
* transformation relative to the scene.
* @param camera Active camera (containing
* projection matrix)
*
* Default implementation does nothing.
*/
virtual void draw(const Matrix4& transformationMatrix, const Matrix4& projectionMatrix) {}
virtual void draw(const Matrix4& transformationMatrix, Camera* camera) {}
private:
Object* _parent;

34
src/Scene.cpp

@ -19,7 +19,7 @@ using namespace std;
namespace Magnum {
Scene::Scene(): Object(nullptr), _features(0), _camera(nullptr) {
Scene::Scene(): Object(nullptr), _features(0) {
_parent = this;
setClearColor(0.1f, 0.1f, 0.1f, 1.0f);
@ -45,44 +45,22 @@ void Scene::setClearColor(const Magnum::Vector4& color) {
_clearColor = color;
}
void Scene::setCamera(Camera* camera) {
/* Don't assign the same camera or camera which is not part of the scene */
if(camera == _camera || (camera && camera->scene() != this)) return;
Camera* oldCamera = _camera;
/* Set new camera active */
_camera = camera;
if(_camera) {
if(oldCamera) _camera->setViewport(oldCamera->viewport());
_camera->setActive(this);
}
/* Set old camera inactive, if it is still active in this scene */
if(oldCamera && oldCamera->active() == this) oldCamera->setActive(nullptr);
setDirty();
}
void Scene::draw() {
/* No camera available, nothing to do */
if(!_camera) return;
void Scene::draw(Camera* camera) {
/** @todo Clear only set features */
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
/* Recursively draw child objects */
drawChildren(this, _camera->cameraMatrix());
drawChildren(this, camera->cameraMatrix(), camera);
}
void Scene::drawChildren(Object* object, const Matrix4& transformationMatrix) {
void Scene::drawChildren(Object* object, const Matrix4& transformationMatrix, Camera* camera) {
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, _camera->projectionMatrix());
drawChildren(*it, matrix);
(*it)->draw(matrix, camera);
drawChildren(*it, matrix, camera);
}
}

29
src/Scene.h

@ -65,9 +65,6 @@ class MAGNUM_EXPORT Scene: public Object {
/** @brief Which features are set */
inline unsigned int features() const { return _features; }
/** @brief Camera */
inline Camera* camera() const { return _camera; }
/** @brief Set feature */
void setFeature(Feature feature, bool enabled);
@ -79,38 +76,20 @@ class MAGNUM_EXPORT Scene: public Object {
setClearColor(Vector4(r, g, b, a));
}
/**
* @brief Set viewport size
*
* Just passes the values to active camera.
*/
inline void setViewport(int width, int height) {
if(_camera) _camera->setViewport(width, height);
}
/**
* @brief Set camera
*
* If the camera is not part of the scene, the function does nothing.
*/
void setCamera(Camera* camera);
/**
* @brief Draw whole scene
*
* Recursively draws all child objects. If no camera is available, does
* nothing.
* Recursively draws all child objects with given camera.
*/
virtual void draw();
virtual void draw(Camera* camera);
private:
unsigned int _features;
Vector4 _clearColor;
Camera* _camera;
GLuint vao;
inline virtual void draw(const Magnum::Matrix4& transformationMatrix, const Magnum::Matrix4& projectionMatrix) {}
void drawChildren(Object* object, const Matrix4& transformationMatrix);
inline virtual void draw(const Magnum::Matrix4& transformationMatrix, Camera* camera) {}
void drawChildren(Object* object, const Matrix4& transformationMatrix, Camera* camera);
};
}

20
src/Test/CameraTest.cpp

@ -52,24 +52,4 @@ void CameraTest::perspective() {
QVERIFY(camera.projectionMatrix() == Matrix4(a));
}
void CameraTest::active() {
Object* object = new Object;
Camera* camera = new Camera(object);
Scene scene;
/* Camera is not part of the scene, do nothing */
scene.setCamera(camera);
QVERIFY(scene.camera() == 0);
/* Add camera if the camera is part of the scene */
object->setParent(&scene);
scene.setCamera(camera);
QVERIFY(scene.camera() == camera);
/* When camera is taken out of the scene, remove it */
object->setParent(0);
QVERIFY(scene.camera() == 0);
}
}}

1
src/Test/CameraTest.h

@ -25,7 +25,6 @@ class CameraTest: public QObject {
private slots:
void orthographic();
void perspective();
void active();
};
}}

14
src/Test/ObjectTest.cpp

@ -83,20 +83,6 @@ void ObjectTest::dirty() {
childTwo->setDirty();
QVERIFY(childTwo->isDirty());
QVERIFY(childThree->isDirty());
/* Set camera, makes everything dirty except path from camera to scene */
Camera* camera = new Camera(&scene);
scene.setCamera(camera);
QVERIFY(childOne->isDirty());
QVERIFY(!camera->isDirty());
QVERIFY(!scene.isDirty());
/* Clean up and try to move the camera -> makes all dirty (except path
from camera to scene) */
childThree->setClean();
QVERIFY(!scene.isDirty());
camera->translate(0, 0, 1);
QVERIFY(childOne->isDirty());
}
}}

Loading…
Cancel
Save