diff --git a/Common/Context.h b/Common/Context.h
index 5a452845d2a182615c70f61a987eb0ae007decb7..54dfcdfcf895553e32bd6e0baf5ce1c657a884f1 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -94,6 +94,7 @@ public :
   double rot[16];             // current rotation matrix 
   double r[3];                // current Euler angles (in degrees!) 
   double t[3], s[3];          // current translation and scale 
+  double t_init[3];           // initial translation before applying modelview transform
   double clip_factor;         // clipping plane distance factor
   double quaternion[4];       // current quaternion used for "trackball" rotation
   int useTrackball;           // do or do not use the trackball for rotations 
@@ -147,7 +148,6 @@ public :
 
   double model[16], proj[16]; // the modelview and projection matrix as they were
                               // at the time of the last InitPosition() call
-  double model_init[16]; // the modelview matrix before applying s, t and rot
 
   int forced_bbox; // dynamic variable tracking if the bbox is currently imposed
 
diff --git a/Common/Options.cpp b/Common/Options.cpp
index b9a708d6713f8aa15cf167ed112c88b3101e5184..ad8bd09fb53bd01e8af93462e925431354acce1e 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.264 2005-12-16 17:35:32 geuzaine Exp $
+// $Id: Options.cpp,v 1.265 2005-12-18 21:10:54 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -2759,13 +2759,12 @@ double opt_general_orthographic(OPT_ARGS_NUM)
   if(WID && (action & GMSH_GUI)) {
     if(CTX.ortho){
       WID->gen_choice[2]->value(0);
-      //WID->persp_bmp->label(WID->g_status_butt[4]);
+      Msg(STATUS1N, "Orthographic projection");
     }
     else{
       WID->gen_choice[2]->value(1);
-      //WID->ortho_bmp->label(WID->g_status_butt[4]);
+      Msg(STATUS1N, "Perspective projection");
     }
-    //WID->g_status_butt[4]->redraw();
   }
 #endif
   return CTX.ortho;
diff --git a/Fltk/Bitmaps.h b/Fltk/Bitmaps.h
index 94fe5bf80ce9ac1bc9e1e5fc55551d4dfcae2ca3..ec615af45b768eb21774d45d8272ad00f2e169a8 100644
--- a/Fltk/Bitmaps.h
+++ b/Fltk/Bitmaps.h
@@ -81,14 +81,7 @@ static unsigned char ortho_bits[] = {
    0x12, 0x09, 0x12, 0x09, 0xf2, 0x0f, 0x0a, 0x05, 0x06, 0x03, 0xfe, 0x01,
    0x00, 0x00 };
 
-// 'Perspective projection' bitmap
-#define persp_width 13
-#define persp_height 13
-static unsigned char persp_bits[] = {
-   0x00, 0x00, 0xf0, 0x0f, 0x10, 0x0c, 0x18, 0x0a, 0x18, 0x09, 0x94, 0x08,
-   0x7c, 0x08, 0x54, 0x08, 0xf4, 0x0f, 0x44, 0x03, 0xfc, 0x00, 0x00, 0x00,
-   0x00, 0x00 };
-
+// '90 degrees rotation' bitmap
 #define rotate_width 12
 #define rotate_height 13
 static unsigned char rotate_bits[] = {
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 1b28f880816b6df883287ce688f6b5ca24ecc990..17387790e5b7b1d192dfd55183c22936f49d948a 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.386 2005-12-16 20:20:17 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.387 2005-12-18 21:10:54 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -449,7 +449,7 @@ void status_xyz1p_cb(CALLBACK_ARGS)
     CTX.setQuaternionFromEulerAngles();
     Draw();
   }
-  else if(!strcmp(str, "p")){ // switch projection mode
+  else if(!strcmp(str, "p")){ // toggle projection mode
     opt_general_orthographic(0, GMSH_SET | GMSH_GUI, 
 			     !opt_general_orthographic(0, GMSH_GET, 0));
     Draw();
@@ -1012,7 +1012,7 @@ void general_options_ok_cb(CALLBACK_ARGS)
   }
   opt_general_vector_type(0, GMSH_SET, val);
   opt_general_graphics_font(0, GMSH_SET, (char *)WID->gen_choice[1]->text());
-  opt_general_orthographic(0, GMSH_SET | GMSH_GUI, !WID->gen_choice[2]->value());
+  opt_general_orthographic(0, GMSH_SET, !WID->gen_choice[2]->value());
   opt_general_axes(0, GMSH_SET, WID->gen_choice[4]->value());
   opt_general_background_gradient(0, GMSH_SET, WID->gen_choice[5]->value());
 }
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index 049adbbe103e772c2540b5972879dfe6d4ad233a..3dd3e9cbd0933a8d3ffd5a56be94e39a1aa571fc 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.472 2005-12-16 17:35:32 geuzaine Exp $
+// $Id: GUI.cpp,v 1.473 2005-12-18 21:10:54 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -1360,15 +1360,12 @@ void GUI::create_graphic_window()
   g_status_butt[3]->callback(status_xyz1p_cb, (void *)"1:1");
   g_status_butt[3]->tooltip("Set unit scale");
 
