diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 5afc611cf9217c9a15bc90b839cabe09c1377634..b0aeaafcb91a350c65e1df0a1670d812044d4b73 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.117 2002-04-13 05:49:50 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.118 2002-04-23 23:07:23 geuzaine Exp $
 
 #include <sys/types.h>
 #include <signal.h>
@@ -322,6 +322,11 @@ void file_save_as_gref_cb(CALLBACK_ARGS) {
     CreateOutputFile(file_chooser_get_name(1),
 		     CTX.print.format = CTX.mesh.format = FORMAT_GREF); 
 }
+void file_save_as_vrml_cb(CALLBACK_ARGS) {
+  if(file_chooser(0,"Save VRML file", "*"))
+    CreateOutputFile(file_chooser_get_name(1),
+		     CTX.print.format = CTX.mesh.format = FORMAT_VRML); 
+}
 void file_save_as_ps_simple_cb(CALLBACK_ARGS) {
   if(file_chooser(0,"Save PS file", "*")){
     int old = CTX.print.eps_quality;
diff --git a/Fltk/Callbacks.h b/Fltk/Callbacks.h
index 733b0364bb3606bb7de0c769ff621a5607fd3362..3c02cf672f8464920f27895268c9218ca118727e 100644
--- a/Fltk/Callbacks.h
+++ b/Fltk/Callbacks.h
@@ -31,6 +31,7 @@ void file_save_as_msh_cb(CALLBACK_ARGS) ;
 void file_save_as_msh_all_cb(CALLBACK_ARGS) ;
 void file_save_as_unv_cb(CALLBACK_ARGS) ;
 void file_save_as_gref_cb(CALLBACK_ARGS) ;
+void file_save_as_vrml_cb(CALLBACK_ARGS) ;
 void file_save_as_ps_simple_cb(CALLBACK_ARGS) ;
 void file_save_as_ps_accurate_cb(CALLBACK_ARGS) ;
 void file_save_as_pstex_simple_cb(CALLBACK_ARGS) ;
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index e5d31aad62c41c2d0e24050471841176365583e4..02d4c4a810d9effb3c6b0b58e06e5fa6e252770f 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.164 2002-04-12 23:59:22 geuzaine Exp $
+// $Id: GUI.cpp,v 1.165 2002-04-23 23:07:23 geuzaine Exp $
 
 // To make the interface as visually consistent as possible, please:
 // - use the IW, BB, BH, BW and WB values
@@ -64,6 +64,7 @@ Fl_Menu_Item m_menubar_table[] = {
          {"Gmsh mesh format, all elements...", 0, (Fl_Callback *)file_save_as_msh_all_cb, 0},
          {"Universal mesh format (unv)...",    0, (Fl_Callback *)file_save_as_unv_cb, 0},
          {"Gref mesh format (gref)...",        0, (Fl_Callback *)file_save_as_gref_cb, 0},
+         {"Vrml surface mesh (wrl)...",        0, (Fl_Callback *)file_save_as_vrml_cb, 0},
          {0},
       {"Image",  0, 0, 0, FL_SUBMENU},
          {"PostScript, fast (ps)...",  0, (Fl_Callback *)file_save_as_ps_simple_cb, 0},
diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp
index 8582555efeca8002b1eef76f123b0419c7c4d940..7579786184ed4abbef3239cef23d8d529cb9df6d 100644
--- a/Graphics/CreateFile.cpp
+++ b/Graphics/CreateFile.cpp
@@ -1,4 +1,4 @@
-// $Id: CreateFile.cpp,v 1.26 2001-11-19 13:48:19 geuzaine Exp $
+// $Id: CreateFile.cpp,v 1.27 2002-04-23 23:07:23 geuzaine Exp $
 
 #include "Gmsh.h"
 #include "GmshUI.h"
@@ -59,6 +59,7 @@ void CreateOutputFile (char *name, int format) {
     else if(!strcmp(ext,".yuv")) CreateOutputFile(name, FORMAT_YUV);
     else if(!strcmp(ext,".gref")) CreateOutputFile(name, FORMAT_GREF);
     else if(!strcmp(ext,".Gref")) CreateOutputFile(name, FORMAT_GREF);
+    else if(!strcmp(ext,".wrl")) CreateOutputFile(name, FORMAT_VRML);
     else Msg(GERROR, "Unknown extension '%s' for automatic format detection", ext);
     break;
 
@@ -82,6 +83,10 @@ void CreateOutputFile (char *name, int format) {
     Print_Mesh(&M, name, FORMAT_GREF); 
     break;
 
+  case FORMAT_VRML :
+    Print_Mesh(&M, name, FORMAT_VRML); 
+    break;
+
   case FORMAT_JPEG :
   case FORMAT_JPEGTEX :
     if(!(fp = fopen(name,"wb"))) {
diff --git a/Mesh/Mesh.h b/Mesh/Mesh.h
index 889083dfe31a3a9d421d5d59263e9289c12be613..07cb5fa13a026811449b4a0f343cebee86e6b224 100644
--- a/Mesh/Mesh.h
+++ b/Mesh/Mesh.h
@@ -23,6 +23,7 @@
 #define FORMAT_PSTEX   16
 #define FORMAT_JPEGTEX 17
 #define FORMAT_TEX     18
+#define FORMAT_VRML    19
 
 #define CONV_VALUE    0.8
 
diff --git a/Mesh/Print_Mesh.cpp b/Mesh/Print_Mesh.cpp
index dc5db8a18c399336f604fb6343f7821c053a8860..f4b270ec17a622aa5fbcebb28cada149cd8c6c77 100644
--- a/Mesh/Print_Mesh.cpp
+++ b/Mesh/Print_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: Print_Mesh.cpp,v 1.33 2001-11-29 09:15:30 geuzaine Exp $
+// $Id: Print_Mesh.cpp,v 1.34 2002-04-23 23:07:23 geuzaine Exp $
 
 #include "Gmsh.h"
 #include "Numeric.h"
@@ -1205,6 +1205,78 @@ void EndConsecutiveNodes (Mesh * M){
   List_Delete (ListSurfaces);
 }
 
+/* ------------------------------------------------------------------------ */
+/*  V R M L 1    F O R M A T                                                */
+/* ------------------------------------------------------------------------ */
+
+static FILE *wrlfile;
+static List_T *wrlnodes=NULL;
+
+void print_wrl_node (void *a, void *b){
+  Vertex *V = *(Vertex **) a;
+  fprintf(wrlfile, "%.16g %.16g %.16g,\n",
+	  V->Pos.X * CTX.mesh.scaling_factor, 
+	  V->Pos.Y * CTX.mesh.scaling_factor, 
+	  V->Pos.Z * CTX.mesh.scaling_factor);
+  List_Add(wrlnodes, &V->Num);
+}
+
+void process_wrl_nodes (Mesh * M){
+  if(!wrlnodes)
+    wrlnodes = List_Create(Tree_Size(M->Vertices),100,sizeof(int));
+  else
+    List_Reset(wrlnodes);
+  fprintf (wrlfile, "#VRML V1.0 ascii\n");
+  fprintf (wrlfile, "#created by Gmsh\n");
+  fprintf (wrlfile, "Coordinate3 {\n");
+  fprintf (wrlfile, "  point [\n");
+  Tree_Action(M->Vertices, print_wrl_node);
+  fprintf (wrlfile, "  ]\n");
+  fprintf (wrlfile, "}\n");
+}
+
+void print_wrl_simplex (void *a, void *b){
+  Simplex *S = *(Simplex **) a;
+  int i=0, j;
+  while(S->V[i]){
+    j = List_ISearch(wrlnodes,&S->V[i]->Num,fcmp_int);
+    if(j < 0) 
+      Msg(GERROR, "Unknown node %d in simplex %d", S->V[i]->Num, S->Num);
+    else 
+      fprintf(wrlfile, "%d,", j);
+    i++;
+  }
+  fprintf(wrlfile, "-1,\n");
+}
+
+void print_all_wrl_curves (void *a, void *b){
+  Curve *c = *(Curve**)a;
+  if(c->Num<0) return;
+  fprintf(wrlfile, "DEF Curve%d IndexedLineSet {\n", c->Num);
+  fprintf(wrlfile, "  coordIndex [\n");
+  Tree_Action (c->Simplexes, print_wrl_simplex);
+  fprintf(wrlfile, "  ]\n");
+  fprintf(wrlfile, "}\n");
+}
+
+void print_all_wrl_surfaces (void *a, void *b){
+  Surface *s = *(Surface**)a;
+  fprintf(wrlfile, "DEF Surface%d IndexedFaceSet {\n", s->Num);
+  fprintf(wrlfile, "  coordIndex [\n");
+  Tree_Action (s->Simplexes, print_wrl_simplex);
+  fprintf(wrlfile, "  ]\n");
+  fprintf(wrlfile, "}\n");
+}
+
+void process_wrl_elements (Mesh * M){
+  if(!wrlnodes)
+    Msg(GERROR, "VRML node list does not exist");
+  else{
+    Tree_Action(M->Curves, print_all_wrl_curves);
+    Tree_Action(M->Surfaces, print_all_wrl_surfaces);
+  }
+}
+
 /* ------------------------------------------------------------------------ */
 /*  P r i n t _ M e s h                                                     */
 /* ------------------------------------------------------------------------ */
@@ -1228,6 +1300,20 @@ void Print_Mesh (Mesh * M, char *c, int Type){
     Msg(STATUS2, "Wrote '%s'", name);
     fclose (mshfile);
   }
+  else if (Type == FORMAT_VRML){
+    c ? strcpy (name, c) : strcat (name, ".wrl");
+    wrlfile = fopen (name, "w");
+    if (!wrlfile){
+      Msg(GERROR, "Unable to open file '%s'", name);
+      return;
+    }
+    Msg(INFO, "Writing file '%s'", name);
+    process_wrl_nodes (M);
+    process_wrl_elements (M);
+    Msg(INFO, "VRML ouput complete '%s'", name);
+    Msg(STATUS2, "Wrote '%s'", name);
+    fclose (wrlfile);
+  }
   else if (Type == FORMAT_UNV){
     c ? strcpy (name, c) : strcat (name, ".unv");
     unvfile = fopen (name, "w");