diff --git a/Graphics/CMakeLists.txt b/Graphics/CMakeLists.txt
index 2f2d72cd3770074af87a9130eb72d1b124d26ad8..ad73469ee614e94c6fae69f34a133252b50764e0 100644
--- a/Graphics/CMakeLists.txt
+++ b/Graphics/CMakeLists.txt
@@ -4,6 +4,7 @@
 # bugs and problems to <gmsh@geuz.org>.
 
 set(SRC
+  Camera.cpp 
   Trackball.cpp 
   ReadImg.cpp 
   drawContext.cpp 
diff --git a/Graphics/Camera.cpp b/Graphics/Camera.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff46c372bf0dbfd40ba58639c46e628a1762105a
--- /dev/null
+++ b/Graphics/Camera.cpp
@@ -0,0 +1,196 @@
+#include <string>
+#include <iostream>
+#include "Camera.h"
+#include "Gmsh.h"
+#include "GmshConfig.h"
+#include "GmshMessage.h"
+#include "Trackball.h"
+#include "Context.h"
+#include "drawContext.h"
+
+#if defined(HAVE_FLTK)
+#include <FL/Fl_JPEG_Image.H>
+#include <FL/Fl_PNG_Image.H>
+#endif
+
+using namespace std;
+  
+  
+Camera::Camera( ) {
+  aperture = 40;
+  focallength = 100.;
+  distance=focallength;
+  //  eyesep =0.88 ;
+  ratio=.015;
+  closeness=1.;
+  target = origin;
+  position = origin;
+  position.z = focallength ;
+  view.x =0.; 
+  view.y =0.; 
+  view.z =-1.;
+  up.x = 0;  
+  up.y = 1; 
+  up.z = 0;
+  screenwidth=400;
+  screenheight=400;
+  stereoEnable=false;
+  ref_distance=distance;
+  this->update();
+}
+  
+Camera::~Camera(){};
+
+
+void Camera::lookAtCg(){
+  target.x=CTX::instance()->cg[0];
+  target.y=CTX::instance()->cg[1];
+  target.z=CTX::instance()->cg[2];
+  double W=CTX::instance()->max[0]-CTX::instance()->min[0];
+  double H=CTX::instance()->max[1]-CTX::instance()->min[1];
+  double P=CTX::instance()->max[2]-CTX::instance()->min[2];
+  //    cout<<" H "<<H << " W"<< W <<endl;
+  Lc=sqrt(1.*W*W+1.*H*H+1.*P*P);
+  //    cout<<"  "<< 1.*W*W+1.*H*H <<endl;
+  //    cout<<"  "<< tan(aperture) <<endl;
+  distance=fabs(.5*Lc*4./3./tan(aperture*.01745329/2.));
+  distance=Lc*1.8;
+  //    cout<<" RC "<<RC << " distance"<< distance <<endl;
+  position.x=target.x-distance*view.x;
+  position.y=target.y-distance*view.y;
+  position.z=target.z-distance*view.z;
+  //  cout<<" cg "<<target.x << " "<< target.y  << " "<<target.z<<endl;
+  update();
+  focallength=distance;
+  ref_distance=distance;
+  eyesep=focallength*ratio;
+}
+
+
+void Camera::init(){  
+  aperture = 40;
+  ratio=.015;
+  focallength = 100;
+  //  ratio=1./50.;
+  target = origin;
+  distance=focallength;
+  position = origin;
+  position.z = distance ;
+  view.x =0.; 
+  view.y =0.; 
+  view.z =-1.;
+  up.x = 0;  
+  up.y = 1; 
+  up.z = 0;
+  ref_distance=distance;
+  eyesep=distance*ratio;
+  lookAtCg();
+}
+
+void Camera::update() {
+  right.x=view.y*up.z-view.z*up.y;
+  right.y=view.z*up.x-view.x*up.z;
+  right.z=view.x*up.y-view.y*up.x;
+  up.x=right.y*view.z-right.z*view.y;
+  up.y=right.z*view.x-right.x*view.z;
+  up.z=right.x*view.y-right.y*view.x;
+  ref_distance=distance;
+  normalize(up);
+  normalize(right);
+  normalize(view);
+}
+
+void Camera::moveRight(double theta) {
+  this->update();
+
+  position.x=position.x-distance*tan(theta)*right.x;
+  position.y=position.y-distance*tan(theta)*right.y;
+  position.z=position.z-distance*tan(theta)*right.z;
+  target.x=position.x+distance*view.x;
+  target.y=position.y+distance*view.y;
+  target.z=position.z+distance*view.z;
+  this->update();
+}
+
+void Camera::moveUp(double theta) {
+  this->update();
+  position.x=position.x+distance*tan(theta)*up.x;
+  position.y=position.y+distance*tan(theta)*up.y;
+  position.z=position.z+distance*tan(theta)*up.z;
+  target.x=position.x+distance*view.x;
+  target.y=position.y+distance*view.y;
+  target.z=position.z+distance*view.z;
+  this->update();
+}
+
+void Camera::rotate(double* q) {
+  this->update();
+  // rotation projection in global coordinates  
+  quaternion omega;
+  omega.x=-q[0]*right.x+q[1]*up.x+q[2]*view.x ;
+  omega.y=-q[0]*right.y+q[1]*up.y+q[2]*view.y ;
+  omega.z=-q[0]*right.z+q[1]*up.z+q[2]*view.z ;
+  omega.w=q[3];
+
+  quaternion q_view,q_position,new_q_view,new_q_position;
+  quaternion q_right,q_up,new_q_right,new_q_up;
+
+  // normalize the axe of rotation in the quaternion omega if not null
+  double sina=sin(acos(omega.w));
+  double length;
+  if (sina != 0.){
+    length=(omega.x*omega.x+omega.y*+omega.y+omega.z*omega.z)/(sina*sina);
+  }
+  else{
+    length=0.;
+  }
+  length=sqrt(length);
+  if (length!=0.){
+
+    omega.x=omega.x/length;
+    omega.y=omega.y/length;
+    omega.z=omega.z/length;
+    //  rotation of the camera (view,up and right vectors) 
+    // arround 0 0 0  the CenterOfRotation  
+    //normalize(camera.view);
+  
+    //rotate view direction
+    q_view.x=view.x;
+    q_view.y=view.y;
+    q_view.z=view.z;
+    q_view.w=0.;
+    normalize(q_view);
+    new_q_view=mult(mult(omega,q_view),conjugate(omega));
+    view.x=new_q_view.x ;
+    view.y=new_q_view.y;
+    view.z=new_q_view.z;
+    //rotate up direction
+    q_up.x=up.x;
+    q_up.y=up.y;
+    q_up.z=up.z;
+    q_up.w=0.;
+    normalize(q_up);
+    new_q_up=mult(mult(omega,q_up),conjugate(omega));
+    up.x=new_q_up.x ;
+    up.y=new_q_up.y;
+    up.z=new_q_up.z;
+    //rotate right direction
+    q_right.x=right.x;
+    q_right.y=right.y;
+    q_right.z=right.z;
+    q_right.w=0.;
+    normalize(q_right);
+    new_q_right=mult(mult(omega,q_right),conjugate(omega));
+    right.x=new_q_right.x ;
+    right.y=new_q_right.y;
+    right.z=new_q_right.z;
+
+     //actualize camera position 
+    position.x=target.x-view.x*distance;
+    position.y=target.y-view.y*distance;
+    position.z=target.z-view.z*distance;
+      
+  }
+  this->update();
+}
+
diff --git a/Graphics/Camera.cpp~ b/Graphics/Camera.cpp~
new file mode 100644
index 0000000000000000000000000000000000000000..fa53fb57f8e97d0c4ef074e10f0a8b5c5bfed590
--- /dev/null
+++ b/Graphics/Camera.cpp~
@@ -0,0 +1,194 @@
+#include <string>
+#include <iostream>
+#include "Camera.h"
+#include "Gmsh.h"
+#include "GmshConfig.h"
+#include "GmshMessage.h"
+#include "Trackball.h"
+#include "Context.h"
+#include "drawContext.h"
+
+#if defined(HAVE_FLTK)
+#include <FL/Fl_JPEG_Image.H>
+#include <FL/Fl_PNG_Image.H>
+#endif
+
+using namespace std;
+  
+  
+Camera::Camera( ) {
+  aperture = 40;
+  focallength = 100.;
+  distance=focallength;
+  //  eyesep =0.88 ;
+  ratio=1./50.;
+  closeness=1.;
+  target = origin;
+  position = origin;
+  position.z = focallength ;
+  view.x =0.; 
+  view.y =0.; 
+  view.z =-1.;
+  up.x = 0;  
+  up.y = 1; 
+  up.z = 0;
+  screenwidth=400;
+  screenheight=400;
+  stereoEnable=false;
+  ref_distance=distance;
+  this->update();
+}
+  
+Camera::~Camera(){};
+
+
+void Camera::lookAtCg(){
+  target.x=CTX::instance()->cg[0];
+  target.y=CTX::instance()->cg[1];
+  target.z=CTX::instance()->cg[2];
+  double W=CTX::instance()->max[0]-CTX::instance()->min[0];
+  double H=CTX::instance()->max[1]-CTX::instance()->min[1];
+  double P=CTX::instance()->max[2]-CTX::instance()->min[2];
+  //    cout<<" H "<<H << " W"<< W <<endl;
+  Lc=sqrt(1.*W*W+1.*H*H+1.*P*P);
+  //    cout<<"  "<< 1.*W*W+1.*H*H <<endl;
+  //    cout<<"  "<< tan(aperture) <<endl;
+  distance=fabs(.5*Lc*4./3./tan(aperture*.01745329/2.));
+  //    cout<<" RC "<<RC << " distance"<< distance <<endl;
+  position.x=target.x-distance*view.x;
+  position.y=target.y-distance*view.y;
+  position.z=target.z-distance*view.z;
+  //  cout<<" cg "<<target.x << " "<< target.y  << " "<<target.z<<endl;
+  update();
+  focallength=distance;
+  eyesep=focallength*ratio;
+}
+
+
+void Camera::init(){  
+  aperture = 40;
+  focallength = 100;
+  ratio=1./50.;
+  target = origin;
+  distance=focallength*1.4;
+  position = origin;
+  position.z = distance ;
+  view.x =0.; 
+  view.y =0.; 
+  view.z =-1.;
+  up.x = 0;  
+  up.y = 1; 
+  up.z = 0;
+  ref_distance=distance;
+  eyesep=focallength*ratio;
+  //  closeness=distance/focallength;
+  lookAtCg();
+}
+
+void Camera::update() {
+  right.x=view.y*up.z-view.z*up.y;
+  right.y=view.z*up.x-view.x*up.z;
+  right.z=view.x*up.y-view.y*up.x;
+  up.x=right.y*view.z-right.z*view.y;
+  up.y=right.z*view.x-right.x*view.z;
+  up.z=right.x*view.y-right.y*view.x;
+  ref_distance=distance;
+  normalize(up);
+  normalize(right);
+  normalize(view);
+}
+
+void Camera::moveRight(double theta) {
+  this->update();
+
+  position.x=position.x-distance*tan(theta)*right.x;
+  position.y=position.y-distance*tan(theta)*right.y;
+  position.z=position.z-distance*tan(theta)*right.z;
+  target.x=position.x+distance*view.x;
+  target.y=position.y+distance*view.y;
+  target.z=position.z+distance*view.z;
+  this->update();
+}
+
+void Camera::moveUp(double theta) {
+  this->update();
+  position.x=position.x+distance*tan(theta)*up.x;
+  position.y=position.y+distance*tan(theta)*up.y;
+  position.z=position.z+distance*tan(theta)*up.z;
+  target.x=position.x+distance*view.x;
+  target.y=position.y+distance*view.y;
+  target.z=position.z+distance*view.z;
+  this->update();
+}
+
+void Camera::rotate(double* q) {
+  this->update();
+  // rotation projection in global coordinates  
+  quaternion omega;
+  omega.x=-q[0]*right.x+q[1]*up.x+q[2]*view.x ;
+  omega.y=-q[0]*right.y+q[1]*up.y+q[2]*view.y ;
+  omega.z=-q[0]*right.z+q[1]*up.z+q[2]*view.z ;
+  omega.w=q[3];
+
+  quaternion q_view,q_position,new_q_view,new_q_position;
+  quaternion q_right,q_up,new_q_right,new_q_up;
+
+  // normalize the axe of rotation in the quaternion omega if not null
+  double sina=sin(acos(omega.w));
+  double length;
+  if (sina != 0.){
+    length=(omega.x*omega.x+omega.y*+omega.y+omega.z*omega.z)/(sina*sina);
+  }
+  else{
+    length=0.;
+  }
+  length=sqrt(length);
+  if (length!=0.){
+
+    omega.x=omega.x/length;
+    omega.y=omega.y/length;
+    omega.z=omega.z/length;
+    //  rotation of the camera (view,up and right vectors) 
+    // arround 0 0 0  the CenterOfRotation  
+    //normalize(camera.view);
+  
+    //rotate view direction
+    q_view.x=view.x;
+    q_view.y=view.y;
+    q_view.z=view.z;
+    q_view.w=0.;
+    normalize(q_view);
+    new_q_view=mult(mult(omega,q_view),conjugate(omega));
+    view.x=new_q_view.x ;
+    view.y=new_q_view.y;
+    view.z=new_q_view.z;
+    //rotate up direction
+    q_up.x=up.x;
+    q_up.y=up.y;
+    q_up.z=up.z;
+    q_up.w=0.;
+    normalize(q_up);
+    new_q_up=mult(mult(omega,q_up),conjugate(omega));
+    up.x=new_q_up.x ;
+    up.y=new_q_up.y;
+    up.z=new_q_up.z;
+    //rotate right direction
+    q_right.x=right.x;
+    q_right.y=right.y;
+    q_right.z=right.z;
+    q_right.w=0.;
+    normalize(q_right);
+    new_q_right=mult(mult(omega,q_right),conjugate(omega));
+    right.x=new_q_right.x ;
+    right.y=new_q_right.y;
+    right.z=new_q_right.z;
+
+     //actualize camera position 
+    position.x=target.x-view.x*distance;
+    position.y=target.y-view.y*distance;
+    position.z=target.z-view.z*distance;
+      
+  }
+  this->update();
+}
+
diff --git a/Graphics/Camera.h b/Graphics/Camera.h
new file mode 100644
index 0000000000000000000000000000000000000000..390030da75983be2c6e23aeb7d73fe2788cfcf98
--- /dev/null
+++ b/Graphics/Camera.h
@@ -0,0 +1,138 @@
+
+#ifndef _CAMERA_H_
+#define _CAMERA_H_
+
+#include <stdio.h>
+#include <math.h>
+#
+
+
+typedef struct {
+  double x,y,z;
+} XYZ;
+typedef struct {
+  double x,y,z,w;
+} quaternion;
+
+XYZ origin = {0.0,0.0,0.0};
+
+class Camera {
+public:
+  XYZ position;          /* camera position           */
+  XYZ view;              /* View direction vector   */
+  XYZ up;                /* View up direction       */
+  XYZ right;              /* View right direction       */
+  XYZ target;   /* center of rotation and screen   */
+  double focallength;  /* Focal Length along vd   */
+  double aperture;     /* Camera aperture         */
+  double eyesep;       /* Eye separation          */
+  int screenwidth,screenheight;
+  double distance;
+  double ref_distance;
+  bool button_left_down;
+  bool button_middle_down;
+  bool button_right_down;
+  bool stereoEnable;
+  double Lc;
+  double ratio;
+  double closeness;
+  Camera();
+  ~Camera();
+  void lookAtCg();
+  void init();
+  void rotate(double* q);
+  void moveRight(double theta);
+  void moveUp(double theta);
+  void update();
+private:
+};  
+
+
+
+class mouseAndKeyboard {
+public:
+  bool button_left_down;
+  bool button_middle_down;
+  bool button_right_down;
+  int key;
+  int mode;
+  mouseAndKeyboard() {};
+  ~mouseAndKeyboard() {};
+};
+
+
+
+
+// Quaternion and XYZ functions
+double length(quaternion quat)
+{
+  return sqrt(quat.x * quat.x + quat.y * quat.y +
+              quat.z * quat.z + quat.w * quat.w);
+}
+double length(XYZ p)
+{
+  return sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
+}
+quaternion normalize(quaternion &quat)
+{
+  double L = length(quat);
+
+  quat.x /= L;
+  quat.y /= L;
+  quat.z /= L;
+  quat.w /= L;
+
+  return quat;
+}
+
+XYZ normalize(XYZ &p)
+{
+  double L = length(p);
+
+  p.x /= L;
+  p.y /= L;
+  p.z /= L;
+
+  return p;
+}
+quaternion conjugate(quaternion quat)
+{
+  quat.x = -quat.x;
+  quat.y = -quat.y;
+  quat.z = -quat.z;
+  return quat;
+}
+quaternion mult(quaternion A, quaternion B)
+{
+  quaternion C;
+
+  C.x = A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
+  C.y = A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
+  C.z = A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
+  C.w = A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
+  return C;
+}
+
+XYZ rotate(quaternion omega,XYZ axe) {
+  XYZ new_axe;
+  quaternion qaxe,new_qaxe;
+  qaxe.x=axe.x;
+  qaxe.y=axe.y;
+  qaxe.z=axe.z;
+  qaxe.w=0.;
+  new_qaxe=mult(mult(omega,qaxe),conjugate(omega));
+  axe.x=new_qaxe.x ;
+  axe.y=new_qaxe.y;
+  axe.z=new_qaxe.z;
+
+}
+
+
+
+
+
+
+
+
+
+#endif
diff --git a/Graphics/Camera.h~ b/Graphics/Camera.h~
new file mode 100644
index 0000000000000000000000000000000000000000..ff5bf4ffc1c9e9de198e8f25a3fe86622ac2309a
--- /dev/null
+++ b/Graphics/Camera.h~
@@ -0,0 +1,138 @@
+
+#ifndef _CAMERA_H_
+#define _CAMERA_H_
+
+#include <stdio.h>
+#include <math.h>
+#
+
+
+typedef struct {
+  double x,y,z;
+} XYZ;
+typedef struct {
+  double x,y,z,w;
+} quaternion;
+
+XYZ origin = {0.0,0.0,0.0};
+
+class Camera {
+public:
+  XYZ position;          /* camera position           */
+  XYZ view;              /* View direction vector   */
+  XYZ up;                /* View up direction       */
+  XYZ right;              /* View right direction       */
+  XYZ target;   /* center of rotation and screen   */
+  double focallength;  /* Focal Length along vd   */
+  double aperture;     /* Camera aperture         */
+  double eyesep;       /* Eye separation          */
+  int screenwidth,screenheight;
+  double distance;
+  double ref_distance;
+  bool button_left_down;
+  bool button_middle_down;
+  bool button_right_down;
+  bool stereoEnable;
+  double Lc;
+  double ratio;
+  double closeness;
+  Camera();
+  ~Camera();
+  void lookAtCg();
+  void init();
+  void rotate(double* q);
+  void moveRight(double theta);
+  void moveUp(double theta);
+private:
+  void update();
+};  
+
+
+
+class mouseAndKeyboard {
+public:
+  bool button_left_down;
+  bool button_middle_down;
+  bool button_right_down;
+  int key;
+  int mode;
+  mouseAndKeyboard() {};
+  ~mouseAndKeyboard() {};
+};
+
+
+
+
+// Quaternion and XYZ functions
+double length(quaternion quat)
+{
+  return sqrt(quat.x * quat.x + quat.y * quat.y +
+              quat.z * quat.z + quat.w * quat.w);
+}
+double length(XYZ p)
+{
+  return sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
+}
+quaternion normalize(quaternion &quat)
+{
+  double L = length(quat);
+
+  quat.x /= L;
+  quat.y /= L;
+  quat.z /= L;
+  quat.w /= L;
+
+  return quat;
+}
+
+XYZ normalize(XYZ &p)
+{
+  double L = length(p);
+
+  p.x /= L;
+  p.y /= L;
+  p.z /= L;
+
+  return p;
+}
+quaternion conjugate(quaternion quat)
+{
+  quat.x = -quat.x;
+  quat.y = -quat.y;
+  quat.z = -quat.z;
+  return quat;
+}
+quaternion mult(quaternion A, quaternion B)
+{
+  quaternion C;
+
+  C.x = A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
+  C.y = A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
+  C.z = A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
+  C.w = A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
+  return C;
+}
+
+XYZ rotate(quaternion omega,XYZ axe) {
+  XYZ new_axe;
+  quaternion qaxe,new_qaxe;
+  qaxe.x=axe.x;
+  qaxe.y=axe.y;
+  qaxe.z=axe.z;
+  qaxe.w=0.;
+  new_qaxe=mult(mult(omega,qaxe),conjugate(omega));
+  axe.x=new_qaxe.x ;
+  axe.y=new_qaxe.y;
+  axe.z=new_qaxe.z;
+
+}
+
+
+
+
+
+
+
+
+
+#endif
diff --git a/Graphics/Trackball.cpp b/Graphics/Trackball.cpp
index 302059b0457469632ed7aceae3e341fd2a740604..209a37f0e9fee0d390a21f0a4ed9b3263e49163e 100644
--- a/Graphics/Trackball.cpp
+++ b/Graphics/Trackball.cpp
@@ -54,7 +54,8 @@
  */
 #include <math.h>
 #include "Trackball.h"
-
+#include "Gmsh.h"
+#include <iostream>
 /*
  * This size should really be based on the distance from the center of
  * rotation to the point on the object underneath the mouse.  That
@@ -62,13 +63,14 @@
  * simple example, though, so that is left as an Exercise for the
  * Programmer.
  */
-#define TRACKBALLSIZE  (0.8)
+#define TRACKBALLSIZE  (.8)
 
 /*
  * Local function prototypes (not defined in trackball.h)
  */
 static double tb_project_to_sphere(double, double, double);
 static void normalize_quat(double [4]);
+using namespace std ;
 
 void
 vzero(double *v)
@@ -162,40 +164,45 @@ vadd(const double *src1, const double *src2, double *dst)
 void
 trackball(double q[4], double p1x, double p1y, double p2x, double p2y)
 {
-    double a[3]; /* Axis of rotation */
-    double phi;  /* how much to rotate about axis */
-    double p1[3], p2[3], d[3];
-    double t;
-
-    if (p1x == p2x && p1y == p2y) {
-        /* Zero rotation */
-        vzero(q);
-        q[3] = 1.0;
-        return;
-    }
-
-    /*
-     * First, figure out z-coordinates for projection of P1 and P2 to
-     * deformed sphere
-     */
-    vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
-    vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
-
-    /*
-     *  Now, we want the cross product of P1 and P2
-     */
-    vcross(p2,p1,a);
-
-    /*
-     *  Figure out how much to rotate around that axis.
-     */
-    vsub(p1,p2,d);
-    t = vlength(d) / (2.0*TRACKBALLSIZE);
-
-    /*
-     * Avoid problems with out-of-control values...
-     */
-    if (t > 1.0) t = 1.0;
+  double a[3]; /* Axis of rotation */
+  double phi;  /* how much to rotate about axis */
+  double p1[3], p2[3], d[3];
+  double t;
+
+  if (p1x == p2x && p1y == p2y) {
+    /* Zero rotation */
+    vzero(q);
+    q[3] = 1.0;
+    return;
+  }
+
+  /*
+   * First, figure out z-coordinates for projection of P1 and P2 to
+   * deformed sphere
+   */
+  vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
+  vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
+  /*
+   *  Now, we want the cross product of P1 and P2
+   */
+  vcross(p2,p1,a);
+   
+  /*
+   *  Figure out how much to rotate around that axis.
+   */
+  vsub(p1,p2,d);
+  //t = vlength(d);
+  t = vlength(d) / (2.0*TRACKBALLSIZE);
+  /*
+   * Avoid problems with out-of-control values...
+   */
+  if (t > 1.0) t = 1.0;
+  if (t < -1.0) t = -1.0;
+  phi = 2.0 * asin(t);
+  /*
+   * Avoid problems with out-of-control values...
+   */
+  if (t > 1.0) t = 1.0;
     if (t < -1.0) t = -1.0;
     phi = 2.0 * asin(t);
 
@@ -221,16 +228,36 @@ axis_to_quat(double a[3], double phi, double q[4])
 static double
 tb_project_to_sphere(double r, double x, double y)
 {
-    double d, t, z;
-
-    d = sqrt(x*x + y*y);
-    if (d < r * 0.70710678118654752440) {    /* Inside sphere */
-        z = sqrt(r*r - d*d);
-    } else {           /* On hyperbola */
-        t = r / 1.41421356237309504880;
-        z = t*t / d;
+  double d, t, z;
+
+  d = sqrt(x*x + y*y);
+
+  double _camera;
+  GmshGetOption("General", "Camera",_camera );
+  if (_camera ) {
+    if (d < r ) {    
+      z = sqrt(r*r - d*d);
+    } else {           
+      z = 0.;
+    }
+  }
+  else{
+    if (d < r * 0.70710678118654752440) {    
+      // Inside sphere 
+      z = sqrt(r*r - d*d);
+    } else {           
+      // On hyperbola 
+      t = r / 1.41421356237309504880;
+      z = t*t / d;
     }
-    return z;
+  }
+
+
+  
+
+return z;
+
+
 }
 
 /*
@@ -325,3 +352,7 @@ build_rotmatrix(double m[16], double q[4])
     m[15] = 1.0;
 }
 
+
+double trackballsize(){
+  return TRACKBALLSIZE;
+}
diff --git a/Graphics/Trackball.h b/Graphics/Trackball.h
index d6f4f144ca21c6e1019629be1915ff1fba118e58..6a4683202243686c3c87572f23f37ca3de9846e4 100644
--- a/Graphics/Trackball.h
+++ b/Graphics/Trackball.h
@@ -76,3 +76,4 @@ build_rotmatrix(double m[16], double q[4]);
 void
 axis_to_quat(double a[3], double phi, double q[4]);
 
+double trackballsize() ;
diff --git a/Graphics/drawAxes.cpp b/Graphics/drawAxes.cpp
index ae8092a3be9b19509f41060122f669570753ac23..26e78bde20e202dc627f418de4ce7d79b4208de9 100644
--- a/Graphics/drawAxes.cpp
+++ b/Graphics/drawAxes.cpp
@@ -4,8 +4,11 @@
 // bugs and problems to <gmsh@geuz.org>.
 
 #include <string>
+#include <iostream>
+#include "Gmsh.h"
 #include <string.h>
 #include "drawContext.h"
+#include "Trackball.h"
 #include "GModel.h"
 #include "Context.h"
 #include "Numeric.h"
@@ -275,7 +278,7 @@ void drawContext::drawAxes()
       break;
     }
   }
-    
+   
   if(geometryExists && (CTX::instance()->drawBBox || !CTX::instance()->mesh.draw)) {
     glColor4ubv((GLubyte *) & CTX::instance()->color.fg);
     glLineWidth((float)CTX::instance()->lineWidth);
@@ -325,6 +328,8 @@ void drawContext::drawAxes()
                  CTX::instance()->geom.light);
   }
 
+
+
 }
 
 void drawContext::drawSmallAxes()
@@ -335,17 +340,36 @@ void drawContext::drawSmallAxes()
   double cx = CTX::instance()->smallAxesPos[0];
   double cy = CTX::instance()->smallAxesPos[1];
   fix2dCoordinates(&cx, &cy);
+  double _camera ;
+  GmshGetOption("General", "Camera", _camera);
+  double xx, xy, yx, yy , zx, zy;
 
-  double xx = l * rot[0];
-  double xy = l * rot[1];
-  double yx = l * rot[4];
-  double yy = l * rot[5];
-  double zx = l * rot[8];
-  double zy = l * rot[9];
+  if (_camera) {
+  
+    glPopMatrix();
+    float fvViewMatrix[ 16 ];
+    glGetFloatv( GL_MODELVIEW_MATRIX, fvViewMatrix ); 
+    glLoadIdentity();
+
+    xx = l * fvViewMatrix[0];
+    xy = l * fvViewMatrix[1];
+    yx = l * fvViewMatrix[4];
+    yy = l * fvViewMatrix[5];
+    zx = l * fvViewMatrix[8];
+    zy = l * fvViewMatrix[9];
+  }
+  else    {   /* if NOT STEREO */
+    xx = l * rot[0];
+    xy = l * rot[1];
+    yx = l * rot[4];
+    yy = l * rot[5];
+    zx = l * rot[8];
+    zy = l * rot[9];
 
+  }
   glLineWidth((float)CTX::instance()->lineWidth);
   gl2psLineWidth((float)(CTX::instance()->lineWidth * 
-                         CTX::instance()->print.epsLineWidthFactor));
+			 CTX::instance()->print.epsLineWidthFactor));
   glColor4ubv((GLubyte *) & CTX::instance()->color.smallAxes);
 
   glBegin(GL_LINES);