-  //FIXME: remove this until we do the perspective projection properly
-  //FIXME: need to change the button number!!
-  //g_status_butt[4] = new Fl_Button(x, glheight + 2, sw, sh - 4);
-  //x += sw;
-  //g_status_butt[4]->callback(status_xyz1p_cb, (void *)"p");
-  //g_status_butt[4]->tooltip("Set orthographic/perspective projection");
+  g_status_butt[8] = new Fl_Button(x, glheight + 2, sw, sh - 4);
+  x += sw;
+  g_status_butt[8]->callback(status_xyz1p_cb, (void *)"p");
+  g_status_butt[8]->tooltip("Toggle projection mode (Alt+o)");
   ortho_bmp = new Fl_Bitmap(ortho_bits, ortho_width, ortho_height);
-  persp_bmp = new Fl_Bitmap(persp_bits, persp_width, persp_height);
-  //persp_bmp->label(g_status_butt[4]);
+  ortho_bmp->label(g_status_butt[8]);
 
   g_status_butt[5] = new Fl_Button(x, glheight + 2, sw, sh - 4, "?");
   x += sw;
@@ -1378,10 +1375,10 @@ void GUI::create_graphic_window()
   g_status_butt[6] = new Fl_Button(x, glheight + 2, sw, sh - 4);
   x += sw;
   g_status_butt[6]->callback(status_rewind_cb);
+  g_status_butt[6]->tooltip("Rewind animation");
   rewind_bmp = new Fl_Bitmap(rewind_bits, rewind_width, rewind_height);
   rewind_bmp->label(g_status_butt[6]);
   g_status_butt[6]->deactivate();
-  g_status_butt[6]->tooltip("Rewind animation");
 
   g_status_butt[7] = new Fl_Button(x, glheight + 2, sw, sh - 4);
   x += sw;
@@ -1392,7 +1389,7 @@ void GUI::create_graphic_window()
   stop_bmp = new Fl_Bitmap(stop_bits, stop_width, stop_height);
   g_status_butt[7]->deactivate();
 
