diff --git a/Common/Context.h b/Common/Context.h
index 3277b14eba14ca751ea30127024b15d53ca0c109..c9235a1079f30d7981c33b2489339844226f51fe 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -148,7 +148,7 @@ public :
     int points, lines, surfaces, volumes;
     int points_num, lines_num, surfaces_num, volumes_num;
     double point_size, line_width, point_sel_size, line_sel_width;
-    int point_type, line_type; // flat or 3D
+    int point_type, line_type, surface_type;
     int draw, light;
     int old_circle, circle_points;
     int extrude_spline_points, extrude_return_lateral, old_newreg;
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index dc1a254d33051c031025bce01917ceee8a29f3e0..b5eaa3edf95a739004800b4805b2913a79615072 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -859,6 +859,8 @@ StringXNumber GeometryOptions_Number[] = {
     "Display geometry surfaces?" },
   { F|O, "SurfaceNumbers" , opt_geometry_surfaces_num , 0. , 
     "Display surface numbers?" },
+  { F|O, "SurfaceType" , opt_geometry_surface_type , 0. , 
+    "Display surfaces as wireframe (0) or solid (1)" },
 
   { F|O, "Tangents" , opt_geometry_tangents , 0. ,
     "Display size of tangent vectors (in pixels)" },
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 0c8fd1a9a66227beff784709f90cfd310947311f..82d5a3664f86c535c61b30192bc880819173b270 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.347 2007-07-26 13:10:47 geuzaine Exp $
+// $Id: Options.cpp,v 1.348 2007-08-03 00:44:28 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -4035,6 +4035,19 @@ double opt_geometry_line_type(OPT_ARGS_NUM)
   return CTX.geom.line_type;
 }
 
+double opt_geometry_surface_type(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET) {
+    CTX.geom.surface_type = (int)val;
+  }
+#if defined(HAVE_FLTK)
+  if(WID && (action & GMSH_GUI)) {
+    WID->geo_choice[2]->value(CTX.geom.surface_type);
+  }
+#endif
+  return CTX.geom.surface_type;
+}
+
 double opt_geometry_light(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
diff --git a/Common/Options.h b/Common/Options.h
index 2115dd4360dce8c76cf3b0425b2cbb79258e6930..bfad509042e9f923c8eeee06f9e6941cae066176 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -407,6 +407,7 @@ double opt_geometry_point_type(OPT_ARGS_NUM);
 double opt_geometry_line_width(OPT_ARGS_NUM);
 double opt_geometry_line_sel_width(OPT_ARGS_NUM);
 double opt_geometry_line_type(OPT_ARGS_NUM);
+double opt_geometry_surface_type(OPT_ARGS_NUM);
 double opt_geometry_light(OPT_ARGS_NUM);
 double opt_geometry_occ_fix_small_edges(OPT_ARGS_NUM);
 double opt_geometry_occ_fix_small_faces(OPT_ARGS_NUM);
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index eb6c2d909dcfa5a8f1fecbdc610a79383e4cb611..d02e5b7f012f46375084ec367d6bb74b3e2d24ee 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.535 2007-07-26 13:10:47 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.536 2007-08-03 00:44:28 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -1069,6 +1069,7 @@ void geometry_options_ok_cb(CALLBACK_ARGS)
 
   opt_geometry_point_type(0, GMSH_SET, WID->geo_choice[0]->value());
   opt_geometry_line_type(0, GMSH_SET, WID->geo_choice[1]->value());
+  opt_geometry_surface_type(0, GMSH_SET, WID->geo_choice[2]->value());
 
   if(CTX.fast_redraw)
     CTX.post.draw = CTX.mesh.draw = 0;
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index 46df991f8edfb1897606d0e1c987005e262d2645..ed26aab50ae29a426d2170c30d129abfa60c48bc 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.627 2007-07-26 17:57:27 geuzaine Exp $
+// $Id: GUI.cpp,v 1.628 2007-08-03 00:44:28 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -349,6 +349,12 @@ static Fl_Menu_Item menu_line_display[] = {
   {0}
 };
 