@@ -362,4 +386,8 @@ void drawContext::drawSmallAxes()
   drawString("Y");
   glRasterPos2d(cx + zx + o, cy + zy + o);
   drawString("Z");
+
+
+
+    
 }
diff --git a/Graphics/drawContext.cpp b/Graphics/drawContext.cpp
index 437ff8516dd37a333e103d2b43aeb9ec91d46d71..a0e49511eb75c832bf0c0aec6356b4f82436ec31 100644
--- a/Graphics/drawContext.cpp
+++ b/Graphics/drawContext.cpp
@@ -4,6 +4,7 @@
 // bugs and problems to <gmsh@geuz.org>.
 
 #include <string>
+#include "Gmsh.h"
 #include "GmshConfig.h"
 #include "GmshMessage.h"
 #include "drawContext.h"
@@ -16,12 +17,13 @@
 #include "PViewOptions.h"
 #include "VertexArray.h"
 #include "gl2ps.h"
-
+ 
 #if defined(HAVE_FLTK)
 #include <FL/Fl_JPEG_Image.H>
 #include <FL/Fl_PNG_Image.H>
 #endif
-
+using namespace std;
+  
 drawContextGlobal *drawContext::_global = 0;
 
 drawContext::drawContext(drawTransform *transform) 
@@ -48,6 +50,7 @@ drawContext::drawContext(drawTransform *transform)
 
   _quadric = 0; // cannot create it here: needs valid opengl context
   _displayLists = 0;
