aboutsummaryrefslogtreecommitdiff
path: root/demos/opengl/camera.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'demos/opengl/camera.cpp')
-rw-r--r--demos/opengl/camera.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/demos/opengl/camera.cpp b/demos/opengl/camera.cpp
new file mode 100644
index 000000000..8a2344c85
--- /dev/null
+++ b/demos/opengl/camera.cpp
@@ -0,0 +1,264 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "camera.h"
+
+#include "gpuhelper.h"
+#include <GL/glu.h>
+
+#include "Eigen/LU"
+using namespace Eigen;
+
+Camera::Camera()
+ : mViewIsUptodate(false), mProjIsUptodate(false)
+{
+ mViewMatrix.setIdentity();
+
+ mFovY = M_PI/3.;
+ mNearDist = 1.;
+ mFarDist = 50000.;
+
+ mVpX = 0;
+ mVpY = 0;
+
+ setPosition(Vector3f::Constant(100.));
+ setTarget(Vector3f::Zero());
+}
+
+Camera& Camera::operator=(const Camera& other)
+{
+ mViewIsUptodate = false;
+ mProjIsUptodate = false;
+
+ mVpX = other.mVpX;
+ mVpY = other.mVpY;
+ mVpWidth = other.mVpWidth;
+ mVpHeight = other.mVpHeight;
+
+ mTarget = other.mTarget;
+ mFovY = other.mFovY;
+ mNearDist = other.mNearDist;
+ mFarDist = other.mFarDist;
+
+ mViewMatrix = other.mViewMatrix;
+ mProjectionMatrix = other.mProjectionMatrix;
+
+ return *this;
+}
+
+Camera::Camera(const Camera& other)
+{
+ *this = other;
+}
+
+Camera::~Camera()
+{
+}
+
+
+void Camera::setViewport(uint offsetx, uint offsety, uint width, uint height)
+{
+ mVpX = offsetx;
+ mVpY = offsety;
+ mVpWidth = width;
+ mVpHeight = height;
+
+ mProjIsUptodate = false;
+}
+
+void Camera::setViewport(uint width, uint height)
+{
+ mVpWidth = width;
+ mVpHeight = height;
+
+ mProjIsUptodate = false;
+}
+
+void Camera::setFovY(float value)
+{
+ mFovY = value;
+ mProjIsUptodate = false;
+}
+
+Vector3f Camera::direction(void) const
+{
+ return - (orientation() * Vector3f::UnitZ());
+}
+Vector3f Camera::up(void) const
+{
+ return orientation() * Vector3f::UnitY();
+}
+Vector3f Camera::right(void) const
+{
+ return orientation() * Vector3f::UnitX();
+}
+
+void Camera::setDirection(const Vector3f& newDirection)
+{
+ // TODO implement it computing the rotation between newDirection and current dir ?
+ Vector3f up = this->up();
+
+ Matrix3f camAxes;
+
+ camAxes.col(2) = (-newDirection).normalized();
+ camAxes.col(0) = up.cross( camAxes.col(2) ).normalized();
+ camAxes.col(1) = camAxes.col(2).cross( camAxes.col(0) ).normalized();
+ setOrientation(Quaternionf(camAxes));
+
+ mViewIsUptodate = false;
+}
+
+void Camera::setTarget(const Vector3f& target)
+{
+ mTarget = target;
+ if (!mTarget.isApprox(position()))
+ {
+ Vector3f newDirection = mTarget - position();
+ setDirection(newDirection.normalized());
+ }
+}
+
+void Camera::setPosition(const Vector3f& p)
+{
+ mFrame.position = p;
+ mViewIsUptodate = false;
+}
+
+void Camera::setOrientation(const Quaternionf& q)
+{
+ mFrame.orientation = q;
+ mViewIsUptodate = false;
+}
+
+void Camera::setFrame(const Frame& f)
+{
+ mFrame = f;
+ mViewIsUptodate = false;
+}
+
+void Camera::rotateAroundTarget(const Quaternionf& q)
+{
+ Matrix4f mrot, mt, mtm;
+
+ // update the transform matrix
+ updateViewMatrix();
+ Vector3f t = mViewMatrix * mTarget;
+
+ mViewMatrix = Translation3f(t)
+ * q
+ * Translation3f(-t)
+ * mViewMatrix;
+
+ Quaternionf qa(mViewMatrix.linear());
+ qa = qa.conjugate();
+ setOrientation(qa);
+ setPosition(- (qa * mViewMatrix.translation()) );
+
+ mViewIsUptodate = true;
+}
+
+void Camera::localRotate(const Quaternionf& q)
+{
+ float dist = (position() - mTarget).norm();
+ setOrientation(orientation() * q);
+ mTarget = position() + dist * direction();
+ mViewIsUptodate = false;
+}
+
+void Camera::zoom(float d)
+{
+ float dist = (position() - mTarget).norm();
+ if(dist > d)
+ {
+ setPosition(position() + direction() * d);
+ mViewIsUptodate = false;
+ }
+}
+
+void Camera::localTranslate(const Vector3f& t)
+{
+ Vector3f trans = orientation() * t;
+ setPosition( position() + trans );
+ setTarget( mTarget + trans );
+
+ mViewIsUptodate = false;
+}
+
+void Camera::updateViewMatrix(void) const
+{
+ if(!mViewIsUptodate)
+ {
+ Quaternionf q = orientation().conjugate();
+ mViewMatrix.linear() = q.toRotationMatrix();
+ mViewMatrix.translation() = - (mViewMatrix.linear() * position());
+
+ mViewIsUptodate = true;
+ }
+}
+
+const Affine3f& Camera::viewMatrix(void) const
+{
+ updateViewMatrix();
+ return mViewMatrix;
+}
+
+void Camera::updateProjectionMatrix(void) const
+{
+ if(!mProjIsUptodate)
+ {
+ mProjectionMatrix.setIdentity();
+ float aspect = float(mVpWidth)/float(mVpHeight);
+ float theta = mFovY*0.5;
+ float range = mFarDist - mNearDist;
+ float invtan = 1./tan(theta);
+
+ mProjectionMatrix(0,0) = invtan / aspect;
+ mProjectionMatrix(1,1) = invtan;
+ mProjectionMatrix(2,2) = -(mNearDist + mFarDist) / range;
+ mProjectionMatrix(3,2) = -1;
+ mProjectionMatrix(2,3) = -2 * mNearDist * mFarDist / range;
+ mProjectionMatrix(3,3) = 0;
+
+ mProjIsUptodate = true;
+ }
+}
+
+const Matrix4f& Camera::projectionMatrix(void) const
+{
+ updateProjectionMatrix();
+ return mProjectionMatrix;
+}
+
+void Camera::activateGL(void)
+{
+ glViewport(vpX(), vpY(), vpWidth(), vpHeight());
+ gpu.loadMatrix(projectionMatrix(),GL_PROJECTION);
+ gpu.loadMatrix(viewMatrix().matrix(),GL_MODELVIEW);
+}
+
+
+Vector3f Camera::unProject(const Vector2f& uv, float depth) const
+{
+ Matrix4f inv = mViewMatrix.inverse().matrix();
+ return unProject(uv, depth, inv);
+}
+
+Vector3f Camera::unProject(const Vector2f& uv, float depth, const Matrix4f& invModelview) const
+{
+ updateViewMatrix();
+ updateProjectionMatrix();
+
+ Vector3f a(2.*uv.x()/float(mVpWidth)-1., 2.*uv.y()/float(mVpHeight)-1., 1.);
+ a.x() *= depth/mProjectionMatrix(0,0);
+ a.y() *= depth/mProjectionMatrix(1,1);
+ a.z() = -depth;
+ // FIXME /\/|
+ Vector4f b = invModelview * Vector4f(a.x(), a.y(), a.z(), 1.);
+ return Vector3f(b.x(), b.y(), b.z());
+}