+static Fl_Menu_Item menu_surface_display[] = {
+  {"Wireframe", 0, 0, 0},
+  {"Solid",   0, 0, 0},
+  {0}
+};
+
 static Fl_Menu_Item menu_axes_mode[] = {
   {"None", 0, 0, 0},
   {"Simple axes", 0, 0, 0},
@@ -2295,6 +2301,11 @@ void GUI::create_option_window()
       geo_value[6]->align(FL_ALIGN_RIGHT);
       geo_value[6]->callback(geometry_options_ok_cb);
 
+      geo_choice[2] = new Fl_Choice(L + 2 * WB, 2 * WB + 7 * BH, IW, BH, "Surface display");
+      geo_choice[2]->menu(menu_surface_display);
+      geo_choice[2]->align(FL_ALIGN_RIGHT);	
+      geo_choice[2]->callback(geometry_options_ok_cb);
+
       o->end();
     }
     {
diff --git a/Fltk/GUI_Projection.cpp b/Fltk/GUI_Projection.cpp
index 21801e39788b424ff30ae7ae6cd6f15d9d1ec3ba..580a1f1ba38562bd38e3faba22bee7a58177c327 100644
--- a/Fltk/GUI_Projection.cpp
+++ b/Fltk/GUI_Projection.cpp
@@ -201,6 +201,7 @@ void update_cb(Fl_Widget *w, void *data)
       p->currentParams[i] = p->parameters[i]->value();
     for (int i = 9; i < 9 + ps->GetNumParameters(); i++)
       ps->SetParameter(i - 9, p->parameters[i]->value());
+    p->face->computeGraphicsRep(64, 64); // FIXME: hardcoded for now!
     Draw();
     
     // project all selected points and update u,v display
diff --git a/Geo/GFace.cpp b/Geo/GFace.cpp
index 7b445da15b9ac1fa70e4b64829d2c8685d079413..ad73f425987a90f15fd5af91bfb7af6d5126b1d7 100644
--- a/Geo/GFace.cpp
+++ b/Geo/GFace.cpp
@@ -1,4 +1,4 @@
-// $Id: GFace.cpp,v 1.34 2007-05-05 08:12:08 geuzaine Exp $
+// $Id: GFace.cpp,v 1.35 2007-08-03 00:44:28 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -513,3 +513,31 @@ SPoint2 GFace::parFromPoint(const SPoint3 &p) const
   return SPoint2(U,V);
 }
 
+void GFace::computeGraphicsRep(int nu, int nv)
+{
+  _graphicsRep.resize(nu);
+  for(unsigned int i = 0; i < nu; i++) _graphicsRep[i].resize(nv);
+
+  Range<double> ubounds = parBounds(0);
+  Range<double> vbounds = parBounds(1);
+  double umin = ubounds.low(), umax = ubounds.high();
+  double vmin = vbounds.low(), vmax = vbounds.high();
+
+  for(int i = 0; i < nu; i++){
+    for(int j = 0; j < nv; j++){
+      double u = umin + (double)i/(double)(nu-1) * (umax - umin);
+      double v = vmin + (double)j/(double)(nv-1) * (vmax - vmin);
+      struct graphics_point gp;
+      GPoint p = point(u, v);
+      gp.xyz[0] = p.x();
+      gp.xyz[1] = p.y();
+      gp.xyz[2] = p.z();
+      SVector3 n = normal(SPoint2(u, v));
+      gp.n[0] = n.x();
+      gp.n[1] = n.y();
+      gp.n[2] = n.z();
+      _graphicsRep[i][j] = gp;
+    }
+  }
+
+}
diff --git a/Geo/GFace.h b/Geo/GFace.h
index 03c453cd5ff60b15a86230a93c38a6bbf865106f..bb36a2ad9b9137c1b54d9670f2b82c340a3487a1 100644
--- a/Geo/GFace.h
+++ b/Geo/GFace.h
@@ -37,11 +37,22 @@ struct mean_plane
   double x, y, z;
 };
 
+struct graphics_point
+{
+  float xyz[3];
+  float n[3];
+};
+
 class GRegion;
 
 // A model face. 
 class GFace : public GEntity 
 {
+ private:
+  // a graphical representation for topologically simple surfaces: a
+  // 2D array of points/normals
+  std::vector<std::vector<graphics_point> > _graphicsRep;
+
  protected: 
   // edge loops, will replace what follows
   // list of al the edges of the face
@@ -141,6 +152,8 @@ class GFace : public GEntity
   // Resets the mesh attributes to default values
   virtual void resetMeshAttributes();
 
+  std::vector<graphics_point> _graphicsRepresentation;
+
   struct {
     // do we recombine the triangles of the mesh ?
     int recombine;
@@ -162,6 +175,12 @@ class GFace : public GEntity
   // of start/end points
   std::vector<SPoint3> cross;
 
+  // fill the graphics representation
+  void computeGraphicsRep(int nu, int nv);
+
+  // fill the graphics representation
+  std::vector<std::vector<graphics_point> > &getGraphicsRep(){ return _graphicsRep;}
+
   // a array for accessing the transfinite vertices using a pair of
   // indices
   std::vector<std::vector<MVertex*> > transfinite_vertices;
diff --git a/Graphics/Geom.cpp b/Graphics/Geom.cpp
index 815b9ccecc2f9f53ca1ad739828360eeb2cd8cea..9b1727eb52a87e01f50c3ca9459e1596aee148fe 100644
--- a/Graphics/Geom.cpp
+++ b/Graphics/Geom.cpp
@@ -1,4 +1,4 @@
-// $Id: Geom.cpp,v 1.133 2007-08-02 22:28:06 geuzaine Exp $
+// $Id: Geom.cpp,v 1.134 2007-08-03 00:44:28 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -243,83 +243,44 @@ class drawGFace {
     }
   }
   