+ 
 }
 
 drawContext::~drawContext()
@@ -226,7 +229,6 @@ void drawContext::draw3d()
   // much simpler to deal with option changes, e.g. arrow shape
   // changes)
   createQuadricsAndDisplayLists();
-
   // We should only enable the polygon offset when there is a mix of
   // lines and polygons to be drawn; enabling it all the time can lead
   // to very small but annoying artifacts in the picture. Since there
@@ -245,19 +247,27 @@ void drawContext::draw3d()
   else
     CTX::instance()->polygonOffset = 0;
 
+
   glDepthFunc(GL_LESS);
   glEnable(GL_DEPTH_TEST);
   initProjection();
   initRenderModel();
-  initPosition();
+
+  double _camera;
+  GmshGetOption("General", "Camera", _camera);
+  if (!_camera)     initPosition();
   drawAxes();
   drawGeom();
   drawMesh();
   drawPost();
+ 
+
+
 }
 
 void drawContext::draw2d()
 {
+
   glDisable(GL_DEPTH_TEST);
   for(int i = 0; i < 6; i++)
     glDisable((GLenum)(GL_CLIP_PLANE0 + i));
@@ -266,44 +276,54 @@ void drawContext::draw2d()
   glLoadIdentity();
   glOrtho((double)viewport[0], (double)viewport[2],
           (double)viewport[1], (double)viewport[3], 
-          -100., 100.); // in pixels, so we can draw some 3D glyphs
+          -1000., 1000.); // in pixels, so we can draw some 3D glyphs
 
   // hack to make the 2D primitives appear "in front" in GL2PS
   glTranslated(0., 0., CTX::instance()->clipFactor > 1. ? 
                1. / CTX::instance()->clipFactor : CTX::instance()->clipFactor);
   glMatrixMode(GL_MODELVIEW);
