From 0945c50aa62d59507d3ae3230e368d3286333922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 12 Feb 2012 22:48:27 +0100 Subject: [PATCH] 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. --- src/Camera.cpp | 39 ++------------------------------------- src/Camera.h | 22 ---------------------- src/Light.cpp | 2 +- src/Light.h | 2 +- src/Object.cpp | 11 ++++++----- src/Object.h | 28 ++++++++++++++++++++-------- src/Scene.cpp | 34 ++++++---------------------------- src/Scene.h | 29 ++++------------------------- src/Test/CameraTest.cpp | 20 -------------------- src/Test/CameraTest.h | 1 - src/Test/ObjectTest.cpp | 14 -------------- 11 files changed, 40 insertions(+), 162 deletions(-) diff --git a/src/Camera.cpp b/src/Camera.cpp index 9ca6bd9c8..d3df1d543 100644 --- a/src/Camera.cpp +++ b/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& 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) { diff --git a/src/Camera.h b/src/Camera.h index 593697152..4e6b5c5f6 100644 --- a/src/Camera.h +++ b/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 _viewport; AspectRatioPolicy _aspectRatioPolicy; diff --git a/src/Light.cpp b/src/Light.cpp index 2b4b4f2d7..a9f424fdc 100644 --- a/src/Light.cpp +++ b/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(); } diff --git a/src/Light.h b/src/Light.h index a2eeff975..3ea340f5d 100644 --- a/src/Light.h +++ b/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(); diff --git a/src/Object.cpp b/src/Object.cpp index eaccf80df..1a05cc84a 100644 --- a/src/Object.cpp +++ b/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(p)->camera(); - if(camera && camera != this) t = camera->cameraMatrix()*t; + if(camera && camera->scene() == scene()) + t = camera->cameraMatrix()*t; break; } diff --git a/src/Object.h b/src/Object.h index ffd5b0d21..2ef3ea211 100644 --- a/src/Object.h +++ b/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; diff --git a/src/Scene.cpp b/src/Scene.cpp index 63cbfa495..9b47a6d28 100644 --- a/src/Scene.cpp +++ b/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::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); } } diff --git a/src/Scene.h b/src/Scene.h index 981a5d71f..281a98be5 100644 --- a/src/Scene.h +++ b/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); }; } diff --git a/src/Test/CameraTest.cpp b/src/Test/CameraTest.cpp index e52978df6..19e6bc623 100644 --- a/src/Test/CameraTest.cpp +++ b/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); -} - }} diff --git a/src/Test/CameraTest.h b/src/Test/CameraTest.h index 0099447f4..e6151394e 100644 --- a/src/Test/CameraTest.h +++ b/src/Test/CameraTest.h @@ -25,7 +25,6 @@ class CameraTest: public QObject { private slots: void orthographic(); void perspective(); - void active(); }; }} diff --git a/src/Test/ObjectTest.cpp b/src/Test/ObjectTest.cpp index c61ed66ed..f4a90a7a5 100644 --- a/src/Test/ObjectTest.cpp +++ b/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()); } }}