-  void _drawProjectionGFace(GFace *f)
+  void _drawParametricGFace(GFace *f)
   {
-    Range<double> ubounds = f->parBounds(0);
-    Range<double> vbounds = f->parBounds(1);
-    double umin = ubounds.low(), umax = ubounds.high();
-    double vmin = vbounds.low(), vmax = vbounds.high();
-    const int N = 25;
-    
-    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-    //glEnable(GL_LIGHTING);
-    //glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
-    glColor4ubv((GLubyte *) & CTX.color.geom.selection);
-    glBegin(GL_QUADS);
-    for(int i = 1; i < N; i++){
-      for(int j = 1; j < N; j++){
-    	double u1 = umin + (double)i/(double)(N-1) * (umax - umin);
-	double v1 = vmin + (double)j/(double)(N-1) * (vmax - vmin);
-    	double u2 = umin + (double)(i-1)/(double)(N-1) * (umax - umin);
-	double v2 = vmin + (double)(j-1)/(double)(N-1) * (vmax - vmin);
-	GPoint p1 = f->point(u1, v1);
-	GPoint p2 = f->point(u2, v1);
-	GPoint p3 = f->point(u2, v2);
-	GPoint p4 = f->point(u1, v2);
-	//SVector3 n1 = f->normal(SPoint2(u1, v1));
-	//SVector3 n2 = f->normal(SPoint2(u2, v1));
-	//SVector3 n3 = f->normal(SPoint2(u2, v2));
-	//SVector3 n4 = f->normal(SPoint2(u1, v2));
-	//glNormal3d(n1.x(), n1.y(), n1.z());
-	glVertex3d(p1.x(), p1.y(), p1.z());
-	//glNormal3d(n2.x(), n2.y(), n2.z());
-	glVertex3d(p2.x(), p2.y(), p2.z());
-	//glNormal3d(n3.x(), n3.y(), n3.z());
-	glVertex3d(p3.x(), p3.y(), p3.z());
-	//glNormal3d(n4.x(), n4.y(), n4.z());
-	glVertex3d(p4.x(), p4.y(), p4.z());
-      }
+    std::vector<std::vector<graphics_point> > &gr(f->getGraphicsRep());
+
+    const int N = 64;
+
+    // We create data here and the routine is not designed to be
+    // reentrant, so we must lock it to avoid race conditions when
+    // redraw events are fired in rapid succession
+   
+    if(gr.size() != N && !CTX.threads_lock) {
+      CTX.threads_lock = 1; 
+      f->computeGraphicsRep(N, N);
+      CTX.threads_lock = 0;
     }
-    glEnd();
-    //glDisable(GL_LIGHTING);
-    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-  }
 
-  void _drawParametricGFace(GFace *f)
-  {
-    Range<double> ubounds = f->parBounds(0);
-    Range<double> vbounds = f->parBounds(1);
-    double umin = ubounds.low(), umax = ubounds.high();
-    double vmin = vbounds.low(), vmax = vbounds.high();
-    const int N = 40;
-    
-    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+    if(gr.size() != N) return;
+
+    if(f->geomType() == GEntity::ProjectionFace)
+      glColor4ubv((GLubyte *) & CTX.color.geom.selection);
+
+    if(CTX.geom.surface_type > 0)
+      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    else
+      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
     glEnable(GL_LIGHTING);
-    glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
-    glColor4ubv((GLubyte *) & CTX.color.geom.selection);
     glBegin(GL_QUADS);
-    for(int i = 1; i < N; i++){
-      for(int j = 1; j < N; j++){
-    	double u1 = umin + (double)i/(double)(N-1) * (umax - umin);
-	double v1 = vmin + (double)j/(double)(N-1) * (vmax - vmin);
-    	double u2 = umin + (double)(i-1)/(double)(N-1) * (umax - umin);
-	double v2 = vmin + (double)(j-1)/(double)(N-1) * (vmax - vmin);
-	GPoint p1 = f->point(u1, v1);
-	GPoint p2 = f->point(u2, v1);
-	GPoint p3 = f->point(u2, v2);
-	GPoint p4 = f->point(u1, v2);
-	SVector3 n1 = f->normal(SPoint2(u1, v1));
-	SVector3 n2 = f->normal(SPoint2(u2, v1));
-	SVector3 n3 = f->normal(SPoint2(u2, v2));
-	SVector3 n4 = f->normal(SPoint2(u1, v2));
-	glNormal3d(n1.x(), n1.y(), n1.z());
-	glVertex3d(p1.x(), p1.y(), p1.z());
-	glNormal3d(n2.x(), n2.y(), n2.z());
-	glVertex3d(p2.x(), p2.y(), p2.z());
-	glNormal3d(n3.x(), n3.y(), n3.z());
-	glVertex3d(p3.x(), p3.y(), p3.z());
-	glNormal3d(n4.x(), n4.y(), n4.z());
-	glVertex3d(p4.x(), p4.y(), p4.z());
+    for(unsigned int i = 1; i < gr.size(); i++){
+      for(unsigned int j = 1; j < gr[0].size(); j++){
+        glNormal3fv(gr[i - 1][j - 1].n);
+        glVertex3fv(gr[i - 1][j - 1].xyz);
+        glNormal3fv(gr[i    ][j - 1].n);
+        glVertex3fv(gr[i    ][j - 1].xyz);
+        glNormal3fv(gr[i    ][j    ].n);
+        glVertex3fv(gr[i    ][j    ].xyz);
+        glNormal3fv(gr[i - 1][j    ].n);
+        glVertex3fv(gr[i - 1][j    ].xyz);
       }
     }
     glEnd();
@@ -450,9 +411,8 @@ public :
 
     if(f->geomType() == GEntity::Plane)
       _drawPlaneGFace(f);
-    else if(f->geomType() == GEntity::ProjectionFace)
-      _drawProjectionGFace(f);
-    else if(f->geomType() == GEntity::ParametricSurface)
+    else if(f->geomType() == GEntity::ProjectionFace ||
+	    f->geomType() == GEntity::ParametricSurface)
       _drawParametricGFace(f);
     else
       _drawNonPlaneGFace(f);
diff --git a/contrib/FourierModel/RevolvedParabolaProjectionSurface.cpp b/contrib/FourierModel/RevolvedParabolaProjectionSurface.cpp
index caaa55106120e2d7e687abd2fc950883a5640189..33a988015091b4fa1c4dd88f6287e8992b3c4006 100755
--- a/contrib/FourierModel/RevolvedParabolaProjectionSurface.cpp
+++ b/contrib/FourierModel/RevolvedParabolaProjectionSurface.cpp
@@ -225,20 +225,6 @@ bool RevolvedParabolaProjectionSurface::OrthoProjectionOnSurface
     return false;
 }
 
-void RevolvedParabolaProjectionSurface::GetNormal
-(double u, double v, double &x, double &y, double &z)
-{
-  x = - 2. * K_[1] * (v - 0.5) * 
-    (E1_[0] * cos(twoPi_ * (u - 0.5)) + E2_[0] * sin(twoPi_ * (u - 0.5))) + 
-    K_[0] * E0_[0];
-  y = - 2. * K_[1] * (v - 0.5) *
-    (E1_[1] * cos(twoPi_ * (u - 0.5)) + E2_[1] * sin(twoPi_ * (u - 0.5))) +
-    K_[0] * E0_[1];
-  z = - 2. * K_[1] * (v - 0.5) *
-    (E1_[2] * cos(twoPi_ * (u - 0.5)) + E2_[2] * sin(twoPi_ * (u - 0.5))) +
-    K_[0] * E0_[2];
-}
-
 void RevolvedParabolaProjectionSurface::
 SetParameter(int i, double x)
 {
diff --git a/contrib/FourierModel/RevolvedParabolaProjectionSurface.h b/contrib/FourierModel/RevolvedParabolaProjectionSurface.h
index 1beb120659f01b251b63c67f00ea1e193b64ee14..a8d720b5447ae4739ed6ba0b87b723b5a8b09255 100755
--- a/contrib/FourierModel/RevolvedParabolaProjectionSurface.h
+++ b/contrib/FourierModel/RevolvedParabolaProjectionSurface.h
@@ -52,11 +52,6 @@ class RevolvedParabolaProjectionSurface : public ProjectionSurface {
     (int i);
   virtual std::string GetLabel
     (int i);
-
-  // Redefinitions for RevolvedParabolaProjectionSurface
-
-  virtual void GetNormal
-    (double u, double v, double &x, double &y, double &z);
 };
 
 #endif