+
+
+  //++++
+  glPushMatrix();
+  //++++
   glLoadIdentity();
 
   drawGraph2d();
   drawText2d();
-  if(CTX::instance()->post.draw) 
-    drawScales();
-  if(CTX::instance()->smallAxes)
-    drawSmallAxes();
+  double _stereo;
+  GmshGetOption("General", "Stereo", _stereo);
+  if (!_stereo) {   
+    if(CTX::instance()->post.draw)    drawScales();
+  }
+  if(CTX::instance()->smallAxes)    drawSmallAxes();
+
 }
 
 void drawContext::initProjection(int xpick, int ypick, int wpick, int hpick)
 {
+
   double Va = 
     (double) (viewport[3] - viewport[1]) /
     (double) (viewport[2] - viewport[0]);
   double Wa = (CTX::instance()->max[1] - CTX::instance()->min[1]) / 
     (CTX::instance()->max[0] - CTX::instance()->min[0]);
 
+
   // compute the viewport in World coordinates (with margins)
   if(Va > Wa) {
     vxmin = CTX::instance()->min[0];
     vxmax = CTX::instance()->max[0];
     vymin = 0.5 * (CTX::instance()->min[1] + CTX::instance()->max[1] - 
-                   Va * (CTX::instance()->max[0] - CTX::instance()->min[0]));
+		   Va * (CTX::instance()->max[0] - CTX::instance()->min[0]));
     vymax = 0.5 * (CTX::instance()->min[1] + CTX::instance()->max[1] + 
-                   Va * (CTX::instance()->max[0] - CTX::instance()->min[0]));
+		   Va * (CTX::instance()->max[0] - CTX::instance()->min[0]));
   }
   else {
     vxmin = 0.5 * (CTX::instance()->min[0] + CTX::instance()->max[0] - 
-                   (CTX::instance()->max[1] - CTX::instance()->min[1]) / Va);
+		   (CTX::instance()->max[1] - CTX::instance()->min[1]) / Va);
     vxmax = 0.5 * (CTX::instance()->min[0] + CTX::instance()->max[0] + 
-                   (CTX::instance()->max[1] - CTX::instance()->min[1]) / Va);
+		   (CTX::instance()->max[1] - CTX::instance()->min[1]) / Va);
     vymin = CTX::instance()->min[1];
     vymax = CTX::instance()->max[1];
   }
