Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Curioni <maxime.curioni@gmail.com>2008-05-25 21:34:21 +0400
committerMaxime Curioni <maxime.curioni@gmail.com>2008-05-25 21:34:21 +0400
commit8518e500d185e68f2c23015b835328e7c6564b13 (patch)
tree9ff1f37fadcf1712439f7b7e8c5e9754740a7bd0 /source/blender/freestyle/intern/app_blender
parent8ef2f1d524d81bce565d08f647805e6084de54de (diff)
soc-2008-mxcurioni: Big update. Finally works (links and compiles). So far, the following steps work:
1. instantiates the config path, the controller and the view 2. sets the controller’s view 3. loads a 3ds file (right now a fixed file) 4. inserts a style module (right now, also fixed) 5. computes the view map The next and final step is running the Python script. A lot of information are fixed and should be changed to test the following code: see source/blender/freestyle/app_blender/*.cpp and search for fixed paths (starting in /Users/). I am currently evaluating whether it's worth making Python run on its own environment (right now, the program crashes because of PyImport_AddModule) or whether it should use Blender's Python capabilities. Also, I need to figure out how to integrate the SWIG wrapper dynamic library into the current scheme.
Diffstat (limited to 'source/blender/freestyle/intern/app_blender')
-rwxr-xr-xsource/blender/freestyle/intern/app_blender/AppCanvas.cpp1
-rwxr-xr-xsource/blender/freestyle/intern/app_blender/AppConfig.cpp10
-rwxr-xr-xsource/blender/freestyle/intern/app_blender/AppGLWidget.cpp32
-rwxr-xr-xsource/blender/freestyle/intern/app_blender/AppGLWidget.h109
-rwxr-xr-xsource/blender/freestyle/intern/app_blender/Controller.cpp11
-rwxr-xr-xsource/blender/freestyle/intern/app_blender/Controller.h4
-rw-r--r--source/blender/freestyle/intern/app_blender/api.cpp20
-rw-r--r--source/blender/freestyle/intern/app_blender/camera.cpp1799
-rw-r--r--source/blender/freestyle/intern/app_blender/camera.h565
-rw-r--r--source/blender/freestyle/intern/app_blender/config.h50
-rw-r--r--source/blender/freestyle/intern/app_blender/constraint.h341
-rw-r--r--source/blender/freestyle/intern/app_blender/frame.cpp1070
-rw-r--r--source/blender/freestyle/intern/app_blender/frame.h408
-rw-r--r--source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.cpp86
-rw-r--r--source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.h169
-rw-r--r--source/blender/freestyle/intern/app_blender/manipulatedFrame.cpp116
-rw-r--r--source/blender/freestyle/intern/app_blender/manipulatedFrame.h256
-rw-r--r--source/blender/freestyle/intern/app_blender/old_camera_vec_quaternion.txt593
-rw-r--r--source/blender/freestyle/intern/app_blender/point.h159
-rw-r--r--source/blender/freestyle/intern/app_blender/quaternion.cpp502
-rw-r--r--source/blender/freestyle/intern/app_blender/quaternion.h304
-rw-r--r--source/blender/freestyle/intern/app_blender/vec.cpp75
-rw-r--r--source/blender/freestyle/intern/app_blender/vec.h366
23 files changed, 6955 insertions, 91 deletions
diff --git a/source/blender/freestyle/intern/app_blender/AppCanvas.cpp b/source/blender/freestyle/intern/app_blender/AppCanvas.cpp
index c9ea2d1391d..5125bf5f70b 100755
--- a/source/blender/freestyle/intern/app_blender/AppCanvas.cpp
+++ b/source/blender/freestyle/intern/app_blender/AppCanvas.cpp
@@ -29,6 +29,7 @@
#include "../rendering/GLStrokeRenderer.h"
#include "../rendering/GLUtils.h"
#include "AppConfig.h"
+
#include "../system/StringUtils.h"
#ifdef WIN32
diff --git a/source/blender/freestyle/intern/app_blender/AppConfig.cpp b/source/blender/freestyle/intern/app_blender/AppConfig.cpp
index baa847322d6..de4b71c5241 100755
--- a/source/blender/freestyle/intern/app_blender/AppConfig.cpp
+++ b/source/blender/freestyle/intern/app_blender/AppConfig.cpp
@@ -31,8 +31,12 @@ namespace Config{
// get the home directory
_HomeDir = getEnvVar("HOME");
// get the root directory
- setRootDir(getEnvVar("FREESTYLE_DIR"));
- //setRootDir(QString("."));
+ //soc
+ //setRootDir(getEnvVar("FREESTYLE_BLENDER_DIR"));
+ setRootDir("/Users/mx/Documents/work/GSoC_2008/bf-blender/branches/soc-2008-mxcurioni/source/blender/freestyle");
+ cout << _PythonPath << endl;
+
+//setRootDir(QString("."));
_pInstance = this;
}
void Path::setRootDir(const string& iRootDir){
@@ -59,7 +63,7 @@ namespace Config{
"python" +
string(PATH_SEP.c_str()) +
_ProjectDir +
- string(DIR_SEP.c_str()) +
+ string(DIR_SEP.c_str()) +
"style_modules" +
string(DIR_SEP.c_str()) ;
if (getenv("PYTHONPATH")) {
diff --git a/source/blender/freestyle/intern/app_blender/AppGLWidget.cpp b/source/blender/freestyle/intern/app_blender/AppGLWidget.cpp
index 44e25ee1321..18e9639342d 100755
--- a/source/blender/freestyle/intern/app_blender/AppGLWidget.cpp
+++ b/source/blender/freestyle/intern/app_blender/AppGLWidget.cpp
@@ -36,9 +36,12 @@
#include "AppConfig.h"
#include "../system/StringUtils.h"
+
+extern "C" {
#include "BLI_blenlib.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+}
// glut.h must be included last to avoid a conflict with stdlib.h on vc .net 2003 and 2005
#ifdef __MACH__
@@ -54,6 +57,9 @@ bool AppGLWidget::_backBufferFlag = true;
AppGLWidget::AppGLWidget(const char *iName)
{
+ //soc
+ _camera = new Camera;
+
_Fovy = 30.f;
//_SceneDepth = 2.f;
_RenderStyle = LINE;
@@ -146,8 +152,6 @@ AppGLWidget::AppGLWidget(const char *iName)
// _backBufferFlag = true;
_record = false;
-_camera = new Camera;
-
}
AppGLWidget::~AppGLWidget()
@@ -609,3 +613,27 @@ bool AppGLWidget::getBackBufferFlag() {
// delete [] colorPixels;
//}
+
+//*******************************
+// COPIED FROM LIBQGLVIEWER
+//*******************************
+
+ // inherited
+ void AppGLWidget::swapBuffers() {}
+
+ //Updates the display. Do not call draw() directly, use this method instead.
+ void AppGLWidget::updateGL() {}
+
+ //Makes this widget's rendering context the current OpenGL rendering context. Useful with several viewers
+ void AppGLWidget::makeCurrent() {}
+
+
+ // not-inherited
+
+ // Convenient way to call setSceneCenter() and setSceneRadius() from a (world axis aligned) bounding box of the scene.
+ void AppGLWidget::setSceneBoundingBox(const Vec& min, const Vec& max) { _camera->setSceneBoundingBox(min,max); }
+
+ void AppGLWidget::saveSnapshot(bool b) {}
+
+ void AppGLWidget::setStateFileName(const string& name) { stateFileName_ = name; };
+
diff --git a/source/blender/freestyle/intern/app_blender/AppGLWidget.h b/source/blender/freestyle/intern/app_blender/AppGLWidget.h
index 0d10049ee15..492fafc883a 100755
--- a/source/blender/freestyle/intern/app_blender/AppGLWidget.h
+++ b/source/blender/freestyle/intern/app_blender/AppGLWidget.h
@@ -47,6 +47,11 @@ using namespace std;
# include "../rendering/GLDebugRenderer.h"
//# include <QGLViewer/qglviewer.h>
+//soc
+#include "camera.h"
+#include "vec.h"
+#include "quaternion.h"
+
using namespace Geometry;
typedef enum {SURFACIC, LINE, DEPTHBUFFER} RenderStyle;
@@ -58,75 +63,9 @@ class GLSelectRenderer;
class GLBBoxRenderer;
class GLMonoColorRenderer;
class GLDebugRenderer;
-
-class Vec{
-public:
- Vec() {};
- Vec(float _x, float _y, float _z): x(_x), y(_y), z(_z) {};
- ~Vec() {}
-
- float operator[] (unsigned i) {
- switch(i){
- case 0: return x; break;
- case 1: return y; break;
- case 2: return z; break;
- }
- return 0.0;
- }
-
-
- float x,y,z;
-};
-
-class Quaternion{
-public:
- Quaternion( float _x, float _y, float _z, float _s): x(_x), y(_y), z(_z), s(_s){};
- ~Quaternion() {}
-
- float operator[] (unsigned i) {
- switch(i){
- case 0: return x; break;
- case 1: return y; break;
- case 2: return z; break;
- case 3: return s; break;
- }
- return 0.0;
- }
-
- float x,y,z,s;
-};
-
-class Camera {
- private:
- float _position[3];
- float _orientation[3];
-
- public:
- Camera(){};
- ~Camera() {};
-
- void setZNearCoefficient(float f) {}
- void playPath(int i) {}
-
- void loadProjectionMatrix() {}
- void loadModelViewMatrix() {}
- real distanceToSceneCenter() { return 0;}
- void showEntireScene() {}
- real zFar() {return 0;}
- real zNear() {return 0;}
- void setPosition(Vec v) {}
- void setOrientation(Quaternion q) {}
- float* position() { return _position; }
- float* orientation() { return _orientation; }
- void getWorldCoordinatesOf(float *src, float *vp_tmp) {}
-
-};
-
-
-//class AppGLWidget : public QGLViewer
+
class AppGLWidget
{
- //Q_OBJECT
public:
@@ -136,17 +75,27 @@ public:
public:
- inline void swapBuffers() {}
- inline void updateGL() {}
- inline void makeCurrent() {}
- inline void setSceneBoundingBox(Vec &min_, Vec &max_) {}
- inline void saveSnapshot(bool b) {}
- inline real width() { return _width; }
- inline real height() { return _height; }
- void setStateFileName(const string& name) { stateFileName_ = name; };
+ //inherited
+ inline real width() { return _width; }
+ inline real height() { return _height; }
+ void swapBuffers();
+ void updateGL();
+ void makeCurrent();
+ // not-inherited
+ void setSceneBoundingBox(const Vec& min, const Vec& max);
+ void saveSnapshot(bool b);
+ void setStateFileName(const string& name);
-Camera * _camera;
+
+ Camera * _camera;
+
+protected:
+ real _width, _height;
+ Vec _min,_max;
+ string stateFileName_;
+
+public:
// captures a frame animation that was previously registered
void captureMovie();
@@ -452,8 +401,8 @@ Camera * _camera;
}
void getCameraState(float* position, float* orientation) const {
- float* pos = _camera->position();
- float* orient = _camera->orientation();
+ Vec pos = _camera->position();
+ Quaternion orient = _camera->orientation();
int i;
for(i=0;i<3;++i){
position[i] = pos[i];
@@ -585,9 +534,7 @@ protected:
bool _record;
-real _width, _height;
-Vec _min,_max;
-string stateFileName_;
+
};
#endif // ARTGLWIDGET_H
diff --git a/source/blender/freestyle/intern/app_blender/Controller.cpp b/source/blender/freestyle/intern/app_blender/Controller.cpp
index edc1b7f663a..9401f1ae281 100755
--- a/source/blender/freestyle/intern/app_blender/Controller.cpp
+++ b/source/blender/freestyle/intern/app_blender/Controller.cpp
@@ -67,9 +67,9 @@
Controller::Controller()
{
+
const string sep(Config::DIR_SEP.c_str());
- const string filename = Config::Path::getInstance()->getHomeDir() + sep +
- Config::OPTIONS_DIR + sep + Config::OPTIONS_CURRENT_DIRS_FILE;
+ //const string filename = Config::Path::getInstance()->getHomeDir() + sep + Config::OPTIONS_DIR + sep + Config::OPTIONS_CURRENT_DIRS_FILE;
//_current_dirs = new ConfigIO(filename, Config::APPLICATION_NAME + "CurrentDirs", true);
_RootNode = new NodeGroup;
@@ -88,6 +88,7 @@ Controller::Controller()
_edgeTesselationNature = (Nature::SILHOUETTE | Nature::BORDER | Nature::CREASE);
+ _ProgressBar = new ProgressBar;
_SceneNumFaces = 0;
_minEdgeSize = DBL_MAX;
_bboxDiag = 0;
@@ -180,9 +181,12 @@ int Controller::Load3DSFile(const char *iFileName)
NodeGroup *maxScene = loader3DS.Load();
if (maxScene == NULL) {
+ cout << "Cannot load scene" << endl;
return 1;
}
+ cout << "Scene loaded\n" << endl;
+
printf("Mesh cleaning : %lf\n", _Chrono.stop());
_SceneNumFaces += loader3DS.numFacesRead();
@@ -199,13 +203,14 @@ int Controller::Load3DSFile(const char *iFileName)
// DEBUG
// ScenePrettyPrinter spp;
// maxScene->accept(spp);
-
+
_RootNode->AddChild(maxScene);
_RootNode->UpdateBBox(); // FIXME: Correct that by making a Renderer to compute the bbox
_pView->SetModel(_RootNode);
_pView->FitBBox();
+
_Chrono.start();
diff --git a/source/blender/freestyle/intern/app_blender/Controller.h b/source/blender/freestyle/intern/app_blender/Controller.h
index 55ef1968129..5727db5705a 100755
--- a/source/blender/freestyle/intern/app_blender/Controller.h
+++ b/source/blender/freestyle/intern/app_blender/Controller.h
@@ -36,6 +36,7 @@
# include "../geometry/HashGrid.h"
# include "../view_map/ViewMapBuilder.h"
# include "../system/TimeUtils.h"
+# include "../system/ProgressBar.h"
# include "../system/Precision.h"
# include "../system/Interpreter.h"
# include "../view_map/FEdgeXDetector.h"
@@ -172,6 +173,9 @@ private:
// Chronometer:
Chronometer _Chrono;
+ // Progress Bar
+ ProgressBar *_ProgressBar;
+
// edges tesselation nature
int _edgeTesselationNature;
diff --git a/source/blender/freestyle/intern/app_blender/api.cpp b/source/blender/freestyle/intern/app_blender/api.cpp
index 78ab50a7c4d..0601ce191f9 100644
--- a/source/blender/freestyle/intern/app_blender/api.cpp
+++ b/source/blender/freestyle/intern/app_blender/api.cpp
@@ -1,4 +1,8 @@
+
+#include "AppGLWidget.h"
#include "Controller.h"
+#include "AppConfig.h"
+
#include <iostream>
using namespace std;
@@ -8,11 +12,23 @@ extern "C" {
#endif
void FRS_execute() {
- cout << "Freestyle" << endl;
+ cout << "Freestyle start" << endl;
+ Config::Path pathconfig;
Controller *c = new Controller;
+ AppGLWidget *view = new AppGLWidget;
+
+ c->SetView(view);
- //c->Load3DSFile( "/Users/mx/Documents/work/GSoC_2008/bf-blender/branches/soc-2008-mxcurioni/source/blender/freestyle/data/models/teapot.3DS" );
+ c->Load3DSFile( "/Users/mx/Documents/work/GSoC_2008/bf-blender/branches/soc-2008-mxcurioni/source/blender/freestyle/data/models/teapot.3DS" );
+
+ c->InsertStyleModule( 0, "/Users/mx/Documents/work/GSoC_2008/bf-blender/branches/soc-2008-mxcurioni/source/blender/freestyle/style_modules/contour.py" );
+ c->toggleLayer(0, true);
+ c->ComputeViewMap();
+
+ //c->DrawStrokes();
+
+ cout << "Freestyle end" << endl;
}
diff --git a/source/blender/freestyle/intern/app_blender/camera.cpp b/source/blender/freestyle/intern/app_blender/camera.cpp
new file mode 100644
index 00000000000..25af0550e6c
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/camera.cpp
@@ -0,0 +1,1799 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "camera.h"
+//#include "qglviewer.h"
+
+using namespace std;
+//using namespace qglviewer;
+
+/*! Default constructor.
+
+ sceneCenter() is set to (0,0,0) and sceneRadius() is set to 1.0. type() is Camera::PERSPECTIVE,
+ with a \c M_PI/4 fieldOfView().
+
+ See IODistance(), physicalDistanceToScreen(), physicalScreenWidth() and focusDistance()
+ documentations for default stereo parameter values. */
+Camera::Camera()
+ : fieldOfView_(M_PI/4.0f)
+{
+ // #CONNECTION# Camera copy constructor
+ //interpolationKfi_ = new KeyFrameInterpolator;
+ // Requires the interpolationKfi_
+ setFrame(new ManipulatedCameraFrame());
+
+ // #CONNECTION# All these default values identical in initFromDOMElement.
+
+ // Requires fieldOfView() to define focusDistance()
+ setSceneRadius(1.0);
+
+ // Initial value (only scaled after this)
+ orthoCoef_ = tan(fieldOfView()/2.0);
+
+ // Also defines the revolveAroundPoint(), which changes orthoCoef_. Requires a frame().
+ setSceneCenter(Vec(0.0, 0.0, 0.0));
+
+ // Requires fieldOfView() when called with ORTHOGRAPHIC. Attention to projectionMatrix_ below.
+ setType(PERSPECTIVE);
+
+ // #CONNECTION# initFromDOMElement default values
+ setZNearCoefficient(0.005f);
+ setZClippingCoefficient(sqrt(3.0));
+
+ // Dummy values
+ setScreenWidthAndHeight(600, 400);
+
+ // Stereo parameters
+ setIODistance(0.062f);
+ setPhysicalDistanceToScreen(0.5f);
+ setPhysicalScreenWidth(0.4f);
+ // focusDistance is set from setFieldOfView()
+
+ // #CONNECTION# Camera copy constructor
+ for (unsigned short j=0; j<16; ++j)
+ {
+ modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0);
+ // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost everywhere.
+ projectionMatrix_[j] = 0.0;
+ }
+ computeProjectionMatrix();
+}
+
+/*! Virtual destructor.
+
+ The frame() is deleted, but the different keyFrameInterpolator() are \e not deleted (in case they
+ are shared). */
+Camera::~Camera()
+{
+ delete frame_;
+ //delete interpolationKfi_;
+}
+
+
+/*! Copy constructor. Performs a deep copy using operator=(). */
+Camera::Camera(const Camera& camera)
+{
+ // #CONNECTION# Camera constructor
+ //interpolationKfi_ = new KeyFrameInterpolator;
+ // Requires the interpolationKfi_
+ setFrame(new ManipulatedCameraFrame());
+
+ for (unsigned short j=0; j<16; ++j)
+ {
+ modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0);
+ // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost everywhere.
+ projectionMatrix_[j] = 0.0;
+ }
+
+ (*this)=camera;
+}
+
+/*! Equal operator.
+
+ All the parameters of \p camera are copied. The frame() pointer is not modified, but its
+ Frame::position() and Frame::orientation() are set to those of \p camera.
+
+ \attention The Camera screenWidth() and screenHeight() are set to those of \p camera. If your
+ Camera is associated with a QGLViewer, you should update these value after the call to this method:
+ \code
+ *(camera()) = otherCamera;
+ camera()->setScreenWidthAndHeight(width(), height());
+ \endcode
+ The same applies to sceneCenter() and sceneRadius(), if needed. */
+Camera& Camera::operator=(const Camera& camera)
+{
+ setScreenWidthAndHeight(camera.screenWidth(), camera.screenHeight());
+ setFieldOfView(camera.fieldOfView());
+ setSceneRadius(camera.sceneRadius());
+ setSceneCenter(camera.sceneCenter());
+ setZNearCoefficient(camera.zNearCoefficient());
+ setZClippingCoefficient(camera.zClippingCoefficient());
+ setType(camera.type());
+
+ // Stereo parameters
+ setIODistance(camera.IODistance());
+ setFocusDistance(camera.focusDistance());
+ setPhysicalScreenWidth(camera.physicalScreenWidth());
+ setPhysicalDistanceToScreen(camera.physicalDistanceToScreen());
+
+ orthoCoef_ = camera.orthoCoef_;
+
+ // frame_ and interpolationKfi_ pointers are not shared.
+ frame_->setReferenceFrame(NULL);
+ frame_->setPosition(camera.position());
+ frame_->setOrientation(camera.orientation());
+
+ //interpolationKfi_->resetInterpolation();
+
+ //kfi_ = camera.kfi_;
+
+ computeProjectionMatrix();
+ computeModelViewMatrix();
+
+ return *this;
+}
+
+/*! Sets Camera screenWidth() and screenHeight() (expressed in pixels).
+
+You should not call this method when the Camera is associated with a QGLViewer, since the
+latter automatically updates these values when it is resized (hence overwritting your values).
+
+Non-positive dimension are silently replaced by a 1 pixel value to ensure frustrum coherence.
+
+If your Camera is used without a QGLViewer (offscreen rendering, shadow maps), use setAspectRatio()
+instead to define the projection matrix. */
+void Camera::setScreenWidthAndHeight(int width, int height)
+{
+ // Prevent negative and zero dimensions that would cause divisions by zero.
+ screenWidth_ = width > 0 ? width : 1;
+ screenHeight_ = height > 0 ? height : 1;
+}
+
+/*! Returns the near clipping plane distance used by the Camera projection matrix.
+
+ The clipping planes' positions depend on the sceneRadius() and sceneCenter() rather than being fixed
+ small-enough and large-enough values. A good scene dimension approximation will hence result in an
+ optimal precision of the z-buffer.
+
+ The near clipping plane is positioned at a distance equal to zClippingCoefficient() * sceneRadius()
+ in front of the sceneCenter():
+ \code
+ zNear = distanceToSceneCenter() - zClippingCoefficient()*sceneRadius();
+ \endcode
+
+ In order to prevent negative or too small zNear() values (which would degrade the z precision),
+ zNearCoefficient() is used when the Camera is inside the sceneRadius() sphere:
+ \code
+ const float zMin = zNearCoefficient() * zClippingCoefficient() * sceneRadius();
+ if (zNear < zMin)
+ zNear = zMin;
+ // With an ORTHOGRAPHIC type, the value is simply clamped to 0.0
+ \endcode
+
+ See also the zFar(), zClippingCoefficient() and zNearCoefficient() documentations.
+
+ If you need a completely different zNear computation, overload the zNear() and zFar() methods in a
+ new class that publicly inherits from Camera and use QGLViewer::setCamera():
+ \code
+ class myCamera :: public qglviewer::Camera
+ {
+ virtual float Camera::zNear() const { return 0.001; };
+ virtual float Camera::zFar() const { return 100.0; };
+ }
+ \endcode
+
+ See the <a href="../examples/standardCamera.html">standardCamera example</a> for an application.
+
+ \attention The value is always positive although the clipping plane is positioned at a negative z
+ value in the Camera coordinate system. This follows the \c gluPerspective standard. */
+float Camera::zNear() const
+{
+ float z = distanceToSceneCenter() - zClippingCoefficient()*sceneRadius();
+
+ // Prevents negative or null zNear values.
+ const float zMin = zNearCoefficient() * zClippingCoefficient() * sceneRadius();
+ if (z < zMin)
+ switch (type())
+ {
+ case Camera::PERSPECTIVE : z = zMin; break;
+ case Camera::ORTHOGRAPHIC : z = 0.0; break;
+ }
+ return z;
+}
+
+/*! Returns the far clipping plane distance used by the Camera projection matrix.
+
+The far clipping plane is positioned at a distance equal to zClippingCoefficient() * sceneRadius()
+behind the sceneCenter():
+\code
+zFar = distanceToSceneCenter() + zClippingCoefficient()*sceneRadius();
+\endcode
+
+See the zNear() documentation for details. */
+float Camera::zFar() const
+{
+ return distanceToSceneCenter() + zClippingCoefficient()*sceneRadius();
+}
+
+/*! Defines the Camera type().
+
+Prefix the type with Camera, as in: \code camera()->setType(Camera::ORTHOGRAPHIC); // or even
+qglviewer::Camera::ORTHOGRAPHIC if you do not use namespace \endcode */
+void Camera::setType(Type type)
+{
+ // make ORTHOGRAPHIC frustum fit PERSPECTIVE (at least in plane normal to viewDirection(), passing
+ // through RAP) Done only when CHANGING type since orthoCoef_ may have been changed with a
+ // setRevolveAroundPoint() in the meantime.
+ if ( (type == Camera::ORTHOGRAPHIC) && (type_ == Camera::PERSPECTIVE) )
+ orthoCoef_ = tan(fieldOfView()/2.0);
+ type_ = type;
+}
+
+/*! Sets the Camera frame().
+
+If you want to move the Camera, use setPosition() and setOrientation() or one of the Camera
+positioning methods (lookAt(), fitSphere(), showEntireScene()...) instead.
+
+If you want to save the Camera position(), there's no need to call this method either. Use
+addKeyFrameToPath() and playPath() instead.
+
+This method is actually mainly useful if you derive the ManipulatedCameraFrame class and want to
+use an instance of your new class to move the Camera.
+
+A \c NULL \p mcf pointer will silently be ignored. The calling method is responsible for
+deleting the previous frame() pointer if needed in order to prevent memory leaks. */
+void Camera::setFrame(ManipulatedCameraFrame* const mcf)
+{
+ if (!mcf)
+ return;
+
+ frame_ = mcf;
+ //interpolationKfi_->setFrame(frame());
+}
+
+/*! Returns the distance from the Camera center to sceneCenter(), projected along the Camera Z axis.
+ Used by zNear() and zFar() to optimize the Z range. */
+float Camera::distanceToSceneCenter() const
+{
+ return fabs((frame()->coordinatesOf(sceneCenter())).z);
+}
+
+
+/*! Returns the \p halfWidth and \p halfHeight of the Camera orthographic frustum.
+
+ These values are only valid and used when the Camera is of type() Camera::ORTHOGRAPHIC. They are
+ expressed in OpenGL units and are used by loadProjectionMatrix() to define the projection matrix
+ using:
+ \code
+ glOrtho( -halfWidth, halfWidth, -halfHeight, halfHeight, zNear(), zFar() )
+ \endcode
+
+ These values are proportional to the Camera (z projected) distance to the revolveAroundPoint().
+ When zooming on the object, the Camera is translated forward \e and its frustum is narrowed, making
+ the object appear bigger on screen, as intuitively expected.
+
+ Overload this method to change this behavior if desired, as is done in the
+ <a href="../examples/standardCamera.html">standardCamera example</a>. */
+void Camera::getOrthoWidthHeight(GLdouble& halfWidth, GLdouble& halfHeight) const
+{
+ const float dist = orthoCoef_ * fabs(cameraCoordinatesOf(revolveAroundPoint()).z);
+ //#CONNECTION# fitScreenRegion
+ halfWidth = dist * ((aspectRatio() < 1.0) ? 1.0 : aspectRatio());
+ halfHeight = dist * ((aspectRatio() < 1.0) ? 1.0/aspectRatio() : 1.0);
+}
+
+
+/*! Computes the projection matrix associated with the Camera.
+
+ If type() is Camera::PERSPECTIVE, defines a \c GL_PROJECTION matrix similar to what would \c
+ gluPerspective() do using the fieldOfView(), window aspectRatio(), zNear() and zFar() parameters.
+
+ If type() is Camera::ORTHOGRAPHIC, the projection matrix is as what \c glOrtho() would do.
+ Frustum's width and height are set using getOrthoWidthHeight().
+
+ Both types use zNear() and zFar() to place clipping planes. These values are determined from
+ sceneRadius() and sceneCenter() so that they best fit the scene size.
+
+ Use getProjectionMatrix() to retrieve this matrix. Overload loadProjectionMatrix() if you want your
+ Camera to use an exotic projection matrix.
+
+ \note You must call this method if your Camera is not associated with a QGLViewer and is used for
+ offscreen computations (using (un)projectedCoordinatesOf() for instance). loadProjectionMatrix()
+ does it otherwise. */
+void Camera::computeProjectionMatrix() const
+{
+ const float ZNear = zNear();
+ const float ZFar = zFar();
+
+ switch (type())
+ {
+ case Camera::PERSPECTIVE:
+ {
+ // #CONNECTION# all non null coefficients were set to 0.0 in constructor.
+ const float f = 1.0/tan(fieldOfView()/2.0);
+ projectionMatrix_[0] = f/aspectRatio();
+ projectionMatrix_[5] = f;
+ projectionMatrix_[10] = (ZNear + ZFar) / (ZNear - ZFar);
+ projectionMatrix_[11] = -1.0;
+ projectionMatrix_[14] = 2.0 * ZNear * ZFar / (ZNear - ZFar);
+ projectionMatrix_[15] = 0.0;
+ // same as gluPerspective( 180.0*fieldOfView()/M_PI, aspectRatio(), zNear(), zFar() );
+ break;
+ }
+ case Camera::ORTHOGRAPHIC:
+ {
+ GLdouble w, h;
+ getOrthoWidthHeight(w,h);
+ projectionMatrix_[0] = 1.0/w;
+ projectionMatrix_[5] = 1.0/h;
+ projectionMatrix_[10] = -2.0/(ZFar - ZNear);
+ projectionMatrix_[11] = 0.0;
+ projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear);
+ projectionMatrix_[15] = 1.0;
+ // same as glOrtho( -w, w, -h, h, zNear(), zFar() );
+ break;
+ }
+ }
+}
+
+/*! Computes the modelView matrix associated with the Camera's position() and orientation().
+
+ This matrix converts from the world coordinates system to the Camera coordinates system, so that
+ coordinates can then be projected on screen using the projection matrix (see computeProjectionMatrix()).
+
+ Use getModelViewMatrix() to retrieve this matrix.
+
+ \note You must call this method if your Camera is not associated with a QGLViewer and is used for
+ offscreen computations (using (un)projectedCoordinatesOf() for instance). loadModelViewMatrix()
+ does it otherwise. */
+void Camera::computeModelViewMatrix() const
+{
+ const Quaternion q = frame()->orientation();
+
+ const double q00 = 2.0l * q[0] * q[0];
+ const double q11 = 2.0l * q[1] * q[1];
+ const double q22 = 2.0l * q[2] * q[2];
+
+ const double q01 = 2.0l * q[0] * q[1];
+ const double q02 = 2.0l * q[0] * q[2];
+ const double q03 = 2.0l * q[0] * q[3];
+
+ const double q12 = 2.0l * q[1] * q[2];
+ const double q13 = 2.0l * q[1] * q[3];
+
+ const double q23 = 2.0l * q[2] * q[3];
+
+ modelViewMatrix_[0] = 1.0l - q11 - q22;
+ modelViewMatrix_[1] = q01 - q23;
+ modelViewMatrix_[2] = q02 + q13;
+ modelViewMatrix_[3] = 0.0l;
+
+ modelViewMatrix_[4] = q01 + q23;
+ modelViewMatrix_[5] = 1.0l - q22 - q00;
+ modelViewMatrix_[6] = q12 - q03;
+ modelViewMatrix_[7] = 0.0l;
+
+ modelViewMatrix_[8] = q02 - q13;
+ modelViewMatrix_[9] = q12 + q03;
+ modelViewMatrix_[10] = 1.0l - q11 - q00;
+ modelViewMatrix_[11] = 0.0l;
+
+ const Vec t = q.inverseRotate(frame()->position());
+
+ modelViewMatrix_[12] = -t.x;
+ modelViewMatrix_[13] = -t.y;
+ modelViewMatrix_[14] = -t.z;
+ modelViewMatrix_[15] = 1.0l;
+}
+
+
+/*! Loads the OpenGL \c GL_PROJECTION matrix with the Camera projection matrix.
+
+ The Camera projection matrix is computed using computeProjectionMatrix().
+
+ When \p reset is \c true (default), the method clears the previous projection matrix by calling \c
+ glLoadIdentity before setting the matrix. Setting \p reset to \c false is useful for \c GL_SELECT
+ mode, to combine the pushed matrix with a picking matrix. See QGLViewer::beginSelection() for details.
+
+ This method is used by QGLViewer::preDraw() (called before user's QGLViewer::draw() method) to
+ set the \c GL_PROJECTION matrix according to the viewer's QGLViewer::camera() settings.
+
+ Use getProjectionMatrix() to retrieve this matrix. Overload this method if you want your Camera to
+ use an exotic projection matrix. See also loadModelViewMatrix().
+
+ \attention \c glMatrixMode is set to \c GL_PROJECTION.
+
+ \attention If you use several OpenGL contexts and bypass the Qt main refresh loop, you should call
+ QGLWidget::makeCurrent() before this method in order to activate the right OpenGL context. */
+void Camera::loadProjectionMatrix(bool reset) const
+{
+ // WARNING: makeCurrent must be called by every calling method
+ glMatrixMode(GL_PROJECTION);
+
+ if (reset)
+ glLoadIdentity();
+
+ computeProjectionMatrix();
+
+ glMultMatrixd(projectionMatrix_);
+}
+
+/*! Loads the OpenGL \c GL_MODELVIEW matrix with the modelView matrix corresponding to the Camera.
+
+ Calls computeModelViewMatrix() to compute the Camera's modelView matrix.
+
+ This method is used by QGLViewer::preDraw() (called before user's QGLViewer::draw() method) to
+ set the \c GL_MODELVIEW matrix according to the viewer's QGLViewer::camera() position() and
+ orientation().
+
+ As a result, the vertices used in QGLViewer::draw() can be defined in the so called world
+ coordinate system. They are multiplied by this matrix to get converted to the Camera coordinate
+ system, before getting projected using the \c GL_PROJECTION matrix (see loadProjectionMatrix()).
+
+ When \p reset is \c true (default), the method loads (overwrites) the \c GL_MODELVIEW matrix. Setting
+ \p reset to \c false simply calls \c glMultMatrixd (might be useful for some applications).
+
+ Overload this method or simply call glLoadMatrixd() at the beginning of QGLViewer::draw() if you
+ want your Camera to use an exotic modelView matrix. See also loadProjectionMatrix().
+
+ getModelViewMatrix() returns the 4x4 modelView matrix.
+
+ \attention glMatrixMode is set to \c GL_MODELVIEW
+
+ \attention If you use several OpenGL contexts and bypass the Qt main refresh loop, you should call
+ QGLWidget::makeCurrent() before this method in order to activate the right OpenGL context. */
+void Camera::loadModelViewMatrix(bool reset) const
+{
+ // WARNING: makeCurrent must be called by every calling method
+ glMatrixMode(GL_MODELVIEW);
+ computeModelViewMatrix();
+ if (reset)
+ glLoadMatrixd(modelViewMatrix_);
+ else
+ glMultMatrixd(modelViewMatrix_);
+}
+
+/*! Same as loadProjectionMatrix() but for a stereo setup.
+
+ Only the Camera::PERSPECTIVE type() is supported for stereo mode. See
+ QGLViewer::setStereoDisplay().
+
+ Uses focusDistance(), IODistance(), and physicalScreenWidth() to compute cameras
+ offset and asymmetric frustums.
+
+ When \p leftBuffer is \c true, computes the projection matrix associated to the left eye (right eye
+ otherwise). See also loadModelViewMatrixStereo().
+
+ See the <a href="../examples/stereoViewer.html">stereoViewer</a> and the <a
+ href="../examples/contribs.html#anaglyph">anaglyph</a> examples for an illustration.
+
+ To retrieve this matrix, use a code like:
+ \code
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ loadProjectionMatrixStereo(left_or_right);
+ glGetFloatv(GL_PROJECTION_MATRIX, m);
+ glPopMatrix();
+ \endcode
+ Note that getProjectionMatrix() always returns the mono-vision matrix.
+
+ \attention glMatrixMode is set to \c GL_PROJECTION. */
+void Camera::loadProjectionMatrixStereo(bool leftBuffer) const
+{
+ float left, right, bottom, top;
+ float screenHalfWidth, halfWidth, side, shift, delta;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ switch (type())
+ {
+ case Camera::PERSPECTIVE:
+ // compute half width of screen,
+ // corresponding to zero parallax plane to deduce decay of cameras
+ screenHalfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0);
+ shift = screenHalfWidth * IODistance() / physicalScreenWidth();
+ // should be * current y / y total
+ // to take into account that the window doesn't cover the entire screen
+
+ // compute half width of "view" at znear and the delta corresponding to
+ // the shifted camera to deduce what to set for asymmetric frustums
+ halfWidth = zNear() * tan(horizontalFieldOfView() / 2.0);
+ delta = shift * zNear() / focusDistance();
+ side = leftBuffer ? -1.0 : 1.0;
+
+ left = -halfWidth + side * delta;
+ right = halfWidth + side * delta;
+ top = halfWidth / aspectRatio();
+ bottom = -top;
+ glFrustum(left, right, bottom, top, zNear(), zFar() );
+ break;
+
+ case Camera::ORTHOGRAPHIC:
+ cout << "Camera::setProjectionMatrixStereo: Stereo not available with Ortho mode";
+ break;
+ }
+}
+
+/*! Same as loadModelViewMatrix() but for a stereo setup.
+
+ Only the Camera::PERSPECTIVE type() is supported for stereo mode. See
+ QGLViewer::setStereoDisplay().
+
+ The modelView matrix is almost identical to the mono-vision one. It is simply translated along its
+ horizontal axis by a value that depends on stereo parameters (see focusDistance(),
+ IODistance(), and physicalScreenWidth()).
+
+ When \p leftBuffer is \c true, computes the modelView matrix associated to the left eye (right eye
+ otherwise).
+
+ loadProjectionMatrixStereo() explains how to retrieve to resulting matrix.
+
+ See the <a href="../examples/stereoViewer.html">stereoViewer</a> and the <a
+ href="../examples/contribs.html#anaglyph">anaglyph</a> examples for an illustration.
+
+ \attention glMatrixMode is set to \c GL_MODELVIEW. */
+void Camera::loadModelViewMatrixStereo(bool leftBuffer) const
+{
+ // WARNING: makeCurrent must be called by every calling method
+ glMatrixMode(GL_MODELVIEW);
+
+ float halfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0);
+ float shift = halfWidth * IODistance() / physicalScreenWidth(); // * current window width / full screen width
+
+ computeModelViewMatrix();
+ if (leftBuffer)
+ modelViewMatrix_[12] -= shift;
+ else
+ modelViewMatrix_[12] += shift;
+ glLoadMatrixd(modelViewMatrix_);
+}
+
+/*! Fills \p m with the Camera projection matrix values.
+
+ Calls computeProjectionMatrix() to define the Camera projection matrix.
+
+ This matrix only reflects the Camera's internal parameters and it may differ from the \c
+ GL_PROJECTION matrix retrieved using \c glGetDoublev(GL_PROJECTION_MATRIX, m). It actually
+ represents the state of the \c GL_PROJECTION after QGLViewer::preDraw(), at the beginning of
+ QGLViewer::draw(). If you modified the \c GL_PROJECTION matrix (for instance using
+ QGLViewer::startScreenCoordinatesSystem()), the two results differ.
+
+ The result is an OpenGL 4x4 matrix, which is given in \e column-major order (see \c glMultMatrix
+ man page for details).
+
+ See also getModelViewMatrix() and setFromProjectionMatrix(). */
+void Camera::getProjectionMatrix(GLdouble m[16]) const
+{
+ // May not be needed, but easier and more robust like this.
+ computeProjectionMatrix();
+ for (unsigned short i=0; i<16; ++i)
+ m[i] = projectionMatrix_[i];
+}
+
+/*! Fills \p m with the Camera modelView matrix values.
+
+ First calls computeModelViewMatrix() to define the Camera modelView matrix.
+
+ Note that this matrix is usually \e not the one you would get from a \c
+ glGetDoublev(GL_MODELVIEW_MATRIX, m). It actually represents the state of the \c
+ GL_MODELVIEW after QGLViewer::preDraw(), at the beginning of QGLViewer::draw(). It converts from
+ the world to the Camera coordinate system. As soon as you modify the \c GL_MODELVIEW in your
+ QGLViewer::draw() method, the two matrices differ.
+
+ The result is an OpenGL 4x4 matrix, which is given in \e column-major order (see \c glMultMatrix
+ man page for details).
+
+ See also getProjectionMatrix() and setFromModelViewMatrix(). */
+void Camera::getModelViewMatrix(GLdouble m[16]) const
+{
+ // May not be needed, but easier like this.
+ // Prevents from retrieving matrix in stereo mode -> overwrites shifted value.
+ computeModelViewMatrix();
+ for (unsigned short i=0; i<16; ++i)
+ m[i] = modelViewMatrix_[i];
+}
+
+/*! Fills \p m with the product of the ModelView and Projection matrices.
+
+ Calls getModelViewMatrix() and getProjectionMatrix() and then fills \p m with the product of these two matrices. */
+void Camera::getModelViewProjectionMatrix(GLdouble m[16]) const
+{
+ GLdouble mv[16];
+ GLdouble proj[16];
+ getModelViewMatrix(mv);
+ getProjectionMatrix(proj);
+
+ for (unsigned short i=0; i<4; ++i)
+ {
+ for (unsigned short j=0; j<4; ++j)
+ {
+ double sum = 0.0;
+ for (unsigned short k=0; k<4; ++k)
+ sum += proj[i+4*k]*mv[k+4*j];
+ m[i+4*j] = sum;
+ }
+ }
+}
+
+#ifndef DOXYGEN
+void Camera::getProjectionMatrix(GLfloat m[16]) const
+{
+ cout << "Warning : Camera::getProjectionMatrix requires a GLdouble matrix array";
+ static GLdouble mat[16];
+ getProjectionMatrix(mat);
+ for (int i=0; i<16; ++i)
+ m[i] = float(mat[i]);
+}
+
+void Camera::getModelViewMatrix(GLfloat m[16]) const
+{
+ cout << "Warning : Camera::getModelViewMatrix requires a GLdouble matrix array";
+ static GLdouble mat[16];
+ getModelViewMatrix(mat);
+ for (int i=0; i<16; ++i)
+ m[i] = float(mat[i]);
+}
+#endif
+
+/*! Sets the sceneRadius() value. Negative values are ignored.
+
+\attention This methods also sets focusDistance() to sceneRadius() / tan(fieldOfView()/2) and
+flySpeed() to 1% of sceneRadius(). */
+void Camera::setSceneRadius(float radius)
+{
+ if (radius <= 0.0)
+ {
+ cout << "Scene radius must be positive - Ignoring value";
+ return;
+ }
+
+ sceneRadius_ = radius;
+
+ setFocusDistance(sceneRadius() / tan(fieldOfView()/2.0));
+
+ frame()->setFlySpeed(0.01*sceneRadius());
+}
+
+/*! Similar to setSceneRadius() and setSceneCenter(), but the scene limits are defined by a (world
+ axis aligned) bounding box. */
+void Camera::setSceneBoundingBox(const Vec& min, const Vec& max)
+{
+ setSceneCenter((min+max)/2.0);
+ setSceneRadius(0.5*(max-min).norm());
+}
+
+
+/*! Sets the sceneCenter().
+
+ \attention This method also sets the revolveAroundPoint() to sceneCenter(). */
+void Camera::setSceneCenter(const Vec& center)
+{
+ sceneCenter_ = center;
+ setRevolveAroundPoint(sceneCenter());
+}
+
+/*! setSceneCenter() to the result of pointUnderPixel(\p pixel).
+
+ Returns \c true if a pointUnderPixel() was found and sceneCenter() was actually changed.
+
+ See also setRevolveAroundPointFromPixel(). See the pointUnderPixel() documentation. */
+bool Camera::setSceneCenterFromPixel(const Point& pixel)
+{
+ bool found;
+ Vec point = pointUnderPixel(pixel, found);
+ if (found)
+ setSceneCenter(point);
+ return found;
+}
+
+/*! Changes the revolveAroundPoint() to \p rap (defined in the world coordinate system). */
+void Camera::setRevolveAroundPoint(const Vec& rap)
+{
+ const float prevDist = fabs(cameraCoordinatesOf(revolveAroundPoint()).z);
+
+ frame()->setRevolveAroundPoint(rap);
+
+ // orthoCoef_ is used to compensate for changes of the revolveAroundPoint, so that the image does
+ // not change when the revolveAroundPoint is changed in ORTHOGRAPHIC mode.
+ const float newDist = fabs(cameraCoordinatesOf(revolveAroundPoint()).z);
+ // Prevents division by zero when rap is set to camera position
+ if ((prevDist > 1E-9) && (newDist > 1E-9))
+ orthoCoef_ *= prevDist / newDist;
+}
+
+/*! The revolveAroundPoint() is set to the point located under \p pixel on screen.
+
+Returns \c true if a pointUnderPixel() was found. If no point was found under \p pixel, the
+revolveAroundPoint() is left unchanged.
+
+\p pixel is expressed in Qt format (origin in the upper left corner of the window). See
+pointUnderPixel().
+
+See also setSceneCenterFromPixel(). */
+bool Camera::setRevolveAroundPointFromPixel(const Point& pixel)
+{
+ bool found;
+ Vec point = pointUnderPixel(pixel, found);
+ if (found)
+ setRevolveAroundPoint(point);
+ return found;
+}
+
+/*! Returns the ratio between pixel and OpenGL units at \p position.
+
+ A line of \c n * pixelGLRatio() OpenGL units, located at \p position in the world coordinates
+ system, will be projected with a length of \c n pixels on screen.
+
+ Use this method to scale objects so that they have a constant pixel size on screen. The following
+ code will draw a 20 pixel line, starting at sceneCenter() and always directed along the screen
+ vertical direction:
+ \code
+ glBegin(GL_LINES);
+ glVertex3fv(sceneCenter());
+ glVertex3fv(sceneCenter() + 20 * pixelGLRatio(sceneCenter()) * camera()->upVector());
+ glEnd();
+ \endcode */
+float Camera::pixelGLRatio(const Vec& position) const
+{
+ switch (type())
+ {
+ case Camera::PERSPECTIVE :
+ return 2.0 * fabs((frame()->coordinatesOf(position)).z) * tan(fieldOfView()/2.0) / screenHeight();
+ case Camera::ORTHOGRAPHIC :
+ {
+ GLdouble w, h;
+ getOrthoWidthHeight(w,h);
+ return 2.0 * h / screenHeight();
+ }
+ }
+ // Bad compilers complain
+ return 1.0;
+}
+
+/*! Changes the Camera fieldOfView() so that the entire scene (defined by QGLViewer::sceneCenter()
+ and QGLViewer::sceneRadius()) is visible from the Camera position().
+
+ The position() and orientation() of the Camera are not modified and you first have to orientate the
+ Camera in order to actually see the scene (see lookAt(), showEntireScene() or fitSphere()).
+
+ This method is especially useful for \e shadow \e maps computation. Use the Camera positioning
+ tools (setPosition(), lookAt()) to position a Camera at the light position. Then use this method to
+ define the fieldOfView() so that the shadow map resolution is optimally used:
+ \code
+ // The light camera needs size hints in order to optimize its fieldOfView
+ lightCamera->setSceneRadius(sceneRadius());
+ lightCamera->setSceneCenter(sceneCenter());
+
+ // Place the light camera.
+ lightCamera->setPosition(lightFrame->position());
+ lightCamera->lookAt(sceneCenter());
+ lightCamera->setFOVToFitScene();
+ \endcode
+
+ See the (soon available) shadowMap contribution example for a practical implementation.
+
+ \attention The fieldOfView() is clamped to M_PI/2.0. This happens when the Camera is at a distance
+ lower than sqrt(2.0) * sceneRadius() from the sceneCenter(). It optimizes the shadow map
+ resolution, although it may miss some parts of the scene. */
+void Camera::setFOVToFitScene()
+{
+ if (distanceToSceneCenter() > sqrt(2.0)*sceneRadius())
+ setFieldOfView(2.0 * asin(sceneRadius() / distanceToSceneCenter()));
+ else
+ setFieldOfView(M_PI / 2.0f);
+}
+
+/*! Makes the Camera smoothly zoom on the pointUnderPixel() \p pixel.
+
+ Nothing happens if no pointUnderPixel() is found. Otherwise a KeyFrameInterpolator is created that
+ animates the Camera on a one second path that brings the Camera closer to the point under \p pixel.
+
+ See also interpolateToFitScene(). */
+// void Camera::interpolateToZoomOnPixel(const Point& pixel)
+// {
+// const float coef = 0.1f;
+//
+// bool found;
+// Vec target = pointUnderPixel(pixel, found);
+//
+// if (!found)
+// return;
+//
+// if (interpolationKfi_->interpolationIsStarted())
+// interpolationKfi_->stopInterpolation();
+//
+// interpolationKfi_->deletePath();
+// interpolationKfi_->addKeyFrame(*(frame()));
+//
+// interpolationKfi_->addKeyFrame(Frame(0.3f*frame()->position() + 0.7f*target, frame()->orientation()), 0.4f);
+//
+// // Small hack: attach a temporary frame to take advantage of lookAt without modifying frame
+// static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame();
+// ManipulatedCameraFrame* const originalFrame = frame();
+// tempFrame->setPosition(coef*frame()->position() + (1.0-coef)*target);
+// tempFrame->setOrientation(frame()->orientation());
+// setFrame(tempFrame);
+// lookAt(target);
+// setFrame(originalFrame);
+//
+// interpolationKfi_->addKeyFrame(*(tempFrame), 1.0);
+//
+// interpolationKfi_->startInterpolation();
+// }
+
+/*! Interpolates the Camera on a one second KeyFrameInterpolator path so that the entire scene fits
+ the screen at the end.
+
+ The scene is defined by its sceneCenter() and its sceneRadius(). See showEntireScene().
+
+ The orientation() of the Camera is not modified. See also interpolateToZoomOnPixel(). */
+// void Camera::interpolateToFitScene()
+// {
+// if (interpolationKfi_->interpolationIsStarted())
+// interpolationKfi_->stopInterpolation();
+//
+// interpolationKfi_->deletePath();
+// interpolationKfi_->addKeyFrame(*(frame()));
+//
+// // Small hack: attach a temporary frame to take advantage of lookAt without modifying frame
+// static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame();
+// ManipulatedCameraFrame* const originalFrame = frame();
+// tempFrame->setPosition(frame()->position());
+// tempFrame->setOrientation(frame()->orientation());
+// setFrame(tempFrame);
+// showEntireScene();
+// setFrame(originalFrame);
+//
+// //interpolationKfi_->addKeyFrame(*(tempFrame));
+//
+// //interpolationKfi_->startInterpolation();
+// }
+
+
+/*! Smoothly interpolates the Camera on a KeyFrameInterpolator path so that it goes to \p fr.
+
+ \p fr is expressed in world coordinates. \p duration tunes the interpolation speed (default is
+ 1 second).
+
+ See also interpolateToFitScene() and interpolateToZoomOnPixel(). */
+// void Camera::interpolateTo(const Frame& fr, float duration)
+// {
+// if (interpolationKfi_->interpolationIsStarted())
+// interpolationKfi_->stopInterpolation();
+//
+// interpolationKfi_->deletePath();
+// interpolationKfi_->addKeyFrame(*(frame()));
+// interpolationKfi_->addKeyFrame(fr, duration);
+//
+// interpolationKfi_->startInterpolation();
+// }
+
+
+/*! Returns the coordinates of the 3D point located at pixel (x,y) on screen.
+
+ Calls a \c glReadPixel to get the pixel depth and applies an unprojectedCoordinatesOf() to the
+ result. \p found indicates whether a point was found or not (i.e. background pixel, result's depth
+ is zFar() in that case).
+
+ \p x and \p y are expressed in pixel units with an origin in the upper left corner. Use
+ screenHeight() - y to convert to OpenGL standard.
+
+ \attention This method assumes that a GL context is available, and that its content was drawn using
+ the Camera (i.e. using its projection and modelview matrices). This method hence cannot be used for
+ offscreen Camera computations. Use cameraCoordinatesOf() and worldCoordinatesOf() to perform
+ similar operations in that case.
+
+ \note The precision of the z-Buffer highly depends on how the zNear() and zFar() values are fitted
+ to your scene. Loose boundaries will result in imprecision along the viewing direction. */
+Vec Camera::pointUnderPixel(const Point& pixel, bool& found) const
+{
+ float depth;
+ // Qt uses upper corner for its origin while GL uses the lower corner.
+ glReadPixels(pixel.x(), screenHeight()-1-pixel.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
+ found = depth < 1.0;
+ Vec point(pixel.x(), pixel.y(), depth);
+ point = unprojectedCoordinatesOf(point);
+ return point;
+}
+
+/*! Moves the Camera so that the entire scene is visible.
+
+ Simply calls fitSphere() on a sphere defined by sceneCenter() and sceneRadius().
+
+ You will typically use this method in QGLViewer::init() after you defined a new sceneRadius(). */
+void Camera::showEntireScene()
+{
+ fitSphere(sceneCenter(), sceneRadius());
+}
+
+/*! Moves the Camera so that its sceneCenter() is projected on the center of the window. The
+ orientation() and fieldOfView() are unchanged.
+
+ Simply projects the current position on a line passing through sceneCenter(). See also
+ showEntireScene().*/
+void Camera::centerScene()
+{
+ frame()->projectOnLine(sceneCenter(), viewDirection());
+}
+
+/*! Sets the Camera orientation(), so that it looks at point \p target (defined in the world
+ coordinate system).
+
+ The Camera position() is not modified. Simply setViewDirection().
+
+ See also setUpVector(), setOrientation(), showEntireScene(), fitSphere() and fitBoundingBox(). */
+void Camera::lookAt(const Vec& target)
+{
+ setViewDirection(target - position());
+}
+
+/*! Moves the Camera so that the sphere defined by (\p center, \p radius) is visible and fits the window.
+
+ The Camera is simply translated along its viewDirection() so that the sphere fits the screen. Its
+ orientation() and its fieldOfView() are unchanged.
+
+ You should therefore orientate the Camera before you call this method. See lookAt(),
+ setOrientation() and setUpVector(). */
+void Camera::fitSphere(const Vec& center, float radius)
+{
+ float distance = 0.0f;
+ switch (type())
+ {
+ case Camera::PERSPECTIVE :
+ {
+ const float yview = radius / sin(fieldOfView()/2.0);
+ const float xview = radius / sin(horizontalFieldOfView()/2.0);
+ distance = qMax(xview,yview);
+ break;
+ }
+ case Camera::ORTHOGRAPHIC :
+ {
+ distance = ((center-revolveAroundPoint()) * viewDirection()) + (radius / orthoCoef_);
+ break;
+ }
+ }
+ Vec newPos(center - distance * viewDirection());
+ frame()->setPositionWithConstraint(newPos);
+}
+
+/*! Moves the Camera so that the (world axis aligned) bounding box (\p min, \p max) is entirely
+ visible, using fitSphere(). */
+void Camera::fitBoundingBox(const Vec& min, const Vec& max)
+{
+ float diameter = qMax(fabs(max[1]-min[1]), fabs(max[0]-min[0]));
+ diameter = qMax(fabsf(max[2]-min[2]), diameter);
+ fitSphere(0.5*(min+max), 0.5*diameter);
+}
+
+/*! Rotates the Camera so that its upVector() becomes \p up (defined in the world coordinate
+ system).
+
+ The Camera is rotated around an axis orthogonal to \p up and to the current upVector() direction.
+ Use this method in order to define the Camera horizontal plane.
+
+ When \p noMove is set to \c false, the orientation modification is compensated by a translation, so
+ that the revolveAroundPoint() stays projected at the same position on screen. This is especially
+ useful when the Camera is an observer of the scene (default mouse binding).
+
+ When \p noMove is \c true (default), the Camera position() is left unchanged, which is an intuitive
+ behavior when the Camera is in a walkthrough fly mode (see the QGLViewer::MOVE_FORWARD and
+ QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction). */
+void Camera::setUpVector(const Vec& up, bool noMove)
+{
+ Quaternion q(Vec(0.0, 1.0, 0.0), frame()->transformOf(up));
+
+ if (!noMove)
+ frame()->setPosition(revolveAroundPoint() - (frame()->orientation()*q).rotate(frame()->coordinatesOf(revolveAroundPoint())));
+
+ frame()->rotate(q);
+
+ // Useful in fly mode to keep the horizontal direction.
+ //frame()->updateFlyUpVector();
+}
+
+/*! Sets the orientation() of the Camera using polar coordinates.
+
+ \p theta rotates the Camera around its Y axis, and \e then \p phi rotates it around its X axis.
+ The polar coordinates are defined in the world coordinates system: \p theta = \p phi = 0 means
+ that the Camera is directed towards the world Z axis. Both angles are expressed in radians.
+
+ See also setUpVector(). The position() of the Camera is unchanged, you may want to call showEntireScene()
+ after this method to move the Camera.
+
+ This method can be useful to create Quicktime VR panoramic sequences, see the
+ QGLViewer::saveSnapshot() documentation for details. */
+void Camera::setOrientation(float theta, float phi)
+{
+ Vec axis(0.0, 1.0, 0.0);
+ const Quaternion rot1(axis, theta);
+ axis = Vec(-cos(theta), 0., sin(theta));
+ const Quaternion rot2(axis, phi);
+ setOrientation(rot1 * rot2);
+}
+
+/*! Sets the Camera orientation(), defined in the world coordinate system. */
+void Camera::setOrientation(const Quaternion& q)
+{
+ frame()->setOrientation(q);
+ //frame()->updateFlyUpVector();
+}
+
+/*! Rotates the Camera so that its viewDirection() is \p direction (defined in the world coordinate
+ system).
+
+ The Camera position() is not modified. The Camera is rotated so that the horizon (defined by its
+ upVector()) is preserved. See also lookAt() and setUpVector(). */
+void Camera::setViewDirection(const Vec& direction)
+{
+ if (direction.squaredNorm() < 1E-10)
+ return;
+
+ Vec xAxis = direction ^ upVector();
+ if (xAxis.squaredNorm() < 1E-10)
+ {
+ // target is aligned with upVector, this means a rotation around X axis
+ // X axis is then unchanged, let's keep it !
+ xAxis = frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0));
+ }
+
+ Quaternion q;
+ q.setFromRotatedBasis(xAxis, xAxis^direction, -direction);
+ frame()->setOrientationWithConstraint(q);
+}
+
+// Compute a 3 by 3 determinant.
+static float det(float m00,float m01,float m02,
+ float m10,float m11,float m12,
+ float m20,float m21,float m22)
+{
+ return m00*m11*m22 + m01*m12*m20 + m02*m10*m21 - m20*m11*m02 - m10*m01*m22 - m00*m21*m12;
+}
+
+// Computes the index of element [i][j] in a \c float matrix[3][4].
+static inline unsigned int ind(unsigned int i, unsigned int j)
+{
+ return (i*4+j);
+}
+
+
+/*! Sets the Camera's position() and orientation() from an OpenGL ModelView matrix.
+
+This enables a Camera initialisation from an other OpenGL application. \p modelView is a 16 GLdouble
+vector representing a valid OpenGL ModelView matrix, such as one can get using:
+\code
+GLdouble mvm[16];
+glGetDoublev(GL_MODELVIEW_MATRIX, mvm);
+myCamera->setFromModelViewMatrix(mvm);
+\endcode
+
+After this method has been called, getModelViewMatrix() returns a matrix equivalent to \p
+modelView.
+
+Only the orientation() and position() of the Camera are modified.
+
+\note If you defined your matrix as \c GLdouble \c mvm[4][4], pass \c &(mvm[0][0]) as a
+parameter. */
+void Camera::setFromModelViewMatrix(const GLdouble* const modelViewMatrix)
+{
+ // Get upper left (rotation) matrix
+ double upperLeft[3][3];
+ for (int i=0; i<3; ++i)
+ for (int j=0; j<3; ++j)
+ upperLeft[i][j] = modelViewMatrix[i*4+j];
+
+ // Transform upperLeft into the associated Quaternion
+ Quaternion q;
+ q.setFromRotationMatrix(upperLeft);
+
+ setOrientation(q);
+ setPosition(-q.rotate(Vec(modelViewMatrix[12], modelViewMatrix[13], modelViewMatrix[14])));
+}
+
+/*! Defines the Camera position(), orientation() and fieldOfView() from a projection matrix.
+
+ \p matrix has to be given in the format used by vision algorithm. It has 3 lines and 4 columns. It
+ transforms a point from the world homogeneous coordinate system (4 coordinates: \c sx, \c sy, \c sz
+ and \c s) into a point in the screen homogeneous coordinate system (3 coordinates: \c sx, \c sy,
+ and \c s, where \c x and \c y are the pixel coordinates on the screen).
+
+ Its three lines correspond to the homogeneous coordinates of the normals to the planes x=0, y=0 and
+ z=0, defined in the Camera coordinate system.
+
+ The elements of the matrix are ordered in line major order: you can call \c
+ setFromProjectionMatrix(&(matrix[0][0])) if you defined your matrix as a \c float \c matrix[3][4].
+
+ \attention Passing the result of getProjectionMatrix() or getModelViewMatrix() to this method is
+ not possible (purposefully incompatible matrix dimensions). \p matrix is more likely to be the
+ product of these two matrices, without the last line.
+
+ Use setFromModelViewMatrix() to set position() and orientation() from a \c GL_MODELVIEW matrix.
+ fieldOfView() can also be retrieved from a \e perspective \c GL_PROJECTION matrix using 2.0 *
+ atan(1.0/projectionMatrix[5]).
+
+ This code was written by Sylvain Paris. */
+void Camera::setFromProjectionMatrix(const float matrix[12])
+{
+ // The 3 lines of the matrix are the normals to the planes x=0, y=0, z=0
+ // in the camera CS. As we normalize them, we do not need the 4th coordinate.
+ Vec line_0(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)]);
+ Vec line_1(matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)]);
+ Vec line_2(matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)]);
+
+ line_0.normalize();
+ line_1.normalize();
+ line_2.normalize();
+
+ // The camera position is at (0,0,0) in the camera CS so it is the
+ // intersection of the 3 planes. It can be seen as the kernel
+ // of the 3x4 projection matrix. We calculate it through 4 dimensional
+ // vectorial product. We go directly into 3D that is to say we directly
+ // divide the first 3 coordinates by the 4th one.
+
+ // We derive the 4 dimensional vectorial product formula from the
+ // computation of a 4x4 determinant that is developped according to
+ // its 4th column. This implies some 3x3 determinants.
+ const Vec cam_pos = Vec(det(matrix[ind(0,1)],matrix[ind(0,2)],matrix[ind(0,3)],
+ matrix[ind(1,1)],matrix[ind(1,2)],matrix[ind(1,3)],
+ matrix[ind(2,1)],matrix[ind(2,2)],matrix[ind(2,3)]),
+
+ -det(matrix[ind(0,0)],matrix[ind(0,2)],matrix[ind(0,3)],
+ matrix[ind(1,0)],matrix[ind(1,2)],matrix[ind(1,3)],
+ matrix[ind(2,0)],matrix[ind(2,2)],matrix[ind(2,3)]),
+
+ det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,3)],
+ matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,3)],
+ matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,3)])) /
+
+ (-det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)],
+ matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)],
+ matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)]));
+
+ // We compute the rotation matrix column by column.
+
+ // GL Z axis is front facing.
+ Vec column_2 = -line_2;
+
+ // X-axis is almost like line_0 but should be orthogonal to the Z axis.
+ Vec column_0 = ((column_2^line_0)^column_2);
+ column_0.normalize();
+
+ // Y-axis is almost like line_1 but should be orthogonal to the Z axis.
+ // Moreover line_1 is downward oriented as the screen CS.
+ Vec column_1 = -((column_2^line_1)^column_2);
+ column_1.normalize();
+
+ double rot[3][3];
+ rot[0][0] = column_0[0];
+ rot[1][0] = column_0[1];
+ rot[2][0] = column_0[2];
+
+ rot[0][1] = column_1[0];
+ rot[1][1] = column_1[1];
+ rot[2][1] = column_1[2];
+
+ rot[0][2] = column_2[0];
+ rot[1][2] = column_2[1];
+ rot[2][2] = column_2[2];
+
+ // We compute the field of view
+
+ // line_1^column_0 -> vector of intersection line between
+ // y_screen=0 and x_camera=0 plane.
+ // column_2*(...) -> cos of the angle between Z vector et y_screen=0 plane
+ // * 2 -> field of view = 2 * half angle
+
+ // We need some intermediate values.
+ Vec dummy = line_1^column_0;
+ dummy.normalize();
+ float fov = acos(column_2*dummy) * 2.0;
+
+ // We set the camera.
+ Quaternion q;
+ q.setFromRotationMatrix(rot);
+ setOrientation(q);
+ setPosition(cam_pos);
+ setFieldOfView(fov);
+}
+
+
+/*
+ // persp : projectionMatrix_[0] = f/aspectRatio();
+void Camera::setFromProjectionMatrix(const GLdouble* projectionMatrix)
+{
+ QString message;
+ if ((fabs(projectionMatrix[1]) > 1E-3) ||
+ (fabs(projectionMatrix[2]) > 1E-3) ||
+ (fabs(projectionMatrix[3]) > 1E-3) ||
+ (fabs(projectionMatrix[4]) > 1E-3) ||
+ (fabs(projectionMatrix[6]) > 1E-3) ||
+ (fabs(projectionMatrix[7]) > 1E-3) ||
+ (fabs(projectionMatrix[8]) > 1E-3) ||
+ (fabs(projectionMatrix[9]) > 1E-3))
+ message = "Non null coefficient in projection matrix - Aborting";
+ else
+ if ((fabs(projectionMatrix[11]+1.0) < 1E-5) && (fabs(projectionMatrix[15]) < 1E-5))
+ {
+ if (projectionMatrix[5] < 1E-4)
+ message="Negative field of view in Camera::setFromProjectionMatrix";
+ else
+ setType(Camera::PERSPECTIVE);
+ }
+ else
+ if ((fabs(projectionMatrix[11]) < 1E-5) && (fabs(projectionMatrix[15]-1.0) < 1E-5))
+ setType(Camera::ORTHOGRAPHIC);
+ else
+ message = "Unable to determine camera type in setFromProjectionMatrix - Aborting";
+
+ if (!message.isEmpty())
+ {
+ qWarning(message);
+ return;
+ }
+
+ switch (type())
+ {
+ case Camera::PERSPECTIVE:
+ {
+ setFieldOfView(2.0 * atan(1.0/projectionMatrix[5]));
+ const float far = projectionMatrix[14] / (2.0 * (1.0 + projectionMatrix[10]));
+ const float near = (projectionMatrix[10]+1.0) / (projectionMatrix[10]-1.0) * far;
+ setSceneRadius((far-near)/2.0);
+ setSceneCenter(position() + (near + sceneRadius())*viewDirection());
+ break;
+ }
+ case Camera::ORTHOGRAPHIC:
+ {
+ GLdouble w, h;
+ getOrthoWidthHeight(w,h);
+ projectionMatrix_[0] = 1.0/w;
+ projectionMatrix_[5] = 1.0/h;
+ projectionMatrix_[10] = -2.0/(ZFar - ZNear);
+ projectionMatrix_[11] = 0.0;
+ projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear);
+ projectionMatrix_[15] = 1.0;
+ // same as glOrtho( -w, w, -h, h, zNear(), zFar() );
+ break;
+ }
+ }
+}
+*/
+
+///////////////////////// Camera to world transform ///////////////////////
+
+/*! Same as cameraCoordinatesOf(), but with \c float[3] parameters (\p src and \p res may be identical pointers). */
+void Camera::getCameraCoordinatesOf(const float src[3], float res[3]) const
+{
+ Vec r = cameraCoordinatesOf(Vec(src));
+ for (int i=0; i<3; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as worldCoordinatesOf(), but with \c float[3] parameters (\p src and \p res may be identical pointers). */
+void Camera::getWorldCoordinatesOf(const float src[3], float res[3]) const
+{
+ Vec r = worldCoordinatesOf(Vec(src));
+ for (int i=0; i<3; ++i)
+ res[i] = r[i];
+}
+
+/*! Fills \p viewport with the Camera OpenGL viewport.
+
+This method is mainly used in conjunction with \c gluProject, which requires such a viewport.
+Returned values are (0, screenHeight(), screenWidth(), - screenHeight()), so that the origin is
+located in the \e upper left corner of the window (Qt style coordinate system). */
+void Camera::getViewport(GLint viewport[4]) const
+{
+ viewport[0] = 0;
+ viewport[1] = screenHeight();
+ viewport[2] = screenWidth();
+ viewport[3] = -screenHeight();
+}
+
+/*! Returns the screen projected coordinates of a point \p src defined in the \p frame coordinate
+ system.
+
+ When \p frame in \c NULL (default), \p src is expressed in the world coordinate system.
+
+ The x and y coordinates of the returned Vec are expressed in pixel, (0,0) being the \e upper left
+ corner of the window. The z coordinate ranges between 0.0 (near plane) and 1.0 (excluded, far
+ plane). See the \c gluProject man page for details.
+
+ unprojectedCoordinatesOf() performs the inverse transformation.
+
+ See the <a href="../examples/screenCoordSystem.html">screenCoordSystem example</a>.
+
+ This method only uses the intrinsic Camera parameters (see getModelViewMatrix(),
+ getProjectionMatrix() and getViewport()) and is completely independent of the OpenGL \c
+ GL_MODELVIEW, \c GL_PROJECTION and viewport matrices. You can hence define a virtual Camera and use
+ this method to compute projections out of a classical rendering context.
+
+ \attention However, if your Camera is not attached to a QGLViewer (used for offscreen computations
+ for instance), make sure the Camera matrices are updated before calling this method. Call
+ computeModelViewMatrix() and computeProjectionMatrix() to do so.
+
+ If you call this method several times with no change in the matrices, consider precomputing the
+ projection times modelview matrix to save computation time if required (\c P x \c M in the \c
+ gluProject man page). */
+Vec Camera::projectedCoordinatesOf(const Vec& src, const Frame* frame) const
+{
+ GLdouble x,y,z;
+ static GLint viewport[4];
+ getViewport(viewport);
+
+ if (frame)
+ {
+ const Vec tmp = frame->inverseCoordinatesOf(src);
+ gluProject(tmp.x,tmp.y,tmp.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
+ }
+ else
+ gluProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
+
+ return Vec(x,y,z);
+}
+
+/*! Returns the world unprojected coordinates of a point \p src defined in the screen coordinate
+ system.
+
+ The \p src.x and \p src.y input values are expressed in pixels, (0,0) being the \e upper left corner
+ of the window. \p src.z is a depth value ranging in [0..1[ (near and far plane respectively). See
+ the \c gluUnProject man page for details.
+
+ The result is expressed in the \p frame coordinate system. When \p frame is \c NULL (default), the
+ result is expressed in the world coordinates system. The possible \p frame Frame::referenceFrame()
+ are taken into account.
+
+ projectedCoordinatesOf() performs the inverse transformation.
+
+ This method only uses the intrinsic Camera parameters (see getModelViewMatrix(),
+ getProjectionMatrix() and getViewport()) and is completely independent of the OpenGL \c
+ GL_MODELVIEW, \c GL_PROJECTION and viewport matrices. You can hence define a virtual Camera and use
+ this method to compute un-projections out of a classical rendering context.
+
+ \attention However, if your Camera is not attached to a QGLViewer (used for offscreen computations
+ for instance), make sure the Camera matrices are updated before calling this method (use
+ computeModelViewMatrix(), computeProjectionMatrix()). See also setScreenWidthAndHeight().
+
+ This method is not computationally optimized. If you call it several times with no change in the
+ matrices, you should buffer the entire inverse projection matrix (modelview, projection and then
+ viewport) to speed-up the queries. See the \c gluUnProject man page for details. */
+Vec Camera::unprojectedCoordinatesOf(const Vec& src, const Frame* frame) const
+{
+ GLdouble x,y,z;
+ static GLint viewport[4];
+ getViewport(viewport);
+ gluUnProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
+ if (frame)
+ return frame->coordinatesOf(Vec(x,y,z));
+ else
+ return Vec(x,y,z);
+}
+
+/*! Same as projectedCoordinatesOf(), but with \c float parameters (\p src and \p res can be identical pointers). */
+void Camera::getProjectedCoordinatesOf(const float src[3], float res[3], const Frame* frame) const
+{
+ Vec r = projectedCoordinatesOf(Vec(src), frame);
+ for (int i=0; i<3; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as unprojectedCoordinatesOf(), but with \c float parameters (\p src and \p res can be identical pointers). */
+void Camera::getUnprojectedCoordinatesOf(const float src[3], float res[3], const Frame* frame) const
+{
+ Vec r = unprojectedCoordinatesOf(Vec(src), frame);
+ for (int i=0; i<3; ++i)
+ res[i] = r[i];
+}
+
+///////////////////////////////////// KFI /////////////////////////////////////////
+
+/*! Returns the KeyFrameInterpolator that defines the Camera path number \p i.
+
+If path \p i is not defined for this index, the method returns a \c NULL pointer. */
+// KeyFrameInterpolator* Camera::keyFrameInterpolator(int i)
+// {
+// if ( kfi_.find(i) != kfi_.end())
+// return kfi_[i];
+// else
+// return NULL;
+// }
+
+/*! Sets the KeyFrameInterpolator that defines the Camera path of index \p i.
+
+ The previous keyFrameInterpolator() is lost and should be deleted by the calling method if
+ needed.
+
+ The KeyFrameInterpolator::interpolated() signal of \p kfi probably needs to be connected to the
+ Camera's associated QGLViewer::updateGL() slot, so that when the Camera position is interpolated
+ using \p kfi, every interpolation step updates the display:
+ \code
+ myViewer.camera()->deletePath(3);
+ myViewer.camera()->setKeyFrameInterpolator(3, myKeyFrameInterpolator);
+ connect(myKeyFrameInterpolator, SIGNAL(interpolated()), myViewer, SLOT(updateGL());
+ \endcode
+
+ \note These connections are done automatically when a Camera is attached to a QGLViewer, or when a
+ new KeyFrameInterpolator is defined using the QGLViewer::addKeyFrameKeyboardModifiers() and
+ QGLViewer::pathKey() (default is Alt+F[1-12]). See the <a href="../keyboard.html">keyboard page</a>
+ for details. */
+// void Camera::setKeyFrameInterpolator(int i, KeyFrameInterpolator* const kfi)
+// {
+// if (kfi)
+// kfi_[i] = kfi;
+// else
+// kfi_.erase(i);
+// }
+
+/*! Adds the current Camera position() and orientation() as a keyFrame to the path number \p i.
+
+This method can also be used if you simply want to save a Camera point of view (a path made of a
+single keyFrame). Use playPath() to make the Camera play the keyFrame path (resp. restore
+the point of view). Use deletePath() to clear the path.
+
+The default keyboard shortcut for this method is Alt+F[1-12]. Set QGLViewer::pathKey() and
+QGLViewer::addKeyFrameKeyboardModifiers().
+
+If you use directly this method and the keyFrameInterpolator(i) does not exist, a new one is
+created. Its KeyFrameInterpolator::interpolated() signal should then be connected to the
+QGLViewer::updateGL() slot (see setKeyFrameInterpolator()). */
+// void Camera::addKeyFrameToPath(int i)
+// {
+// if (kfi_.find(i) != kfi_.end())
+// setKeyFrameInterpolator(i, new KeyFrameInterpolator(frame()));
+//
+// kfi_[i]->addKeyFrame(*(frame()));
+// }
+
+/*! Makes the Camera follow the path of keyFrameInterpolator() number \p i.
+
+ If the interpolation is started, it stops it instead.
+
+ This method silently ignores undefined (empty) paths (see keyFrameInterpolator()).
+
+ The default keyboard shortcut for this method is F[1-12]. Set QGLViewer::pathKey() and
+ QGLViewer::playPathKeyboardModifiers(). */
+// void Camera::playPath(int i)
+// {
+// if (kfi_.find(i) != kfi_.end())
+// if (kfi_[i]->interpolationIsStarted())
+// kfi_[i]->stopInterpolation();
+// else
+// kfi_[i]->startInterpolation();
+// }
+
+/*! Resets the path of the keyFrameInterpolator() number \p i.
+
+If this path is \e not being played (see playPath() and
+KeyFrameInterpolator::interpolationIsStarted()), resets it to is its starting position (see
+KeyFrameInterpolator::resetInterpolation()). If the path is played, simply stops interpolation. */
+// void Camera::resetPath(int i)
+// {
+// // if (kfi_.contains(i))
+// if (kfi_.find(i) != kfi_.end())
+// if ((kfi_[i]->interpolationIsStarted()))
+// kfi_[i]->stopInterpolation();
+// else
+// {
+// kfi_[i]->resetInterpolation();
+// kfi_[i]->interpolateAtTime(kfi_[i]->interpolationTime());
+// }
+// }
+
+/*! Deletes the keyFrameInterpolator() of index \p i.
+
+Disconnect the keyFrameInterpolator() KeyFrameInterpolator::interpolated() signal before deleting the
+keyFrameInterpolator() if needed:
+\code
+disconnect(camera()->keyFrameInterpolator(i), SIGNAL(interpolated()), this, SLOT(updateGL()));
+camera()->deletePath(i);
+\endcode */
+// void Camera::deletePath(int i)
+// {
+// if (kfi_.find(i) != kfi_.end())
+// {
+// kfi_[i]->stopInterpolation();
+// delete kfi_[i];
+// kfi_.erase(i);
+// }
+// }
+
+
+
+/*! Gives the coefficients of a 3D half-line passing through the Camera eye and pixel (x,y).
+
+ The origin of the half line (eye position) is stored in \p orig, while \p dir contains the properly
+ oriented and normalized direction of the half line.
+
+ \p x and \p y are expressed in Qt format (origin in the upper left corner). Use screenHeight() - y
+ to convert to OpenGL units.
+
+ This method is useful for analytical intersection in a selection method.
+
+ See the <a href="../examples/select.html">select example</a> for an illustration. */
+void Camera::convertClickToLine(const Point& pixel, Vec& orig, Vec& dir) const
+{
+ switch (type())
+ {
+ case Camera::PERSPECTIVE:
+ orig = position();
+ dir = Vec( ((2.0 * pixel.x() / screenWidth()) - 1.0) * tan(fieldOfView()/2.0) * aspectRatio(),
+ ((2.0 * (screenHeight()-pixel.y()) / screenHeight()) - 1.0) * tan(fieldOfView()/2.0),
+ -1.0 );
+ dir = worldCoordinatesOf(dir) - orig;
+ dir.normalize();
+ break;
+
+ case Camera::ORTHOGRAPHIC:
+ {
+ GLdouble w,h;
+ getOrthoWidthHeight(w,h);
+ orig = Vec((2.0 * pixel.x() / screenWidth() - 1.0)*w, -(2.0 * pixel.y() / screenHeight() - 1.0)*h, 0.0);
+ orig = worldCoordinatesOf(orig);
+ dir = viewDirection();
+ break;
+ }
+ }
+}
+
+#ifndef DOXYGEN
+/*! This method has been deprecated in libQGLViewer version 2.2.0 */
+void Camera::drawCamera(float, float, float)
+{
+ cout << "drawCamera is deprecated. Use Camera::draw() instead.";
+}
+#endif
+
+/*! Draws a representation of the Camera in the 3D world.
+
+The near and far planes are drawn as quads, the frustum is drawn using lines and the camera up
+vector is represented by an arrow to disambiguate the drawing. See the
+<a href="../examples/standardCamera.html">standardCamera example</a> for an illustration.
+
+Note that the current \c glColor and \c glPolygonMode are used to draw the near and far planes. See
+the <a href="../examples/frustumCulling.html">frustumCulling example</a> for an example of
+semi-transparent plane drawing. Similarly, the current \c glLineWidth and \c glColor is used to draw
+the frustum outline.
+
+When \p drawFarPlane is \c false, only the near plane is drawn. \p scale can be used to scale the
+drawing: a value of 1.0 (default) will draw the Camera's frustum at its actual size.
+
+This method assumes that the \c glMatrixMode is \c GL_MODELVIEW and that the current ModelView
+matrix corresponds to the world coordinate system (as it is at the beginning of QGLViewer::draw()).
+The Camera is then correctly positioned and orientated.
+
+\note The drawing of a QGLViewer's own QGLViewer::camera() should not be visible, but may create
+artefacts due to numerical imprecisions. */
+void Camera::draw(bool drawFarPlane, float scale) const
+{
+ glPushMatrix();
+ glMultMatrixd(frame()->worldMatrix());
+
+ // 0 is the upper left coordinates of the near corner, 1 for the far one
+ Vec points[2];
+
+ points[0].z = scale * zNear();
+ points[1].z = scale * zFar();
+
+ switch (type())
+ {
+ case Camera::PERSPECTIVE:
+ {
+ points[0].y = points[0].z * tan(fieldOfView()/2.0);
+ points[0].x = points[0].y * aspectRatio();
+
+ const float ratio = points[1].z / points[0].z;
+
+ points[1].y = ratio * points[0].y;
+ points[1].x = ratio * points[0].x;
+ break;
+ }
+ case Camera::ORTHOGRAPHIC:
+ {
+ GLdouble hw, hh;
+ getOrthoWidthHeight(hw, hh);
+ points[0].x = points[1].x = scale * float(hw);
+ points[0].y = points[1].y = scale * float(hh);
+ break;
+ }
+ }
+
+ const int farIndex = drawFarPlane?1:0;
+
+ // Near and (optionally) far plane(s)
+ glBegin(GL_QUADS);
+ for (int i=farIndex; i>=0; --i)
+ {
+ glNormal3f(0.0, 0.0, (i==0)?1.0:-1.0);
+ glVertex3f( points[i].x, points[i].y, -points[i].z);
+ glVertex3f(-points[i].x, points[i].y, -points[i].z);
+ glVertex3f(-points[i].x, -points[i].y, -points[i].z);
+ glVertex3f( points[i].x, -points[i].y, -points[i].z);
+ }
+ glEnd();
+
+ // Up arrow
+ const float arrowHeight = 1.5f * points[0].y;
+ const float baseHeight = 1.2f * points[0].y;
+ const float arrowHalfWidth = 0.5f * points[0].x;
+ const float baseHalfWidth = 0.3f * points[0].x;
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ // Base
+ glBegin(GL_QUADS);
+ glVertex3f(-baseHalfWidth, points[0].y, -points[0].z);
+ glVertex3f( baseHalfWidth, points[0].y, -points[0].z);
+ glVertex3f( baseHalfWidth, baseHeight, -points[0].z);
+ glVertex3f(-baseHalfWidth, baseHeight, -points[0].z);
+ glEnd();
+
+ // Arrow
+ glBegin(GL_TRIANGLES);
+ glVertex3f( 0.0f, arrowHeight, -points[0].z);
+ glVertex3f(-arrowHalfWidth, baseHeight, -points[0].z);
+ glVertex3f( arrowHalfWidth, baseHeight, -points[0].z);
+ glEnd();
+
+ // Frustum lines
+ switch (type())
+ {
+ case Camera::PERSPECTIVE :
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3f( points[farIndex].x, points[farIndex].y, -points[farIndex].z);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3f(-points[farIndex].x, points[farIndex].y, -points[farIndex].z);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3f(-points[farIndex].x, -points[farIndex].y, -points[farIndex].z);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3f( points[farIndex].x, -points[farIndex].y, -points[farIndex].z);
+ glEnd();
+ break;
+ case Camera::ORTHOGRAPHIC :
+ if (drawFarPlane)
+ {
+ glBegin(GL_LINES);
+ glVertex3f( points[0].x, points[0].y, -points[0].z);
+ glVertex3f( points[1].x, points[1].y, -points[1].z);
+ glVertex3f(-points[0].x, points[0].y, -points[0].z);
+ glVertex3f(-points[1].x, points[1].y, -points[1].z);
+ glVertex3f(-points[0].x, -points[0].y, -points[0].z);
+ glVertex3f(-points[1].x, -points[1].y, -points[1].z);
+ glVertex3f( points[0].x, -points[0].y, -points[0].z);
+ glVertex3f( points[1].x, -points[1].y, -points[1].z);
+ glEnd();
+ }
+ }
+
+ glPopMatrix();
+}
+
+
+/*! Returns the 6 plane equations of the Camera frustum.
+
+The six 4-component vectors of \p coef respectively correspond to the left, right, near, far, top
+and bottom Camera frustum planes. Each vector holds a plane equation of the form:
+\code
+a*x + b*y + c*z + d = 0
+\endcode
+where \c a, \c b, \c c and \c d are the 4 components of each vector, in that order.
+
+See the <a href="../examples/frustumCulling.html">frustumCulling example</a> for an application.
+
+This format is compatible with the \c glClipPlane() function. One camera frustum plane can hence be
+applied in an other viewer to visualize the culling results:
+\code
+ // Retrieve plance equations
+ GLdouble coef[6][4];
+ mainViewer->camera()->getFrustumPlanesCoefficients(coef);
+
+ // These two additional clipping planes (which must have been enabled)
+ // will reproduce the mainViewer's near and far clipping.
+ glClipPlane(GL_CLIP_PLANE0, coef[2]);
+ glClipPlane(GL_CLIP_PLANE1, coef[3]);
+\endcode */
+void Camera::getFrustumPlanesCoefficients(GLdouble coef[6][4]) const
+{
+ // Computed once and for all
+ const Vec pos = position();
+ const Vec viewDir = viewDirection();
+ const Vec up = upVector();
+ const Vec right = rightVector();
+ const float posViewDir = pos * viewDir;
+
+ static Vec normal[6];
+ static GLdouble dist[6];
+
+ switch (type())
+ {
+ case Camera::PERSPECTIVE :
+ {
+ const float hhfov = horizontalFieldOfView() / 2.0;
+ const float chhfov = cos(hhfov);
+ const float shhfov = sin(hhfov);
+ normal[0] = - shhfov * viewDir;
+ normal[1] = normal[0] + chhfov * right;
+ normal[0] = normal[0] - chhfov * right;
+
+ normal[2] = -viewDir;
+ normal[3] = viewDir;
+
+ const float hfov = fieldOfView() / 2.0;
+ const float chfov = cos(hfov);
+ const float shfov = sin(hfov);
+ normal[4] = - shfov * viewDir;
+ normal[5] = normal[4] - chfov * up;
+ normal[4] = normal[4] + chfov * up;
+
+ for (int i=0; i<2; ++i)
+ dist[i] = pos * normal[i];
+ for (int j=4; j<6; ++j)
+ dist[j] = pos * normal[j];
+
+ // Natural equations are:
+ // dist[0,1,4,5] = pos * normal[0,1,4,5];
+ // dist[2] = (pos + zNear() * viewDir) * normal[2];
+ // dist[3] = (pos + zFar() * viewDir) * normal[3];
+
+ // 2 times less computations using expanded/merged equations. Dir vectors are normalized.
+ const float posRightCosHH = chhfov * pos * right;
+ dist[0] = -shhfov * posViewDir;
+ dist[1] = dist[0] + posRightCosHH;
+ dist[0] = dist[0] - posRightCosHH;
+ const float posUpCosH = chfov * pos * up;
+ dist[4] = - shfov * posViewDir;
+ dist[5] = dist[4] - posUpCosH;
+ dist[4] = dist[4] + posUpCosH;
+
+ break;
+ }
+ case Camera::ORTHOGRAPHIC :
+ normal[0] = -right;
+ normal[1] = right;
+ normal[4] = up;
+ normal[5] = -up;
+
+ GLdouble hw, hh;
+ getOrthoWidthHeight(hw, hh);
+ dist[0] = (pos - hw * right) * normal[0];
+ dist[1] = (pos + hw * right) * normal[1];
+ dist[4] = (pos + hh * up) * normal[4];
+ dist[5] = (pos - hh * up) * normal[5];
+ break;
+ }
+
+ // Front and far planes are identical for both camera types.
+ normal[2] = -viewDir;
+ normal[3] = viewDir;
+ dist[2] = -posViewDir - zNear();
+ dist[3] = posViewDir + zFar();
+
+ for (int i=0; i<6; ++i)
+ {
+ coef[i][0] = GLdouble(normal[i].x);
+ coef[i][1] = GLdouble(normal[i].y);
+ coef[i][2] = GLdouble(normal[i].z);
+ coef[i][3] = dist[i];
+ }
+}
diff --git a/source/blender/freestyle/intern/app_blender/camera.h b/source/blender/freestyle/intern/app_blender/camera.h
new file mode 100644
index 00000000000..d6dad1dd895
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/camera.h
@@ -0,0 +1,565 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef QGLVIEWER_CAMERA_H
+#define QGLVIEWER_CAMERA_H
+
+#include "manipulatedCameraFrame.h"
+
+ /*! \brief A perspective or orthographic camera.
+ \class Camera camera.h QGLViewer/camera.h
+
+ A Camera defines some intrinsic parameters (fieldOfView(), position(), viewDirection(),
+ upVector()...) and useful positioning tools that ease its placement (showEntireScene(),
+ fitSphere(), lookAt()...). It exports its associated OpenGL projection and modelview matrices and
+ can interactively be modified using the mouse.
+
+ <h3>Mouse manipulation</h3>
+
+ The position() and orientation() of the Camera are defined by a ManipulatedCameraFrame (retrieved
+ using frame()). These methods are just convenient wrappers to the equivalent Frame methods. This
+ also means that the Camera frame() can be attached to a Frame::referenceFrame() which enables
+ complex Camera setups.
+
+ Different displacements can be performed using the mouse. The list of possible actions is defined
+ by the QGLViewer::MouseAction enum. Use QGLViewer::setMouseBinding() to attach a specific action
+ to an arbitrary mouse button-state key binding. These actions are detailed in the <a
+ href="../mouse.html">mouse page</a>.
+
+ The default button binding are: QGLViewer::ROTATE (left), QGLViewer::ZOOM (middle) and
+ QGLViewer::TRANSLATE (right). With this configuration, the Camera \e observes a scene and rotates
+ around its revolveAroundPoint(). You can switch between this mode and a fly mode using the
+ QGLViewer::CAMERA_MODE (see QGLViewer::toggleCameraMode()) keyboard shortcut (default is 'Space').
+
+ <h3>Other functionalities</h3>
+
+ The type() of the Camera can be Camera::ORTHOGRAPHIC or Camera::PERSPECTIVE (see Type()).
+ fieldOfView() is meaningless with Camera::ORTHOGRAPHIC.
+
+ The near and far planes of the Camera are fitted to the scene and determined from
+ QGLViewer::sceneRadius(), QGLViewer::sceneCenter() and zClippingCoefficient() by the zNear() and
+ zFar() methods. Reasonable values on the scene extends hence have to be provided to the QGLViewer
+ in order for the Camera to correctly display the scene. High level positioning methods also use
+ this information (showEntireScene(), centerScene()...).
+
+ A Camera holds KeyFrameInterpolator that can be used to save Camera positions and paths. You can
+ interactively addKeyFrameToPath() to a given path using the default \c Alt+F[1-12] shortcuts. Use
+ playPath() to make the Camera follow the path (default shortcut is F[1-12]). See the <a
+ href="../keyboard.html">keyboard page</a> for details on key customization.
+
+ Use cameraCoordinatesOf() and worldCoordinatesOf() to convert to and from the Camera frame()
+ coordinate system. projectedCoordinatesOf() and unprojectedCoordinatesOf() will convert from
+ screen to 3D coordinates. convertClickToLine() is very useful for analytical object selection.
+
+ Stereo display is possible on machines with quad buffer capabilities (with Camera::PERSPECTIVE
+ type() only). Test the <a href="../examples/stereoViewer.html">stereoViewer example</a> to check.
+
+ A Camera can also be used outside of a QGLViewer or even without OpenGL for its coordinate system
+ conversion capabilities. Note however that some of them explicitly rely on the presence of a
+ Z-buffer. \nosubgrouping */
+ class Camera
+ {
+
+ public:
+ Camera();
+ virtual ~Camera();
+
+ Camera(const Camera& camera);
+ Camera& operator=(const Camera& camera);
+
+
+ /*! Enumerates the two possible types of Camera.
+
+ See type() and setType(). This type mainly defines different Camera projection matrix (see
+ loadProjectionMatrix()). Many other methods (pointUnderPixel(), convertClickToLine(),
+ projectedCoordinatesOf(), pixelGLRatio()...) take this Type into account. */
+ enum Type { PERSPECTIVE, ORTHOGRAPHIC };
+
+ /*! @name Position and orientation */
+ //@{
+ public:
+ /*! Returns the Camera position (the eye), defined in the world coordinate system.
+
+ Use setPosition() to set the Camera position. Other convenient methods are showEntireScene() or
+ fitSphere(). Actually returns \c frame()->position().
+
+ This position corresponds to the projection center of a Camera::PERSPECTIVE Camera. It is not
+ located in the image plane, which is at a zNear() distance ahead. */
+ Vec position() const { return frame()->position(); };
+
+ /*! Returns the normalized up vector of the Camera, defined in the world coordinate system.
+
+ Set using setUpVector() or setOrientation(). It is orthogonal to viewDirection() and to
+ rightVector().
+
+ It corresponds to the Y axis of the associated frame() (actually returns
+ frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0)) ). */
+ Vec upVector() const
+ {
+ return frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0));
+ }
+ /*! Returns the normalized view direction of the Camera, defined in the world coordinate system.
+
+ Change this value using setViewDirection(), lookAt() or setOrientation(). It is orthogonal to
+ upVector() and to rightVector().
+
+ This corresponds to the negative Z axis of the frame() ( frame()->inverseTransformOf(Vec(0.0,
+ 0.0, -1.0)) ). */
+ Vec viewDirection() const { return frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)); };
+
+ /*! Returns the normalized right vector of the Camera, defined in the world coordinate system.
+
+ This vector lies in the Camera horizontal plane, directed along the X axis (orthogonal to
+ upVector() and to viewDirection()). Set using setUpVector(), lookAt() or setOrientation().
+
+ Simply returns frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0)). */
+ Vec rightVector() const
+ {
+ return frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0));
+ }
+
+ /*! Returns the Camera orientation, defined in the world coordinate system.
+
+ Actually returns \c frame()->orientation(). Use setOrientation(), setUpVector() or lookAt() to
+ set the Camera orientation. */
+ Quaternion orientation() const { return frame()->orientation(); };
+
+ void setFromModelViewMatrix(const GLdouble* const modelViewMatrix);
+ void setFromProjectionMatrix(const float matrix[12]);
+
+ public:
+ /*! Sets the Camera position() (the eye), defined in the world coordinate system. */
+ void setPosition(const Vec& pos) { frame()->setPosition(pos); };
+ void setOrientation(const Quaternion& q);
+ void setOrientation(float theta, float phi);
+ void setUpVector(const Vec& up, bool noMove=true);
+ void setViewDirection(const Vec& direction);
+ //@}
+
+
+ /*! @name Positioning tools */
+ //@{
+ public:
+ void lookAt(const Vec& target);
+ void showEntireScene();
+ void fitSphere(const Vec& center, float radius);
+ void fitBoundingBox(const Vec& min, const Vec& max);
+ void centerScene();
+ void interpolateToZoomOnPixel(const Point& pixel);
+ void interpolateToFitScene();
+ void interpolateTo(const Frame& fr, float duration);
+ //@}
+
+
+ /*! @name Frustum */
+ //@{
+ public:
+ /*! Returns the Camera::Type of the Camera.
+
+ Set by setType(). Mainly used by loadProjectionMatrix().
+
+ A Camera::PERSPECTIVE Camera uses a classical projection mainly defined by its fieldOfView().
+
+ With a Camera::ORTHOGRAPHIC type(), the fieldOfView() is meaningless and the width and height of
+ the Camera frustum are inferred from the distance to the revolveAroundPoint() using
+ getOrthoWidthHeight().
+
+ Both types use zNear() and zFar() (to define their clipping planes) and aspectRatio() (for
+ frustum shape). */
+ Type type() const { return type_; };
+
+ /*! Returns the vertical field of view of the Camera (in radians).
+
+ Value is set using setFieldOfView(). Default value is pi/4 radians. This value is meaningless if
+ the Camera type() is Camera::ORTHOGRAPHIC.
+
+ The field of view corresponds the one used in \c gluPerspective (see manual). It sets the Y
+ (vertical) aperture of the Camera. The X (horizontal) angle is inferred from the window aspect
+ ratio (see aspectRatio() and horizontalFieldOfView()).
+
+ Use setFOVToFitScene() to adapt the fieldOfView() to a given scene. */
+ float fieldOfView() const { return fieldOfView_; };
+
+ /*! Returns the horizontal field of view of the Camera (in radians).
+
+ Value is set using setHorizontalFieldOfView() or setFieldOfView(). These values
+ are always linked by:
+ \code
+ horizontalFieldOfView() = 2.0 * atan ( tan(fieldOfView()/2.0) * aspectRatio() ).
+ \endcode */
+ float horizontalFieldOfView() const { return 2.0 * atan ( tan(fieldOfView()/2.0) * aspectRatio() ); };
+
+ /*! Returns the Camera aspect ratio defined by screenWidth() / screenHeight().
+
+ When the Camera is attached to a QGLViewer, these values and hence the aspectRatio() are
+ automatically fitted to the viewer's window aspect ratio using setScreenWidthAndHeight(). */
+ float aspectRatio() const { return static_cast<float>(screenWidth_)/static_cast<float>(screenHeight_); };
+ /*! Returns the width (in pixels) of the Camera screen.
+
+ Set using setScreenWidthAndHeight(). This value is automatically fitted to the QGLViewer's
+ window dimensions when the Camera is attached to a QGLViewer. See also QGLWidget::width() */
+ int screenWidth() const { return screenWidth_; };
+ /*! Returns the height (in pixels) of the Camera screen.
+
+ Set using setScreenWidthAndHeight(). This value is automatically fitted to the QGLViewer's
+ window dimensions when the Camera is attached to a QGLViewer. See also QGLWidget::height() */
+ int screenHeight() const { return screenHeight_; };
+ void getViewport(GLint viewport[4]) const;
+ float pixelGLRatio(const Vec& position) const;
+
+ /*! Returns the coefficient which is used to set zNear() when the Camera is inside the sphere
+ defined by sceneCenter() and zClippingCoefficient() * sceneRadius().
+
+ In that case, the zNear() value is set to zNearCoefficient() * zClippingCoefficient() *
+ sceneRadius(). See the zNear() documentation for details.
+
+ Default value is 0.005, which is appropriate for most applications. In case you need a high
+ dynamic ZBuffer precision, you can increase this value (~0.1). A lower value will prevent
+ clipping of very close objects at the expense of a worst Z precision.
+
+ Only meaningful when Camera type is Camera::PERSPECTIVE. */
+ float zNearCoefficient() const { return zNearCoef_; };
+ /*! Returns the coefficient used to position the near and far clipping planes.
+
+ The near (resp. far) clipping plane is positioned at a distance equal to zClippingCoefficient() *
+ sceneRadius() in front of (resp. behind) the sceneCenter(). This garantees an optimal use of
+ the z-buffer range and minimizes aliasing. See the zNear() and zFar() documentations.
+
+ Default value is square root of 3.0 (so that a cube of size sceneRadius() is not clipped).
+
+ However, since the sceneRadius() is used for other purposes (see showEntireScene(), flySpeed(),
+ ...) and you may want to change this value to define more precisely the location of the clipping
+ planes. See also zNearCoefficient().
+
+ For a total control on clipping planes' positions, an other option is to overload the zNear()
+ and zFar() methods. See the <a href="../examples/standardCamera.html">standardCamera example</a>.
+
+ \attention When QGLViewer::cameraPathAreEdited(), this value is set to 5.0 so that the Camera
+ paths are not clipped. The previous zClippingCoefficient() value is restored back when you leave
+ this mode. */
+ float zClippingCoefficient() const { return zClippingCoef_; }
+
+ virtual float zNear() const;
+ virtual float zFar() const;
+ virtual void getOrthoWidthHeight(GLdouble& halfWidth, GLdouble& halfHeight) const;
+ void getFrustumPlanesCoefficients(GLdouble coef[6][4]) const;
+
+ public:
+ void setType(Type type);
+
+ /*! Sets the vertical fieldOfView() of the Camera (in radians).
+
+ Note that focusDistance() is set to sceneRadius() / tan(fieldOfView()/2) by this method. */
+ void setFieldOfView(float fov) { fieldOfView_ = fov; setFocusDistance(sceneRadius() / tan(fov/2.0)); };
+
+ /*! Sets the horizontalFieldOfView() of the Camera (in radians).
+
+ horizontalFieldOfView() and fieldOfView() are linked by the aspectRatio(). This method actually
+ calls setFieldOfView(( 2.0 * atan (tan(hfov / 2.0) / aspectRatio()) )) so that a call to
+ horizontalFieldOfView() returns the expected value. */
+ void setHorizontalFieldOfView(float hfov) { setFieldOfView( 2.0 * atan (tan(hfov / 2.0) / aspectRatio()) ); };
+
+ void setFOVToFitScene();
+
+ /*! Defines the Camera aspectRatio().
+
+ This value is actually inferred from the screenWidth() / screenHeight() ratio. You should use
+ setScreenWidthAndHeight() instead.
+
+ This method might however be convenient when the Camera is not associated with a QGLViewer. It
+ actually sets the screenHeight() to 100 and the screenWidth() accordingly. See also
+ setFOVToFitScene().
+
+ \note If you absolutely need an aspectRatio() that does not correspond to your viewer's window
+ dimensions, overload loadProjectionMatrix() or multiply the created GL_PROJECTION matrix by a
+ scaled diagonal matrix in your QGLViewer::draw() method. */
+ void setAspectRatio(float aspect) { setScreenWidthAndHeight(int(100.0*aspect), 100); };
+
+ void setScreenWidthAndHeight(int width, int height);
+ /*! Sets the zNearCoefficient() value. */
+ void setZNearCoefficient(float coef) { zNearCoef_ = coef; };
+ /*! Sets the zClippingCoefficient() value. */
+ void setZClippingCoefficient(float coef) { zClippingCoef_ = coef; }
+ //@}
+
+
+ /*! @name Scene radius and center */
+ //@{
+ public:
+ /*! Returns the radius of the scene observed by the Camera.
+
+ You need to provide such an approximation of the scene dimensions so that the Camera can adapt
+ its zNear() and zFar() values. See the sceneCenter() documentation.
+
+ See also setSceneBoundingBox().
+
+ Note that QGLViewer::sceneRadius() (resp. QGLViewer::setSceneRadius()) simply call this method
+ (resp. setSceneRadius()) on its associated QGLViewer::camera(). */
+ float sceneRadius() const { return sceneRadius_; };
+
+ /*! Returns the position of the scene center, defined in the world coordinate system.
+
+ The scene observed by the Camera should be roughly centered on this position, and included in a
+ sceneRadius() sphere. This approximate description of the scene permits a zNear() and zFar()
+ clipping planes definition, and allows convenient positioning methods such as showEntireScene().
+
+ Default value is (0,0,0) (world origin). Use setSceneCenter() to change it. See also
+ setSceneBoundingBox().
+
+ Note that QGLViewer::sceneCenter() (resp. QGLViewer::setSceneCenter()) simply call this method
+ (resp. setSceneCenter()) on its associated QGLViewer::camera(). */
+ Vec sceneCenter() const { return sceneCenter_; };
+ float distanceToSceneCenter() const;
+
+ public:
+ void setSceneRadius(float radius);
+ void setSceneCenter(const Vec& center);
+ bool setSceneCenterFromPixel(const Point& pixel);
+ void setSceneBoundingBox(const Vec& min, const Vec& max);
+ //@}
+
+
+ /*! @name Revolve Around Point */
+ //@{
+ public:
+ void setRevolveAroundPoint(const Vec& rap);
+ bool setRevolveAroundPointFromPixel(const Point& pixel);
+
+ public:
+ /*! The point the Camera revolves around with the QGLViewer::ROTATE mouse binding. Defined in world coordinate system.
+
+ Default value is the sceneCenter().
+
+ \attention setSceneCenter() changes this value. */
+ Vec revolveAroundPoint() const { return frame()->revolveAroundPoint(); };
+ //@}
+
+
+ /*! @name Associated frame */
+ //@{
+ public:
+ /*! Returns the ManipulatedCameraFrame attached to the Camera.
+
+ This ManipulatedCameraFrame defines its position() and orientation() and can translate mouse
+ events into Camera displacement. Set using setFrame(). */
+ ManipulatedCameraFrame* frame() const { return frame_; };
+ public:
+ void setFrame(ManipulatedCameraFrame* const mcf);
+ //@}
+
+
+ /*! @name KeyFramed paths */
+ //@{
+ public:
+ //KeyFrameInterpolator* keyFrameInterpolator(int i);
+
+public:
+ //void setKeyFrameInterpolator(int i, KeyFrameInterpolator* const kfi);
+
+ //virtual void addKeyFrameToPath(int i);
+ //virtual void playPath(int i);
+ //virtual void deletePath(int i);
+ //virtual void resetPath(int i);
+ //@}
+
+
+ /*! @name OpenGL matrices */
+ //@{
+ public:
+ virtual void loadProjectionMatrix(bool reset=true) const;
+ virtual void loadModelViewMatrix(bool reset=true) const;
+ void computeProjectionMatrix() const;
+ void computeModelViewMatrix() const;
+
+ virtual void loadProjectionMatrixStereo(bool leftBuffer=true) const;
+ virtual void loadModelViewMatrixStereo(bool leftBuffer=true) const;
+
+ void getProjectionMatrix(GLdouble m[16]) const;
+ void getModelViewMatrix(GLdouble m[16]) const;
+ void getModelViewProjectionMatrix(GLdouble m[16]) const;
+
+#ifndef DOXYGEN
+ // Required for windows which otherwise silently fills
+ void getProjectionMatrix(GLfloat m[16]) const;
+ void getModelViewMatrix(GLfloat m[16]) const;
+#endif
+ //@}
+
+
+ /*! @name Drawing */
+ //@{
+#ifndef DOXYGEN
+ static void drawCamera(float scale=1.0, float aspectRatio=1.33, float fieldOfView=M_PI/4.0);
+#endif
+ virtual void draw(bool drawFarPlane=true, float scale=1.0) const;
+ //@}
+
+
+ /*! @name World to Camera coordinate systems conversions */
+ //@{
+ public:
+ /*! Returns the Camera frame coordinates of a point \p src defined in world coordinates.
+
+ worldCoordinatesOf() performs the inverse transformation.
+
+ Note that the point coordinates are simply converted in a different coordinate system. They are
+ not projected on screen. Use projectedCoordinatesOf() for that. */
+ Vec cameraCoordinatesOf(const Vec& src) const { return frame()->coordinatesOf(src); };
+ /*! Returns the world coordinates of the point whose position \p src is defined in the Camera
+ coordinate system.
+
+ cameraCoordinatesOf() performs the inverse transformation. */
+ Vec worldCoordinatesOf(const Vec& src) const { return frame()->inverseCoordinatesOf(src); };
+ void getCameraCoordinatesOf(const float src[3], float res[3]) const;
+ void getWorldCoordinatesOf(const float src[3], float res[3]) const;
+ //@}
+
+
+ /*! @name 2D screen to 3D world coordinate systems conversions */
+ //@{
+ public:
+ Vec projectedCoordinatesOf(const Vec& src, const Frame* frame=NULL) const;
+ Vec unprojectedCoordinatesOf(const Vec& src, const Frame* frame=NULL) const;
+ void getProjectedCoordinatesOf(const float src[3], float res[3], const Frame* frame=NULL) const;
+ void getUnprojectedCoordinatesOf(const float src[3], float res[3], const Frame* frame=NULL) const;
+ void convertClickToLine(const Point& pixel, Vec& orig, Vec& dir) const;
+ Vec pointUnderPixel(const Point& pixel, bool& found) const;
+ //@}
+
+
+ /*! @name Fly speed */
+ //@{
+ public:
+ /*! Returns the fly speed of the Camera.
+
+ Simply returns frame()->flySpeed(). See the ManipulatedCameraFrame::flySpeed() documentation.
+ This value is only meaningful when the MouseAction bindings is QGLViewer::MOVE_FORWARD or
+ QGLViewer::MOVE_BACKWARD.
+
+ Set to 0.5% of the sceneRadius() by setSceneRadius(). See also setFlySpeed(). */
+ float flySpeed() const { return frame()->flySpeed(); };
+ public:
+ /*! Sets the Camera flySpeed().
+
+ \attention This value is modified by setSceneRadius(). */
+ void setFlySpeed(float speed) { frame()->setFlySpeed(speed); };
+ //@}
+
+
+ /*! @name Stereo parameters */
+ //@{
+ public:
+ /*! Returns the user's inter-ocular distance (in meters). Default value is 0.062m, which fits most people.
+
+ loadProjectionMatrixStereo() uses this value to define the Camera offset and frustum. See
+ setIODistance(). */
+ float IODistance() const { return IODistance_; };
+
+ /*! Returns the physical distance between the user's eyes and the screen (in meters).
+
+ Default value is 0.5m.
+
+ Used by loadModelViewMatrixStereo() and loadProjectionMatrixStereo() for stereo display. Value
+ is set using setPhysicalDistanceToScreen().
+
+ physicalDistanceToScreen() and focusDistance() represent the same distance. The first one is
+ expressed in physical real world units, while the latter is expressed in OpenGL virtual world
+ units. Use their ratio to convert distances between these worlds.
+
+ Use the following code to detect a reality center configuration (using its screen aspect ratio)
+ and to automatically set physical distances accordingly:
+ \code
+ QDesktopWidget screen;
+ if (fabs((float)screen.width() / (float)screen.height()) > 2.0)
+ {
+ camera()->setPhysicalDistanceToScreen(4.0);
+ camera()->setPhysicalScreenWidth(10.0);
+ }
+ \endcode */
+ float physicalDistanceToScreen() const { return physicalDistanceToScreen_; };
+
+ /*! Returns the physical screen width, in meters. Default value is 0.4m (average monitor).
+
+ Used for stereo display only (see loadModelViewMatrixStereo() and loadProjectionMatrixStereo()).
+ Set using setPhysicalScreenWidth().
+
+ See physicalDistanceToScreen() for reality center automatic configuration. */
+ float physicalScreenWidth() const { return physicalScreenWidth_; };
+
+ /*! Returns the focus distance used by stereo display, expressed in OpenGL units.
+
+ This is the distance in the virtual world between the Camera and the plane where the horizontal
+ stereo parallax is null (the stereo left and right images are superimposed).
+
+ This distance is the virtual world equivalent of the real-world physicalDistanceToScreen().
+
+ \attention This value is modified by QGLViewer::setSceneRadius(), setSceneRadius() and
+ setFieldOfView(). When one of these values is modified, focusDistance() is set to sceneRadius()
+ / tan(fieldOfView()/2), which provides good results. */
+ float focusDistance() const { return focusDistance_; };
+ public:
+ /*! Sets the IODistance(). */
+ void setIODistance(float distance) { IODistance_ = distance; };
+
+ /*! Sets the physicalDistanceToScreen(). */
+ void setPhysicalDistanceToScreen(float distance) { physicalDistanceToScreen_ = distance; };
+
+ /*! Sets the physical screen (monitor or projected wall) width (in meters). */
+ void setPhysicalScreenWidth(float width) { physicalScreenWidth_ = width; };
+
+ /*! Sets the focusDistance(), in OpenGL scene units. */
+ void setFocusDistance(float distance) { focusDistance_ = distance; };
+ //@}
+
+
+ private:
+ // F r a m e
+ ManipulatedCameraFrame* frame_;
+
+ // C a m e r a p a r a m e t e r s
+ int screenWidth_, screenHeight_; // size of the window, in pixels
+ float fieldOfView_; // in radians
+ Vec sceneCenter_;
+ float sceneRadius_; // OpenGL units
+ float zNearCoef_;
+ float zClippingCoef_;
+ float orthoCoef_;
+ Type type_; // PERSPECTIVE or ORTHOGRAPHIC
+ mutable GLdouble modelViewMatrix_[16]; // Buffered model view matrix.
+ mutable GLdouble projectionMatrix_[16]; // Buffered projection matrix.
+
+ // S t e r e o p a r a m e t e r s
+ float IODistance_; // inter-ocular distance, in meters
+ float focusDistance_; // in scene units
+ float physicalDistanceToScreen_; // in meters
+ float physicalScreenWidth_; // in meters
+
+ // P o i n t s o f V i e w s a n d K e y F r a m e s
+ //map<int, KeyFrameInterpolator*> kfi_;
+ //KeyFrameInterpolator* interpolationKfi_;
+ };
+
+
+#endif // QGLVIEWER_CAMERA_H
diff --git a/source/blender/freestyle/intern/app_blender/config.h b/source/blender/freestyle/intern/app_blender/config.h
new file mode 100644
index 00000000000..c1b65aad560
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/config.h
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////
+// libQGLViewer configuration file //
+// Modify these settings according to your local configuration //
+///////////////////////////////////////////////////////////////////
+
+#ifndef QGLVIEWER_CONFIG_H
+#define QGLVIEWER_CONFIG_H
+
+
+
+
+
+#include <map>
+#include <ostream>
+
+#include <math.h>
+#include <iostream>
+
+using namespace std;
+
+#include "point.h"
+
+# ifdef WIN32
+# include <windows.h>
+# endif
+# ifdef __MACH__
+# include <OpenGL/gl.h>
+# else
+# include <GL/gl.h>
+# endif
+
+#ifdef __APPLE_CC__
+ #include <GLUT/glut.h>
+#else
+ #include <GL/glut.h>
+#endif
+
+#ifndef Q_UNUSED
+ # define Q_UNUSED(x) (void)x;
+#endif
+
+template <typename T>
+inline const T &qMin(const T &a, const T &b) { if (a < b) return a; return b; }
+template <typename T>
+inline const T &qMax(const T &a, const T &b) { if (a < b) return b; return a; }
+template <typename T>
+inline const T &qBound(const T &min, const T &val, const T &max)
+{ return qMax(min, qMin(max, val)); }
+
+#endif // QGLVIEWER_CONFIG_H
diff --git a/source/blender/freestyle/intern/app_blender/constraint.h b/source/blender/freestyle/intern/app_blender/constraint.h
new file mode 100644
index 00000000000..871cb2be098
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/constraint.h
@@ -0,0 +1,341 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef QGLVIEWER_CONSTRAINT_H
+#define QGLVIEWER_CONSTRAINT_H
+
+#include "vec.h"
+#include "quaternion.h"
+
+//namespace qglviewer {
+ class Frame;
+ class Camera;
+
+ /*! \brief An interface class for Frame constraints.
+ \class Constraint constraint.h QGLViewer/constraint.h
+
+ This class defines the interface for the Constraints that can be applied to a Frame to limit its
+ motion. Use Frame::setConstraint() to associate a Constraint to a Frame (default is a \c NULL
+ Frame::constraint()).
+
+ <h3>How does it work ?</h3>
+
+ The Constraint acts as a filter on the translation and rotation Frame increments.
+ constrainTranslation() and constrainRotation() should be overloaded to specify the constraint
+ behavior: the desired displacement is given as a parameter that can optionally be modified.
+
+ Here is how the Frame::translate() and Frame::rotate() methods use the Constraint:
+ \code
+ Frame::translate(Vec& T)
+ {
+ if (constraint())
+ constraint()->constrainTranslation(T, this);
+ t += T;
+ }
+
+ Frame::rotate(Quaternion& Q)
+ {
+ if (constraint())
+ constraint()->constrainRotation(Q, this);
+ q *= Q;
+ }
+ \endcode
+
+ The default behavior of constrainTranslation() and constrainRotation() is empty (meaning no
+ filtering).
+
+ The Frame which uses the Constraint is passed as a parameter to the constrainTranslation() and
+ constrainRotation() methods, so that they can have access to its current state (mainly
+ Frame::position() and Frame::orientation()). It is not \c const for versatility reasons, but
+ directly modifying it should be avoided.
+
+ \attention Frame::setTranslation(), Frame::setRotation() and similar methods will actually indeed
+ set the frame position and orientation, without taking the constraint into account. Use the \e
+ WithConstraint versions of these methods to enforce the Constraint.
+
+ <h3>Implemented Constraints</h3>
+
+ Classical axial and plane Constraints are provided for convenience: see the LocalConstraint,
+ WorldConstraint and CameraConstraint classes' documentations.
+
+ Try the <a href="../examples/constrainedFrame.html">constrainedFrame</a> and <a
+ href="../examples/constrainedCamera.html">constrainedCamera</a> examples for an illustration.
+
+ <h3>Creating new Constraints</h3>
+
+ The implementation of a new Constraint class simply consists in overloading the filtering methods:
+ \code
+ // This Constraint enforces that the Frame cannot have a negative z world coordinate.
+ class myConstraint : public Constraint
+ {
+ public:
+ virtual void constrainTranslation(Vec& t, Frame * const fr)
+ {
+ // Express t in the world coordinate system.
+ const Vec tWorld = fr->inverseTransformOf(t);
+ if (fr->position().z + tWorld.z < 0.0) // check the new fr z coordinate
+ t.z = fr->transformOf(-fr->position().z); // t.z is clamped so that next z position is 0.0
+ }
+ };
+ \endcode
+
+ Note that the translation (resp. rotation) parameter passed to constrainTranslation() (resp.
+ constrainRotation()) is expressed in the \e local Frame coordinate system. Here, we use the
+ Frame::transformOf() and Frame::inverseTransformOf() method to convert it to and from the world
+ coordinate system.
+
+ Combined constraints can easily be achieved by creating a new class that applies the different
+ constraint filters:
+ \code
+ myConstraint::constrainTranslation(Vec& v, Frame* const fr)
+ {
+ constraint1->constrainTranslation(v, fr);
+ constraint2->constrainTranslation(v, fr);
+ // and so on, with possible branches, tests, loops...
+ }
+ \endcode
+ */
+ class Constraint
+ {
+ public:
+ /*! Virtual destructor. Empty. */
+ virtual ~Constraint() {};
+
+ /*! Filters the translation applied to the \p frame. This default implementation is empty (no
+ filtering).
+
+ Overload this method in your own Constraint class to define a new translation constraint. \p
+ frame is the Frame to which is applied the translation. It is not defined \c const, but you
+ should refrain from directly changing its value in the constraint. Use its Frame::position() and
+ update the \p translation accordingly instead.
+
+ \p translation is expressed in local frame coordinate system. Use Frame::inverseTransformOf() to
+ express it in the world coordinate system if needed. */
+ virtual void constrainTranslation(Vec& translation, Frame* const frame) { Q_UNUSED(translation); Q_UNUSED(frame); };
+ /*! Filters the rotation applied to the \p frame. This default implementation is empty (no
+ filtering).
+
+ Overload this method in your own Constraint class to define a new rotation constraint. See
+ constrainTranslation() for details.
+
+ Use Frame::inverseTransformOf() on the \p rotation Quaternion::axis() to express \p rotation in
+ the world coordinate system if needed. */
+ virtual void constrainRotation(Quaternion& rotation, Frame* const frame) { Q_UNUSED(rotation); Q_UNUSED(frame); };
+ };
+
+ /*!
+ \brief An abstract class for Frame Constraints defined by an axis or a plane.
+ \class AxisPlaneConstraint constraint.h QGLViewer/constraint.h
+
+ AxisPlaneConstraint is an interface for (translation and/or rotation) Constraint that are defined
+ by a direction. translationConstraintType() and rotationConstraintType() define how this
+ direction should be interpreted: as an axis (AxisPlaneConstraint::AXIS) or as a plane normal
+ (AxisPlaneConstraint::PLANE). See the Type() documentation for details.
+
+ The three implementations of this class: LocalConstraint, WorldConstraint and CameraConstraint
+ differ by the coordinate system in which this direction is expressed.
+
+ Different implementations of this class are illustrated in the
+ <a href="../examples/constrainedCamera.html">contrainedCamera</a> and
+ <a href="../examples/constrainedFrame.html">constrainedFrame</a> examples.
+
+ \attention When applied, the rotational Constraint may not intuitively follow the mouseQU
+ displacement. A solution would be to directly measure the rotation angle in screen coordinates,
+ but that would imply to know the QGLViewer::camera(), so that we can compute the projected
+ coordinates of the rotation center (as is done with the QGLViewer::SCREEN_ROTATE binding).
+ However, adding an extra pointer to the QGLViewer::camera() in all the AxisPlaneConstraint
+ derived classes (which the user would have to update in a multi-viewer application) was judged as
+ an overkill. */
+ class AxisPlaneConstraint : public Constraint
+ {
+ public:
+ AxisPlaneConstraint();
+ /*! Virtual destructor. Empty. */
+ virtual ~AxisPlaneConstraint() {};
+
+ /*! Type lists the different types of translation and rotation constraints that are available.
+
+ It specifies the meaning of the constraint direction (see translationConstraintDirection() and
+ rotationConstraintDirection()): as an axis direction (AxisPlaneConstraint::AXIS) or a plane
+ normal (AxisPlaneConstraint::PLANE). AxisPlaneConstraint::FREE means no constraint while
+ AxisPlaneConstraint::FORBIDDEN completely forbids the translation and/or the rotation.
+
+ See translationConstraintType() and rotationConstraintType().
+
+ \attention The AxisPlaneConstraint::PLANE Type is not valid for rotational constraint.
+
+ New derived classes can use their own extended enum for specific constraints:
+ \code
+ class MyAxisPlaneConstraint : public AxisPlaneConstraint
+ {
+ public:
+ enum MyType { FREE, AXIS, PLANE, FORBIDDEN, CUSTOM };
+ virtual void constrainTranslation(Vec &translation, Frame *const frame)
+ {
+ // translationConstraintType() is simply an int. CUSTOM Type is handled seamlessly.
+ switch (translationConstraintType())
+ {
+ case MyAxisPlaneConstraint::FREE: ... break;
+ case MyAxisPlaneConstraint::CUSTOM: ... break;
+ }
+ };
+
+ MyAxisPlaneConstraint* c = new MyAxisPlaneConstraint();
+ // Note the Type conversion
+ c->setTranslationConstraintType(AxisPlaneConstraint::Type(MyAxisPlaneConstraint::CUSTOM));
+ };
+ \endcode */
+ enum Type { FREE, AXIS, PLANE, FORBIDDEN };
+
+ /*! @name Translation constraint */
+ //@{
+ /*! Overloading of Constraint::constrainTranslation(). Empty */
+ virtual void constrainTranslation(Vec& translation, Frame* const frame) { Q_UNUSED(translation); Q_UNUSED(frame); };
+
+ void setTranslationConstraint(Type type, const Vec& direction);
+ /*! Sets the Type() of the translationConstraintType(). Default is AxisPlaneConstraint::FREE. */
+ void setTranslationConstraintType(Type type) { translationConstraintType_ = type; };
+ void setTranslationConstraintDirection(const Vec& direction);
+
+ /*! Returns the translation constraint Type().
+
+ Depending on this value, the Frame will freely translate (AxisPlaneConstraint::FREE), will only
+ be able to translate along an axis direction (AxisPlaneConstraint::AXIS), will be forced to stay
+ into a plane (AxisPlaneConstraint::PLANE) or will not able to translate at all
+ (AxisPlaneConstraint::FORBIDDEN).
+
+ Use Frame::setPosition() to define the position of the constrained Frame before it gets
+ constrained. */
+ Type translationConstraintType() const { return translationConstraintType_; };
+ /*! Returns the direction used by the translation constraint.
+
+ It represents the axis direction (AxisPlaneConstraint::AXIS) or the plane normal
+ (AxisPlaneConstraint::PLANE) depending on the translationConstraintType(). It is undefined for
+ AxisPlaneConstraint::FREE or AxisPlaneConstraint::FORBIDDEN.
+
+ The AxisPlaneConstraint derived classes express this direction in different coordinate system
+ (camera for CameraConstraint, local for LocalConstraint, and world for WorldConstraint). This
+ value can be modified with setTranslationConstraintDirection(). */
+ Vec translationConstraintDirection() const { return translationConstraintDir_; };
+ //@}
+
+ /*! @name Rotation constraint */
+ //@{
+ /*! Overloading of Constraint::constrainRotation(). Empty. */
+ virtual void constrainRotation(Quaternion& rotation, Frame* const frame) { Q_UNUSED(rotation); Q_UNUSED(frame); };
+
+ void setRotationConstraint(Type type, const Vec& direction);
+ void setRotationConstraintType(Type type);
+ void setRotationConstraintDirection(const Vec& direction);
+
+ /*! Returns the rotation constraint Type(). */
+ Type rotationConstraintType() const { return rotationConstraintType_; };
+ /*! Returns the axis direction used by the rotation constraint.
+
+ This direction is defined only when rotationConstraintType() is AxisPlaneConstraint::AXIS.
+
+ The AxisPlaneConstraint derived classes express this direction in different coordinate system
+ (camera for CameraConstraint, local for LocalConstraint, and world for WorldConstraint). This
+ value can be modified with setRotationConstraintDirection(). */
+ Vec rotationConstraintDirection() const { return rotationConstraintDir_; };
+ //@}
+
+ private:
+ // int and not Type to allow for overloading and new types definition.
+ Type translationConstraintType_;
+ Type rotationConstraintType_;
+
+ Vec translationConstraintDir_;
+ Vec rotationConstraintDir_;
+ };
+
+
+ /*! \brief An AxisPlaneConstraint defined in the Frame local coordinate system.
+ \class LocalConstraint constraint.h QGLViewer/constraint.h
+
+ The translationConstraintDirection() and rotationConstraintDirection() are expressed in the Frame
+ local coordinate system (see Frame::referenceFrame()).
+
+ See the <a href="../examples/constrainedFrame.html">constrainedFrame</a> example for an illustration. */
+ class LocalConstraint : public AxisPlaneConstraint
+ {
+ public:
+ /*! Virtual destructor. Empty. */
+ virtual ~LocalConstraint() {};
+
+ virtual void constrainTranslation(Vec& translation, Frame* const frame);
+ virtual void constrainRotation (Quaternion& rotation, Frame* const frame);
+ };
+
+
+
+ /*! \brief An AxisPlaneConstraint defined in the world coordinate system.
+ \class WorldConstraint constraint.h QGLViewer/constraint.h
+
+ The translationConstraintDirection() and rotationConstraintDirection() are expressed in world
+ coordinate system.
+
+ See the <a href="../examples/constrainedFrame.html">constrainedFrame</a> and <a
+ href="../examples/multiView.html">multiView</a> examples for an illustration. */
+ class WorldConstraint : public AxisPlaneConstraint
+ {
+ public:
+ /*! Virtual destructor. Empty. */
+ virtual ~WorldConstraint() {};
+
+ virtual void constrainTranslation(Vec& translation, Frame* const frame);
+ virtual void constrainRotation (Quaternion& rotation, Frame* const frame);
+ };
+
+
+
+ /*! \brief An AxisPlaneConstraint defined in the camera coordinate system.
+ \class CameraConstraint constraint.h QGLViewer/constraint.h
+
+ The translationConstraintDirection() and rotationConstraintDirection() are expressed in the
+ associated camera() coordinate system.
+
+ See the <a href="../examples/constrainedFrame.html">constrainedFrame</a> and <a
+ href="../examples/constrainedCamera.html">constrainedCamera</a> examples for an illustration. */
+ class CameraConstraint : public AxisPlaneConstraint
+ {
+ public:
+ explicit CameraConstraint(const Camera* const camera);
+ /*! Virtual destructor. Empty. */
+ virtual ~CameraConstraint() {};
+
+ virtual void constrainTranslation(Vec& translation, Frame* const frame);
+ virtual void constrainRotation (Quaternion& rotation, Frame* const frame);
+
+ /*! Returns the associated Camera. Set using the CameraConstraint constructor. */
+ const Camera* camera() const { return camera_; };
+
+ private:
+ const Camera* const camera_;
+ };
+
+//} // namespace qglviewer
+
+#endif // QGLVIEWER_CONSTRAINT_H
diff --git a/source/blender/freestyle/intern/app_blender/frame.cpp b/source/blender/freestyle/intern/app_blender/frame.cpp
new file mode 100644
index 00000000000..26c2ee5d2b4
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/frame.cpp
@@ -0,0 +1,1070 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "frame.h"
+#include <math.h>
+
+//using namespace qglviewer;
+using namespace std;
+
+
+/*! Creates a default Frame.
+
+ Its position() is (0,0,0) and it has an identity orientation() Quaternion. The referenceFrame()
+ and the constraint() are \c NULL. */
+Frame::Frame()
+ : constraint_(NULL), referenceFrame_(NULL)
+{}
+
+/*! Creates a Frame with a position() and an orientation().
+
+ See the Vec and Quaternion documentations for convenient constructors and methods.
+
+ The Frame is defined in the world coordinate system (its referenceFrame() is \c NULL). It
+ has a \c NULL associated constraint(). */
+Frame::Frame(const Vec& position, const Quaternion& orientation)
+ : t_(position), q_(orientation), constraint_(NULL), referenceFrame_(NULL)
+{}
+
+/*! Equal operator.
+
+ The referenceFrame() and constraint() pointers are copied.
+
+ \attention Signal and slot connections are not copied. */
+Frame& Frame::operator=(const Frame& frame)
+{
+ // Automatic compiler generated version would not emit the modified signals as is done in
+ // setTranslationAndRotation.
+ setTranslationAndRotation(frame.translation(), frame.rotation());
+ setConstraint(frame.constraint());
+ setReferenceFrame(frame.referenceFrame());
+ return *this;
+}
+
+/*! Copy constructor.
+
+ The translation() and rotation() as well as constraint() and referenceFrame() pointers are
+ copied. */
+Frame::Frame(const Frame& frame)
+{
+ (*this) = frame;
+}
+
+/////////////////////////////// MATRICES //////////////////////////////////////
+
+/*! Returns the 4x4 OpenGL transformation matrix represented by the Frame.
+
+ This method should be used in conjunction with \c glMultMatrixd() to modify the OpenGL modelview
+ matrix from a Frame hierarchy. With this Frame hierarchy:
+ \code
+ Frame* body = new Frame();
+ Frame* leftArm = new Frame();
+ Frame* rightArm = new Frame();
+ leftArm->setReferenceFrame(body);
+ rightArm->setReferenceFrame(body);
+ \endcode
+
+ The associated OpenGL drawing code should look like:
+ \code
+ void Viewer::draw()
+ {
+ glPushMatrix();
+ glMultMatrixd(body->matrix());
+ drawBody();
+
+ glPushMatrix();
+ glMultMatrixd(leftArm->matrix());
+ drawArm();
+ glPopMatrix();
+
+ glPushMatrix();
+ glMultMatrixd(rightArm->matrix());
+ drawArm();
+ glPopMatrix();
+
+ glPopMatrix();
+ }
+ \endcode
+ Note the use of nested \c glPushMatrix() and \c glPopMatrix() blocks to represent the frame hierarchy: \c
+ leftArm and \c rightArm are both correctly drawn with respect to the \c body coordinate system.
+
+ This matrix only represents the local Frame transformation (i.e. with respect to the
+ referenceFrame()). Use worldMatrix() to get the full Frame transformation matrix (i.e. from the
+ world to the Frame coordinate system). These two match when the referenceFrame() is \c NULL.
+
+ The result is only valid until the next call to matrix(), getMatrix(), worldMatrix() or
+ getWorldMatrix(). Use it immediately (as above) or use getMatrix() instead.
+
+ \attention The OpenGL format of the result is the transpose of the actual mathematical European
+ representation (translation is on the last \e line instead of the last \e column).
+
+ \note The scaling factor of the 4x4 matrix is 1.0. */
+const GLdouble* Frame::matrix() const
+{
+ static GLdouble m[4][4];
+ getMatrix(m);
+ return (const GLdouble*)(m);
+}
+
+/*! \c GLdouble[4][4] version of matrix(). See also getWorldMatrix() and matrix(). */
+void Frame::getMatrix(GLdouble m[4][4]) const
+{
+ q_.getMatrix(m);
+
+ m[3][0] = t_[0];
+ m[3][1] = t_[1];
+ m[3][2] = t_[2];
+}
+
+/*! \c GLdouble[16] version of matrix(). See also getWorldMatrix() and matrix(). */
+void Frame::getMatrix(GLdouble m[16]) const
+{
+ q_.getMatrix(m);
+
+ m[12] = t_[0];
+ m[13] = t_[1];
+ m[14] = t_[2];
+}
+
+/*! Returns a Frame representing the inverse of the Frame space transformation.
+
+ The rotation() of the new Frame is the Quaternion::inverse() of the original rotation.
+ Its translation() is the negated inverse rotated image of the original translation.
+
+ If a Frame is considered as a space rigid transformation (translation and rotation), the inverse()
+ Frame performs the inverse transformation.
+
+ Only the local Frame transformation (i.e. defined with respect to the referenceFrame()) is inverted.
+ Use worldInverse() for a global inverse.
+
+ The resulting Frame has the same referenceFrame() as the Frame and a \c NULL constraint().
+
+ \note The scaling factor of the 4x4 matrix is 1.0. */
+Frame Frame::inverse() const
+{
+ Frame fr(-(q_.inverseRotate(t_)), q_.inverse());
+ fr.setReferenceFrame(referenceFrame());
+ return fr;
+}
+
+/*! Returns the 4x4 OpenGL transformation matrix represented by the Frame.
+
+ This method should be used in conjunction with \c glMultMatrixd() to modify
+ the OpenGL modelview matrix from a Frame:
+ \code
+ // The modelview here corresponds to the world coordinate system.
+ Frame fr(pos, Quaternion(from, to));
+ glPushMatrix();
+ glMultMatrixd(fr.worldMatrix());
+ // draw object in the fr coordinate system.
+ glPopMatrix();
+ \endcode
+
+ This matrix represents the global Frame transformation: the entire referenceFrame() hierarchy is
+ taken into account to define the Frame transformation from the world coordinate system. Use
+ matrix() to get the local Frame transformation matrix (i.e. defined with respect to the
+ referenceFrame()). These two match when the referenceFrame() is \c NULL.
+
+ The OpenGL format of the result is the transpose of the actual mathematical European
+ representation (translation is on the last \e line instead of the last \e column).
+
+ \attention The result is only valid until the next call to matrix(), getMatrix(), worldMatrix() or
+ getWorldMatrix(). Use it immediately (as above) or use getWorldMatrix() instead.
+
+ \note The scaling factor of the 4x4 matrix is 1.0. */
+const GLdouble* Frame::worldMatrix() const
+{
+ // This test is done for efficiency reasons (creates lots of temp objects otherwise).
+ if (referenceFrame())
+ {
+ static Frame fr;
+ fr.setTranslation(position());
+ fr.setRotation(orientation());
+ return fr.matrix();
+ }
+ else
+ return matrix();
+}
+
+/*! float[4][4] parameter version of worldMatrix(). See also getMatrix() and matrix(). */
+void Frame::getWorldMatrix(GLdouble m[4][4]) const
+{
+ const GLdouble* mat = worldMatrix();
+ for (int i=0; i<4; ++i)
+ for (int j=0; j<4; ++j)
+ m[i][j] = mat[i*4+j];
+}
+
+/*! float[16] parameter version of worldMatrix(). See also getMatrix() and matrix(). */
+void Frame::getWorldMatrix(GLdouble m[16]) const
+{
+ const GLdouble* mat = worldMatrix();
+ for (int i=0; i<16; ++i)
+ m[i] = mat[i];
+}
+
+/*! This is an overloaded method provided for convenience. Same as setFromMatrix(). */
+void Frame::setFromMatrix(const GLdouble m[4][4])
+{
+ if (fabs(m[3][3]) < 1E-8)
+ {
+ cout << "Frame::setFromMatrix: Null homogeneous coefficient" << endl;
+ return;
+ }
+
+ double rot[3][3];
+ for (int i=0; i<3; ++i)
+ {
+ t_[i] = m[3][i] / m[3][3];
+ for (int j=0; j<3; ++j)
+ // Beware of the transposition (OpenGL to European math)
+ rot[i][j] = m[j][i] / m[3][3];
+ }
+ q_.setFromRotationMatrix(rot);
+}
+
+/*! Sets the Frame from an OpenGL matrix representation (rotation in the upper left 3x3 matrix and
+ translation on the last line).
+
+ Hence, if a code fragment looks like:
+ \code
+ GLdouble m[16]={...};
+ glMultMatrixd(m);
+ \endcode
+ It is equivalent to write:
+ \code
+ Frame fr;
+ fr.setFromMatrix(m);
+ glMultMatrixd(fr.matrix());
+ \endcode
+
+ Using this conversion, you can benefit from the powerful Frame transformation methods to translate
+ points and vectors to and from the Frame coordinate system to any other Frame coordinate system
+ (including the world coordinate system). See coordinatesOf() and transformOf().
+
+ Emits the modified() signal. See also matrix(), getMatrix() and
+ Quaternion::setFromRotationMatrix().
+
+ \attention A Frame does not contain a scale factor. The possible scaling in \p m will not be
+ converted into the Frame by this method. */
+void Frame::setFromMatrix(const GLdouble m[16])
+{
+ GLdouble mat[4][4];
+ for (int i=0; i<4; ++i)
+ for (int j=0; j<4; ++j)
+ mat[i][j] = m[i*4+j];
+ setFromMatrix(mat);
+}
+
+//////////////////// SET AND GET LOCAL TRANSLATION AND ROTATION ///////////////////////////////
+
+
+/*! Same as setTranslation(), but with \p float parameters. */
+void Frame::setTranslation(float x, float y, float z)
+{
+ setTranslation(Vec(x, y, z));
+}
+
+/*! Fill \c x, \c y and \c z with the translation() of the Frame. */
+void Frame::getTranslation(float& x, float& y, float& z) const
+{
+ const Vec t = translation();
+ x = t[0];
+ y = t[1];
+ z = t[2];
+}
+
+/*! Same as setRotation() but with \c float Quaternion parameters. */
+void Frame::setRotation(double q0, double q1, double q2, double q3)
+{
+ setRotation(Quaternion(q0, q1, q2, q3));
+}
+
+/*! The \p q are set to the rotation() of the Frame.
+
+See Quaternion::Quaternion(double, double, double, double) for details on \c q. */
+void Frame::getRotation(double& q0, double& q1, double& q2, double& q3) const
+{
+ const Quaternion q = rotation();
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/*! Translates the Frame of \p t (defined in the Frame coordinate system).
+
+ The translation actually applied to the Frame may differ from \p t since it can be filtered by the
+ constraint(). Use translate(Vec&) or setTranslationWithConstraint() to retrieve the filtered
+ translation value. Use setTranslation() to directly translate the Frame without taking the
+ constraint() into account.
+
+ See also rotate(const Quaternion&). Emits the modified() signal. */
+void Frame::translate(const Vec& t)
+{
+ Vec tbis = t;
+ translate(tbis);
+}
+
+/*! Same as translate(const Vec&) but \p t may be modified to satisfy the translation constraint().
+ Its new value corresponds to the translation that has actually been applied to the Frame. */
+void Frame::translate(Vec& t)
+{
+ if (constraint())
+ constraint()->constrainTranslation(t, this);
+ t_ += t;
+}
+
+/*! Same as translate(const Vec&) but with \c float parameters. */
+void Frame::translate(float x, float y, float z)
+{
+ Vec t(x,y,z);
+ translate(t);
+}
+
+/*! Same as translate(Vec&) but with \c float parameters. */
+void Frame::translate(float& x, float& y, float& z)
+{
+ Vec t(x,y,z);
+ translate(t);
+ x = t[0];
+ y = t[1];
+ z = t[2];
+}
+
+/*! Rotates the Frame by \p q (defined in the Frame coordinate system): R = R*q.
+
+ The rotation actually applied to the Frame may differ from \p q since it can be filtered by the
+ constraint(). Use rotate(Quaternion&) or setRotationWithConstraint() to retrieve the filtered
+ rotation value. Use setRotation() to directly rotate the Frame without taking the constraint()
+ into account.
+
+ See also translate(const Vec&). Emits the modified() signal. */
+void Frame::rotate(const Quaternion& q)
+{
+ Quaternion qbis = q;
+ rotate(qbis);
+}
+
+/*! Same as rotate(const Quaternion&) but \p q may be modified to satisfy the rotation constraint().
+ Its new value corresponds to the rotation that has actually been applied to the Frame. */
+void Frame::rotate(Quaternion& q)
+{
+ if (constraint())
+ constraint()->constrainRotation(q, this);
+ q_ *= q;
+ q_.normalize(); // Prevents numerical drift
+}
+
+/*! Same as rotate(Quaternion&) but with \c float Quaternion parameters. */
+void Frame::rotate(double& q0, double& q1, double& q2, double& q3)
+{
+ Quaternion q(q0,q1,q2,q3);
+ rotate(q);
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+}
+
+/*! Same as rotate(const Quaternion&) but with \c float Quaternion parameters. */
+void Frame::rotate(double q0, double q1, double q2, double q3)
+{
+ Quaternion q(q0,q1,q2,q3);
+ rotate(q);
+}
+
+/*! Makes the Frame rotate() by \p rotation around \p point.
+
+ \p point is defined in the world coordinate system, while the \p rotation axis is defined in the
+ Frame coordinate system.
+
+ If the Frame has a constraint(), \p rotation is first constrained using
+ Constraint::constrainRotation(). The translation which results from the filtered rotation around
+ \p point is then computed and filtered using Constraint::constrainTranslation(). The new \p
+ rotation value corresponds to the rotation that has actually been applied to the Frame.
+
+ Emits the modified() signal. */
+void Frame::rotateAroundPoint(Quaternion& rotation, const Vec& point)
+{
+ if (constraint())
+ constraint()->constrainRotation(rotation, this);
+ q_ *= rotation;
+ q_.normalize(); // Prevents numerical drift
+ Vec trans = point + Quaternion(inverseTransformOf(rotation.axis()), rotation.angle()).rotate(position()-point) - t_;
+ if (constraint())
+ constraint()->constrainTranslation(trans, this);
+ t_ += trans;
+}
+
+/*! Same as rotateAroundPoint(), but with a \c const \p rotation Quaternion. Note that the actual
+ rotation may differ since it can be filtered by the constraint(). */
+void Frame::rotateAroundPoint(const Quaternion& rotation, const Vec& point)
+{
+ Quaternion rot = rotation;
+ rotateAroundPoint(rot, point);
+}
+
+//////////////////// SET AND GET WORLD POSITION AND ORIENTATION ///////////////////////////////
+
+/*! Sets the position() of the Frame, defined in the world coordinate system. Emits the modified()
+ signal.
+
+Use setTranslation() to define the \e local frame translation (with respect to the
+referenceFrame()). The potential constraint() of the Frame is not taken into account, use
+setPositionWithConstraint() instead. */
+void Frame::setPosition(const Vec& position)
+{
+ if (referenceFrame())
+ setTranslation(referenceFrame()->coordinatesOf(position));
+ else
+ setTranslation(position);
+}
+
+/*! Same as setPosition(), but with \c float parameters. */
+void Frame::setPosition(float x, float y, float z)
+{
+ setPosition(Vec(x, y, z));
+}
+
+/*! Same as successive calls to setPosition() and then setOrientation().
+
+Only one modified() signal is emitted, which is convenient if this signal is connected to a
+QGLViewer::updateGL() slot. See also setTranslationAndRotation() and
+setPositionAndOrientationWithConstraint(). */
+void Frame::setPositionAndOrientation(const Vec& position, const Quaternion& orientation)
+{
+ if (referenceFrame())
+ {
+ t_ = referenceFrame()->coordinatesOf(position);
+ q_ = referenceFrame()->orientation().inverse() * orientation;
+ }
+ else
+ {
+ t_ = position;
+ q_ = orientation;
+ }
+}
+
+
+/*! Same as successive calls to setTranslation() and then setRotation().
+
+Only one modified() signal is emitted, which is convenient if this signal is connected to a
+QGLViewer::updateGL() slot. See also setPositionAndOrientation() and
+setTranslationAndRotationWithConstraint(). */
+void Frame::setTranslationAndRotation(const Vec& translation, const Quaternion& rotation)
+{
+ t_ = translation;
+ q_ = rotation;
+}
+
+
+/*! \p x, \p y and \p z are set to the position() of the Frame. */
+void Frame::getPosition(float& x, float& y, float& z) const
+{
+ Vec p = position();
+ x = p.x;
+ y = p.y;
+ z = p.z;
+}
+
+/*! Sets the orientation() of the Frame, defined in the world coordinate system. Emits the modified() signal.
+
+Use setRotation() to define the \e local frame rotation (with respect to the referenceFrame()). The
+potential constraint() of the Frame is not taken into account, use setOrientationWithConstraint()
+instead. */
+void Frame::setOrientation(const Quaternion& orientation)
+{
+ if (referenceFrame())
+ setRotation(referenceFrame()->orientation().inverse() * orientation);
+ else
+ setRotation(orientation);
+}
+
+/*! Same as setOrientation(), but with \c float parameters. */
+void Frame::setOrientation(double q0, double q1, double q2, double q3)
+{
+ setOrientation(Quaternion(q0, q1, q2, q3));
+}
+
+/*! Get the current orientation of the frame (same as orientation()).
+ Parameters are the orientation Quaternion values.
+ See also setOrientation(). */
+
+/*! The \p q are set to the orientation() of the Frame.
+
+See Quaternion::Quaternion(double, double, double, double) for details on \c q. */
+void Frame::getOrientation(double& q0, double& q1, double& q2, double& q3) const
+{
+ Quaternion o = orientation();
+ q0 = o[0];
+ q1 = o[1];
+ q2 = o[2];
+ q3 = o[3];
+}
+
+/*! Returns the orientation of the Frame, defined in the world coordinate system. See also
+ position(), setOrientation() and rotation(). */
+Quaternion Frame::orientation() const
+{
+ Quaternion res = rotation();
+ const Frame* fr = referenceFrame();
+ while (fr != NULL)
+ {
+ res = fr->rotation() * res;
+ fr = fr->referenceFrame();
+ }
+ return res;
+}
+
+
+////////////////////// C o n s t r a i n t V e r s i o n s //////////////////////////
+
+/*! Same as setTranslation(), but \p translation is modified so that the potential constraint() of the
+ Frame is satisfied.
+
+ Emits the modified() signal. See also setRotationWithConstraint() and setPositionWithConstraint(). */
+void Frame::setTranslationWithConstraint(Vec& translation)
+{
+ Vec deltaT = translation - this->translation();
+ if (constraint())
+ constraint()->constrainTranslation(deltaT, this);
+
+ setTranslation(this->translation() + deltaT);
+ translation = this->translation();
+}
+
+/*! Same as setRotation(), but \p rotation is modified so that the potential constraint() of the
+ Frame is satisfied.
+
+ Emits the modified() signal. See also setTranslationWithConstraint() and setOrientationWithConstraint(). */
+void Frame::setRotationWithConstraint(Quaternion& rotation)
+{
+ Quaternion deltaQ = this->rotation().inverse() * rotation;
+ if (constraint())
+ constraint()->constrainRotation(deltaQ, this);
+
+ // Prevent numerical drift
+ deltaQ.normalize();
+
+ setRotation(this->rotation() * deltaQ);
+ q_.normalize();
+ rotation = this->rotation();
+}
+
+/*! Same as setTranslationAndRotation(), but \p translation and \p orientation are modified to
+ satisfy the constraint(). Emits the modified() signal. */
+void Frame::setTranslationAndRotationWithConstraint(Vec& translation, Quaternion& rotation)
+{
+ Vec deltaT = translation - this->translation();
+ Quaternion deltaQ = this->rotation().inverse() * rotation;
+
+ if (constraint())
+ {
+ constraint()->constrainTranslation(deltaT, this);
+ constraint()->constrainRotation(deltaQ, this);
+ }
+
+ // Prevent numerical drift
+ deltaQ.normalize();
+
+ t_ += deltaT;
+ q_ *= deltaQ;
+ q_.normalize();
+
+ translation = this->translation();
+ rotation = this->rotation();
+
+}
+
+/*! Same as setPosition(), but \p position is modified so that the potential constraint() of the
+ Frame is satisfied. See also setOrientationWithConstraint() and setTranslationWithConstraint(). */
+void Frame::setPositionWithConstraint(Vec& position)
+{
+ if (referenceFrame())
+ position = referenceFrame()->coordinatesOf(position);
+
+ setTranslationWithConstraint(position);
+}
+
+/*! Same as setOrientation(), but \p orientation is modified so that the potential constraint() of the Frame
+ is satisfied. See also setPositionWithConstraint() and setRotationWithConstraint(). */
+void Frame::setOrientationWithConstraint(Quaternion& orientation)
+{
+ if (referenceFrame())
+ orientation = referenceFrame()->orientation().inverse() * orientation;
+
+ setRotationWithConstraint(orientation);
+}
+
+/*! Same as setPositionAndOrientation() but \p position and \p orientation are modified to satisfy
+the constraint. Emits the modified() signal. */
+void Frame::setPositionAndOrientationWithConstraint(Vec& position, Quaternion& orientation)
+{
+ if (referenceFrame())
+ {
+ position = referenceFrame()->coordinatesOf(position);
+ orientation = referenceFrame()->orientation().inverse() * orientation;
+ }
+ setTranslationAndRotationWithConstraint(position, orientation);
+}
+
+
+///////////////////////////// REFERENCE FRAMES ///////////////////////////////////////
+
+/*! Sets the referenceFrame() of the Frame.
+
+The Frame translation() and rotation() are then defined in the referenceFrame() coordinate system.
+Use position() and orientation() to express these in the world coordinate system.
+
+Emits the modified() signal if \p refFrame differs from the current referenceFrame().
+
+Using this method, you can create a hierarchy of Frames. This hierarchy needs to be a tree, which
+root is the world coordinate system (i.e. a \c NULL referenceFrame()). A warning is printed and no
+action is performed if setting \p refFrame as the referenceFrame() would create a loop in the Frame
+hierarchy (see settingAsReferenceFrameWillCreateALoop()). */
+void Frame::setReferenceFrame(const Frame* const refFrame)
+{
+ if (settingAsReferenceFrameWillCreateALoop(refFrame))
+ cout << "Frame::setReferenceFrame would create a loop in Frame hierarchy" << endl;
+ else
+ {
+ bool identical = (referenceFrame_ == refFrame);
+ referenceFrame_ = refFrame;
+ }
+}
+
+/*! Returns \c true if setting \p frame as the Frame's referenceFrame() would create a loop in the
+ Frame hierarchy. */
+bool Frame::settingAsReferenceFrameWillCreateALoop(const Frame* const frame)
+{
+ const Frame* f = frame;
+ while (f != NULL)
+ {
+ if (f == this)
+ return true;
+ f = f->referenceFrame();
+ }
+ return false;
+}
+
+///////////////////////// FRAME TRANSFORMATIONS OF 3D POINTS //////////////////////////////
+
+/*! Returns the Frame coordinates of a point \p src defined in the world coordinate system (converts
+ from world to Frame).
+
+ inverseCoordinatesOf() performs the inverse convertion. transformOf() converts 3D vectors instead
+ of 3D coordinates.
+
+ See the <a href="../examples/frameTransform.html">frameTransform example</a> for an
+ illustration. */
+Vec Frame::coordinatesOf(const Vec& src) const
+{
+ if (referenceFrame())
+ return localCoordinatesOf(referenceFrame()->coordinatesOf(src));
+ else
+ return localCoordinatesOf(src);
+}
+
+/*! Returns the world coordinates of the point whose position in the Frame coordinate system is \p
+ src (converts from Frame to world).
+
+ coordinatesOf() performs the inverse convertion. Use inverseTransformOf() to transform 3D vectors
+ instead of 3D coordinates. */
+Vec Frame::inverseCoordinatesOf(const Vec& src) const
+{
+ const Frame* fr = this;
+ Vec res = src;
+ while (fr != NULL)
+ {
+ res = fr->localInverseCoordinatesOf(res);
+ fr = fr->referenceFrame();
+ }
+ return res;
+}
+
+/*! Returns the Frame coordinates of a point \p src defined in the referenceFrame() coordinate
+ system (converts from referenceFrame() to Frame).
+
+ localInverseCoordinatesOf() performs the inverse convertion. See also localTransformOf(). */
+Vec Frame::localCoordinatesOf(const Vec& src) const
+{
+ return rotation().inverseRotate(src - translation());
+}
+
+/*! Returns the referenceFrame() coordinates of a point \p src defined in the Frame coordinate
+ system (converts from Frame to referenceFrame()).
+
+ localCoordinatesOf() performs the inverse convertion. See also localInverseTransformOf(). */
+Vec Frame::localInverseCoordinatesOf(const Vec& src) const
+{
+ return rotation().rotate(src) + translation();
+}
+
+/*! Returns the Frame coordinates of the point whose position in the \p from coordinate system is \p
+ src (converts from \p from to Frame).
+
+ coordinatesOfIn() performs the inverse transformation. */
+Vec Frame::coordinatesOfFrom(const Vec& src, const Frame* const from) const
+{
+ if (this == from)
+ return src;
+ else
+ if (referenceFrame())
+ return localCoordinatesOf(referenceFrame()->coordinatesOfFrom(src, from));
+ else
+ return localCoordinatesOf(from->inverseCoordinatesOf(src));
+}
+
+/*! Returns the \p in coordinates of the point whose position in the Frame coordinate system is \p
+ src (converts from Frame to \p in).
+
+ coordinatesOfFrom() performs the inverse transformation. */
+Vec Frame::coordinatesOfIn(const Vec& src, const Frame* const in) const
+{
+ const Frame* fr = this;
+ Vec res = src;
+ while ((fr != NULL) && (fr != in))
+ {
+ res = fr->localInverseCoordinatesOf(res);
+ fr = fr->referenceFrame();
+ }
+
+ if (fr != in)
+ // in was not found in the branch of this, res is now expressed in the world
+ // coordinate system. Simply convert to in coordinate system.
+ res = in->coordinatesOf(res);
+
+ return res;
+}
+
+////// float[3] versions
+
+/*! Same as coordinatesOf(), but with \c float parameters. */
+void Frame::getCoordinatesOf(const float src[3], float res[3]) const
+{
+ const Vec r = coordinatesOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as inverseCoordinatesOf(), but with \c float parameters. */
+void Frame::getInverseCoordinatesOf(const float src[3], float res[3]) const
+{
+ const Vec r = inverseCoordinatesOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as localCoordinatesOf(), but with \c float parameters. */
+void Frame::getLocalCoordinatesOf(const float src[3], float res[3]) const
+{
+ const Vec r = localCoordinatesOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+ /*! Same as localInverseCoordinatesOf(), but with \c float parameters. */
+void Frame::getLocalInverseCoordinatesOf(const float src[3], float res[3]) const
+{
+ const Vec r = localInverseCoordinatesOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as coordinatesOfIn(), but with \c float parameters. */
+void Frame::getCoordinatesOfIn(const float src[3], float res[3], const Frame* const in) const
+{
+ const Vec r = coordinatesOfIn(Vec(src), in);
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as coordinatesOfFrom(), but with \c float parameters. */
+void Frame::getCoordinatesOfFrom(const float src[3], float res[3], const Frame* const from) const
+{
+ const Vec r = coordinatesOfFrom(Vec(src), from);
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+
+///////////////////////// FRAME TRANSFORMATIONS OF VECTORS //////////////////////////////
+
+/*! Returns the Frame transform of a vector \p src defined in the world coordinate system (converts
+ vectors from world to Frame).
+
+ inverseTransformOf() performs the inverse transformation. coordinatesOf() converts 3D coordinates
+ instead of 3D vectors (here only the rotational part of the transformation is taken into account).
+
+ See the <a href="../examples/frameTransform.html">frameTransform example</a> for an
+ illustration. */
+Vec Frame::transformOf(const Vec& src) const
+{
+ if (referenceFrame())
+ return localTransformOf(referenceFrame()->transformOf(src));
+ else
+ return localTransformOf(src);
+}
+
+/*! Returns the world transform of the vector whose coordinates in the Frame coordinate
+ system is \p src (converts vectors from Frame to world).
+
+ transformOf() performs the inverse transformation. Use inverseCoordinatesOf() to transform 3D
+ coordinates instead of 3D vectors. */
+Vec Frame::inverseTransformOf(const Vec& src) const
+{
+ const Frame* fr = this;
+ Vec res = src;
+ while (fr != NULL)
+ {
+ res = fr->localInverseTransformOf(res);
+ fr = fr->referenceFrame();
+ }
+ return res;
+}
+
+/*! Returns the Frame transform of a vector \p src defined in the referenceFrame() coordinate system
+ (converts vectors from referenceFrame() to Frame).
+
+ localInverseTransformOf() performs the inverse transformation. See also localCoordinatesOf(). */
+Vec Frame::localTransformOf(const Vec& src) const
+{
+ return rotation().inverseRotate(src);
+}
+
+/*! Returns the referenceFrame() transform of a vector \p src defined in the Frame coordinate
+ system (converts vectors from Frame to referenceFrame()).
+
+ localTransformOf() performs the inverse transformation. See also localInverseCoordinatesOf(). */
+Vec Frame::localInverseTransformOf(const Vec& src) const
+{
+ return rotation().rotate(src);
+}
+
+/*! Returns the Frame transform of the vector whose coordinates in the \p from coordinate system is \p
+ src (converts vectors from \p from to Frame).
+
+ transformOfIn() performs the inverse transformation. */
+Vec Frame::transformOfFrom(const Vec& src, const Frame* const from) const
+{
+ if (this == from)
+ return src;
+ else
+ if (referenceFrame())
+ return localTransformOf(referenceFrame()->transformOfFrom(src, from));
+ else
+ return localTransformOf(from->inverseTransformOf(src));
+}
+
+/*! Returns the \p in transform of the vector whose coordinates in the Frame coordinate system is \p
+ src (converts vectors from Frame to \p in).
+
+ transformOfFrom() performs the inverse transformation. */
+Vec Frame::transformOfIn(const Vec& src, const Frame* const in) const
+{
+ const Frame* fr = this;
+ Vec res = src;
+ while ((fr != NULL) && (fr != in))
+ {
+ res = fr->localInverseTransformOf(res);
+ fr = fr->referenceFrame();
+ }
+
+ if (fr != in)
+ // in was not found in the branch of this, res is now expressed in the world
+ // coordinate system. Simply convert to in coordinate system.
+ res = in->transformOf(res);
+
+ return res;
+}
+
+///////////////// float[3] versions //////////////////////
+
+/*! Same as transformOf(), but with \c float parameters. */
+void Frame::getTransformOf(const float src[3], float res[3]) const
+{
+ Vec r = transformOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as inverseTransformOf(), but with \c float parameters. */
+void Frame::getInverseTransformOf(const float src[3], float res[3]) const
+{
+ Vec r = inverseTransformOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as localTransformOf(), but with \c float parameters. */
+void Frame::getLocalTransformOf(const float src[3], float res[3]) const
+{
+ Vec r = localTransformOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as localInverseTransformOf(), but with \c float parameters. */
+void Frame::getLocalInverseTransformOf(const float src[3], float res[3]) const
+{
+ Vec r = localInverseTransformOf(Vec(src));
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as transformOfIn(), but with \c float parameters. */
+void Frame::getTransformOfIn(const float src[3], float res[3], const Frame* const in) const
+{
+ Vec r = transformOfIn(Vec(src), in);
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+/*! Same as transformOfFrom(), but with \c float parameters. */
+void Frame::getTransformOfFrom(const float src[3], float res[3], const Frame* const from) const
+{
+ Vec r = transformOfFrom(Vec(src), from);
+ for (int i=0; i<3 ; ++i)
+ res[i] = r[i];
+}
+
+///////////////////////////////// ALIGN /////////////////////////////////
+
+/*! Aligns the Frame with \p frame, so that two of their axis are parallel.
+
+If one of the X, Y and Z axis of the Frame is almost parallel to any of the X, Y, or Z axis of \p
+frame, the Frame is rotated so that these two axis actually become parallel.
+
+If, after this first rotation, two other axis are also almost parallel, a second alignment is
+performed. The two frames then have identical orientations, up to 90 degrees rotations.
+
+\p threshold measures how close two axis must be to be considered parallel. It is compared with the
+absolute values of the dot product of the normalized axis.
+
+When \p move is set to \c true, the Frame position() is also affected by the alignment. The new
+Frame position() is such that the \p frame position (computed with coordinatesOf(), in the Frame
+coordinates system) does not change.
+
+\p frame may be \c NULL and then represents the world coordinate system (same convention than for
+the referenceFrame()).
+
+The rotation (and translation when \p move is \c true) applied to the Frame are filtered by the
+possible constraint(). */
+void Frame::alignWithFrame(const Frame* const frame, bool move, float threshold)
+{
+ Vec directions[2][3];
+ for (int d=0; d<3; ++d)
+ {
+ Vec dir((d==0)? 1.0 : 0.0, (d==1)? 1.0 : 0.0, (d==2)? 1.0 : 0.0);
+ if (frame)
+ directions[0][d] = frame->inverseTransformOf(dir);
+ else
+ directions[0][d] = dir;
+ directions[1][d] = inverseTransformOf(dir);
+ }
+
+ float maxProj = 0.0f;
+ float proj;
+ unsigned short index[2];
+ index[0] = index[1] = 0;
+ for (int i=0; i<3; ++i)
+ for (int j=0; j<3; ++j)
+ if ( (proj=fabs(directions[0][i]*directions[1][j])) >= maxProj )
+ {
+ index[0] = i;
+ index[1] = j;
+ maxProj = proj;
+ }
+
+ Frame old;
+ old=*this;
+
+ float coef = directions[0][index[0]] * directions[1][index[1]];
+ if (fabs(coef) >= threshold)
+ {
+ const Vec axis = cross(directions[0][index[0]], directions[1][index[1]]);
+ float angle = asin(axis.norm());
+ if (coef >= 0.0)
+ angle = -angle;
+ // setOrientation(Quaternion(axis, angle) * orientation());
+ rotate(rotation().inverse() * Quaternion(axis, angle) * orientation());
+
+ // Try to align an other axis direction
+ unsigned short d = (index[1]+1) % 3;
+ Vec dir((d==0)? 1.0 : 0.0, (d==1)? 1.0 : 0.0, (d==2)? 1.0 : 0.0);
+ dir = inverseTransformOf(dir);
+
+ float max = 0.0f;
+ for (int i=0; i<3; ++i)
+ {
+ float proj = fabs(directions[0][i]*dir);
+ if (proj > max)
+ {
+ index[0] = i;
+ max = proj;
+ }
+ }
+
+ if (max >= threshold)
+ {
+ const Vec axis = cross(directions[0][index[0]], dir);
+ float angle = asin(axis.norm());
+ if (directions[0][index[0]] * dir >= 0.0)
+ angle = -angle;
+ // setOrientation(Quaternion(axis, angle) * orientation());
+ rotate(rotation().inverse() * Quaternion(axis, angle) * orientation());
+ }
+ }
+
+ if (move)
+ {
+ Vec center;
+ if (frame)
+ center = frame->position();
+
+ // setPosition(center - orientation().rotate(old.coordinatesOf(center)));
+ translate(center - orientation().rotate(old.coordinatesOf(center)) - translation());
+ }
+}
+
+/*! Translates the Frame so that its position() lies on the line defined by \p origin and \p
+ direction (defined in the world coordinate system).
+
+Simply uses an orthogonal projection. \p direction does not need to be normalized. */
+void Frame::projectOnLine(const Vec& origin, const Vec& direction)
+{
+ // If you are trying to find a bug here, because of memory problems, you waste your time.
+ // This is a bug in the gcc 3.3 compiler. Compile the library in debug mode and test.
+ // Uncommenting this line also seems to solve the problem. Horrible.
+ // cout << "position = " << position() << endl;
+ // If you found a problem or are using a different compiler, please let me know.
+ const Vec shift = origin - position();
+ Vec proj = shift;
+ proj.projectOnAxis(direction);
+ translate(shift-proj);
+}
diff --git a/source/blender/freestyle/intern/app_blender/frame.h b/source/blender/freestyle/intern/app_blender/frame.h
new file mode 100644
index 00000000000..1ff3d91f75c
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/frame.h
@@ -0,0 +1,408 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef QGLVIEWER_FRAME_H
+#define QGLVIEWER_FRAME_H
+
+#include "constraint.h"
+// #include "GL/gl.h" is now included in config.h for ease of configuration
+
+//namespace qglviewer {
+ /*! \brief The Frame class represents a coordinate system, defined by a position and an
+ orientation. \class Frame frame.h QGLViewer/frame.h
+
+ A Frame is a 3D coordinate system, represented by a position() and an orientation(). The order of
+ these transformations is important: the Frame is first translated \e and \e then rotated around
+ the new translated origin.
+
+ A Frame is useful to define the position and orientation of a 3D rigid object, using its matrix()
+ method, as shown below:
+ \code
+ // Builds a Frame at position (0.5,0,0) and oriented such that its Y axis is along the (1,1,1)
+ // direction. One could also have used setPosition() and setOrientation().
+ Frame fr(Vec(0.5,0,0), Quaternion(Vec(0,1,0), Vec(1,1,1)));
+ glPushMatrix();
+ glMultMatrixd(fr.matrix());
+ // Draw your object here, in the local fr coordinate system.
+ glPopMatrix();
+ \endcode
+
+ Many functions are provided to transform a 3D point from one coordinate system (Frame) to an
+ other: see coordinatesOf(), inverseCoordinatesOf(), coordinatesOfIn(), coordinatesOfFrom()...
+
+ You may also want to transform a 3D vector (such as a normal), which corresponds to applying only
+ the rotational part of the frame transformation: see transformOf() and inverseTransformOf(). See
+ the <a href="../examples/frameTransform.html">frameTransform example</a> for an illustration.
+
+ The translation() and the rotation() that are encapsulated in a Frame can also be used to
+ represent a \e rigid \e transformation of space. Such a transformation can also be interpreted as
+ a change of coordinate system, and the coordinate system conversion functions actually allow you
+ to use a Frame as a rigid transformation. Use inverseCoordinatesOf() (resp. coordinatesOf()) to
+ apply the transformation (resp. its inverse). Note the inversion.
+
+ <h3>Hierarchy of Frames</h3>
+
+ The position and the orientation of a Frame are actually defined with respect to a
+ referenceFrame(). The default referenceFrame() is the world coordinate system (represented by a \c
+ NULL referenceFrame()). If you setReferenceFrame() to a different Frame, you must then
+ differentiate:
+
+ \arg the \e local translation() and rotation(), defined with respect to the referenceFrame(),
+
+ \arg the \e global position() and orientation(), always defined with respect to the world
+ coordinate system.
+
+ A Frame is actually defined by its translation() with respect to its referenceFrame(), and then by
+ a rotation() of the coordinate system around the new translated origin.
+
+ This terminology for \e local (translation() and rotation()) and \e global (position() and
+ orientation()) definitions is used in all the methods' names and should be sufficient to prevent
+ ambiguities. These notions are obviously identical when the referenceFrame() is \c NULL, i.e. when
+ the Frame is defined in the world coordinate system (the one you are in at the beginning of the
+ QGLViewer::draw() method, see the <a href="../introduction.html">introduction page</a>).
+
+ Frames can hence easily be organized in a tree hierarchy, which root is the world coordinate
+ system. A loop in the hierarchy would result in an inconsistent (multiple) Frame definition.
+ settingAsReferenceFrameWillCreateALoop() checks this and prevents setReferenceFrame() from
+ creating such a loop.
+
+ This frame hierarchy is used in methods like coordinatesOfIn(), coordinatesOfFrom()... which allow
+ coordinates (or vector) conversions from a Frame to any other one (including the world coordinate
+ system).
+
+ However, one must note that this hierarchical representation is internal to the Frame classes.
+ When the Frames represent OpenGL coordinates system, one should map this hierarchical
+ representation to the OpenGL GL_MODELVIEW matrix stack. See the matrix() documentation for
+ details.
+
+ <h3>Constraints</h3>
+
+ An interesting feature of Frames is that their displacements can be constrained. When a Constraint
+ is attached to a Frame, it filters the input of translate() and rotate(), and only the resulting
+ filtered motion is applied to the Frame. The default constraint() is \c NULL resulting in no
+ filtering. Use setConstraint() to attach a Constraint to a frame.
+
+ Constraints are especially usefull for the ManipulatedFrame instances, in order to forbid some
+ mouse motions. See the <a href="../examples/constrainedFrame.html">constrainedFrame</a>, <a
+ href="../examples/constrainedCamera.html">constrainedCamera</a> and <a
+ href="../examples/luxo.html">luxo</a> examples for an illustration.
+
+ Classical constraints are provided for convenience (see LocalConstraint, WorldConstraint and
+ CameraConstraint) and new constraints can very easily be implemented.
+
+ <h3>Derived classes</h3>
+
+ The ManipulatedFrame class inherits Frame and implements a mouse motion convertion, so that a
+ Frame (and hence an object) can be manipulated in the scene with the mouse.
+
+ \nosubgrouping */
+ class Frame
+ {
+
+ public:
+ Frame();
+
+ /*! Virtual destructor. Empty. */
+ virtual ~Frame() {};
+
+ Frame(const Frame& frame);
+ Frame& operator=(const Frame& frame);
+
+ /*! This signal is emitted whenever the position() or the orientation() of the Frame is modified.
+
+ Connect this signal to any object that must be notified:
+ \code
+ QObject::connect(myFrame, SIGNAL(modified()), myObject, SLOT(update()));
+ \endcode
+ Use the QGLViewer::QGLViewerPool() to connect the signal to all the viewers.
+
+ \note If your Frame is part of a Frame hierarchy (see referenceFrame()), a modification of one
+ of the parents of this Frame will \e not emit this signal. Use code like this to change this
+ behavior (you can do this recursively for all the referenceFrame() until the \c NULL world root
+ frame is encountered):
+ \code
+ // Emits the Frame modified() signal when its referenceFrame() is modified().
+ connect(myFrame->referenceFrame(), SIGNAL(modified()), myFrame, SIGNAL(modified()));
+ \endcode
+
+ \attention Connecting this signal to a QGLWidget::updateGL() slot (or a method that calls it)
+ will prevent you from modifying the Frame \e inside your QGLViewer::draw() method as it would
+ result in an infinite loop. However, QGLViewer::draw() should not modify the scene.
+
+ \note For efficiency reasons, this signal is emitted even if the Frame is not actually modified, for
+ instance with translate(Vec(0,0,0)) or setPosition(position()). */
+ void modified();
+
+ /*! This signal is emitted when the Frame is interpolated by a KeyFrameInterpolator.
+
+ See the KeyFrameInterpolator documentation for details.
+
+ If a KeyFrameInterpolator is used to successively interpolate several Frames in your scene,
+ connect the KeyFrameInterpolator::interpolated() signal instead (identical, but independent of
+ the interpolated Frame). */
+ void interpolated();
+
+ public:
+ /*! @name World coordinates position and orientation */
+ //@{
+ Frame(const Vec& position, const Quaternion& orientation);
+
+ void setPosition(const Vec& position);
+ void setPosition(float x, float y, float z);
+ void setPositionWithConstraint(Vec& position);
+
+ void setOrientation(const Quaternion& orientation);
+ void setOrientation(double q0, double q1, double q2, double q3);
+ void setOrientationWithConstraint(Quaternion& orientation);
+
+ void setPositionAndOrientation(const Vec& position, const Quaternion& orientation);
+ void setPositionAndOrientationWithConstraint(Vec& position, Quaternion& orientation);
+
+ /*! Returns the position of the Frame, defined in the world coordinate system. See also
+ orientation(), setPosition() and translation(). */
+ Vec position() const { return inverseCoordinatesOf(Vec(0.0,0.0,0.0)); };
+ Quaternion orientation() const;
+
+ void getPosition(float& x, float& y, float& z) const;
+ void getOrientation(double& q0, double& q1, double& q2, double& q3) const;
+ //@}
+
+
+ public:
+ /*! @name Local translation and rotation w/r reference Frame */
+ //@{
+ /*! Sets the translation() of the frame, locally defined with respect to the referenceFrame().
+ Emits the modified() signal.
+
+ Use setPosition() to define the world coordinates position(). Use
+ setTranslationWithConstraint() to take into account the potential constraint() of the Frame. */
+ void setTranslation(const Vec& translation) { t_ = translation; };
+ void setTranslation(float x, float y, float z);
+ void setTranslationWithConstraint(Vec& translation);
+
+ /*! Set the current rotation Quaternion. See rotation() and the different Quaternion
+ constructors. Emits the modified() signal. See also setTranslation() and
+ setRotationWithConstraint(). */
+
+ /*! Sets the rotation() of the Frame, locally defined with respect to the referenceFrame().
+ Emits the modified() signal.
+
+ Use setOrientation() to define the world coordinates orientation(). The potential
+ constraint() of the Frame is not taken into account, use setRotationWithConstraint()
+ instead. */
+ void setRotation(const Quaternion& rotation) { q_ = rotation; };
+ void setRotation(double q0, double q1, double q2, double q3);
+ void setRotationWithConstraint(Quaternion& rotation);
+
+ void setTranslationAndRotation(const Vec& translation, const Quaternion& rotation);
+ void setTranslationAndRotationWithConstraint(Vec& translation, Quaternion& rotation);
+
+ /*! Returns the Frame translation, defined with respect to the referenceFrame().
+
+ Use position() to get the result in the world coordinates. These two values are identical
+ when the referenceFrame() is \c NULL (default).
+
+ See also setTranslation() and setTranslationWithConstraint(). */
+ Vec translation() const { return t_; };
+ /*! Returns the Frame rotation, defined with respect to the referenceFrame().
+
+ Use orientation() to get the result in the world coordinates. These two values are identical
+ when the referenceFrame() is \c NULL (default).
+
+ See also setRotation() and setRotationWithConstraint(). */
+
+ /*! Returns the current Quaternion orientation. See setRotation(). */
+ Quaternion rotation() const { return q_; };
+
+ void getTranslation(float& x, float& y, float& z) const;
+ void getRotation(double& q0, double& q1, double& q2, double& q3) const;
+ //@}
+
+ public:
+ /*! @name Frame hierarchy */
+ //@{
+ /*! Returns the reference Frame, in which coordinates system the Frame is defined.
+
+ The translation() and rotation() of the Frame are defined with respect to the referenceFrame()
+ coordinate system. A \c NULL referenceFrame() (default value) means that the Frame is defined in
+ the world coordinate system.
+
+ Use position() and orientation() to recursively convert values along the referenceFrame() chain
+ and to get values expressed in the world coordinate system. The values match when the
+ referenceFrame() is \c NULL.
+
+ Use setReferenceFrame() to set this value and create a Frame hierarchy. Convenient functions
+ allow you to convert 3D coordinates from one Frame to an other: see coordinatesOf(),
+ localCoordinatesOf(), coordinatesOfIn() and their inverse functions.
+
+ Vectors can also be converted using transformOf(), transformOfIn, localTransformOf() and their
+ inverse functions. */
+ const Frame* referenceFrame() const { return referenceFrame_; };
+ void setReferenceFrame(const Frame* const refFrame);
+ bool settingAsReferenceFrameWillCreateALoop(const Frame* const frame);
+ //@}
+
+
+ /*! @name Frame modification */
+ //@{
+ void translate(Vec& t);
+ void translate(const Vec& t);
+ // Some compilers complain about "overloading cannot distinguish from previous declaration"
+ // Simply comment out the following method and its associated implementation
+ void translate(float x, float y, float z);
+ void translate(float& x, float& y, float& z);
+
+ void rotate(Quaternion& q);
+ void rotate(const Quaternion& q);
+ // Some compilers complain about "overloading cannot distinguish from previous declaration"
+ // Simply comment out the following method and its associated implementation
+ void rotate(double q0, double q1, double q2, double q3);
+ void rotate(double& q0, double& q1, double& q2, double& q3);
+
+ void rotateAroundPoint(Quaternion& rotation, const Vec& point);
+ void rotateAroundPoint(const Quaternion& rotation, const Vec& point);
+
+ void alignWithFrame(const Frame* const frame, bool move=false, float threshold=0.85f);
+ void projectOnLine(const Vec& origin, const Vec& direction);
+ //@}
+
+
+ /*! @name Coordinate system transformation of 3D coordinates */
+ //@{
+ Vec coordinatesOf(const Vec& src) const;
+ Vec inverseCoordinatesOf(const Vec& src) const;
+ Vec localCoordinatesOf(const Vec& src) const;
+ Vec localInverseCoordinatesOf(const Vec& src) const;
+ Vec coordinatesOfIn(const Vec& src, const Frame* const in) const;
+ Vec coordinatesOfFrom(const Vec& src, const Frame* const from) const;
+
+ void getCoordinatesOf(const float src[3], float res[3]) const;
+ void getInverseCoordinatesOf(const float src[3], float res[3]) const;
+ void getLocalCoordinatesOf(const float src[3], float res[3]) const;
+ void getLocalInverseCoordinatesOf(const float src[3], float res[3]) const;
+ void getCoordinatesOfIn(const float src[3], float res[3], const Frame* const in) const;
+ void getCoordinatesOfFrom(const float src[3], float res[3], const Frame* const from) const;
+ //@}
+
+ /*! @name Coordinate system transformation of vectors */
+ // A frame is as a new coordinate system, defined with respect to a reference frame (the world
+ // coordinate system by default, see the "Composition of frame" section).
+
+ // The transformOf() (resp. inverseTransformOf()) functions transform a 3D vector from (resp.
+ // to) the world coordinates system. This section defines the 3D vector transformation
+ // functions. See the Coordinate system transformation of 3D points above for the transformation
+ // of 3D points. The difference between the two sets of functions is simple: for vectors, only
+ // the rotational part of the transformations is taken into account, while translation is also
+ // considered for 3D points.
+
+ // The length of the resulting transformed vector is identical to the one of the source vector
+ // for all the described functions.
+
+ // When local is prepended to the names of the functions, the functions simply transform from
+ // (and to) the reference frame.
+
+ // When In (resp. From) is appended to the names, the functions transform from (resp. To) the
+ // frame that is given as an argument. The frame does not need to be in the same branch or the
+ // hierarchical tree, and can be \c NULL (the world coordinates system).
+
+ // Combining any of these functions with its inverse (in any order) leads to the identity.
+ //@{
+ Vec transformOf(const Vec& src) const;
+ Vec inverseTransformOf(const Vec& src) const;
+ Vec localTransformOf(const Vec& src) const;
+ Vec localInverseTransformOf(const Vec& src) const;
+ Vec transformOfIn(const Vec& src, const Frame* const in) const;
+ Vec transformOfFrom(const Vec& src, const Frame* const from) const;
+
+ void getTransformOf(const float src[3], float res[3]) const;
+ void getInverseTransformOf(const float src[3], float res[3]) const;
+ void getLocalTransformOf(const float src[3], float res[3]) const;
+ void getLocalInverseTransformOf(const float src[3], float res[3]) const;
+ void getTransformOfIn(const float src[3], float res[3], const Frame* const in) const;
+ void getTransformOfFrom(const float src[3], float res[3], const Frame* const from) const;
+ //@}
+
+
+ /*! @name Constraint on the displacement */
+ //@{
+ /*! Returns the current constraint applied to the Frame.
+
+ A \c NULL value (default) means that no Constraint is used to filter Frame translation and
+ rotation. See the Constraint class documentation for details.
+
+ You may have to use a \c dynamic_cast to convert the result to a Constraint derived class. */
+ Constraint* constraint() const { return constraint_; }
+ /*! Sets the constraint() attached to the Frame.
+
+ A \c NULL value means no constraint. The previous constraint() should be deleted by the calling
+ method if needed. */
+ void setConstraint(Constraint* const constraint) { constraint_ = constraint; }
+ //@}
+
+ /*! @name Associated matrices */
+ //@{
+ public:
+ const GLdouble* matrix() const;
+ void getMatrix(GLdouble m[4][4]) const;
+ void getMatrix(GLdouble m[16]) const;
+
+ const GLdouble* worldMatrix() const;
+ void getWorldMatrix(GLdouble m[4][4]) const;
+ void getWorldMatrix(GLdouble m[16]) const;
+
+ void setFromMatrix(const GLdouble m[4][4]);
+ void setFromMatrix(const GLdouble m[16]);
+ //@}
+
+ /*! @name Inversion of the transformation */
+ //@{
+ Frame inverse() const;
+ /*! Returns the inverse() of the Frame world transformation.
+
+ The orientation() of the new Frame is the Quaternion::inverse() of the original orientation.
+ Its position() is the negated and inverse rotated image of the original position.
+
+ The result Frame has a \c NULL referenceFrame() and a \c NULL constraint().
+
+ Use inverse() for a local (i.e. with respect to referenceFrame()) transformation inverse. */
+ Frame worldInverse() const { return Frame(-(orientation().inverseRotate(position())), orientation().inverse()); }
+ //@}
+
+
+ private:
+ // P o s i t i o n a n d o r i e n t a t i o n
+ Vec t_;
+ Quaternion q_;
+
+ // C o n s t r a i n t s
+ Constraint* constraint_;
+
+ // F r a m e c o m p o s i t i o n
+ const Frame* referenceFrame_;
+ };
+
+//} // namespace qglviewer
+
+#endif // QGLVIEWER_FRAME_H
diff --git a/source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.cpp b/source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.cpp
new file mode 100644
index 00000000000..c4e2e67b26a
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "manipulatedCameraFrame.h"
+#include "camera.h"
+//#include "qglviewer.h"
+
+// #if QT_VERSION >= 0x040000
+// # include <QMouseEvent>
+// #endif
+//
+// using namespace qglviewer;
+using namespace std;
+
+/*! Default constructor.
+
+ flySpeed() is set to 0.0 and flyUpVector() is (0,1,0). The revolveAroundPoint() is set to (0,0,0).
+
+ \attention Created object is removeFromMouseGrabberPool(). */
+ManipulatedCameraFrame::ManipulatedCameraFrame()
+ : driveSpeed_(0.0), flyUpVector_(0.0, 1.0, 0.0)
+{
+ setFlySpeed(0.0);
+ //removeFromMouseGrabberPool();
+
+ //connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate()));
+}
+
+/*! Equal operator. Calls ManipulatedFrame::operator=() and then copy attributes. */
+ManipulatedCameraFrame& ManipulatedCameraFrame::operator=(const ManipulatedCameraFrame& mcf)
+{
+ ManipulatedFrame::operator=(mcf);
+
+ setFlySpeed(mcf.flySpeed());
+ setFlyUpVector(mcf.flyUpVector());
+
+ return *this;
+}
+
+/*! Copy constructor. Performs a deep copy of all members using operator=(). */
+ManipulatedCameraFrame::ManipulatedCameraFrame(const ManipulatedCameraFrame& mcf)
+ : ManipulatedFrame(mcf)
+{
+ //removeFromMouseGrabberPool();
+ (*this)=(mcf);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/*! Returns a Quaternion that is a rotation around current camera Y, proportionnal to the horizontal mouse position. */
+Quaternion ManipulatedCameraFrame::turnQuaternion(int x, const Camera* const camera)
+{
+ return Quaternion(Vec(0.0, 1.0, 0.0), rotationSensitivity()*(prevPos_.x()-x)/camera->screenWidth());
+}
+
+/*! Returns a Quaternion that is the composition of two rotations, inferred from the
+ mouse pitch (X axis) and yaw (flyUpVector() axis). */
+Quaternion ManipulatedCameraFrame::pitchYawQuaternion(int x, int y, const Camera* const camera)
+{
+ const Quaternion rotX(Vec(1.0, 0.0, 0.0), rotationSensitivity()*(prevPos_.y()-y)/camera->screenHeight());
+ const Quaternion rotY(transformOf(flyUpVector()), rotationSensitivity()*(prevPos_.x()-x)/camera->screenWidth());
+ return rotY * rotX;
+}
diff --git a/source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.h b/source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.h
new file mode 100644
index 00000000000..3c28edab622
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/manipulatedCameraFrame.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef QGLVIEWER_MANIPULATED_CAMERA_FRAME_H
+#define QGLVIEWER_MANIPULATED_CAMERA_FRAME_H
+
+#include "manipulatedFrame.h"
+
+//namespace qglviewer {
+ /*! \brief The ManipulatedCameraFrame class represents a ManipulatedFrame with Camera specific mouse bindings.
+ \class ManipulatedCameraFrame manipulatedCameraFrame.h QGLViewer/manipulatedCameraFrame.h
+
+ A ManipulatedCameraFrame is a specialization of a ManipulatedFrame, designed to be set as the
+ Camera::frame(). Mouse motions are basically interpreted in a negated way: when the mouse goes to
+ the right, the ManipulatedFrame translation goes to the right, while the ManipulatedCameraFrame
+ has to go to the \e left, so that the \e scene seems to move to the right.
+
+ A ManipulatedCameraFrame rotates around its revolveAroundPoint(), which corresponds to the
+ associated Camera::revolveAroundPoint().
+
+ A ManipulatedCameraFrame can also "fly" in the scene. It basically moves forward, and turns
+ according to the mouse motion. See flySpeed(), flyUpVector() and the QGLViewer::MOVE_FORWARD and
+ QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction.
+
+ See the <a href="../mouse.html">mouse page</a> for a description of the possible actions that can
+ be performed using the mouse and their bindings.
+ \nosubgrouping */
+ class ManipulatedCameraFrame : public ManipulatedFrame
+ {
+#ifndef DOXYGEN
+ friend class Camera;
+ //friend class ::QGLViewer;
+#endif
+
+ //Q_OBJECT
+
+ public:
+ ManipulatedCameraFrame();
+ /*! Virtual destructor. Empty. */
+ virtual ~ManipulatedCameraFrame() {};
+
+ ManipulatedCameraFrame(const ManipulatedCameraFrame& mcf);
+ ManipulatedCameraFrame& operator=(const ManipulatedCameraFrame& mcf);
+
+ /*! @name Revolve around point */
+ //@{
+ public:
+ /*! Returns the point the ManipulatedCameraFrame revolves around when rotated.
+
+ It is defined in the world coordinate system. Default value is (0,0,0).
+
+ When the ManipulatedCameraFrame is associated to a Camera, Camera::revolveAroundPoint() also
+ returns this value. This point can interactively be changed using the mouse (see
+ QGLViewer::RAP_FROM_PIXEL and QGLViewer::RAP_IS_CENTER in the <a href="../mouse.html">mouse
+ page</a>). */
+ Vec revolveAroundPoint() const { return revolveAroundPoint_; }
+ /*! Sets the revolveAroundPoint(), defined in the world coordinate system. */
+ void setRevolveAroundPoint(const Vec& revolveAroundPoint) { revolveAroundPoint_ = revolveAroundPoint; }
+ //@}
+
+ /*! @name Fly parameters */
+ //@{
+ public: //slots:
+ /*! Sets the flySpeed(), defined in OpenGL units.
+
+ Default value is 0.0, but it is modified according to the QGLViewer::sceneRadius() when the
+ ManipulatedCameraFrame is set as the Camera::frame(). */
+ void setFlySpeed(float speed) { flySpeed_ = speed; };
+
+ /*! Sets the flyUpVector(), defined in the world coordinate system.
+
+ Default value is (0,1,0), but it is updated by the Camera when set as its Camera::frame(). Use
+ Camera::setUpVector() instead in that case. */
+ void setFlyUpVector(const Vec& up) { flyUpVector_ = up; };
+
+ public:
+ /*! Returns the fly speed, expressed in OpenGL units.
+
+ It corresponds to the incremental displacement that is periodically applied to the
+ ManipulatedCameraFrame position when a QGLViewer::MOVE_FORWARD or QGLViewer::MOVE_BACKWARD
+ QGLViewer::MouseAction is proceeded.
+
+ \attention When the ManipulatedCameraFrame is set as the Camera::frame(), this value is set
+ according to the QGLViewer::sceneRadius() by QGLViewer::setSceneRadius(). */
+ float flySpeed() const { return flySpeed_; };
+
+ /*! Returns the up vector used in fly mode, expressed in the world coordinate system.
+
+ Fly mode corresponds to the QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD
+ QGLViewer::MouseAction bindings. In these modes, horizontal displacements of the mouse rotate
+ the ManipulatedCameraFrame around this vector. Vertical displacements rotate always around the
+ Camera \c X axis.
+
+ Default value is (0,1,0), but it is updated by the Camera when set as its Camera::frame().
+ Camera::setOrientation() and Camera::setUpVector()) modify this value and should be used
+ instead. */
+ Vec flyUpVector() const { return flyUpVector_; };
+ //@}
+
+ /*! @name Mouse event handlers */
+ //@{
+ // protected:
+ // virtual void mouseReleaseEvent(QMouseEvent* const event, Camera* const camera);
+ // virtual void mouseMoveEvent (QMouseEvent* const event, Camera* const camera);
+ // virtual void wheelEvent (QWheelEvent* const event, Camera* const camera);
+ // //@}
+
+ /*! @name Spinning */
+ //@{
+ // protected slots:
+ // virtual void spin();
+ //@}
+
+ /*! @name XML representation */
+ //@{
+ // public:
+ // virtual QDomElement domElement(const QString& name, QDomDocument& document) const;
+ // public slots:
+ // virtual void initFromDOMElement(const QDomElement& element);
+ // //@}
+
+// #ifndef DOXYGEN
+// protected:
+// virtual void startAction(int ma, bool withConstraint=true); // int is really a QGLViewer::MouseAction
+// #endif
+
+ private: //slots:
+ //virtual void flyUpdate();
+
+ private:
+ void updateFlyUpVector();
+ Quaternion turnQuaternion(int x, const Camera* const camera);
+ Quaternion pitchYawQuaternion(int x, int y, const Camera* const camera);
+
+ private:
+ // Fly mode data
+ float flySpeed_;
+ float driveSpeed_;
+ Vec flyUpVector_;
+ //QTimer flyTimer_;
+
+ Vec revolveAroundPoint_;
+ };
+
+//} // namespace qglviewer
+
+#endif // QGLVIEWER_MANIPULATED_CAMERA_FRAME_H
diff --git a/source/blender/freestyle/intern/app_blender/manipulatedFrame.cpp b/source/blender/freestyle/intern/app_blender/manipulatedFrame.cpp
new file mode 100644
index 00000000000..6721204383d
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/manipulatedFrame.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "manipulatedFrame.h"
+//#include "qglviewer.h"
+#include "camera.h"
+
+//using namespace qglviewer;
+using namespace std;
+
+/*! Default constructor.
+
+ The translation is set to (0,0,0), with an identity rotation (0,0,0,1) (see Frame constructor
+ for details).
+
+ The different sensitivities are set to their default values (see rotationSensitivity(),
+ translationSensitivity(), spinningSensitivity() and wheelSensitivity()). */
+ManipulatedFrame::ManipulatedFrame()
+{
+ // #CONNECTION# initFromDOMElement and accessor docs
+ setRotationSensitivity(1.0f);
+ setTranslationSensitivity(1.0f);
+ setSpinningSensitivity(0.3f);
+ setWheelSensitivity(1.0f);
+
+ isSpinning_ = false;
+ previousConstraint_ = false;
+
+ //connect(&spinningTimer_, SIGNAL(timeout()), SLOT(spinUpdate()));
+}
+
+/*! Equal operator. Calls Frame::operator=() and then copy attributes. */
+ManipulatedFrame& ManipulatedFrame::operator=(const ManipulatedFrame& mf)
+{
+ Frame::operator=(mf);
+
+ setRotationSensitivity(mf.rotationSensitivity());
+ setTranslationSensitivity(mf.translationSensitivity());
+ setSpinningSensitivity(mf.spinningSensitivity());
+ setWheelSensitivity(mf.wheelSensitivity());
+
+ mouseSpeed_ = 0.0;
+ dirIsFixed_ = false;
+ keepsGrabbingMouse_ = false;
+
+ return *this;
+}
+
+/*! Copy constructor. Performs a deep copy of all attributes using operator=(). */
+ManipulatedFrame::ManipulatedFrame(const ManipulatedFrame& mf)
+ : Frame(mf)
+{
+ (*this)=mf;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/*! Returns "pseudo-distance" from (x,y) to ball of radius size.
+\arg for a point inside the ball, it is proportional to the euclidean distance to the ball
+\arg for a point outside the ball, it is proportional to the inverse of this distance (tends to
+zero) on the ball, the function is continuous. */
+static float projectOnBall(float x, float y)
+{
+ // If you change the size value, change angle computation in deformedBallQuaternion().
+ const float size = 1.0f;
+ const float size2 = size*size;
+ const float size_limit = size2*0.5;
+
+ const float d = x*x + y*y;
+ return d < size_limit ? sqrt(size2 - d) : size_limit/sqrt(d);
+}
+
+#ifndef DOXYGEN
+/*! Returns a quaternion computed according to the mouse motion. Mouse positions are projected on a
+deformed ball, centered on (\p cx,\p cy). */
+Quaternion ManipulatedFrame::deformedBallQuaternion(int x, int y, float cx, float cy, const Camera* const camera)
+{
+ // Points on the deformed ball
+ float px = rotationSensitivity() * (prevPos_.x() - cx) / camera->screenWidth();
+ float py = rotationSensitivity() * (cy - prevPos_.y()) / camera->screenHeight();
+ float dx = rotationSensitivity() * (x - cx) / camera->screenWidth();
+ float dy = rotationSensitivity() * (cy - y) / camera->screenHeight();
+
+ const Vec p1(px, py, projectOnBall(px, py));
+ const Vec p2(dx, dy, projectOnBall(dx, dy));
+ // Approximation of rotation angle
+ // Should be divided by the projectOnBall size, but it is 1.0
+ const Vec axis = cross(p2,p1);
+ const float angle = 2.0 * asin(sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm()));
+ return Quaternion(axis, angle);
+}
+#endif // DOXYGEN
diff --git a/source/blender/freestyle/intern/app_blender/manipulatedFrame.h b/source/blender/freestyle/intern/app_blender/manipulatedFrame.h
new file mode 100644
index 00000000000..8ad815f0a63
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/manipulatedFrame.h
@@ -0,0 +1,256 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef QGLVIEWER_MANIPULATED_FRAME_H
+#define QGLVIEWER_MANIPULATED_FRAME_H
+
+#include "frame.h"
+
+//namespace qglviewer {
+ /*! \brief A ManipulatedFrame is a Frame that can be rotated and translated using the mouse.
+ \class ManipulatedFrame manipulatedFrame.h QGLViewer/manipulatedFrame.h
+
+ It converts the mouse motion into a translation and an orientation updates. A ManipulatedFrame is
+ used to move an object in the scene. Combined with object selection, its MouseGrabber properties
+ and a dynamic update of the scene, the ManipulatedFrame introduces a great reactivity in your
+ applications.
+
+ A ManipulatedFrame is attached to a QGLViewer using QGLViewer::setManipulatedFrame():
+ \code
+ init() { setManipulatedFrame( new ManipulatedFrame() ); }
+
+ draw()
+ {
+ glPushMatrix();
+ glMultMatrixd(manipulatedFrame()->matrix());
+ // draw the manipulated object here
+ glPopMatrix();
+ }
+ \endcode
+ See the <a href="../examples/manipulatedFrame.html">manipulatedFrame example</a> for a complete
+ application.
+
+ Mouse events are normally sent to the QGLViewer::camera(). You have to press the QGLViewer::FRAME
+ state key (default is \c Control) to move the QGLViewer::manipulatedFrame() instead. See the <a
+ href="../mouse.html">mouse page</a> for a description of mouse button bindings.
+
+ <h3>Inherited functionalities</h3>
+
+ A ManipulatedFrame is an overloaded instance of a Frame. The powerful coordinate system
+ transformation functions (Frame::coordinatesOf(), Frame::transformOf(), ...) can hence be applied
+ to a ManipulatedFrame.
+
+ A ManipulatedFrame is also a MouseGrabber. If the mouse cursor gets within a distance of 10 pixels
+ from the projected position of the ManipulatedFrame, the ManipulatedFrame becomes the new
+ QGLViewer::mouseGrabber(). It can then be manipulated directly, without any specific state key,
+ object selection or GUI intervention. This is very convenient to directly move some objects in the
+ scene (typically a light). See the <a href="../examples/mouseGrabber.html">mouseGrabber
+ example</a> as an illustration. Note that QWidget::setMouseTracking() needs to be enabled in order
+ to use this feature (see the MouseGrabber documentation).
+
+ <h3>Advanced functionalities</h3>
+
+ A QGLViewer can handle at most one ManipulatedFrame at a time. If you want to move several objects
+ in the scene, you simply have to keep a list of the different ManipulatedFrames, and to activate
+ the right one (using QGLViewer::setManipulatedFrame()) when needed. This can for instance be done
+ according to an object selection: see the <a href="../examples/luxo.html">luxo example</a> for an
+ illustration.
+
+ When the ManipulatedFrame is being manipulated using the mouse (mouse pressed and not yet
+ released), isManipulated() returns \c true. This might be used to trigger a specific action or
+ display (as is done with QGLViewer::fastDraw()).
+
+ The ManipulatedFrame also emits a manipulated() signal each time its state is modified by the
+ mouse. This signal is automatically connected to the QGLViewer::updateGL() slot when the
+ ManipulatedFrame is attached to a viewer using QGLViewer::setManipulatedFrame().
+
+ You can make the ManipulatedFrame spin() if you release the rotation mouse button while moving the
+ mouse fast enough (see spinningSensitivity()). See also translationSensitivity() and
+ rotationSensitivity() for sensitivity tuning. \nosubgrouping */
+ class ManipulatedFrame : public Frame
+ {
+
+ public:
+ ManipulatedFrame();
+ /*! Virtual destructor. Empty. */
+ virtual ~ManipulatedFrame() {};
+
+ ManipulatedFrame(const ManipulatedFrame& mf);
+ ManipulatedFrame& operator=(const ManipulatedFrame& mf);
+
+ /*! This signal is emitted when ever the ManipulatedFrame is manipulated (i.e. rotated or
+ translated) using the mouse. Connect this signal to any object that should be notified.
+
+ Note that this signal is automatically connected to the QGLViewer::updateGL() slot, when the
+ ManipulatedFrame is attached to a viewer using QGLViewer::setManipulatedFrame(), which is
+ probably all you need.
+
+ Use the QGLViewer::QGLViewerPool() if you need to connect this signal to all the viewers.
+
+ See also the spun(), modified(), interpolated() and KeyFrameInterpolator::interpolated()
+ signals' documentations. */
+ void manipulated();
+
+ /*! This signal is emitted when the ManipulatedFrame isSpinning().
+
+ Note that for the QGLViewer::manipulatedFrame(), this signal is automatically connected to the
+ QGLViewer::updateGL() slot.
+
+ Connect this signal to any object that should be notified. Use the QGLViewer::QGLViewerPool() if
+ you need to connect this signal to all the viewers.
+
+ See also the manipulated(), modified(), interpolated() and KeyFrameInterpolator::interpolated()
+ signals' documentations. */
+ void spun();
+
+ /*! @name Manipulation sensitivity */
+ //@{
+ public:
+ /*! Defines the rotationSensitivity(). */
+ void setRotationSensitivity(float sensitivity) { rotSensitivity_ = sensitivity; };
+ /*! Defines the translationSensitivity(). */
+ void setTranslationSensitivity(float sensitivity) { transSensitivity_ = sensitivity; };
+ /*! Defines the spinningSensitivity(), in pixels per milliseconds. */
+ void setSpinningSensitivity(float sensitivity) { spinningSensitivity_ = sensitivity; };
+ /*! Defines the wheelSensitivity(). */
+ void setWheelSensitivity(float sensitivity) { wheelSensitivity_ = sensitivity; };
+ public:
+ /*! Returns the influence of a mouse displacement on the ManipulatedFrame rotation.
+
+ Default value is 1.0. With an identical mouse displacement, a higher value will generate a
+ larger rotation (and inversely for lower values). A 0.0 value will forbid ManipulatedFrame mouse
+ rotation (see also constraint()).
+
+ See also setRotationSensitivity(), translationSensitivity(), spinningSensitivity() and
+ wheelSensitivity(). */
+ float rotationSensitivity() const { return rotSensitivity_; };
+ /*! Returns the influence of a mouse displacement on the ManipulatedFrame translation.
+
+ Default value is 1.0. You should not have to modify this value, since with 1.0 the
+ ManipulatedFrame precisely stays under the mouse cursor.
+
+ With an identical mouse displacement, a higher value will generate a larger translation (and
+ inversely for lower values). A 0.0 value will forbid ManipulatedFrame mouse translation (see
+ also constraint()).
+
+ \note When the ManipulatedFrame is used to move a \e Camera (see the ManipulatedCameraFrame
+ class documentation), after zooming on a small region of your scene, the camera may translate
+ too fast. For a camera, it is the Camera::revolveAroundPoint() that exactly matches the mouse
+ displacement. Hence, instead of changing the translationSensitivity(), solve the problem by
+ (temporarily) setting the Camera::revolveAroundPoint() to a point on the zoomed region (see the
+ QGLViewer::RAP_FROM_PIXEL mouse binding in the <a href="../mouse.html">mouse page</a>).
+
+ See also setTranslationSensitivity(), rotationSensitivity(), spinningSensitivity() and
+ wheelSensitivity(). */
+ float translationSensitivity() const { return transSensitivity_; };
+ /*! Returns the minimum mouse speed required (at button release) to make the ManipulatedFrame
+ spin().
+
+ See spin(), spinningQuaternion() and startSpinning() for details.
+
+ Mouse speed is expressed in pixels per milliseconds. Default value is 0.3 (300 pixels per
+ second). Use setSpinningSensitivity() to tune this value. A higher value will make spinning more
+ difficult (a value of 100.0 forbids spinning in practice).
+
+ See also setSpinningSensitivity(), translationSensitivity(), rotationSensitivity() and
+ wheelSensitivity(). */
+ float spinningSensitivity() const { return spinningSensitivity_; };
+ /*! Returns the mouse wheel sensitivity.
+
+ Default value is 1.0. A higher value will make the wheel action more efficient (usually meaning
+ a faster zoom). Use a negative value to invert the zoom in and out directions.
+
+ See also setWheelSensitivity(), translationSensitivity(), rotationSensitivity() and
+ spinningSensitivity(). */
+ float wheelSensitivity() const { return wheelSensitivity_; };
+ //@}
+
+
+ /*! @name Spinning */
+ //@{
+ public:
+ /*! Returns \c true when the ManipulatedFrame is spinning.
+
+ During spinning, spin() rotates the ManipulatedFrame by its spinningQuaternion() at a frequency
+ defined when the ManipulatedFrame startSpinning().
+
+ Use startSpinning() and stopSpinning() to change this state. Default value is \c false. */
+ bool isSpinning() const { return isSpinning_; };
+ /*! Returns the incremental rotation that is applied by spin() to the ManipulatedFrame
+ orientation when it isSpinning().
+
+ Default value is a null rotation (identity Quaternion). Use setSpinningQuaternion() to change
+ this value.
+
+ The spinningQuaternion() axis is defined in the ManipulatedFrame coordinate system. You can use
+ Frame::transformOfFrom() to convert this axis from an other Frame coordinate system. */
+ Quaternion spinningQuaternion() const { return spinningQuaternion_; }
+ public:
+ /*! Defines the spinningQuaternion(). Its axis is defined in the ManipulatedFrame coordinate
+ system. */
+ void setSpinningQuaternion(const Quaternion& spinningQuaternion) { spinningQuaternion_ = spinningQuaternion; }
+ protected:
+ //virtual void spin();
+ private:
+ void spinUpdate();
+ //@}
+
+
+#ifndef DOXYGEN
+ protected:
+ Quaternion deformedBallQuaternion(int x, int y, float cx, float cy, const Camera* const camera);
+
+ int action_; // Should be a QGLViewer::MouseAction, but include loop
+ Constraint* previousConstraint_; // When manipulation is without Contraint.
+
+ //virtual void startAction(int ma, bool withConstraint=true); // int is really a QGLViewer::MouseAction
+
+ // Previous mouse position (used for incremental updates) and mouse press position.
+ Point prevPos_, pressPos_;
+#endif // DOXYGEN
+
+ private:
+ // Sensitivity
+ float rotSensitivity_;
+ float transSensitivity_;
+ float spinningSensitivity_;
+ float wheelSensitivity_;
+
+ // Mouse speed and spinning
+ float mouseSpeed_;
+ int delay_;
+ bool isSpinning_;
+ Quaternion spinningQuaternion_;
+
+ // Whether the SCREEN_TRANS direction (horizontal or vertical) is fixed or not.
+ bool dirIsFixed_;
+
+ // MouseGrabber
+ bool keepsGrabbingMouse_;
+ };
+
+//} // namespace qglviewer
+
+#endif // QGLVIEWER_MANIPULATED_FRAME_H
diff --git a/source/blender/freestyle/intern/app_blender/old_camera_vec_quaternion.txt b/source/blender/freestyle/intern/app_blender/old_camera_vec_quaternion.txt
new file mode 100644
index 00000000000..0d10049ee15
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/old_camera_vec_quaternion.txt
@@ -0,0 +1,593 @@
+//
+// Filename : AppConfig.h
+// Author : Stephane Grabli
+// Purpose : Configuration file
+// Date of creation : 26/02/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Copyright (C) : Please refer to the COPYRIGHT file distributed
+// with this source distribution.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ARTGLWIDGET_H
+# define ARTGLWIDGET_H
+
+# ifndef WIN32
+# include <algorithm>
+using namespace std;
+# define __min(x,y) (min(x,y))
+# define __max(x,y) (max(x,y))
+# endif // WIN32
+
+
+//# include <qstringlist.h>
+# include "../geometry/Geom.h"
+# include "../geometry/BBox.h"
+# include "../scene_graph/NodeDrawingStyle.h"
+# include "../system/TimeUtils.h"
+# include "../system/Precision.h"
+# include "AppConfig.h"
+# include "../rendering/GLDebugRenderer.h"
+//# include <QGLViewer/qglviewer.h>
+
+using namespace Geometry;
+
+typedef enum {SURFACIC, LINE, DEPTHBUFFER} RenderStyle;
+
+class FEdge;
+class QMainWindow;
+class GLRenderer;
+class GLSelectRenderer;
+class GLBBoxRenderer;
+class GLMonoColorRenderer;
+class GLDebugRenderer;
+
+class Vec{
+public:
+ Vec() {};
+ Vec(float _x, float _y, float _z): x(_x), y(_y), z(_z) {};
+ ~Vec() {}
+
+ float operator[] (unsigned i) {
+ switch(i){
+ case 0: return x; break;
+ case 1: return y; break;
+ case 2: return z; break;
+ }
+ return 0.0;
+ }
+
+
+ float x,y,z;
+};
+
+class Quaternion{
+public:
+ Quaternion( float _x, float _y, float _z, float _s): x(_x), y(_y), z(_z), s(_s){};
+ ~Quaternion() {}
+
+ float operator[] (unsigned i) {
+ switch(i){
+ case 0: return x; break;
+ case 1: return y; break;
+ case 2: return z; break;
+ case 3: return s; break;
+ }
+ return 0.0;
+ }
+
+ float x,y,z,s;
+};
+
+class Camera {
+ private:
+ float _position[3];
+ float _orientation[3];
+
+ public:
+ Camera(){};
+ ~Camera() {};
+
+ void setZNearCoefficient(float f) {}
+ void playPath(int i) {}
+
+ void loadProjectionMatrix() {}
+ void loadModelViewMatrix() {}
+ real distanceToSceneCenter() { return 0;}
+ void showEntireScene() {}
+ real zFar() {return 0;}
+ real zNear() {return 0;}
+ void setPosition(Vec v) {}
+ void setOrientation(Quaternion q) {}
+ float* position() { return _position; }
+ float* orientation() { return _orientation; }
+ void getWorldCoordinatesOf(float *src, float *vp_tmp) {}
+
+};
+
+
+//class AppGLWidget : public QGLViewer
+class AppGLWidget
+{
+ //Q_OBJECT
+
+
+public:
+
+ AppGLWidget(const char *iName = 0);
+ virtual ~AppGLWidget();
+
+public:
+
+ inline void swapBuffers() {}
+ inline void updateGL() {}
+ inline void makeCurrent() {}
+ inline void setSceneBoundingBox(Vec &min_, Vec &max_) {}
+ inline void saveSnapshot(bool b) {}
+ inline real width() { return _width; }
+ inline real height() { return _height; }
+ void setStateFileName(const string& name) { stateFileName_ = name; };
+
+
+Camera * _camera;
+
+ // captures a frame animation that was previously registered
+ void captureMovie();
+
+ /*! Sets the rendering style.
+ iStyle
+ The style used to render. Can be:
+ SURFACIC : usual rendering
+ LINES : line rendering
+ DEPTHBUFFER : grey-levels rendering of the depth buffer
+ */
+ inline void SetRenderStyle(RenderStyle iStyle)
+ {
+ _RenderStyle = iStyle;
+ }
+
+ /*! Sets the model to draw in the viewer
+ * iModel
+ * The Root Node of the model
+ */
+ inline void SetModel(NodeGroup *iModel)
+ {
+ if(0 != _ModelRootNode->numberOfChildren())
+ {
+ _ModelRootNode->DetachChildren();
+ _ModelRootNode->clearBBox();
+ }
+
+ AddModel(iModel);
+ }
+
+ /*! Adds a model for displaying in the viewer */
+ inline void AddModel(NodeGroup *iModel)
+ {
+ _ModelRootNode->AddChild(iModel);
+
+ _ModelRootNode->UpdateBBox();
+
+ _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0],
+ _ModelRootNode->bbox().getMin()[1]),
+ _ModelRootNode->bbox().getMin()[2]);
+ _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0],
+ _ModelRootNode->bbox().getMax()[1]),
+ _ModelRootNode->bbox().getMax()[2]);
+
+ _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox));
+
+ _minAbs = __min(rabs(_minBBox), rabs(_maxBBox));
+
+ // DEBUG:
+ ReInitRenderers();
+
+ }
+
+ inline void AddSilhouette(NodeGroup* iSilhouette)
+ {
+ _SilhouetteRootNode->AddChild(iSilhouette);
+ //ToggleSilhouette(true);
+ updateGL();
+ }
+
+ inline void Add2DSilhouette(NodeGroup *iSilhouette)
+ {
+ //_pFENode->AddChild(iSilhouette);
+ //ToggleSilhouette(true);
+ updateGL();
+ }
+
+ inline void Add2DVisibleSilhouette(NodeGroup *iVSilhouette)
+ {
+ //_pVisibleSilhouetteNode->AddChild(iVSilhouette);
+ updateGL();
+ }
+
+ inline void SetDebug(NodeGroup* iDebug)
+ {
+ if(0 != _DebugRootNode->numberOfChildren())
+ {
+ _DebugRootNode->DetachChildren();
+ _DebugRootNode->clearBBox();
+ }
+
+ AddDebug(iDebug);
+ }
+
+ inline void AddDebug(NodeGroup* iDebug)
+ {
+ _DebugRootNode->AddChild(iDebug);
+ updateGL();
+ }
+
+ inline void DetachModel(Node *iModel)
+ {
+ _ModelRootNode->DetachChild(iModel);
+ _ModelRootNode->UpdateBBox();
+
+ _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0],
+ _ModelRootNode->bbox().getMin()[1]),
+ _ModelRootNode->bbox().getMin()[2]);
+ _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0],
+ _ModelRootNode->bbox().getMax()[1]),
+ _ModelRootNode->bbox().getMax()[2]);
+
+ _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox));
+ _minAbs = __min(rabs(_minBBox), rabs(_maxBBox));
+ }
+
+ inline void DetachModel()
+ {
+ _ModelRootNode->DetachChildren();
+ _ModelRootNode->clearBBox();
+
+ // 2D Scene
+ //_p2DNode.DetachChildren();
+ //_pFENode->DetachChildren();
+ //_pVisibleSilhouetteNode->DetachChildren();
+ updateGL();
+ }
+
+ inline void DetachSilhouette()
+ {
+ _SilhouetteRootNode->DetachChildren();
+ //_pFENode->DetachChildren();
+ //_pVisibleSilhouetteNode->DetachChildren();
+ _p2DSelectionNode->destroy();
+ //updateGL(); //FIXME
+ }
+
+ inline void DetachVisibleSilhouette()
+ {
+ //_pVisibleSilhouetteNode->DetachChildren();
+ _p2DSelectionNode->destroy();
+ updateGL();
+ }
+
+ inline void DetachDebug()
+ {
+ _DebugRootNode->DetachChildren();
+ updateGL();
+ }
+
+ void SetMainWindow(QMainWindow *iMainWindow) ;
+
+ inline void Set3DContext()
+ {
+ // GL_PROJECTION matrix
+ _camera->loadProjectionMatrix();
+ // GL_MODELVIEW matrix
+ _camera->loadModelViewMatrix();
+ }
+
+ inline void RetriveModelViewMatrix(float *p)
+ {
+ makeCurrent();
+ glGetFloatv(GL_MODELVIEW_MATRIX, p);
+ }
+ inline void RetriveModelViewMatrix(real *p)
+ {
+ makeCurrent();
+ glGetDoublev(GL_MODELVIEW_MATRIX, p);
+ }
+
+ inline void RetrieveProjectionMatrix(float *p)
+ {
+ makeCurrent();
+ glGetFloatv(GL_PROJECTION_MATRIX, p);
+
+ }
+ inline void RetrieveProjectionMatrix(real *p)
+ {
+ makeCurrent();
+ glGetDoublev(GL_PROJECTION_MATRIX, p);
+
+ }
+
+ inline void RetrieveViewport(int *p)
+ {
+ makeCurrent();
+ glGetIntegerv(GL_VIEWPORT,(GLint *)p);
+ }
+
+ inline real GetFocalLength() const
+ {
+ real Near = __max(0.1,(real)(-2.f*_maxAbs+_camera->distanceToSceneCenter()));
+ return Near;
+ }
+
+ inline real GetAspect() const
+ {
+ return ((real) _width/(real) _height);
+ }
+
+ inline real GetFovyRadian() const
+ {
+ return _Fovy/180.0 * M_PI;
+ }
+
+ inline real GetFovyDegrees() const
+ {
+ return _Fovy;
+ }
+
+ inline void FitBBox()
+ {
+ Vec min_(_ModelRootNode->bbox().getMin()[0],
+ _ModelRootNode->bbox().getMin()[1],
+ _ModelRootNode->bbox().getMin()[2]);
+ Vec max_(_ModelRootNode->bbox().getMax()[0],
+ _ModelRootNode->bbox().getMax()[1],
+ _ModelRootNode->bbox().getMax()[2]);
+ setSceneBoundingBox(min_, max_);
+ _camera->showEntireScene();
+ }
+
+ inline void ToggleSilhouette(bool enabled)
+ {
+ _fedges = enabled;
+ updateGL();
+ }
+
+ // Reinit the renderers which need to be informed
+ // when a model is added to the scene.
+ void ReInitRenderers();
+
+ inline void SetSelectedFEdge(FEdge* iFEdge) { _pDebugRenderer->SetSelectedFEdge(iFEdge); }
+
+ inline GLDebugRenderer* debugRenderer() { return _pDebugRenderer; }
+ inline void toggle3D() { _Draw3DScene == true ? _Draw3DScene = false : _Draw3DScene = true; updateGL();}
+
+ /*! glReadPixels */
+ typedef enum{
+ RGB,
+ DEPTH
+ } PixelFormat;
+ void readPixels(int x,
+ int y,
+ int width,
+ int height,
+ PixelFormat format,
+ float *pixels)
+ {
+ makeCurrent();
+ //glReadBuffer(GL_FRONT); //in reality: glReadBuffer and glDrawBuffer are both set to GL_BACK
+ glReadBuffer(GL_BACK);
+ GLenum glformat;
+ switch(format)
+ {
+ case RGB:
+ glformat = GL_RGB;
+ break;
+ case DEPTH:
+ glformat = GL_DEPTH_COMPONENT;
+ break;
+ default:
+ break;
+ }
+ glReadPixels(x,y,width, height, glformat, GL_FLOAT, (GLfloat*)pixels);
+ }
+
+ void clear() { makeCurrent(); glClear(GL_COLOR_BUFFER_BIT ); }
+
+ void prepareCanvas();
+ void releaseCanvas();
+
+ typedef enum {
+ FRONT,
+ BACK
+ } GLBuffer;
+
+ void setReadPixelsBuffer(int iBuffer)
+ {
+ makeCurrent();
+ switch(iBuffer)
+ {
+ case FRONT:
+ glReadBuffer(GL_FRONT);
+ break;
+ case BACK:
+ glReadBuffer(GL_BACK);
+ break;
+ default:
+ break;
+ }
+ }
+
+ BBox<Vec3r> scene3DBBox() const { return _ModelRootNode->bbox(); }
+
+ inline real znear() const {
+ return _camera->zNear();
+ }
+
+ inline real zfar() const {
+ return _camera->zFar();
+ }
+
+ inline bool draw3DsceneEnabled() const { return _Draw3DScene; }
+
+ inline bool getRecordFlag() const {return _record;}
+
+ void setCameraState(const float* position, const float* orientation) {
+ _camera->setPosition(Vec(position[0], position[1], position[2]));
+ _camera->setOrientation(Quaternion(orientation[0], orientation[1], orientation[2], orientation[3]));
+ }
+
+ void getCameraState(float* position, float* orientation) const {
+ float* pos = _camera->position();
+ float* orient = _camera->orientation();
+ int i;
+ for(i=0;i<3;++i){
+ position[i] = pos[i];
+ }
+ for(i=0;i<4;++i){
+ orientation[i] = orient[i];
+ }
+ }
+
+ void saveCameraState() {
+ getCameraState(_cameraPosition, _cameraOrientation);
+ _cameraStateSaved = true;
+ }
+
+ void setUpdateMode(bool b) {
+ _enableUpdateSilhouettes = b;
+ }
+
+ bool getUpdateMode() const {
+ return _enableUpdateSilhouettes;
+ }
+ static void setFrontBufferFlag(bool iBool);
+ static bool getFrontBufferFlag();
+ static void setBackBufferFlag(bool iBool);
+ static bool getBackBufferFlag();
+
+protected:
+ virtual void init();
+ virtual void draw();
+
+ /*! Loads an envmap */
+ void LoadEnvMap(const char *filename);
+
+public:
+ /*! Core scene drawing */
+ void DrawScene(SceneVisitor *iRenderer);
+
+ /*! 2D Scene Drawing */
+ void Draw2DScene(SceneVisitor *iRenderer);
+
+ /*! Draws scene silhouettes in real time */
+ void DrawSilhouette();
+
+ /*! Draws the Scene in lines style */
+ // void DrawLines();
+ // /*! Draws the scene in surfacic style */
+ // void DrawSurfacic();
+ // /*! Draws the scene as a depth buffer image */
+ // void DrawDepthBuffer();
+
+ GLRenderer* glRenderer() {return _pGLRenderer;}
+
+protected:
+
+
+ //QString shortcutBindingsString() const;
+
+ /*! fabs or abs */
+ inline int rabs(int x) {return abs(x);}
+ inline real rabs(real x) {return fabs(x);}
+
+
+protected:
+ float _Fovy;
+ //float _SceneDepth;
+ //BBox<Vec3f> _BBox;
+
+ RenderStyle _RenderStyle;
+
+ //The root node container
+ NodeGroup _RootNode;
+ NodeDrawingStyle *_ModelRootNode;
+ NodeDrawingStyle *_SilhouetteRootNode;
+ NodeDrawingStyle *_DebugRootNode;
+
+ bool _silhouette;
+ bool _fedges;
+ bool _debug;
+ bool _selection_mode;
+
+ //a Universal light:
+ NodeGroup _Light;
+
+ real _minBBox;
+ real _maxBBox;
+ real _maxAbs;
+
+ real _minAbs;
+ bool _drawBBox;
+
+ // OpenGL Renderer
+ GLRenderer *_pGLRenderer;
+ GLSelectRenderer *_pSelectRenderer;
+ GLBBoxRenderer *_pBBoxRenderer;
+ GLMonoColorRenderer *_pMonoColorRenderer;
+ GLDebugRenderer *_pDebugRenderer;
+
+ QMainWindow *_pMainWindow;
+
+ Chronometer _Chrono;
+
+ // 2D Scene
+ bool _Draw2DScene;
+ bool _Draw3DScene; NodeGroup _p2DNode;
+ //NodeDrawingStyle *_pFENode; // Feature edges node
+ //NodeDrawingStyle *_pVisibleSilhouetteNode;
+ NodeDrawingStyle *_p2DSelectionNode;
+
+ // EnvMap
+ bool _drawEnvMap;
+ int _currentEnvMap;
+ int _maxId;
+ int _blendFunc;
+
+ // Each time we compute the view map, the camera state is
+ // saved in order to be able to restore it later
+ bool _cameraStateSaved;
+ float _cameraPosition[3];
+ float _cameraOrientation[4];
+
+ // interactive silhouette update
+ bool _enableUpdateSilhouettes;
+ //capture movie
+ bool _captureMovie;
+ // 2D drawing buffers
+ static bool _frontBufferFlag;
+ static bool _backBufferFlag;
+
+ bool _record;
+
+
+real _width, _height;
+Vec _min,_max;
+string stateFileName_;
+};
+
+#endif // ARTGLWIDGET_H
diff --git a/source/blender/freestyle/intern/app_blender/point.h b/source/blender/freestyle/intern/app_blender/point.h
new file mode 100644
index 00000000000..81903f174a8
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/point.h
@@ -0,0 +1,159 @@
+#ifndef POINT_H
+#define POINT_H
+
+typedef int QCOORD;
+
+class Point
+{
+public:
+ Point();
+ Point( int xpos, int ypos );
+
+ bool isNull() const;
+
+ int x() const;
+ int y() const;
+ void setX( int x );
+ void setY( int y );
+
+ int manhattanLength() const;
+
+ QCOORD &rx();
+ QCOORD &ry();
+
+ Point &operator+=( const Point &p );
+ Point &operator-=( const Point &p );
+ Point &operator*=( int c );
+ Point &operator*=( double c );
+ Point &operator/=( int c );
+ Point &operator/=( double c );
+
+ friend inline bool operator==( const Point &, const Point & );
+ friend inline bool operator!=( const Point &, const Point & );
+ friend inline const Point operator+( const Point &, const Point & );
+ friend inline const Point operator-( const Point &, const Point & );
+ friend inline const Point operator*( const Point &, int );
+ friend inline const Point operator*( int, const Point & );
+ friend inline const Point operator*( const Point &, double );
+ friend inline const Point operator*( double, const Point & );
+ friend inline const Point operator-( const Point & );
+ friend inline const Point operator/( const Point &, int );
+ friend inline const Point operator/( const Point &, double );
+
+private:
+ QCOORD xp;
+ QCOORD yp;
+};
+
+static void warningDivByZero() {
+ // cout << "warning: dividing by zero"
+}
+
+
+/*****************************************************************************
+ Point inline functions
+ *****************************************************************************/
+
+inline Point::Point()
+{ xp=0; yp=0; }
+
+inline Point::Point( int xpos, int ypos )
+{ xp=(QCOORD)xpos; yp=(QCOORD)ypos; }
+
+inline bool Point::isNull() const
+{ return xp == 0 && yp == 0; }
+
+inline int Point::x() const
+{ return xp; }
+
+inline int Point::y() const
+{ return yp; }
+
+inline void Point::setX( int x )
+{ xp = (QCOORD)x; }
+
+inline void Point::setY( int y )
+{ yp = (QCOORD)y; }
+
+inline QCOORD &Point::rx()
+{ return xp; }
+
+inline QCOORD &Point::ry()
+{ return yp; }
+
+inline Point &Point::operator+=( const Point &p )
+{ xp+=p.xp; yp+=p.yp; return *this; }
+
+inline Point &Point::operator-=( const Point &p )
+{ xp-=p.xp; yp-=p.yp; return *this; }
+
+inline Point &Point::operator*=( int c )
+{ xp*=(QCOORD)c; yp*=(QCOORD)c; return *this; }
+
+inline Point &Point::operator*=( double c )
+{ xp=(QCOORD)(xp*c); yp=(QCOORD)(yp*c); return *this; }
+
+inline bool operator==( const Point &p1, const Point &p2 )
+{ return p1.xp == p2.xp && p1.yp == p2.yp; }
+
+inline bool operator!=( const Point &p1, const Point &p2 )
+{ return p1.xp != p2.xp || p1.yp != p2.yp; }
+
+inline const Point operator+( const Point &p1, const Point &p2 )
+{ return Point(p1.xp+p2.xp, p1.yp+p2.yp); }
+
+inline const Point operator-( const Point &p1, const Point &p2 )
+{ return Point(p1.xp-p2.xp, p1.yp-p2.yp); }
+
+inline const Point operator*( const Point &p, int c )
+{ return Point(p.xp*c, p.yp*c); }
+
+inline const Point operator*( int c, const Point &p )
+{ return Point(p.xp*c, p.yp*c); }
+
+inline const Point operator*( const Point &p, double c )
+{ return Point((QCOORD)(p.xp*c), (QCOORD)(p.yp*c)); }
+
+inline const Point operator*( double c, const Point &p )
+{ return Point((QCOORD)(p.xp*c), (QCOORD)(p.yp*c)); }
+
+inline const Point operator-( const Point &p )
+{ return Point(-p.xp, -p.yp); }
+
+inline Point &Point::operator/=( int c )
+{
+ if ( c == 0 )
+ warningDivByZero();
+
+ xp/=(QCOORD)c;
+ yp/=(QCOORD)c;
+ return *this;
+}
+
+inline Point &Point::operator/=( double c )
+{
+ if ( c == 0.0 )
+ warningDivByZero();
+
+ xp=(QCOORD)(xp/c);
+ yp=(QCOORD)(yp/c);
+ return *this;
+}
+
+inline const Point operator/( const Point &p, int c )
+{
+ if ( c == 0 )
+ warningDivByZero();
+
+ return Point(p.xp/c, p.yp/c);
+}
+
+inline const Point operator/( const Point &p, double c )
+{
+ if ( c == 0.0 )
+ warningDivByZero();
+
+ return Point((QCOORD)(p.xp/c), (QCOORD)(p.yp/c));
+}
+
+#endif // POINT_H \ No newline at end of file
diff --git a/source/blender/freestyle/intern/app_blender/quaternion.cpp b/source/blender/freestyle/intern/app_blender/quaternion.cpp
new file mode 100644
index 00000000000..3dd42ed6ed3
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/quaternion.cpp
@@ -0,0 +1,502 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "quaternion.h"
+#include <stdlib.h> // RAND_MAX
+
+// All the methods are declared inline in Quaternion.h
+using namespace std;
+
+/*! Constructs a Quaternion that will rotate from the \p from direction to the \p to direction.
+
+Note that this rotation is not uniquely defined. The selected axis is usually orthogonal to \p from
+and \p to. However, this method is robust and can handle small or almost identical vectors. */
+Quaternion::Quaternion(const Vec& from, const Vec& to)
+{
+ const float epsilon = 1E-10f;
+
+ const float fromSqNorm = from.squaredNorm();
+ const float toSqNorm = to.squaredNorm();
+ // Identity Quaternion when one vector is null
+ if ((fromSqNorm < epsilon) || (toSqNorm < epsilon))
+ {
+ q[0]=q[1]=q[2]=0.0;
+ q[3]=1.0;
+ }
+ else
+ {
+ Vec axis = cross(from, to);
+ const float axisSqNorm = axis.squaredNorm();
+
+ // Aligned vectors, pick any axis, not aligned with from or to
+ if (axisSqNorm < epsilon)
+ axis = from.orthogonalVec();
+
+ double angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm)));
+
+ if (from*to < 0.0)
+ angle = M_PI-angle;
+
+ setAxisAngle(axis, angle);
+ }
+}
+
+/*! Returns the image of \p v by the Quaternion inverse() rotation.
+
+rotate() performs an inverse transformation. Same as inverse().rotate(v). */
+Vec Quaternion::inverseRotate(const Vec& v) const
+{
+ return inverse().rotate(v);
+}
+
+/*! Returns the image of \p v by the Quaternion rotation.
+
+See also inverseRotate() and operator*(const Quaternion&, const Vec&). */
+Vec Quaternion::rotate(const Vec& v) const
+{
+ const double q00 = 2.0l * q[0] * q[0];
+ const double q11 = 2.0l * q[1] * q[1];
+ const double q22 = 2.0l * q[2] * q[2];
+
+ const double q01 = 2.0l * q[0] * q[1];
+ const double q02 = 2.0l * q[0] * q[2];
+ const double q03 = 2.0l * q[0] * q[3];
+
+ const double q12 = 2.0l * q[1] * q[2];
+ const double q13 = 2.0l * q[1] * q[3];
+
+ const double q23 = 2.0l * q[2] * q[3];
+
+ return Vec((1.0 - q11 - q22)*v[0] + ( q01 - q23)*v[1] + ( q02 + q13)*v[2],
+ ( q01 + q23)*v[0] + (1.0 - q22 - q00)*v[1] + ( q12 - q03)*v[2],
+ ( q02 - q13)*v[0] + ( q12 + q03)*v[1] + (1.0 - q11 - q00)*v[2] );
+}
+
+/*! Set the Quaternion from a (supposedly correct) 3x3 rotation matrix.
+
+ The matrix is expressed in European format: its three \e columns are the images by the rotation of
+ the three vectors of an orthogonal basis. Note that OpenGL uses a symmetric representation for its
+ matrices.
+
+ setFromRotatedBasis() sets a Quaternion from the three axis of a rotated frame. It actually fills
+ the three columns of a matrix with these rotated basis vectors and calls this method. */
+void Quaternion::setFromRotationMatrix(const double m[3][3])
+{
+ // Compute one plus the trace of the matrix
+ const double onePlusTrace = 1.0 + m[0][0] + m[1][1] + m[2][2];
+
+ if (onePlusTrace > 1E-5)
+ {
+ // Direct computation
+ const double s = sqrt(onePlusTrace) * 2.0;
+ q[0] = (m[2][1] - m[1][2]) / s;
+ q[1] = (m[0][2] - m[2][0]) / s;
+ q[2] = (m[1][0] - m[0][1]) / s;
+ q[3] = 0.25 * s;
+ }
+ else
+ {
+ // Computation depends on major diagonal term
+ if ((m[0][0] > m[1][1])&(m[0][0] > m[2][2]))
+ {
+ const double s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2.0;
+ q[0] = 0.25 * s;
+ q[1] = (m[0][1] + m[1][0]) / s;
+ q[2] = (m[0][2] + m[2][0]) / s;
+ q[3] = (m[1][2] - m[2][1]) / s;
+ }
+ else
+ if (m[1][1] > m[2][2])
+ {
+ const double s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2.0;
+ q[0] = (m[0][1] + m[1][0]) / s;
+ q[1] = 0.25 * s;
+ q[2] = (m[1][2] + m[2][1]) / s;
+ q[3] = (m[0][2] - m[2][0]) / s;
+ }
+ else
+ {
+ const double s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2.0;
+ q[0] = (m[0][2] + m[2][0]) / s;
+ q[1] = (m[1][2] + m[2][1]) / s;
+ q[2] = 0.25 * s;
+ q[3] = (m[0][1] - m[1][0]) / s;
+ }
+ }
+ normalize();
+}
+
+#ifndef DOXYGEN
+void Quaternion::setFromRotationMatrix(const float m[3][3])
+{
+ cout << "setFromRotationMatrix now waits for a double[3][3] parameter" << endl;
+
+ double mat[3][3];
+ for (int i=0; i<3; ++i)
+ for (int j=0; j<3; ++j)
+ mat[i][j] = double(m[i][j]);
+
+ setFromRotationMatrix(mat);
+}
+
+void Quaternion::setFromRotatedBase(const Vec& X, const Vec& Y, const Vec& Z)
+{
+ cout << "setFromRotatedBase is deprecated, use setFromRotatedBasis instead" << endl;
+ setFromRotatedBasis(X,Y,Z);
+}
+#endif
+
+/*! Sets the Quaternion from the three rotated vectors of an orthogonal basis.
+
+ The three vectors do not have to be normalized but must be orthogonal and direct (X^Y=k*Z, with k>0).
+
+ \code
+ Quaternion q;
+ q.setFromRotatedBasis(X, Y, Z);
+ // Now q.rotate(Vec(1,0,0)) == X and q.inverseRotate(X) == Vec(1,0,0)
+ // Same goes for Y and Z with Vec(0,1,0) and Vec(0,0,1).
+ \endcode
+
+ See also setFromRotationMatrix() and Quaternion(const Vec&, const Vec&). */
+void Quaternion::setFromRotatedBasis(const Vec& X, const Vec& Y, const Vec& Z)
+{
+ double m[3][3];
+ double normX = X.norm();
+ double normY = Y.norm();
+ double normZ = Z.norm();
+
+ for (int i=0; i<3; ++i)
+ {
+ m[i][0] = X[i] / normX;
+ m[i][1] = Y[i] / normY;
+ m[i][2] = Z[i] / normZ;
+ }
+
+ setFromRotationMatrix(m);
+}
+
+/*! Returns the axis vector and the angle (in radians) of the rotation represented by the Quaternion.
+ See the axis() and angle() documentations. */
+void Quaternion::getAxisAngle(Vec& axis, float& angle) const
+{
+ angle = 2.0*acos(q[3]);
+ axis = Vec(q[0], q[1], q[2]);
+ const float sinus = axis.norm();
+ if (sinus > 1E-8)
+ axis /= sinus;
+
+ if (angle > M_PI)
+ {
+ angle = 2.0*M_PI - angle;
+ axis = -axis;
+ }
+}
+
+/*! Returns the normalized axis direction of the rotation represented by the Quaternion.
+
+It is null for an identity Quaternion. See also angle() and getAxisAngle(). */
+Vec Quaternion::axis() const
+{
+ Vec res = Vec(q[0], q[1], q[2]);
+ const float sinus = res.norm();
+ if (sinus > 1E-8)
+ res /= sinus;
+ return (acos(q[3]) <= M_PI/2.0) ? res : -res;
+}
+
+/*! Returns the angle (in radians) of the rotation represented by the Quaternion.
+
+ This value is always in the range [0-pi]. Larger rotational angles are obtained by inverting the
+ axis() direction.
+
+ See also axis() and getAxisAngle(). */
+float Quaternion::angle() const
+{
+ const float angle = 2.0 * acos(q[3]);
+ return (angle <= M_PI) ? angle : 2.0*M_PI - angle;
+}
+
+
+
+
+/*! Returns the Quaternion associated 4x4 OpenGL rotation matrix.
+
+ Use \c glMultMatrixd(q.matrix()) to apply the rotation represented by Quaternion \c q to the
+ current OpenGL matrix.
+
+ See also getMatrix(), getRotationMatrix() and inverseMatrix().
+
+ \attention The result is only valid until the next call to matrix(). Use it immediately (as shown
+ above) or consider using getMatrix() instead.
+
+ \attention The matrix is given in OpenGL format (row-major order) and is the transpose of the
+ actual mathematical European representation. Consider using getRotationMatrix() instead. */
+const GLdouble* Quaternion::matrix() const
+{
+ static GLdouble m[4][4];
+ getMatrix(m);
+ return (const GLdouble*)(m);
+}
+
+/*! Fills \p m with the OpenGL representation of the Quaternion rotation.
+
+Use matrix() if you do not need to store this matrix and simply want to alter the current OpenGL
+matrix. See also getInverseMatrix() and Frame::getMatrix(). */
+void Quaternion::getMatrix(GLdouble m[4][4]) const
+{
+ const double q00 = 2.0l * q[0] * q[0];
+ const double q11 = 2.0l * q[1] * q[1];
+ const double q22 = 2.0l * q[2] * q[2];
+
+ const double q01 = 2.0l * q[0] * q[1];
+ const double q02 = 2.0l * q[0] * q[2];
+ const double q03 = 2.0l * q[0] * q[3];
+
+ const double q12 = 2.0l * q[1] * q[2];
+ const double q13 = 2.0l * q[1] * q[3];
+
+ const double q23 = 2.0l * q[2] * q[3];
+
+ m[0][0] = 1.0l - q11 - q22;
+ m[1][0] = q01 - q23;
+ m[2][0] = q02 + q13;
+
+ m[0][1] = q01 + q23;
+ m[1][1] = 1.0l - q22 - q00;
+ m[2][1] = q12 - q03;
+
+ m[0][2] = q02 - q13;
+ m[1][2] = q12 + q03;
+ m[2][2] = 1.0l - q11 - q00;
+
+ m[0][3] = 0.0l;
+ m[1][3] = 0.0l;
+ m[2][3] = 0.0l;
+
+ m[3][0] = 0.0l;
+ m[3][1] = 0.0l;
+ m[3][2] = 0.0l;
+ m[3][3] = 1.0l;
+}
+
+/*! Same as getMatrix(), but with a \c GLdouble[16] parameter. See also getInverseMatrix() and Frame::getMatrix(). */
+void Quaternion::getMatrix(GLdouble m[16]) const
+{
+ static GLdouble mat[4][4];
+ getMatrix(mat);
+ int count = 0;
+ for (int i=0; i<4; ++i)
+ for (int j=0; j<4; ++j)
+ m[count++] = mat[i][j];
+}
+
+/*! Fills \p m with the 3x3 rotation matrix associated with the Quaternion.
+
+ See also getInverseRotationMatrix().
+
+ \attention \p m uses the European mathematical representation of the rotation matrix. Use matrix()
+ and getMatrix() to retrieve the OpenGL transposed version. */
+void Quaternion::getRotationMatrix(float m[3][3]) const
+{
+ static GLdouble mat[4][4];
+ getMatrix(mat);
+ for (int i=0; i<3; ++i)
+ for (int j=0; j<3; ++j)
+ // Beware of transposition
+ m[i][j] = mat[j][i];
+}
+
+/*! Returns the associated 4x4 OpenGL \e inverse rotation matrix. This is simply the matrix() of the
+ inverse().
+
+ \attention The result is only valid until the next call to inverseMatrix(). Use it immediately (as
+ in \c glMultMatrixd(q.inverseMatrix())) or use getInverseMatrix() instead.
+
+ \attention The matrix is given in OpenGL format (row-major order) and is the transpose of the
+ actual mathematical European representation. Consider using getInverseRotationMatrix() instead. */
+const GLdouble* Quaternion::inverseMatrix() const
+{
+ static GLdouble m[4][4];
+ getInverseMatrix(m);
+ return (const GLdouble*)(m);
+}
+
+/*! Fills \p m with the OpenGL matrix corresponding to the inverse() rotation.
+
+Use inverseMatrix() if you do not need to store this matrix and simply want to alter the current
+OpenGL matrix. See also getMatrix(). */
+void Quaternion::getInverseMatrix(GLdouble m[4][4]) const
+{
+ inverse().getMatrix(m);
+}
+
+/*! Same as getInverseMatrix(), but with a \c GLdouble[16] parameter. See also getMatrix(). */
+void Quaternion::getInverseMatrix(GLdouble m[16]) const
+{
+ inverse().getMatrix(m);
+}
+
+/*! \p m is set to the 3x3 \e inverse rotation matrix associated with the Quaternion.
+
+ \attention This is the classical mathematical rotation matrix. The OpenGL format uses its
+ transposed version. See inverseMatrix() and getInverseMatrix(). */
+void Quaternion::getInverseRotationMatrix(float m[3][3]) const
+{
+ static GLdouble mat[4][4];
+ getInverseMatrix(mat);
+ for (int i=0; i<3; ++i)
+ for (int j=0; j<3; ++j)
+ // Beware of transposition
+ m[i][j] = mat[j][i];
+}
+
+
+/*! Returns the slerp interpolation of Quaternions \p a and \p b, at time \p t.
+
+ \p t should range in [0,1]. Result is \p a when \p t=0 and \p b when \p t=1.
+
+ When \p allowFlip is \c true (default) the slerp interpolation will always use the "shortest path"
+ between the Quaternions' orientations, by "flipping" the source Quaternion if needed (see
+ negate()). */
+Quaternion Quaternion::slerp(const Quaternion& a, const Quaternion& b, float t, bool allowFlip)
+{
+ float cosAngle = Quaternion::dot(a, b);
+
+ float c1, c2;
+ // Linear interpolation for close orientations
+ if ((1.0 - fabs(cosAngle)) < 0.01)
+ {
+ c1 = 1.0 - t;
+ c2 = t;
+ }
+ else
+ {
+ // Spherical interpolation
+ float angle = acos(fabs(cosAngle));
+ float sinAngle = sin(angle);
+ c1 = sin(angle * (1.0 - t)) / sinAngle;
+ c2 = sin(angle * t) / sinAngle;
+ }
+
+ // Use the shortest path
+ if (allowFlip && (cosAngle < 0.0))
+ c1 = -c1;
+
+ return Quaternion(c1*a[0] + c2*b[0], c1*a[1] + c2*b[1], c1*a[2] + c2*b[2], c1*a[3] + c2*b[3]);
+}
+
+/*! Returns the slerp interpolation of the two Quaternions \p a and \p b, at time \p t, using
+ tangents \p tgA and \p tgB.
+
+ The resulting Quaternion is "between" \p a and \p b (result is \p a when \p t=0 and \p b for \p
+ t=1).
+
+ Use squadTangent() to define the Quaternion tangents \p tgA and \p tgB. */
+Quaternion Quaternion::squad(const Quaternion& a, const Quaternion& tgA, const Quaternion& tgB, const Quaternion& b, float t)
+{
+ Quaternion ab = Quaternion::slerp(a, b, t);
+ Quaternion tg = Quaternion::slerp(tgA, tgB, t, false);
+ return Quaternion::slerp(ab, tg, 2.0*t*(1.0-t), false);
+}
+
+/*! Returns the logarithm of the Quaternion. See also exp(). */
+Quaternion Quaternion::log()
+{
+ float len = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
+
+ if (len < 1E-6)
+ return Quaternion(q[0], q[1], q[2], 0.0);
+ else
+ {
+ float coef = acos(q[3]) / len;
+ return Quaternion(q[0]*coef, q[1]*coef, q[2]*coef, 0.0);
+ }
+}
+
+/*! Returns the exponential of the Quaternion. See also log(). */
+Quaternion Quaternion::exp()
+{
+ float theta = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2]);
+
+ if (theta < 1E-6)
+ return Quaternion(q[0], q[1], q[2], cos(theta));
+ else
+ {
+ float coef = sin(theta) / theta;
+ return Quaternion(q[0]*coef, q[1]*coef, q[2]*coef, cos(theta));
+ }
+}
+
+/*! Returns log(a. inverse() * b). Useful for squadTangent(). */
+Quaternion Quaternion::lnDif(const Quaternion& a, const Quaternion& b)
+{
+ Quaternion dif = a.inverse()*b;
+ dif.normalize();
+ return dif.log();
+}
+
+/*! Returns a tangent Quaternion for \p center, defined by \p before and \p after Quaternions.
+
+ Useful for smooth spline interpolation of Quaternion with squad() and slerp(). */
+Quaternion Quaternion::squadTangent(const Quaternion& before, const Quaternion& center, const Quaternion& after)
+{
+ Quaternion l1 = Quaternion::lnDif(center,before);
+ Quaternion l2 = Quaternion::lnDif(center,after);
+ Quaternion e;
+ for (int i=0; i<4; ++i)
+ e.q[i] = -0.25 * (l1.q[i] + l2.q[i]);
+ e = center*(e.exp());
+
+ // if (Quaternion::dot(e,b) < 0.0)
+ // e.negate();
+
+ return e;
+}
+
+ostream& operator<<(ostream& o, const Quaternion& Q)
+{
+ return o << Q[0] << '\t' << Q[1] << '\t' << Q[2] << '\t' << Q[3];
+}
+
+/*! Returns a random unit Quaternion.
+
+You can create a randomly directed unit vector using:
+\code
+Vec randomDir = Quaternion::randomQuaternion() * Vec(1.0, 0.0, 0.0); // or any other Vec
+\endcode
+
+\note This function uses rand() to create pseudo-random numbers and the random number generator can
+be initialized using srand().*/
+Quaternion Quaternion::randomQuaternion()
+{
+ // The rand() function is not very portable and may not be available on your system.
+ // Add the appropriate include or replace by an other random function in case of problem.
+ double seed = rand()/(float)RAND_MAX;
+ double r1 = sqrt(1.0 - seed);
+ double r2 = sqrt(seed);
+ double t1 = 2.0 * M_PI * (rand()/(float)RAND_MAX);
+ double t2 = 2.0 * M_PI * (rand()/(float)RAND_MAX);
+ return Quaternion(sin(t1)*r1, cos(t1)*r1, sin(t2)*r2, cos(t2)*r2);
+}
diff --git a/source/blender/freestyle/intern/app_blender/quaternion.h b/source/blender/freestyle/intern/app_blender/quaternion.h
new file mode 100644
index 00000000000..e3bc876aa4c
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/quaternion.h
@@ -0,0 +1,304 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef QGLVIEWER_QUATERNION_H
+#define QGLVIEWER_QUATERNION_H
+
+#include "config.h"
+#include "vec.h"
+
+ /*! \brief The Quaternion class represents 3D rotations and orientations.
+ \class Quaternion quaternion.h QGLViewer/quaternion.h
+
+ The Quaternion is an appropriate (although not very intuitive) representation for 3D rotations and
+ orientations. Many tools are provided to ease the definition of a Quaternion: see constructors,
+ setAxisAngle(), setFromRotationMatrix(), setFromRotatedBasis().
+
+ You can apply the rotation represented by the Quaternion to 3D points using rotate() and
+ inverseRotate(). See also the Frame class that represents a coordinate system and provides other
+ conversion functions like Frame::coordinatesOf() and Frame::transformOf().
+
+ You can apply the Quaternion \c q rotation to the OpenGL matrices using:
+ \code
+ glMultMatrixd(q.matrix());
+ // equvalent to glRotate(q.angle()*180.0/M_PI, q.axis().x, q.axis().y, q.axis().z);
+ \endcode
+
+ Quaternion is part of the \c qglviewer namespace, specify \c qglviewer::Quaternion or use the qglviewer
+ namespace: \code using namespace qglviewer; \endcode
+
+ <h3>Internal representation</h3>
+
+ The internal representation of a Quaternion corresponding to a rotation around axis \c axis, with an angle
+ \c alpha is made of four doubles q[i]:
+ \code
+ {q[0],q[1],q[2]} = sin(alpha/2) * {axis[0],axis[1],axis[2]}
+ q[3] = cos(alpha/2)
+ \endcode
+
+ Note that certain implementations place the cosine term in first position (instead of last here).
+
+ The Quaternion is always normalized, so that its inverse() is actually its conjugate.
+
+ See also the Vec and Frame classes' documentations.
+ \nosubgrouping */
+class Quaternion
+{
+public:
+ /*! @name Defining a Quaternion */
+ //@{
+ /*! Default constructor, builds an identity rotation. */
+ Quaternion()
+ { q[0]=q[1]=q[2]=0.0; q[3]=1.0; }
+
+ /*! Constructor from rotation axis (non null) and angle (in radians). See also setAxisAngle(). */
+ Quaternion(const Vec& axis, double angle)
+ {
+ setAxisAngle(axis, angle);
+ }
+
+ Quaternion(const Vec& from, const Vec& to);
+
+ /*! Constructor from the four values of a Quaternion. First three values are axis*sin(angle/2) and
+ last one is cos(angle/2).
+
+ \attention The identity Quaternion is Quaternion(0,0,0,1) and \e not Quaternion(0,0,0,0) (which is
+ not unitary). The default Quaternion() creates such identity Quaternion. */
+ Quaternion(double q0, double q1, double q2, double q3)
+ { q[0]=q0; q[1]=q1; q[2]=q2; q[3]=q3; }
+
+ /*! Copy constructor. */
+ Quaternion(const Quaternion& Q)
+ { for (int i=0; i<4; ++i) q[i] = Q.q[i]; }
+
+ /*! Equal operator. */
+ Quaternion& operator=(const Quaternion& Q)
+ {
+ for (int i=0; i<4; ++i)
+ q[i] = Q.q[i];
+ return (*this);
+ }
+
+ /*! Sets the Quaternion as a rotation of axis \p axis and angle \p angle (in radians).
+
+ \p axis does not need to be normalized. A null \p axis will result in an identity Quaternion. */
+ void setAxisAngle(const Vec& axis, double angle)
+ {
+ const double norm = axis.norm();
+ if (norm < 1E-8)
+ {
+ // Null rotation
+ q[0] = 0.0; q[1] = 0.0; q[2] = 0.0; q[3] = 1.0;
+ }
+ else
+ {
+ const double sin_half_angle = sin(angle / 2.0);
+ q[0] = sin_half_angle*axis[0]/norm;
+ q[1] = sin_half_angle*axis[1]/norm;
+ q[2] = sin_half_angle*axis[2]/norm;
+ q[3] = cos(angle / 2.0);
+ }
+ }
+
+ /*! Sets the Quaternion value. See the Quaternion(double, double, double, double) constructor documentation. */
+ void setValue(double q0, double q1, double q2, double q3)
+ { q[0]=q0; q[1]=q1; q[2]=q2; q[3]=q3; }
+
+#ifndef DOXYGEN
+ void setFromRotationMatrix(const float m[3][3]);
+ void setFromRotatedBase(const Vec& X, const Vec& Y, const Vec& Z);
+#endif
+ void setFromRotationMatrix(const double m[3][3]);
+ void setFromRotatedBasis(const Vec& X, const Vec& Y, const Vec& Z);
+ //@}
+
+
+ /*! @name Accessing values */
+ //@{
+ Vec axis() const;
+ float angle() const;
+ void getAxisAngle(Vec& axis, float& angle) const;
+
+ /*! Bracket operator, with a constant return value. \p i must range in [0..3]. See the Quaternion(double, double, double, double) documentation. */
+ double operator[](int i) const { return q[i]; }
+
+ /*! Bracket operator returning an l-value. \p i must range in [0..3]. See the Quaternion(double, double, double, double) documentation. */
+ double& operator[](int i) { return q[i]; }
+ //@}
+
+
+ /*! @name Rotation computations */
+ //@{
+ /*! Returns the composition of the \p a and \p b rotations.
+
+ The order is important. When applied to a Vec \c v (see operator*(const Quaternion&, const Vec&)
+ and rotate()) the resulting Quaternion acts as if \p b was applied first and then \p a was
+ applied. This is obvious since the image \c v' of \p v by the composited rotation satisfies: \code
+ v'= (a*b) * v = a * (b*v) \endcode
+
+ Note that a*b usually differs from b*a.
+
+ \attention For efficiency reasons, the resulting Quaternion is not normalized. Use normalize() in
+ case of numerical drift with small rotation composition. */
+ friend Quaternion operator*(const Quaternion& a, const Quaternion& b)
+ {
+ return Quaternion(a.q[3]*b.q[0] + b.q[3]*a.q[0] + a.q[1]*b.q[2] - a.q[2]*b.q[1],
+ a.q[3]*b.q[1] + b.q[3]*a.q[1] + a.q[2]*b.q[0] - a.q[0]*b.q[2],
+ a.q[3]*b.q[2] + b.q[3]*a.q[2] + a.q[0]*b.q[1] - a.q[1]*b.q[0],
+ a.q[3]*b.q[3] - b.q[0]*a.q[0] - a.q[1]*b.q[1] - a.q[2]*b.q[2]);
+ }
+
+ /*! Quaternion rotation is composed with \p q.
+
+ See operator*(), since this is equivalent to \c this = \c this * \p q.
+
+ \note For efficiency reasons, the resulting Quaternion is not normalized.
+ You may normalize() it after each application in case of numerical drift. */
+ Quaternion& operator*=(const Quaternion &q)
+ {
+ *this = (*this)*q;
+ return *this;
+ }
+
+ /*! Returns the image of \p v by the rotation \p q.
+
+ Same as q.rotate(v). See rotate() and inverseRotate(). */
+ friend Vec operator*(const Quaternion& q, const Vec& v)
+ {
+ return q.rotate(v);
+ }
+
+ Vec rotate(const Vec& v) const;
+ Vec inverseRotate(const Vec& v) const;
+ //@}
+
+
+ /*! @name Inversion */
+ //@{
+ /*! Returns the inverse Quaternion (inverse rotation).
+
+ Result has a negated axis() direction and the same angle(). A composition (see operator*()) of a
+ Quaternion and its inverse() results in an identity function.
+
+ Use invert() to actually modify the Quaternion. */
+ Quaternion inverse() const { return Quaternion(-q[0], -q[1], -q[2], q[3]); }
+
+ /*! Inverses the Quaternion (same rotation angle(), but negated axis()).
+
+ See also inverse(). */
+ void invert() { q[0] = -q[0]; q[1] = -q[1]; q[2] = -q[2]; }
+
+ /*! Negates all the coefficients of the Quaternion.
+
+ This results in an other representation of the \e same rotation (opposite rotation angle, but with
+ a negated axis direction: the two cancel out). However, note that the results of axis() and
+ angle() are unchanged after a call to this method since angle() always returns a value in [0,pi].
+
+ This method is mainly useful for Quaternion interpolation, so that the spherical
+ interpolation takes the shortest path on the unit sphere. See slerp() for details. */
+ void negate() { invert(); q[3] = -q[3]; }
+
+ /*! Normalizes the Quaternion coefficients.
+
+ This method should not need to be called since we only deal with unit Quaternions. This is however
+ useful to prevent numerical drifts, especially with small rotational increments. See also
+ normalized(). */
+ double normalize()
+ {
+ const double norm = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+ for (int i=0; i<4; ++i)
+ q[i] /= norm;
+ return norm;
+ }
+
+ /*! Returns a normalized version of the Quaternion.
+
+ See also normalize(). */
+ Quaternion normalized() const
+ {
+ double Q[4];
+ const double norm = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+ for (int i=0; i<4; ++i)
+ Q[i] = q[i] / norm;
+ return Quaternion(Q[0], Q[1], Q[2], Q[3]);
+ }
+//@}
+
+
+ /*! @name Associated matrix */
+ //@{
+ const GLdouble* matrix() const;
+ void getMatrix(GLdouble m[4][4]) const;
+ void getMatrix(GLdouble m[16]) const;
+
+ void getRotationMatrix(float m[3][3]) const;
+
+ const GLdouble* inverseMatrix() const;
+ void getInverseMatrix(GLdouble m[4][4]) const;
+ void getInverseMatrix(GLdouble m[16]) const;
+
+ void getInverseRotationMatrix(float m[3][3]) const;
+ //@}
+
+
+ /*! @name Slerp interpolation */
+ //@{
+ static Quaternion slerp(const Quaternion& a, const Quaternion& b, float t, bool allowFlip=true);
+ static Quaternion squad(const Quaternion& a, const Quaternion& tgA, const Quaternion& tgB, const Quaternion& b, float t);
+ /*! Returns the "dot" product of \p a and \p b: a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]. */
+ static double dot(const Quaternion& a, const Quaternion& b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]; }
+
+ Quaternion log();
+ Quaternion exp();
+ static Quaternion lnDif(const Quaternion& a, const Quaternion& b);
+ static Quaternion squadTangent(const Quaternion& before, const Quaternion& center, const Quaternion& after);
+ //@}
+
+ /*! @name Random Quaternion */
+ //@{
+ static Quaternion randomQuaternion();
+ //@}
+
+#ifdef DOXYGEN
+ /*! @name Output stream */
+ //@{
+ /*! Output stream operator. Enables debugging code like:
+ \code
+ Quaternion rot(...);
+ cout << "Rotation=" << rot << endl;
+ \endcode */
+ std::ostream& operator<<(std::ostream& o, const Vec&);
+ //@}
+#endif
+
+private:
+ /*! The internal data representation is private, use operator[] to access values. */
+ double q[4];
+};
+
+
+std::ostream& operator<<(std::ostream& o, const Quaternion&);
+
+#endif // QGLVIEWER_QUATERNION_H
diff --git a/source/blender/freestyle/intern/app_blender/vec.cpp b/source/blender/freestyle/intern/app_blender/vec.cpp
new file mode 100644
index 00000000000..a44dd1ed6ed
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/vec.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#include "vec.h"
+
+// Most of the methods are declared inline in vec.h
+using namespace std;
+
+/*! Projects the Vec on the axis of direction \p direction that passes through the origin.
+
+\p direction does not need to be normalized (but must be non null). */
+void Vec::projectOnAxis(const Vec& direction)
+{
+#ifndef QT_NO_DEBUG
+ if (direction.squaredNorm() < 1.0E-10)
+ cout << "Vec::projectOnAxis: axis direction is not normalized (norm=" << direction.norm() << ")." << endl;
+#endif
+
+ *this = (((*this)*direction) / direction.squaredNorm()) * direction;
+}
+
+/*! Projects the Vec on the plane whose normal is \p normal that passes through the origin.
+
+\p normal does not need to be normalized (but must be non null). */
+void Vec::projectOnPlane(const Vec& normal)
+{
+#ifndef QT_NO_DEBUG
+ if (normal.squaredNorm() < 1.0E-10)
+ cout << "Vec::projectOnPlane: plane normal is not normalized (norm=" << normal.norm() << ")." << endl;
+#endif
+
+ *this -= (((*this)*normal) / normal.squaredNorm()) * normal;
+}
+
+/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is zero only for a
+ null Vec. Note that the function that associates an orthogonalVec() to a Vec is not continous. */
+Vec Vec::orthogonalVec() const
+{
+ // Find smallest component. Keep equal case for null values.
+ if ((fabs(y) >= 0.9*fabs(x)) && (fabs(z) >= 0.9*fabs(x)))
+ return Vec(0.0, -z, y);
+ else
+ if ((fabs(x) >= 0.9*fabs(y)) && (fabs(z) >= 0.9*fabs(y)))
+ return Vec(-z, 0.0, x);
+ else
+ return Vec(-y, x, 0.0);
+}
+
+ostream& operator<<(ostream& o, const Vec& v)
+{
+ return o << v.x << '\t' << v.y << '\t' << v.z;
+}
+
diff --git a/source/blender/freestyle/intern/app_blender/vec.h b/source/blender/freestyle/intern/app_blender/vec.h
new file mode 100644
index 00000000000..ff17917fac8
--- /dev/null
+++ b/source/blender/freestyle/intern/app_blender/vec.h
@@ -0,0 +1,366 @@
+/****************************************************************************
+
+ Copyright (C) 2002-2007 Gilles Debunne (Gilles.Debunne@imag.fr)
+
+ This file is part of the QGLViewer library.
+ Version 2.2.6-3, released on August 28, 2007.
+
+ http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
+
+ libQGLViewer is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libQGLViewer is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libQGLViewer; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+#ifndef QGLVIEWER_VEC_H
+#define QGLVIEWER_VEC_H
+
+#include "config.h"
+
+// #include <qapplication.h>
+
+// Included by all files as vec.h is at the end of the include hierarchy
+//soc #include "config.h" // Specific configuration options.
+
+/*! \brief The Vec class represents 3D positions and 3D vectors.
+ \class Vec vec.h QGLViewer/vec.h
+
+ Vec is used as a parameter and return type by many methods of the library. It provides classical
+ algebraic computational methods and is compatible with OpenGL:
+
+ \code
+ // Draws a point located at 3.0 OpenGL units in front of the camera
+ Vec pos = camera()->position() + 3.0 * camera()->viewDirection();
+ glBegin(GL_POINTS);
+ glVertex3fv(pos);
+ glEnd();
+ \endcode
+
+ This makes of Vec a good candidate for representing positions and vectors in your programs. Since
+ it is part of the \c qglviewer namespace, specify \c qglviewer::Vec or use the qglviewer
+ namespace:
+ \code
+ using namespace qglviewer;
+ \endcode
+
+ <h3>Interface with other vector classes</h3>
+
+ Vec implements a universal explicit converter, based on the \c [] \c operator.
+ Everywhere a \c const \c Vec& argument is expected, you can use your own vector type
+ instead, as long as it implements this operator (see the Vec(const C& c) documentation).
+
+ See also the Quaternion and the Frame documentations.
+ \nosubgrouping */
+class Vec
+{
+
+ // If your compiler complains the "The class "qglviewer::Vec" has no member "x"."
+ // Add your architecture Q_OS_XXXX flag (see qglobal.h) in this list.
+#if defined (Q_OS_IRIX) || defined (Q_OS_AIX) || defined (Q_OS_HPUX)
+# define QGLVIEWER_UNION_NOT_SUPPORTED
+#endif
+
+public:
+ /*! The internal data representation is public. One can use v.x, v.y, v.z. See also operator[](). */
+#if defined (DOXYGEN) || defined (QGLVIEWER_UNION_NOT_SUPPORTED)
+ float x, y, z;
+#else
+ union
+ {
+ struct { float x, y, z; };
+ float v_[3];
+ };
+#endif
+
+ /*! @name Setting the value */
+ //@{
+ /*! Default constructor. Value is set to (0,0,0). */
+ Vec() : x(0.0), y(0.0), z(0.0) {}
+
+ /*! Standard constructor with the x, y and z values. */
+ Vec(float X, float Y, float Z) : x(X), y(Y), z(Z) {}
+
+ /*! Universal explicit converter from any class to Vec. You can use your own vector class everywhere
+ a \c const \c Vec& parameter is required, as long as it implements the \c operator[ ]:
+
+ \code
+ class MyVec
+ {
+ // ...
+ float operator[](int i) const { returns x, y or z when i=0, 1 or 2; }
+ }
+
+ MyVec v(...);
+ camera()->setPosition(v);
+ \endcode
+
+ Note that standard vector types (stl, \c float[3], ...) implement this operator and can hence
+ be used in place of Vec. See also operator const float*() .*/
+ template <class C>
+ explicit Vec(const C& c) : x(c[0]), y(c[1]), z(c[2]) {}
+ // Should NOT be explicit to prevent conflicts with operator<<.
+
+ // ! Copy constructor
+ // Vec(const Vec& v) : x(v.x), y(v.y), z(v.z) {}
+
+ /*! Equal operator. */
+ Vec& operator=(const Vec& v)
+ {
+ x = v.x; y = v.y; z = v.z;
+ return *this;
+ }
+
+ /*! Set the current value. Maybe faster than using operator=() with a temporary Vec(x,y,z). */
+ void setValue(float X, float Y, float Z)
+ { x=X; y=Y; z=Z; }
+
+ // Universal equal operator which allows the use of any type in place of Vec,
+ // as long as the [] operator is implemented (v[0]=v.x, v[1]=v.y, v[2]=v.z).
+ // template <class C>
+ // Vec& operator=(const C& c)
+ // {
+ // x=c[0]; y=c[1]; z=c[2];
+ // return *this;
+ // }
+ //@}
+
+ /*! @name Accessing the value */
+ //@{
+ /*! Bracket operator, with a constant return value. \p i must range in [0..2]. */
+ float operator[](int i) const {
+#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
+ return (&x)[i];
+#else
+ return v_[i];
+#endif
+ }
+
+ /*! Bracket operator returning an l-value. \p i must range in [0..2]. */
+ float& operator[](int i) {
+#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
+ return (&x)[i];
+#else
+ return v_[i];
+#endif
+ }
+
+#ifndef DOXYGEN
+ /*! This method is deprecated since version 2.0. Use operator const float* instead. */
+ const float* address() const { cout << "Vec::address() is deprecated, use operator const float* instead." << endl; return operator const float*(); };
+#endif
+
+ /*! Conversion operator returning the memory address of the vector.
+
+ Very convenient to pass a Vec pointer as a parameter to OpenGL functions:
+ \code
+ Vec pos, normal;
+ glNormal3fv(normal);
+ glVertex3fv(pos);
+ \endcode */
+ operator const float*() const {
+#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
+ return &x;
+#else
+ return v_;
+#endif
+ }
+
+ /*! Non const conversion operator returning the memory address of the vector.
+
+ Useful to pass a Vec to a method that requires and fills a \c float*, as provided by certain libraries. */
+ operator float*() {
+#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
+ return &x;
+#else
+ return v_;
+#endif
+ }
+ //@}
+
+ /*! @name Algebraic computations */
+ //@{
+ /*! Returns the sum of the two vectors. */
+ friend Vec operator+(const Vec &a, const Vec &b)
+ {
+ return Vec(a.x+b.x, a.y+b.y, a.z+b.z);
+ }
+
+ /*! Returns the difference of the two vectors. */
+ friend Vec operator-(const Vec &a, const Vec &b)
+ {
+ return Vec(a.x-b.x, a.y-b.y, a.z-b.z);
+ }
+
+ /*! Unary minus operator. */
+ friend Vec operator-(const Vec &a)
+ {
+ return Vec(-a.x, -a.y, -a.z);
+ }
+
+ /*! Returns the product of the vector with a scalar. */
+ friend Vec operator*(const Vec &a, float k)
+ {
+ return Vec(a.x*k, a.y*k, a.z*k);
+ }
+
+ /*! Returns the product of the vector with a scalar. */
+ friend Vec operator*(float k, const Vec &a)
+ {
+ return a*k;
+ }
+
+ /*! Returns the division of the vector with a scalar.
+
+ Too small \p k values are \e not tested (unless the library was compiled with the "debug" Qt \c
+ CONFIG flag) and may result in \c NaN values. */
+ friend Vec operator/(const Vec &a, float k)
+ {
+#ifndef QT_NO_DEBUG
+ if (fabs(k) < 1.0E-10)
+ cout << "Vec::operator / : dividing by a null value" << endl;
+#endif
+ return Vec(a.x/k, a.y/k, a.z/k);
+ }
+
+ /*! Returns \c true only when the two vector are not equal (see operator==()). */
+ friend bool operator!=(const Vec &a, const Vec &b)
+ {
+ return !(a==b);
+ }
+
+ /*! Returns \c true when the squaredNorm() of the difference vector is lower than 1E-10. */
+ friend bool operator==(const Vec &a, const Vec &b)
+ {
+ const float epsilon = 1.0E-10f;
+ return (a-b).squaredNorm() < epsilon;
+ }
+
+ /*! Adds \p a to the vector. */
+ Vec& operator+=(const Vec &a)
+ {
+ x += a.x; y += a.y; z += a.z;
+ return *this;
+ }
+
+ /*! Subtracts \p a to the vector. */
+ Vec& operator-=(const Vec &a)
+ {
+ x -= a.x; y -= a.y; z -= a.z;
+ return *this;
+ }
+
+ /*! Multiply the vector by a scalar \p k. */
+ Vec& operator*=(float k)
+ {
+ x *= k; y *= k; z *= k;
+ return *this;
+ }
+
+ /*! Divides the vector by a scalar \p k.
+
+ An absolute \p k value lower than 1E-10 will print a warning if the library was compiled with the
+ "debug" Qt \c CONFIG flag. Otherwise, no test is performed for efficiency reasons. */
+ Vec& operator/=(float k)
+ {
+#ifndef QT_NO_DEBUG
+ if (fabs(k)<1.0E-10)
+ cout << "Vec::operator /= : dividing by a null value" << endl;
+#endif
+ x /= k; y /= k; z /= k;
+ return *this;
+ }
+
+ /*! Dot product of the two Vec. */
+ friend float operator*(const Vec &a, const Vec &b)
+ {
+ return a.x*b.x + a.y*b.y + a.z*b.z;
+ }
+
+ /*! Cross product of the two vectors. Same as cross(). */
+ friend Vec operator^(const Vec &a, const Vec &b)
+ {
+ return cross(a,b);
+ }
+
+ /*! Cross product of the two Vec. Mind the order ! */
+ friend Vec cross(const Vec &a, const Vec &b)
+ {
+ return Vec(a.y*b.z - a.z*b.y,
+ a.z*b.x - a.x*b.z,
+ a.x*b.y - a.y*b.x);
+ }
+
+ Vec orthogonalVec() const;
+ //@}
+
+ /*! @name Norm of the vector */
+ //@{
+#ifndef DOXYGEN
+ /*! This method is deprecated since version 2.0. Use squaredNorm() instead. */
+ float sqNorm() const { return x*x + y*y + z*z; }
+#endif
+
+ /*! Returns the \e squared norm of the Vec. */
+ float squaredNorm() const { return x*x + y*y + z*z; }
+
+ /*! Returns the norm of the vector. */
+ float norm() const { return sqrt(x*x + y*y + z*z); }
+
+ /*! Normalizes the Vec and returns its original norm.
+
+ Normalizing a null vector will result in \c NaN values. */
+ float normalize()
+ {
+ const float n = norm();
+#ifndef QT_NO_DEBUG
+ if (n < 1.0E-10)
+ cout << "Vec::normalize: normalizing a null vector" << endl;
+#endif
+ *this /= n;
+ return n;
+ }
+
+ /*! Returns a unitary (normalized) \e representation of the vector. The original Vec is not modified. */
+ Vec unit() const
+ {
+ Vec v = *this;
+ v.normalize();
+ return v;
+ }
+ //@}
+
+ /*! @name Projection */
+ //@{
+ void projectOnAxis(const Vec& direction);
+ void projectOnPlane(const Vec& normal);
+ //@}
+
+
+#ifdef DOXYGEN
+ /*! @name Output stream */
+ //@{
+ /*! Output stream operator. Enables debugging code like:
+ \code
+ Vec pos(...);
+ cout << "Position=" << pos << endl;
+ \endcode */
+ std::ostream& operator<<(std::ostream& o, const qglviewer::Vec&);
+ //@}
+#endif
+};
+
+
+std::ostream& operator<<(std::ostream& o, const Vec&);
+
+#endif // QGLVIEWER_VEC_H