Browse Source

Finally, camera matrix.

As matrix inversion is costly operation, the matrix is cached, so it's
regenerated only when the transformation / parent is changed.
vectorfields
Vladimír Vondruš 16 years ago
parent
commit
38d4c8581c
  1. 49
      src/Camera.cpp
  2. 33
      src/Camera.h
  3. 16
      src/Scene.cpp
  4. 6
      src/Scene.h
  5. 24
      src/Test/CameraTest.cpp
  6. 1
      src/Test/CameraTest.h
  7. 14
      src/Test/ObjectTest.cpp

49
src/Camera.cpp

@ -14,13 +14,31 @@
*/ */
#include "Camera.h" #include "Camera.h"
#include "Scene.h"
namespace Magnum { namespace Magnum {
Camera::Camera(Object* parent): Object(parent), viewportWidth(0), viewportHeight(0), _aspectRatioPolicy(Extend) { Camera::Camera(Object* parent): Object(parent), _active(0), viewportWidth(0), viewportHeight(0), _aspectRatioPolicy(Extend) {
setOrthographic(2, 1, 1000); 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(0);
/* Clean the path to scene */
setClean();
}
void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) { void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
/* Scale the volume down so it fits in (-1, 1) in all directions */ /* Scale the volume down so it fits in (-1, 1) in all directions */
GLfloat xyScale = 2/size; GLfloat xyScale = 2/size;
@ -55,11 +73,6 @@ void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
fixAspectRatio(); fixAspectRatio();
} }
Matrix4 Camera::cameraMatrix() const {
/** @todo How to do that? */
return Matrix4();
}
void Camera::setViewport(int width, int height) { void Camera::setViewport(int width, int height) {
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
@ -68,6 +81,30 @@ void Camera::setViewport(int width, int height) {
fixAspectRatio(); fixAspectRatio();
} }
void Camera::setClean() {
if(!isDirty()) return;
_cameraMatrix = transformation(true).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(0);
/* Otherwise set the scene dirty */
else _active->setDirty();
/* Clean up the path to scene immediately */
setClean();
}
}
void Camera::fixAspectRatio() { void Camera::fixAspectRatio() {
/* Don't divide by zero */ /* Don't divide by zero */
if(viewportWidth == 0 || viewportHeight == 0) { if(viewportWidth == 0 || viewportHeight == 0) {

33
src/Camera.h

@ -45,6 +45,20 @@ class Camera: public Object {
*/ */
Camera(Object* parent = 0); Camera(Object* parent = 0);
/**
* @brief Scene in which the camera is active
* @return If the camera is not active anywhere, returns 0.
*/
inline Scene* active() const { return _active; }
/**
* @brief Make camera active in given scene
*
* If passed 0 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 */ /** @brief Aspect ratio policy */
AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; } AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; }
@ -76,7 +90,10 @@ class Camera: public Object {
* Camera matrix describes world position relative to the camera and is * Camera matrix describes world position relative to the camera and is
* applied as first. * applied as first.
*/ */
Matrix4 cameraMatrix() const; inline Matrix4 cameraMatrix() {
setClean();
return _cameraMatrix;
}
/** /**
* @brief Projection matrix * @brief Projection matrix
@ -96,9 +113,23 @@ class Camera: public Object {
*/ */
void setViewport(int width, int height); void setViewport(int width, int height);
/**
* Recalculates camera matrix.
*/
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(0) on the scene.
*/
virtual void setDirty();
private: private:
Matrix4 rawProjectionMatrix; Matrix4 rawProjectionMatrix;
Matrix4 _projectionMatrix; Matrix4 _projectionMatrix;
Matrix4 _cameraMatrix;
Scene* _active;
int viewportWidth, viewportHeight; int viewportWidth, viewportHeight;
AspectRatioPolicy _aspectRatioPolicy; AspectRatioPolicy _aspectRatioPolicy;

16
src/Scene.cpp

@ -37,8 +37,22 @@ void Scene::setClearColor(const Magnum::Vector4& color) {
} }
void Scene::setCamera(Camera* camera) { void Scene::setCamera(Camera* camera) {
camera->setViewport(viewportWidth, viewportHeight); /* 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; _camera = camera;
if(_camera) {
_camera->setViewport(viewportWidth, viewportHeight);
_camera->setActive(this);
}
/* Set old camera inactive, if it is still active in this scene */
if(oldCamera && oldCamera->active() == this) oldCamera->setActive(0);
setDirty();
} }
void Scene::draw() { void Scene::draw() {

6
src/Scene.h

@ -77,7 +77,11 @@ class Scene: public Object {
if(_camera) _camera->setViewport(width, height); if(_camera) _camera->setViewport(width, height);
} }
/** @brief Set camera */ /**
* @brief Set camera
*
* If the camera is not part of the scene, the function does nothing.
*/
void setCamera(Camera* camera); void setCamera(Camera* camera);
/** /**

24
src/Test/CameraTest.cpp

@ -14,10 +14,12 @@
*/ */
#include "CameraTest.h" #include "CameraTest.h"
#include "Camera.h"
#include <QtTest/QTest> #include <QtTest/QTest>
#include "Camera.h"
#include "Scene.h"
QTEST_APPLESS_MAIN(Magnum::Test::CameraTest) QTEST_APPLESS_MAIN(Magnum::Test::CameraTest)
namespace Magnum { namespace Test { namespace Magnum { namespace Test {
@ -50,4 +52,24 @@ void CameraTest::perspective() {
QVERIFY(camera.projectionMatrix() == Matrix4(a)); 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,6 +25,7 @@ class CameraTest: public QObject {
private slots: private slots:
void orthographic(); void orthographic();
void perspective(); void perspective();
void active();
}; };
}} }}

14
src/Test/ObjectTest.cpp

@ -83,6 +83,20 @@ void ObjectTest::dirty() {
childTwo->setDirty(); childTwo->setDirty();
QVERIFY(childTwo->isDirty()); QVERIFY(childTwo->isDirty());
QVERIFY(childThree->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