@@ -324,42 +344,33 @@ void drawContext::initProjection(int xpick, int ypick, int wpick, int hpick)
   // (otherwise the z-buffer resolution e.g. with Mesa can become
   // insufficient)
   double zmax = std::max(fabs(CTX::instance()->min[2]),
-                         fabs(CTX::instance()->max[2]));
+			 fabs(CTX::instance()->max[2]));
   if(zmax < CTX::instance()->lc) zmax = CTX::instance()->lc;
+ 
+  double _camera;
+  GmshGetOption("General", "Camera", _camera);
 
-  double clip_near, clip_far;
-  if(CTX::instance()->ortho) {
-    clip_near = -zmax * s[2] * CTX::instance()->clipFactor;
-    clip_far = -clip_near;
-  }
-  else {
-    clip_near = 0.75 * CTX::instance()->clipFactor * zmax;
-    clip_far = 75. * CTX::instance()->clipFactor * zmax;
-  }
 
-  // setup projection matrix
-  glMatrixMode(GL_PROJECTION);
-  glLoadIdentity();
 
-  // restrict picking to a rectangular region around xpick,ypick
-  if(render_mode == GMSH_SELECT)
-    gluPickMatrix((GLdouble)xpick, (GLdouble)(viewport[3] - ypick),
-                  (GLdouble)wpick, (GLdouble)hpick, (GLint *)viewport);
+  if (_camera) { /* if  Camera */
 
-  // draw background if not in selection mode
-  if(render_mode != GMSH_SELECT && (CTX::instance()->bgGradient || 
-                                    CTX::instance()->bgImageFileName.size())){
+    double clip_near, clip_far;
+    clip_near = 0.75 * CTX::instance()->clipFactor * zmax;
+    clip_far = 75. * CTX::instance()->clipFactor * zmax;
+    // draw background if not in selection mode
     glDisable(GL_DEPTH_TEST);
     glPushMatrix();
     glLoadIdentity();
     // the z values and the translation are only needed for GL2PS,
     // which does not understand "no depth test" (hence we must make
     // sure that we draw the background behind the rest of the scene)
+        
     glOrtho((double)viewport[0], (double)viewport[2],
-            (double)viewport[1], (double)viewport[3], 
-            clip_near, clip_far);
-    glTranslated(0., 0., -0.99 * clip_far);
-
+	    (double)viewport[1], (double)viewport[3], 
+	    clip_near, clip_far);
+    
+    //  glTranslated(0., 0., clip_near);
+    //  glScaled(1.2,1.2,1.);
     // background gradient
     if(CTX::instance()->bgGradient == 1){ // vertical
       glBegin(GL_QUADS);
@@ -385,7 +396,7 @@ void drawContext::initProjection(int xpick, int ypick, int wpick, int hpick)
       double cx = 0.5 * (viewport[0] + viewport[2]);
       double cy = 0.5 * (viewport[1] + viewport[3]);
       double r = 0.5 * std::max(viewport[2] - viewport[0],
-                                viewport[3] - viewport[1]);
+				viewport[3] - viewport[1]);
       glBegin(GL_TRIANGLE_FAN);
       glColor4ubv((GLubyte *) & CTX::instance()->color.bgGrad);
       glVertex2d(cx, cy);
@@ -393,173 +404,342 @@ void drawContext::initProjection(int xpick, int ypick, int wpick, int hpick)
       glVertex2d(cx + r, cy);
       int ntheta = 36;
       for(int i = 1; i < ntheta + 1; i ++){
-        double theta = i * 2 * M_PI / (double)ntheta;
-        glVertex2d(cx + r * cos(theta), cy + r * sin(theta));       
+	double theta = i * 2 * M_PI / (double)ntheta;
+	glVertex2d(cx + r * cos(theta), cy + r * sin(theta));       
       }
       glEnd();
     }