-  for(i = 0; i < 8; i++) {
+  for(i = 0; i < 9; i++) {
     g_status_butt[i]->box(FL_FLAT_BOX);
     g_status_butt[i]->selection_color(FL_WHITE);
     g_status_butt[i]->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
diff --git a/Fltk/GUI.h b/Fltk/GUI.h
index 1617338295bc6980148e943913d9fa676ba57c17..df3a05ccce6e1f677accfc0372c792bf185d7f6b 100644
--- a/Fltk/GUI.h
+++ b/Fltk/GUI.h
@@ -126,14 +126,12 @@ class GUI{
   Fl_Scroll *m_scroll;
 
   // Bitmaps
-  Fl_Bitmap  *abort_bmp, *start_bmp, *stop_bmp, *rewind_bmp, *rotate_bmp ;
+  Fl_Bitmap  *abort_bmp, *start_bmp, *stop_bmp, *rewind_bmp, *rotate_bmp, *ortho_bmp ;
   void add_post_plugins ( Fl_Menu_Button *button , int iView);
   void add_multiline_in_browser(Fl_Browser *o, char* prefix, char *str);
 
 public:
 
-  Fl_Bitmap  *ortho_bmp, *persp_bmp;
-
   // menu window
   Fl_Window        *m_window ;
 #if defined(__APPLE__) && defined(HAVE_FLTK_1_1_5_OR_ABOVE)
@@ -153,7 +151,7 @@ public:
   // graphic window
   Fl_Window        *g_window ;
   Opengl_Window    *g_opengl_window ;
-  Fl_Button        *g_status_butt[8] ;
+  Fl_Button        *g_status_butt[9] ;
   Fl_Box           *g_status_label[3] ;
 
   // Option window
diff --git a/Fltk/Opengl_Window.cpp b/Fltk/Opengl_Window.cpp
index 3f00be67a0f20218dbf79680a6b928672dff2ca7..43c126ba37095d5592ed90bba69c83ba5e6022b3 100644
--- a/Fltk/Opengl_Window.cpp
+++ b/Fltk/Opengl_Window.cpp
@@ -1,4 +1,4 @@
-// $Id: Opengl_Window.cpp,v 1.55 2005-12-18 18:10:46 geuzaine Exp $
+// $Id: Opengl_Window.cpp,v 1.56 2005-12-18 21:10:54 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -44,53 +44,24 @@ void MousePosition::set()
   win[1] = (double)Fl::event_y();
   win[2] = 0.;
 
-  wnr[0] = (CTX.vxmin + win[0] / (double)CTX.viewport[2] * 
-	    (CTX.vxmax - CTX.vxmin)) / CTX.s[0] - CTX.t[0];
-  wnr[1] = (CTX.vymax - win[1] / (double)CTX.viewport[3] * 
-	    (CTX.vymax - CTX.vymin)) / CTX.s[1] - CTX.t[1];
+  wnr[0] = 
+    (CTX.vxmin + win[0] / (double)CTX.viewport[2] * (CTX.vxmax - CTX.vxmin)) 
+    / CTX.s[0] - CTX.t[0] + CTX.t_init[0] / CTX.s[0];
+  wnr[1] = 
+    (CTX.vymax - win[1] / (double)CTX.viewport[3] * (CTX.vymax - CTX.vymin))
+    / CTX.s[1] - CTX.t[1] + CTX.t_init[1] / CTX.s[1];
   wnr[2] = 0.;
-
-  // might need this later
-  // Viewport2World(win, world);
 }
 
 void MousePosition::recenter()
 {
-  // this computes the equivalent translation to apply after the
-  // scaling so that the scaling is done around the point which was
-  // clicked. FIXME: needs to be generalized to the case where an
-  // initial translation is done BEFORE the scaling (necessary for the
-  // general perspective case, with the line of sight in the middle of
-  // the screen, and not just the z-axis).
+  // compute the equivalent translation to apply *after* the scaling
+  // so that the scaling is done around the point which was clicked:
   CTX.t[0] = t[0] * (s[0] / CTX.s[0]) - wnr[0] * (1. - (s[0] / CTX.s[0]));
   CTX.t[1] = t[1] * (s[1] / CTX.s[1]) - wnr[1] * (1. - (s[1] / CTX.s[1]));
-
-  /*
-  double sx, sy;
-  double tx0, ty0;
-  double tx, ty;
-  double model_new[16];
-
-  glPushMatrix();
-  glLoadMatrix(CTX.model_init);
-  glTranslated(tx0, ty0, 0.);
-  glScaled(sx, sy, sz);
-  glTranslated(-tx0, -ty0, 0.);
-  glTranslated(tx, ty, 0.);
-  glGetDoublev(GL_MODELVIEW_MATRIX, model_new);
-  glPopMatrix();
-
-  CTX.s[0] = model_new[0][0];
-  CTX.s[1] = model_new[1][1];
-  CTX.s[2] = model_new[2][2];
-
-  CTX.t[0] = model_new[0][3];
-  CTX.t[1] = model_new[1][3];
-  CTX.t[2] = model_new[2][3];
-  */
 }
   
-void myZoom(MousePosition &click1, MousePosition &click2)
+void lasso_zoom(MousePosition &click1, MousePosition &click2)
 {
   if(click1.win[0] == click2.win[0] || click1.win[1] == click2.win[1])
     return;
@@ -99,6 +70,7 @@ void myZoom(MousePosition &click1, MousePosition &click2)
   CTX.s[1] *= (double)CTX.viewport[3] / (click2.win[1] - click1.win[1]);
   CTX.s[2] = MIN(CTX.s[0], CTX.s[1]); // bof...
   
+  // recenter around the center of the lasso rectangle
   MousePosition tmp(click1);
   tmp.wnr[0] = 0.5 * (click1.wnr[0] + click2.wnr[0]);
   tmp.wnr[1] = 0.5 * (click1.wnr[1] + click2.wnr[1]);
@@ -210,7 +182,7 @@ int Opengl_Window::handle(int event)
       }
       else if(ZoomMode) {
         ZoomMode = false;
-	myZoom(click, curr);
+	lasso_zoom(click, curr);
       }
       else {
         WID->try_selection = 1;
diff --git a/Fltk/Opengl_Window.h b/Fltk/Opengl_Window.h
index 3e6f8e80a8a75aaa0b1cb5909846899a01a86f69..0525470918f629f9f3e98b999dbdb641a27ce63b 100644
--- a/Fltk/Opengl_Window.h
+++ b/Fltk/Opengl_Window.h
@@ -28,18 +28,16 @@ class MousePosition {
  public:
   double win[3]; // window coordinates
   double wnr[3]; // world coordinates BEFORE rotation
-  double world[3]; // world coordinates (in a given plane // to screen)
   double s[3]; // scaling state when the event was recorded
   double t[3];  // translation state when the event was recorded
   MousePosition(){
     for(int i = 0; i < 3; i++)
-      win[i] = wnr[i] = world[i] = s[i] = t[i] = 0.;
+      win[i] = wnr[i] = s[i] = t[i] = 0.;
   }
   MousePosition(const MousePosition &instance){
     for(int i = 0; i < 3; i++){
       win[i] = instance.win[i];
       wnr[i] = instance.wnr[i];
-      world[i] = instance.world[i];
       s[i] = instance.s[i];
       t[i] = instance.t[i];
     }
diff --git a/Graphics/Draw.cpp b/Graphics/Draw.cpp
index 00b5e2c71e3a8ea0da3a4ae45102f11caffbf627..186b73dcf27143bad79c6219cfb6da294ff534a5 100644
--- a/Graphics/Draw.cpp
+++ b/Graphics/Draw.cpp
@@ -1,4 +1,4 @@
-// $Id: Draw.cpp,v 1.84 2005-12-18 18:10:46 geuzaine Exp $
+// $Id: Draw.cpp,v 1.85 2005-12-18 21:10:54 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -162,6 +162,9 @@ void InitProjection(int x, int y)
   CTX.pixel_equiv_x = (CTX.vxmax - CTX.vxmin) / (CTX.viewport[2] - CTX.viewport[0]);
   CTX.pixel_equiv_y = (CTX.vymax - CTX.vymin) / (CTX.viewport[3] - CTX.viewport[1]);
 
+  // no initial translation of the model
+  CTX.t_init[0] = CTX.t_init[1] = CTX.t_init[2] = 0.;
+
   // setup ortho or perspective projection matrix
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
@@ -192,21 +195,19 @@ void InitProjection(int x, int y)
     double near = 0.75 * CTX.clip_factor * CTX.lc;
     double far = 75. * CTX.clip_factor * CTX.lc;
     // recenter the model such that the perspective is always at the
-    // center of the screen. FIXME: this screws up the zoom, so let's
-    // leave it out for now
-    //double w = (CTX.max[0] - CTX.min[0]) / 2.;
-    //double h = (CTX.max[1] - CTX.min[1]) / 2.;
-    //CTX.vxmin -= w;
-    //CTX.vxmax -= w;
-    //CTX.vymin -= h;
-    //CTX.vymax -= h;
-    double w = 0.;
-    double h = 0.;
+    // center of gravity (we should maybe add an option to choose
+    // this, as we do for the rotation center)
+    CTX.t_init[0] = CTX.cg[0];
+    CTX.t_init[1] = CTX.cg[1];
+    CTX.vxmin -= CTX.t_init[0];
+    CTX.vxmax -= CTX.t_init[0];
+    CTX.vymin -= CTX.t_init[1];
+    CTX.vymax -= CTX.t_init[1];
     glFrustum(CTX.vxmin, CTX.vxmax, CTX.vymin, CTX.vymax, near, far);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
-    glTranslated(-5 * w, -5 * h, -5 * near);
-    glScaled(5., 5., 5.);
+    glTranslated(-10 * CTX.t_init[0], -10 * CTX.t_init[1], -10 * near);
+    glScaled(10., 10., 10.);
     gradient_zdist = 0.99 * far;
     gradient_xyfact = far / near;
   }
@@ -301,11 +302,6 @@ void InitRenderModel(void)
 
 void InitPosition(void)
 {
-  // store the model transfo matrix before we position the object
-  // (this way we can isolate the scaling/translation/rotation) from
-  // any transformations made before to adjust the viewpoint
-  glGetDoublev(GL_MODELVIEW_MATRIX, CTX.model_init);
-
   glScaled(CTX.s[0], CTX.s[1], CTX.s[2]);
   glTranslated(CTX.t[0], CTX.t[1], CTX.t[2]);