Commit 033d6150 authored by Robert Menzel's avatar Robert Menzel
Browse files

added new camera class and space navigator support

parent 67d811a3
......@@ -7,6 +7,7 @@ Included third-party software:
* Includes lodepng by Lode Vandevenne, unchanged except for the include path in lodepng.cpp. lodepng is provided as-is, see license text in the lodepng source code.
* Includes OpenGL loader code created by a modified glLoadGen by Jason McKesson.
* Includes GLM by Christophe Riccio.
* Includes data type definitions from libspnav header originally by John Tsiombikas (see mini_spnav.h for details).
See LICENSE.TXT for licensing information.
......
/***********************************************************************
* Copyright 2011-2013 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#pragma once
#include <ACGL/ACGL.hh>
#include <ACGL/Scene/GenericCamera.hh>
namespace ACGL{
namespace HardwareSupport{
/// Controls a GenericCamera with a space navigator
class SpaceNavControl
{
public:
SpaceNavControl(Scene::GenericCamera *_cam, const glm::vec3 &_moveSensitivity = glm::vec3(1.0), const glm::vec3 &_rotateSensitivity = glm::vec3(1.0));
~SpaceNavControl();
/// Updates the camera: call this once a frame, it will poll the SpaceNavigator. The elapsed time is used to scale the movement to
/// to be framerate independent.
void update(float _elapsedSeconds);
private:
/// The referenced camera
Scene::GenericCamera *mCamera;
/// Sensitivity for moving the camera
glm::vec3 mMoveSensitivity;
/// Sensitivity for rotating the camera
glm::vec3 mRotateSensitivity;
};
} // HardwareSupport
} // ACGL
/***********************************************************************
* Copyright 2011-2013 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#pragma once
#include <ACGL/ACGL.hh>
namespace ACGL{
namespace HardwareSupport{
/*
* To compile:
* Linux: do nothing
* MacOS X: link to 3DconnexionClient,
* e.g. add 'SET(LIBRARIES -Wl,-framework,3DconnexionClient)' to CMakeLists.txt
* to build a version without space nav support, define NO_SPACE_NAVIGATOR_SUPPORT
* Windows: only dummy functionality will get build
*/
// Each listener should call this *once* before starting to poll,
// the first listener will start a connection to the driver.
// If the connection could be made, true will be returned, false otherwise.
// If false gets returned, SpaceNavUnregisterListener() should not get called
// and all SpaceNavPollEvent() calls will return 0 events.
bool SpaceNavRegisterListener();
// Each listener should call this *once* when stopping to listen iff the call
// to SpaceNavRegisterListener() returned true.
// Last unregister call will trigger disconnection from the driver.
void SpaceNavUnregisterListener();
enum SpaceNavEventType {
movement,
button,
other
};
// Values of the buttons:
// the 2 button space navigator:
static const int SNE_BUTTON_LEFT = 0;
static const int SNE_BUTTON_RIGHT = 1;
// the larger space pilot:
static const int SNE_BUTTON_1 = 0;
static const int SNE_BUTTON_2 = 1;
static const int SNE_BUTTON_3 = 2;
static const int SNE_BUTTON_4 = 3;
static const int SNE_BUTTON_5 = 4;
static const int SNE_BUTTON_6 = 5;
static const int SNE_BUTTON_ESC = 10;
static const int SNE_BUTTON_CTRL = 13;
static const int SNE_BUTTON_ALT = 11;
static const int SNE_BUTTON_SHIFT = 12;
static const int SNE_BUTTON_CONFIG = 20;
static const int SNE_BUTTON_PANEL = 15;
static const int SNE_BUTTON_VOL_DOWN = 17;
static const int SNE_BUTTON_VOL_UP = 16;
static const int SNE_BUTTON_DOM = 18;
static const int SNE_BUTTON_T = 6;
static const int SNE_BUTTON_L = 7;
static const int SNE_BUTTON_R = 8;
static const int SNE_BUTTON_F = 9;
static const int SNE_BUTTON_3D = 19;
static const int SNE_BUTTON_FIT = 14;
//
// translation and rotation can go from about -500 to 500.
// note that the neutral postion might not be 0,0,0
// not all axes have the same maximum value (-361 to 441 might be possible)
struct SpaceNavEvent {
SpaceNavEventType type;
int x,y,z; // translation, right-handed-coord-system (right/up/towards the user are positive)
int rx,ry,rz; // rotation, pitch-yaw-roll
int button; // button number, see values above
bool pressed; // button state, pressing the button down and release will create two events
};
// Call this to poll for new events.
// Return value is the number of valid events waiting, 0 means no event
// is waiting and the eventToFill will not get changed in that situation.
// If no device was found or the connection to the driver failed for other
// reasons, 0 will get returned.
// -> polling for events and only interpreting them if >0 gets returned
// should be always save!
unsigned int SpaceNavPollEvent( SpaceNavEvent &eventToFill );
} // HardwareSupport
} // ACGL
/*
This file is based on a part of libspnav, part of the spacenav project (spacenav.sf.net)
Original file (spnav.h) Copyright (C) 2007-2010 John Tsiombikas <nuclear@member.fsf.org>
This file (mini_spnav.h) Copyright (C) 2013 Robert Menzel
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#ifndef MINI_SPACENAV_H_
#define MINI_SPACENAV_H_
/*
* This file can be used as an alternative to spnav.h iff the library should get loaded
* dynamically. Add this to your project and the code will compile independent of the
* presence of libspnav (and also run independent of it).
*/
#include <dlfcn.h> // for dlopen
enum {
SPNAV_EVENT_ANY, /* used by spnav_remove_events() */
SPNAV_EVENT_MOTION,
SPNAV_EVENT_BUTTON /* includes both press and release */
};
struct spnav_event_motion {
int type;
int x, y, z;
int rx, ry, rz;
unsigned int period;
int *data;
};
struct spnav_event_button {
int type;
int press;
int bnum;
};
typedef union spnav_event {
int type;
struct spnav_event_motion motion;
struct spnav_event_button button;
} spnav_event;
#ifdef __cplusplus
extern "C" {
#endif
/* Open connection to the daemon via AF_UNIX socket.
* The unix domain socket interface is an alternative to the original magellan
* protocol, and it is *NOT* compatible with the 3D connexion driver. If you wish
* to remain compatible, use the X11 protocol (spnav_x11_open, see below).
* Returns -1 on failure.
*/
typedef int (*spnav_open_ptr)(void);
/* Close connection to the daemon. Use it for X11 or AF_UNIX connections.
* Returns -1 on failure
*/
typedef int (*spnav_close_ptr)(void);
/* Retrieves the file descriptor used for communication with the daemon, for
* use with select() by the application, if so required.
* If the X11 mode is used, the socket used to communicate with the X server is
* returned, so the result of this function is always reliable.
* If AF_UNIX mode is used, the fd of the socket is returned or -1 if
* no connection is open / failure occured.
*/
//int spnav_fd(void);
/* TODO: document */
//int spnav_sensitivity(double sens);
/* blocks waiting for space-nav events. returns 0 if an error occurs */
//int spnav_wait_event(spnav_event *event);
/* checks the availability of space-nav events (non-blocking)
* returns the event type if available, or 0 otherwise.
*/
typedef int (*spnav_poll_event_ptr)(spnav_event *event);
/* Removes any pending events from the specified type, or all pending events
* events if the type argument is SPNAV_EVENT_ANY. Returns the number of
* removed events.
*/
//int spnav_remove_events(int type);
#ifdef __cplusplus
}
#endif
#endif /* MINI_SPACENAV_H_ */
......@@ -7,6 +7,7 @@
#ifndef ACGL_SCENE_CAMERA_HH
#define ACGL_SCENE_CAMERA_HH
#ifdef ACGL_INCLUDE_DEPRECATED_FUNCTIONALITY
/*
* A generic camera class.
*/
......@@ -201,4 +202,6 @@ private:
} // Scene
} // ACGL
#endif
#endif // ACGL_SCENE_CAMERA_HH
/***********************************************************************
* Copyright 2011-2013 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#pragma once
#include <ACGL/ACGL.hh>
#include <ACGL/Math/Math.hh>
#include <glm/gtx/quaternion.hpp>
/*
* What you definitly want to set:
* - a position in 3D space (a vec3)
* - a viewing direction, this can be defined by:
* - roll/pitch/jaw rotations
* - up/left/forward vectors
* - the aspect ratio (width/height)
*
* What you maybe want to change:
* - a lookAtDistance, this is internaly only used for the orthographic
* projection, can be be used externaly e.g. for field of view effects
* (if no focal distance is given, a default will be used, but often this
* value is not used at all), also a lookAt point can be calculated with this
* - Stereo settings:
* - the eyedistance
* - the StereoMode
* - Horizontal/Vertical FoV
* - near- and far-clipping plane
*
* A Camera can calculate:
* - a ViewMatrix
* - a ProjectionMatrix for Mono view
* - ProjectionMatrices for Stereo view
*
*
* TODO: support stereo!
*/
namespace ACGL{
namespace Scene{
class GenericCamera
{
public:
enum ProjectionMode
{
ISOMETRIC_PROJECTION = 0,
PERSPECTIVE_PROJECTION
};
enum StereoMode
{
MONO = 0,
PARALLEL_SHIFT,
OFF_AXIS,
TOE_IN
};
enum Eye
{
EYE_LEFT = 0,
EYE_RIGHT
};
/**
* Constructor of a camera.
*/
GenericCamera();
/**
* Destructor of a camera.
*/
~GenericCamera() {}
/**
* Set the position of the camera.
* @param _position New position of the camera.
*/
void setPosition( const glm::vec3 &_position ) { mPosition = _position; }
glm::vec3 getPosition() const { return mPosition; }
/// Will change the look at distance!
/// Will change the rotation!
/// Uses stored up-vector as reference
void setTarget( const glm::vec3 &_target ) { setTarget(_target, getUpDirection()); }
/// Will change the look at distance!
/// Will change the rotation!
/// Uses given up-vector as reference
void setTarget( const glm::vec3 &_target, const glm::vec3 &_up );
/// Gets the reconstructed target
glm::vec3 getTarget() const { return mPosition + getForwardDirection() * getLookAtDistance(); }
/**
* Set the distance between the eyes (only needed for stereo rendering).
* @param _eyeDistance Eye distance in meter(!)
*/
void setEyeDistance( float _eyeDistance ) { mEyeDistance = _eyeDistance; }
float getEyeDistance() const { return mEyeDistance; }
/**
* Set the projection mode of the camera.
* @param _projection New projection mode of the camera.
*/
void setProjectionMode( ProjectionMode _projection ) { mProjectionMode = _projection; }
ProjectionMode getProjectionMode() const { return mProjectionMode; }
/**
* Set the stereo mode of the camera.
* @param _stereoMode New stereo mode of the camera.
*/
void setStereoMode( StereoMode _stereoMode ) { mStereoMode = _stereoMode; }
StereoMode getStereoMode() const { return mStereoMode; }
/// Sets the currently active eye
void setEye( Eye _eye ) { mCurrentEye = _eye; }
Eye getEye() const { return mCurrentEye; }
/**
* Set the horizontal field of view of the camera.
* vertical FoV will get (implicitly) changed!
* @param _fovh New horizontal field of view of the camera.
*/
void setHorizontalFieldOfView( double _fovh );
double getHorizontalFieldOfView() const { return mHorizontalFieldOfView; }
/**
* Set the vertical field of view of the camera.
* Aspect ratio will get changed!
* @param _fovv New vertical field of view of the camera.
*/
void setVerticalFieldOfView( double _fovv );
double getVerticalFieldOfView() const;
/**
* Set the aspect ratio of the camera. The horizontal FoV stays the same, the
* vertical FoV gets updated.
* @param aspectRatio New aspect ratio (width/height)
*/
void setAspectRatio( double _aspectRatio ) { mAspectRatio = _aspectRatio; }
double getAspectRatio() const { return mAspectRatio; }
/**
* Set the near clipping plane of the camera.
* The plane is defined only by a distance from the camera.
* @param _plane New near clipping plane of the camera.
*/
void setNearClippingPlane( double _plane );
/// Gets the near clip distance
float getNearClippingPlane() const { return mNearClippingPlane; }
/**
* Set the far clipping plane of the camera.
* The plane is defined only by a distance from the camera.
* @param _plane New far clipping plane of the camera.
*/
void setFarClippingPlane( double _plane );
/// Gets the far clip distance
float getFarClippingPlane() const { return mFarClippingPlane; }
/**
* Set the distance of the camera to the object we're looking at.
* Will change the target!
* @param _distance New focal distance of the camera.
*/
void setLookAtDistance( double _distance );
/// Gets the look-at distance
float getLookAtDistance() const { return mLookAtDistance; }
/// Moves the camera by a given vector (in eyespace)
void move( const glm::vec3 &_vector );
void moveRight( float _distance ) { move( glm::vec3(_distance,0,0) ); }
void moveBack( float _distance ) { move( glm::vec3(0,0,_distance) ); }
void moveUp( float _distance ) { move( glm::vec3(0,_distance,0) ); }
void moveLeft( float _distance ) { move( glm::vec3(-_distance,0,0) ); }
void moveForward( float _distance ) { move( glm::vec3(0,0,-_distance) ); }
void moveDown( float _distance ) { move( glm::vec3(0,-_distance,0) ); }
/**
* Look around with a mouse, works like a FPS camera:
* No roll possible.
* Up/down is limited to 90 degree.
* This method assumes there is no roll in the current camera rotation, if
* there is a roll component, it will get destroyed -> don't mix this
* way to stear with other, more flexible methods!
* @param _deltaX How much the mouse moved on the viewport (0..1, 1 = full viewport width)
* @param _deltaY How much the mouse moved on the viewport (0..1, 1 = full viewport height)
*/
void FPSstyleLookAround( float _deltaX, float _deltaY );
/// Gets the orthonormal rotation matrix (mat3)
const glm::mat3 &getRotationMatrix3() const { return mRotationMatrix; }
/// Gets the inverse orthonormal rotation matrix (mat3)
glm::mat3 getInverseRotationMatrix3() const { return glm::transpose(mRotationMatrix); }
/// Gets the orthonormal rotation matrix (mat3)
glm::mat4 getRotationMatrix4() const { return glm::mat4(mRotationMatrix); }
/// Sets the rotation matrix (mat3)
void setRotationMatrix( glm::mat3 _matrix );
/// Sets the rotation matrix (mat3-part of a mat4)
void setRotationMatrix( glm::mat4 _matrix );
/// Sets the complete camera lookat (position and rotation)
void setLookAtMatrix( const glm::vec3 &_position, const glm::vec3 &_target, const glm::vec3 &_up );
/// Gets the translation matrix of this camera
glm::mat4 getTranslationMatrix4() const;
/// Get the unit up direction
glm::vec3 getUpDirection () const;
/// Get the unit right direction
glm::vec3 getRightDirection () const;
/// Get the unit forward direction
glm::vec3 getForwardDirection() const;
/// Gets the currently active projection matrix (depends on stereo mode and current eye)
glm::mat4 getProjectionMatrix() const;
/**
* Compute a camera projection matrix for stereo rendering.
* In stereo mode, the Cameras position is the point in the middle between the two eyes.
* So we just need one additional info to calculate two matrices:
* @param stereoCamMode How to calculate the cameras (toe-in, off-axis).
*/
glm::mat4 getMonoProjectionMatrix() const;
/*
glm::mat4 getStereoProjectionMatrix( bool _leftEye, StereoMode _stereoMode = OFF_AXIS );
glm::mat4 getLeftStereoProjectionMatrix() { return getStereoProjectionMatrix(true, mStereoMode); }
glm::mat4 getRightStereoProjectionMatrix() { return getStereoProjectionMatrix(false, mStereoMode); }
glm::mat4 getLeftParallelShiftStereoProjectionMatrix() { return getStereoProjectionMatrix(true, PARALLEL_SHIFT); }
glm::mat4 getRightParallelShiftStereoProjectionMatrix() { return getStereoProjectionMatrix(false, PARALLEL_SHIFT); }
glm::mat4 getLeftOffAxisStereoProjectionMatrix() { return getStereoProjectionMatrix(true, OFF_AXIS); }
glm::mat4 getRightOffAxisStereoProjectionMatrix() { return getStereoProjectionMatrix(false, OFF_AXIS); }
glm::mat4 getLeftToeInStereoProjectionMatrix() { return getStereoProjectionMatrix(true, TOE_IN); }
glm::mat4 getRightToeInStereoProjectionMatrix() { return getStereoProjectionMatrix(false, TOE_IN); }
*/
// mono:
/// Gets the currently active view matrix (depends on stereo mode and current eye)
glm::mat4 getViewMatrix() const;
/// Gets the currently active view matrix (depends on stereo mode and current eye)
glm::mat4 getInverseViewMatrix() const;
/**
* Compute a camera view matrix for stereo rendering.
* In stereo mode, the view matrix is the mono view matrix but also the shift
* by half the eye distance to the left/right and a small rotation inwards in
* case of toe in mode.
* @param stereoCamMode How to calculate the cameras (toe-in, off-axis).
*/
glm::mat4 getMonoViewMatrix() const;
glm::mat4 getMonoInverseViewMatrix() const;
/*
glm::mat4 getStereoViewMatrix( bool _leftEye, StereoMode _stereoMode = OFF_AXIS );
glm::mat4 getLeftStereoViewMatrix() { return getStereoViewMatrix(true, mStereoMode); }
glm::mat4 getRightStereoViewMatrix() { return getStereoViewMatrix(false, mStereoMode); }
glm::mat4 getLeftParallelShiftStereoViewMatrix() { return getStereoViewMatrix(true, PARALLEL_SHIFT); }
glm::mat4 getRightParallelShiftStereoViewMatrix() { return getStereoViewMatrix(false, PARALLEL_SHIFT); }
glm::mat4 getLeftOffAxisStereoViewMatrix() { return getStereoViewMatrix(true, OFF_AXIS); }
glm::mat4 getRightOffAxisStereoViewMatrix() { return getStereoViewMatrix(false, OFF_AXIS); }
glm::mat4 getLeftToeInStereoViewMatrix() { return getStereoViewMatrix(true, TOE_IN); }
glm::mat4 getRightToeInStereoViewMatrix() { return getStereoViewMatrix(false, TOE_IN); }
*/
/// Gets size of the viewport
glm::uvec2 getViewportSize() const { return mViewportSize; }
/// Gets width of the viewport
unsigned int getViewportWidth() const { return mViewportSize.x; }
/// Gets height of the viewport
unsigned int getViewportHeight() const { return mViewportSize.y; }
/// Sets size of the viewport
void setViewportSize( glm::uvec2 _size ) { mViewportSize = _size; }
/// Sets size of the viewport
void setViewportSize( unsigned int _width, unsigned int _height ) { setViewportSize(glm::uvec2(_width, _height)); }
/// Sets new viewport size and calculates new aspect ratio
void resize(int _newWidth, int _newHeight) { setViewportSize(_newWidth, _newHeight); setAspectRatio(_newWidth / (float)_newHeight); }
private:
/// the Matrix with the camera position/orientation.
/// eyeShift is the half of the eyeDistance (can be 0 if we don't want stereo)
/// toeInValue is the value of how many degrees the camera will be looking to the right/left for toe in
//glm::mat4 getCameraMatrix( double _eyeShift = 0.0f, double _toeInValue = 0.0f );
/// the projection matrix
/// for non-symetric projections set eyeShift != 0.
/// this is used for off-axis projections (value in meters, negativ for the left eye)
//glm::mat4 getPerspectiveProjectionMatrix( double _eyeShift = 0.0f );
/// Current camera position
glm::vec3 mPosition;
glm::mat3 mRotationMatrix;
/// Current camera projection mode
ProjectionMode mProjectionMode;
/// stereo view mode
StereoMode mStereoMode;
/// Current eye
Eye mCurrentEye;
/// Current camera horizontal field of view
double mHorizontalFieldOfView;
/// Current aspect ratio: width/height.
double mAspectRatio;
/// Distance of the eyes for stereo projection. In that case, the left eye is 0.5*eyeDistance
/// shifted to the left of position and the right eye is 0.5*eyeDistance to the right shifted.
/// We assume that 1 unit equals 1 meter. The mean eye distance is 6.5 cm == 0.065 units
float mEyeDistance;
/// Current camera near clipping plane
double mNearClippingPlane;
/// Current camera far clipping plane
double mFarClippingPlane;
/// Current camera focal distance
double mLookAtDistance;
/// viewport in pixel:
glm::uvec2 mViewportSize;
};
} // Scene
} // ACGL