-
     // hack for GL2PS (to make sure that the image is in front of the
     // gradient)
     glTranslated(0., 0., 0.01 * clip_far);
 
     // background image
     if(CTX::instance()->bgImageFileName.size()){
-#if defined(HAVE_FLTK)
-      if(_bgImage.empty()){
-        int idot = CTX::instance()->bgImageFileName.find_last_of('.');
-        std::string ext;
-        if(idot > 0 && idot < (int)CTX::instance()->bgImageFileName.size())
-          ext = CTX::instance()->bgImageFileName.substr(idot + 1);
-        Fl_RGB_Image *img = 0;
-        if(ext == "jpg" || ext == "JPG" || ext == "jpeg" || ext == "JPEG")
-          img = new Fl_JPEG_Image(CTX::instance()->bgImageFileName.c_str());
-        else if(ext == "png" || ext == "PNG")
-          img = new Fl_PNG_Image(CTX::instance()->bgImageFileName.c_str());
-        if(img && img->d() >= 3){
-          const unsigned char *data = img->array;
-          for(int j = img->h() - 1; j >= 0; j--) {
-            for(int i = 0; i < img->w(); i++) {
-              int idx = j * img->w() * img->d() + i * img->d();
-              _bgImage.push_back((GLfloat)data[idx] / 255.F);
-              _bgImage.push_back((GLfloat)data[idx + 1] / 255.F);
-              _bgImage.push_back((GLfloat)data[idx + 2] / 255.F);
-            }
-          }
-          _bgImageSize[0] = img->w();
-          _bgImageSize[1] = img->h();
-        }
-        if(!_bgImageSize[0] || !_bgImageSize[1]){
-          Msg::Error("Could not load valid background image");
-          // make sure we don't try to load it again
-          for(int i = 0; i < 3; i++) _bgImage.push_back(0);
-          _bgImageSize[0] = _bgImageSize[1] = 1;
-        }
-        if(img) delete img;
-      }
-      double x = CTX::instance()->bgImagePosition[0];
-      double y = CTX::instance()->bgImagePosition[1];
-      int c = fix2dCoordinates(&x, &y);
-      if(c & 1) x -= _bgImageSize[0] / 2.;
-      if(c & 2) y -= _bgImageSize[1] / 2.;
-      if(x < viewport[0]) x = viewport[0];
-      if(y < viewport[1]) y = viewport[1];
-      glRasterPos2d(x, y);
-      glPixelStorei(GL_PACK_ALIGNMENT, 1);
-      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-      glDrawPixels(_bgImageSize[0], _bgImageSize[1], GL_RGB, GL_FLOAT,
-                   (void*)&_bgImage[0]);
-      gl2psDrawPixels(_bgImageSize[0], _bgImageSize[1], 0, 0, GL_RGB, GL_FLOAT,
-                      (void*)&_bgImage[0]);
-#endif
     }
-
     glPopMatrix();
-    glEnable(GL_DEPTH_TEST);
-  }
+    glEnable(GL_DEPTH_TEST);   
+  } 
 
-  if(CTX::instance()->ortho) {
-    glOrtho(vxmin, vxmax, vymin, vymax, clip_near, clip_far);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-  }
-  else {
-    // recenter the model such that the perspective is always at the
-    // center of gravity (we should maybe add an option to choose
-    // this, as we do for the rotation center)
-    t_init[0] = CTX::instance()->cg[0];
-    t_init[1] = CTX::instance()->cg[1];
-    vxmin -= t_init[0];
-    vxmax -= t_init[0];
-    vymin -= t_init[1];
-    vymax -= t_init[1];
-    glFrustum(vxmin, vxmax, vymin, vymax, clip_near, clip_far);
-    glMatrixMode(GL_MODELVIEW);
+  else    {   /* if NOT Camera */
+
+    double clip_near, clip_far;
+    if(CTX::instance()->ortho) {
+      clip_near = -zmax * s[2] * CTX::instance()->clipFactor;
+      clip_far = -clip_near;
+    }
+    else {
+      clip_near = 0.75 * CTX::instance()->clipFactor * zmax;
+      clip_far = 75. * CTX::instance()->clipFactor * zmax;
+    }
+    // setup projection matrix
+    glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
-    double coef = (clip_far / clip_near) / 3.;
-    glTranslated(-coef * t_init[0], -coef * t_init[1], -coef * clip_near);
-    glScaled(coef, coef, coef);
-  }
+
+    // restrict picking to a rectangular region around xpick,ypick
+    if(render_mode == GMSH_SELECT)
+      gluPickMatrix((GLdouble)xpick, (GLdouble)(viewport[3] - ypick),
+		    (GLdouble)wpick, (GLdouble)hpick, (GLint *)viewport);
+    // draw background if not in selection mode
+    if(render_mode != GMSH_SELECT && (CTX::instance()->bgGradient || 
+				      CTX::instance()->bgImageFileName.size())){
+      glDisable(GL_DEPTH_TEST);
+      glPushMatrix();
+      glLoadIdentity();
+      // the z values and the translation are only needed for GL2PS,
+      // which does not understand "no depth test" (hence we must make
+      // sure that we draw the background behind the rest of the scene)
+      glOrtho((double)viewport[0], (double)viewport[2],
+	      (double)viewport[1], (double)viewport[3], 
+	      clip_near, clip_far);
+      glTranslated(0., 0., -0.99 * clip_far);
+      // background gradient
+      if(CTX::instance()->bgGradient == 1){ // vertical
+	glBegin(GL_QUADS);
+	glColor4ubv((GLubyte *) & CTX::instance()->color.bg);
+	glVertex2i(viewport[0], viewport[1]);
+	glVertex2i(viewport[2], viewport[1]);
+	glColor4ubv((GLubyte *) & CTX::instance()->color.bgGrad);
+	glVertex2i(viewport[2], viewport[3]);
+	glVertex2i(viewport[0], viewport[3]);
+	glEnd();
+      }
+      else if(CTX::instance()->bgGradient == 2){ // horizontal
+	glBegin(GL_QUADS);
+	glColor4ubv((GLubyte *) & CTX::instance()->color.bg);
+	glVertex2i(viewport[2], viewport[1]);
+	glVertex2i(viewport[2], viewport[3]);
+	glColor4ubv((GLubyte *) & CTX::instance()->color.bgGrad);
+	glVertex2i(viewport[0], viewport[3]);
+	glVertex2i(viewport[0], viewport[1]);
+	glEnd();
+      }
+      else if(CTX::instance()->bgGradient == 3){ // radial
+	double cx = 0.5 * (viewport[0] + viewport[2]);
+	double cy = 0.5 * (viewport[1] + viewport[3]);
+	double r = 0.5 * std::max(viewport[2] - viewport[0],
+				  viewport[3] - viewport[1]);
+	glBegin(GL_TRIANGLE_FAN);
+	glColor4ubv((GLubyte *) & CTX::instance()->color.bgGrad);
+	glVertex2d(cx, cy);
+	glColor4ubv((GLubyte *) & CTX::instance()->color.bg);
+	glVertex2d(cx + r, cy);
+	int ntheta = 36;
+	for(int i = 1; i < ntheta + 1; i ++){
+	  double theta = i * 2 * M_PI / (double)ntheta;
+	  glVertex2d(cx + r * cos(theta), cy + r * sin(theta));       
+	}
+	glEnd();
+      }
+      // hack for GL2PS (to make sure that the image is in front of the
+      // gradient)
+      glTranslated(0., 0., 0.01 * clip_far);
+      // background image
+      if(CTX::instance()->bgImageFileName.size()){
+#if defined(HAVE_FLTK)
+	if(_bgImage.empty()){
+	  int idot = CTX::instance()->bgImageFileName.find_last_of('.');
+	  std::string ext;
+	  if(idot > 0 && idot < (int)CTX::instance()->bgImageFileName.size())
+	    ext = CTX::instance()->bgImageFileName.substr(idot + 1);
+	  Fl_RGB_Image *img = 0;
+	  if(ext == "jpg" || ext == "JPG" || ext == "jpeg" || ext == "JPEG")
+	    img = new Fl_JPEG_Image(CTX::instance()->bgImageFileName.c_str());
+	  else if(ext == "png" || ext == "PNG")
+	    img = new Fl_PNG_Image(CTX::instance()->bgImageFileName.c_str());
+	  if(img && img->d() >= 3){
+	    const unsigned char *data = img->array;
+	    for(int j = img->h() - 1; j >= 0; j--) {
+	      for(int i = 0; i < img->w(); i++) {
+		int idx = j * img->w() * img->d() + i * img->d();
+		_bgImage.push_back((GLfloat)data[idx] / 255.F);
+		_bgImage.push_back((GLfloat)data[idx + 1] / 255.F);
+		_bgImage.push_back((GLfloat)data[idx + 2] / 255.F);
+	      }
+	    }
+	    _bgImageSize[0] = img->w();
+	    _bgImageSize[1] = img->h();
+	  }
+	  if(!_bgImageSize[0] || !_bgImageSize[1]){
+	    Msg::Error("Could not load valid background image");
+	    // make sure we don't try to load it again
+	    for(int i = 0; i < 3; i++) _bgImage.push_back(0);
+	    _bgImageSize[0] = _bgImageSize[1] = 1;
+	  }
+	  if(img) delete img;
+	}
+	double x = CTX::instance()->bgImagePosition[0];
+	double y = CTX::instance()->bgImagePosition[1];
+	int c = fix2dCoordinates(&x, &y);
+	if(c & 1) x -= _bgImageSize[0] / 2.;
+	if(c & 2) y -= _bgImageSize[1] / 2.;
+	if(x < viewport[0]) x = viewport[0];
+	if(y < viewport[1]) y = viewport[1];
+	glRasterPos2d(x, y);
+	glPixelStorei(GL_PACK_ALIGNMENT, 1);
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+	glDrawPixels(_bgImageSize[0], _bgImageSize[1], GL_RGB, GL_FLOAT,
+		     (void*)&_bgImage[0]);
+	gl2psDrawPixels(_bgImageSize[0], _bgImageSize[1], 0, 0, GL_RGB, GL_FLOAT,
+			(void*)&_bgImage[0]);
+#endif
+      }
+      glPopMatrix();
+      glEnable(GL_DEPTH_TEST);
+    }
+    if(CTX::instance()->ortho) {
+      glOrtho(vxmin, vxmax, vymin, vymax, clip_near, clip_far);
+      glMatrixMode(GL_MODELVIEW);
+      glLoadIdentity();
+    }
+    else {
+      // recenter the model such that the perspective is always at the
+      // center of gravity (we should maybe add an option to choose
+      // this, as we do for the rotation center)
+      t_init[0] = CTX::instance()->cg[0];
+      t_init[1] = CTX::instance()->cg[1];
+      vxmin -= t_init[0];
+      vxmax -= t_init[0];
+      vymin -= t_init[1];
+      vymax -= t_init[1];
+      glFrustum(vxmin, vxmax, vymin, vymax, clip_near, clip_far);
+      glMatrixMode(GL_MODELVIEW);
+      glLoadIdentity();
+      double coef = (clip_far / clip_near) / 3.;
+      glTranslated(-coef * t_init[0], -coef * t_init[1], -coef * clip_near);
+      glScaled(coef, coef, coef);
+    }
+  } /*end  if NOT Camera */ 
 }
 
 void drawContext::initRenderModel()
 {
-  glPushMatrix();
-  glLoadIdentity();
-  glScaled(s[0], s[1], s[2]);
-  glTranslated(t[0], t[1], t[2]);
+  double _camera;
+  GmshGetOption("General", "Camera", _camera);
+  if (_camera) {
+    glPushMatrix();
+    glLoadIdentity();
+    glScaled(s[0], s[1], s[2]);
+    glTranslated(t[0], t[1], t[2]);
   
-  for(int i = 0; i < 6; i++) {
-    if(CTX::instance()->light[i]) {
-      GLfloat position[4] = {(GLfloat)CTX::instance()->lightPosition[i][0],
-                             (GLfloat)CTX::instance()->lightPosition[i][1],
-                             (GLfloat)CTX::instance()->lightPosition[i][2],
-                             (GLfloat)CTX::instance()->lightPosition[i][3]};
-      glLightfv((GLenum)(GL_LIGHT0 + i), GL_POSITION, position);
-
-      GLfloat r = (GLfloat)(CTX::instance()->unpackRed
-                            (CTX::instance()->color.ambientLight[i]) / 255.);
-      GLfloat g = (GLfloat)(CTX::instance()->unpackGreen
-                            (CTX::instance()->color.ambientLight[i]) / 255.);
-      GLfloat b = (GLfloat)(CTX::instance()->unpackBlue
-                            (CTX::instance()->color.ambientLight[i]) / 255.);
-      GLfloat ambient[4] = {r, g, b, 1.0F};
-      glLightfv((GLenum)(GL_LIGHT0 + i), GL_AMBIENT, ambient);
-
-      r = (GLfloat)(CTX::instance()->unpackRed
-                    (CTX::instance()->color.diffuseLight[i]) / 255.);
-      g = (GLfloat)(CTX::instance()->unpackGreen
-                    (CTX::instance()->color.diffuseLight[i]) / 255.);
-      b = (GLfloat)(CTX::instance()->unpackBlue
-                    (CTX::instance()->color.diffuseLight[i]) / 255.);
-      GLfloat diffuse[4] = {r, g, b, 1.0F};
-      glLightfv((GLenum)(GL_LIGHT0 + i), GL_DIFFUSE, diffuse);
-
-      r = (GLfloat)(CTX::instance()->unpackRed
-                    (CTX::instance()->color.specularLight[i]) / 255.);
-      g = (GLfloat)(CTX::instance()->unpackGreen
-                    (CTX::instance()->color.specularLight[i]) / 255.);
-      b = (GLfloat)(CTX::instance()->unpackBlue
-                    (CTX::instance()->color.specularLight[i]) / 255.);
-      GLfloat specular[4] = {r, g, b, 1.0F};
-      glLightfv((GLenum)(GL_LIGHT0 + i), GL_SPECULAR, specular);
-
-      glEnable((GLenum)(GL_LIGHT0 + i));
-    }
-    else{
-      glDisable((GLenum)(GL_LIGHT0 + i));
+    for(int i = 0; i < 6; i++) {
+      if(CTX::instance()->light[i]) {
+	GLfloat position[4] = {(GLfloat)CTX::instance()->lightPosition[i][0],
+			       (GLfloat)CTX::instance()->lightPosition[i][1],
+			       (GLfloat)CTX::instance()->lightPosition[i][2],
+			       (GLfloat)CTX::instance()->lightPosition[i][3]};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_POSITION, position);
+
+	GLfloat r = (GLfloat)(CTX::instance()->unpackRed
+			      (CTX::instance()->color.ambientLight[i]) / 255.);
+	GLfloat g = (GLfloat)(CTX::instance()->unpackGreen
+			      (CTX::instance()->color.ambientLight[i]) / 255.);
+	GLfloat b = (GLfloat)(CTX::instance()->unpackBlue
+			      (CTX::instance()->color.ambientLight[i]) / 255.);
+	GLfloat ambient[4] = {r, g, b, 1.0F};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_AMBIENT, ambient);
+
+	r = (GLfloat)(CTX::instance()->unpackRed
+		      (CTX::instance()->color.diffuseLight[i]) / 255.);
+	g = (GLfloat)(CTX::instance()->unpackGreen
+		      (CTX::instance()->color.diffuseLight[i]) / 255.);
+	b = (GLfloat)(CTX::instance()->unpackBlue
+		      (CTX::instance()->color.diffuseLight[i]) / 255.);
+	GLfloat diffuse[4] = {r, g, b, 1.0F};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_DIFFUSE, diffuse);
+
+	r = (GLfloat)(CTX::instance()->unpackRed
+		      (CTX::instance()->color.specularLight[i]) / 255.);
+	g = (GLfloat)(CTX::instance()->unpackGreen
+		      (CTX::instance()->color.specularLight[i]) / 255.);
+	b = (GLfloat)(CTX::instance()->unpackBlue
+		      (CTX::instance()->color.specularLight[i]) / 255.);
+	GLfloat specular[4] = {r, g, b, 1.0F};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_SPECULAR, specular);
+
+	glEnable((GLenum)(GL_LIGHT0 + i));
+      }
+      else{
+	glDisable((GLenum)(GL_LIGHT0 + i));
+      }
     }
+
+    glPopMatrix();
+
+    // ambient and diffuse material colors track glColor automatically
+    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+    glEnable(GL_COLOR_MATERIAL);
+    // "white"-only specular material reflection color
+    GLfloat spec[4] = {(GLfloat)CTX::instance()->shine, 
+		       (GLfloat)CTX::instance()->shine, 
+		       (GLfloat)CTX::instance()->shine, 1.0F};
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
+    // specular exponent in [0,128] (larger means more "focused"
+    // reflection)
+    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 
+		(GLfloat)CTX::instance()->shineExponent);
+
+    glShadeModel(GL_SMOOTH);
+
+    // Normalize the normals automatically. We could use the more
+    // efficient glEnable(GL_RESCALE_NORMAL) instead (since we initially
+    // specify unit normals), but GL_RESCALE_NORMAL does only work with
+    // isotropic scalings (and we allow anistotropic scalings in
+    // myZoom). Note that GL_RESCALE_NORMAL is only available in
+    // GL_VERSION_1_2.
+    glEnable(GL_NORMALIZE);
+
+    // lighting is enabled/disabled for each particular primitive later
+    glDisable(GL_LIGHTING);
   }
+  else    {   
+    glPushMatrix();
+    glLoadIdentity();
+    glScaled(s[0], s[1], s[2]);
+    glTranslated(t[0], t[1], t[2]);
+  
+    for(int i = 0; i < 6; i++) {
+      if(CTX::instance()->light[i]) {
+	GLfloat position[4] = {(GLfloat)CTX::instance()->lightPosition[i][0],
+			       (GLfloat)CTX::instance()->lightPosition[i][1],
+			       (GLfloat)CTX::instance()->lightPosition[i][2],
+			       (GLfloat)CTX::instance()->lightPosition[i][3]};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_POSITION, position);
+
+	GLfloat r = (GLfloat)(CTX::instance()->unpackRed
+			      (CTX::instance()->color.ambientLight[i]) / 255.);
+	GLfloat g = (GLfloat)(CTX::instance()->unpackGreen
+			      (CTX::instance()->color.ambientLight[i]) / 255.);
+	GLfloat b = (GLfloat)(CTX::instance()->unpackBlue
+			      (CTX::instance()->color.ambientLight[i]) / 255.);
+	GLfloat ambient[4] = {r, g, b, 1.0F};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_AMBIENT, ambient);
+
+	r = (GLfloat)(CTX::instance()->unpackRed
+		      (CTX::instance()->color.diffuseLight[i]) / 255.);
+	g = (GLfloat)(CTX::instance()->unpackGreen
+		      (CTX::instance()->color.diffuseLight[i]) / 255.);
+	b = (GLfloat)(CTX::instance()->unpackBlue
+		      (CTX::instance()->color.diffuseLight[i]) / 255.);
+	GLfloat diffuse[4] = {r, g, b, 1.0F};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_DIFFUSE, diffuse);
+
+	r = (GLfloat)(CTX::instance()->unpackRed
+		      (CTX::instance()->color.specularLight[i]) / 255.);
+	g = (GLfloat)(CTX::instance()->unpackGreen
+		      (CTX::instance()->color.specularLight[i]) / 255.);
+	b = (GLfloat)(CTX::instance()->unpackBlue
+		      (CTX::instance()->color.specularLight[i]) / 255.);
+	GLfloat specular[4] = {r, g, b, 1.0F};
+	glLightfv((GLenum)(GL_LIGHT0 + i), GL_SPECULAR, specular);
+
+	glEnable((GLenum)(GL_LIGHT0 + i));
+      }
+      else{
+	glDisable((GLenum)(GL_LIGHT0 + i));
+      }
+    }
 
-  glPopMatrix();
+    glPopMatrix();
+
+    // ambient and diffuse material colors track glColor automatically
+    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+    glEnable(GL_COLOR_MATERIAL);
+    // "white"-only specular material reflection color
+    GLfloat spec[4] = {(GLfloat)CTX::instance()->shine, 
+		       (GLfloat)CTX::instance()->shine, 
+		       (GLfloat)CTX::instance()->shine, 1.0F};
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
+    // specular exponent in [0,128] (larger means more "focused"
+    // reflection)
+    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 
+		(GLfloat)CTX::instance()->shineExponent);
+
+    glShadeModel(GL_SMOOTH);
+
+    // Normalize the normals automatically. We could use the more
+    // efficient glEnable(GL_RESCALE_NORMAL) instead (since we initially
+    // specify unit normals), but GL_RESCALE_NORMAL does only work with
+    // isotropic scalings (and we allow anistotropic scalings in
+    // myZoom). Note that GL_RESCALE_NORMAL is only available in
+    // GL_VERSION_1_2.
+    glEnable(GL_NORMALIZE);
+
+    // lighting is enabled/disabled for each particular primitive later
+    glDisable(GL_LIGHTING);
+  }
 
-  // ambient and diffuse material colors track glColor automatically
-  glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
-  glEnable(GL_COLOR_MATERIAL);
-  // "white"-only specular material reflection color
-  GLfloat spec[4] = {(GLfloat)CTX::instance()->shine, 
-                     (GLfloat)CTX::instance()->shine, 
-                     (GLfloat)CTX::instance()->shine, 1.0F};
-  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
-  // specular exponent in [0,128] (larger means more "focused"
-  // reflection)
-  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 
-              (GLfloat)CTX::instance()->shineExponent);
-
-  glShadeModel(GL_SMOOTH);
-
-  // Normalize the normals automatically. We could use the more
-  // efficient glEnable(GL_RESCALE_NORMAL) instead (since we initially
-  // specify unit normals), but GL_RESCALE_NORMAL does only work with
-  // isotropic scalings (and we allow anistotropic scalings in
-  // myZoom). Note that GL_RESCALE_NORMAL is only available in
-  // GL_VERSION_1_2.
-  glEnable(GL_NORMALIZE);
-
-  // lighting is enabled/disabled for each particular primitive later
-  glDisable(GL_LIGHTING);
 }
 
+
+
+
+
+
+
+
+
+
+
 void drawContext::initPosition()
 {
   glScaled(s[0], s[1], s[2]);
diff --git a/Graphics/drawContext.h b/Graphics/drawContext.h
index 750e25c2542b8f88a0580118964d6f62ddccf582..fd65ddf972ee9644449da794be52d2af493b4065 100644
--- a/Graphics/drawContext.h
+++ b/Graphics/drawContext.h
@@ -25,6 +25,7 @@
 #include <GL/glu.h>
 #endif
 
+
 class PView;
 class GModel;
 class GVertex;
@@ -47,6 +48,7 @@ class drawTransformScaled : public drawTransform {
  private:
   double _mat[3][3];
   double _tra[3];
+
  public:
   drawTransformScaled(double mat[3][3], double tra[3]=0)
     : drawTransform()
@@ -76,7 +78,7 @@ class drawTransformScaled : public drawTransform {
     z += _tra[2];
   }
 };
-
+ 
 // global drawing functions, which need to be redefined for each
 // widget toolkit (FLTK, Qt, etc.)
 class drawContextGlobal {
@@ -121,7 +123,6 @@ class drawContext {
                               // at the time of the last InitPosition() call
   enum RenderMode {GMSH_RENDER=1, GMSH_SELECT=2, GMSH_FEEDBACK=3};
   int render_mode; // current rendering mode
-
  public:
   drawContext(drawTransform *transform=0);
   ~drawContext();
@@ -190,6 +191,7 @@ class drawContext {
                 std::string label[3], SBoundingBox3d &bb, int mikado);
   void drawAxes();
   void drawSmallAxes();
+  void drawTrackball();
   void drawScales();
   void drawString(const std::string &s, const std::string &font_name, int font_enum, 
                   int font_size, int align);