diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 825245ee602eb8e2b7e73b3b553c809f8c3e2d88..9df72bd4921f90acd03d95ac6b49f84277974915 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1349,7 +1349,7 @@ StringXNumber PrintOptions_Number[] = {
   { F|O, "EpsPS3Shading" , opt_print_eps_ps3shading , 0. ,
     "Enable PostScript Level 3 shading" },
   { F|O, "EpsQuality" , opt_print_eps_quality , 1. ,
-    "PostScript/PDF quality (0=bitmap, 1=vector (simple sort), 2=vector (accurate sort)" },
+    "PostScript/PDF quality (0=bitmap, 1=vector (simple sort), 2=vector (accurate sort), 3=vector (unsorted)" },
 
   { F|O, "Format" , opt_print_format , FORMAT_AUTO , 
     "File format (10=automatic)" }, 
diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 51dd647f5c41423120019feb5da9b2240c6c3c06..f09eacc03e71f23790f7bd4951ff3a1cb5b5753d 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -28,6 +28,7 @@
 #define FORMAT_LC            26
 #define FORMAT_STL           27
 #define FORMAT_P3D           28
+#define FORMAT_SVG           29
 
 #define CONV_VALUE    0.8
 
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 330198107e6c214b4c897dd02920c57473a28cd9..03a6b3b43db2e7bb93cf1fbc843f1777a1c4ee90 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.419 2006-07-14 12:17:05 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.420 2006-07-24 14:05:50 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -704,6 +704,11 @@ int _save_pdftex(char *name)
   return gl2ps_dialog(name, "PDF Options", 2, 1);
 }
 
+int _save_svg(char *name)
+{
+  return gl2ps_dialog(name, "SVG Options", 3, 0);
+}
+
 int _save_jpegtex(char *name)
 {
   return jpeg_dialog(name, 1);
@@ -759,6 +764,7 @@ int _save_auto(char *name)
   case FORMAT_EPSTEX  : return _save_epstex(name);
   case FORMAT_PDF     : return _save_pdf(name);
   case FORMAT_PDFTEX  : return _save_pdftex(name);
+  case FORMAT_SVG     : return _save_svg(name);
   case FORMAT_JPEGTEX : return _save_jpegtex(name);
   case FORMAT_JPEG    : return _save_jpeg(name);
   case FORMAT_GIF     : return _save_gif(name);
@@ -778,7 +784,7 @@ void file_save_as_cb(CALLBACK_ARGS)
   int i, nbformats;
   static char *pat = NULL;
   static patXfunc formats[] = {
-    {"By extension (*)", _save_auto},
+    {"Guess from extension (*.*)", _save_auto},
     {"Gmsh options (*.opt)", _save_options},
     {"Gmsh unrolled geometry (*.geo)", _save_geo},
     {"Gmsh mesh (*.msh)", _save_msh},
@@ -795,18 +801,19 @@ void file_save_as_cb(CALLBACK_ARGS)
 #if defined(HAVE_LIBPNG)
     {"PNG (*.png)", _save_png},
 #endif
-    {"PS (*.ps)", _save_ps},
-    {"EPS (*.eps)", _save_eps},
+    {"PostScript (*.ps)", _save_ps},
+    {"Encapsulated PostScript (*.eps)", _save_eps},
     {"PDF (*.pdf)", _save_pdf},
+    {"SVG (*.svg)", _save_svg},
     {"PPM (*.ppm)", _save_ppm},
 #if defined(HAVE_LIBJPEG)
-    {"LaTeX JPEG part w/o text (*.jpg)", _save_jpegtex},
+    {"LaTeX JPEG part without text (*.jpg)", _save_jpegtex},
 #endif
 #if defined(HAVE_LIBPNG)
-    {"LaTeX PNG part w/o text (*.png)", _save_pngtex},
+    {"LaTeX PNG part without text (*.png)", _save_pngtex},
 #endif
-    {"LaTeX EPS part w/o text (*.eps)", _save_epstex},
-    {"LaTeX PDF part w/o text (*.pdf)", _save_pdftex},
+    {"LaTeX EPS part without text (*.eps)", _save_epstex},
+    {"LaTeX PDF part without text (*.pdf)", _save_pdftex},
     {"LaTeX text part (*.tex)", _save_tex},
     {"YUV (*.yuv)", _save_yuv}
   };
diff --git a/Fltk/GUI_Extras.cpp b/Fltk/GUI_Extras.cpp
index 378cbe734f4581a0e38e93a3ad5d61d16948b9b9..efbbcbcbe931f5272afab014943983cb88c54263 100644
--- a/Fltk/GUI_Extras.cpp
+++ b/Fltk/GUI_Extras.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI_Extras.cpp,v 1.15 2006-04-24 00:26:48 geuzaine Exp $
+// $Id: GUI_Extras.cpp,v 1.16 2006-07-24 14:05:50 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -339,25 +339,38 @@ int gif_dialog(char *name)
 
 // ps/eps/pdf dialog
 
-static void activate_gl2ps_choices(int format, Fl_Check_Button *b[5])
+static void activate_gl2ps_choices(int format, int quality, Fl_Check_Button *b[5])
 {
 #if defined(HAVE_LIBZ)
   b[0]->activate();
 #else
   b[0]->deactivate();
 #endif
-  switch(format){
-  case 0: 
-    b[1]->deactivate(); b[2]->deactivate(); 
-    b[3]->deactivate(); b[4]->deactivate();
+  switch(quality){
+  case 0: // raster
+    b[1]->deactivate(); 
+    b[2]->deactivate(); 
+    b[3]->deactivate(); 
+    b[4]->deactivate();
     break;
-  case 1:
-    b[1]->activate();   b[2]->activate();
-    b[3]->deactivate(); b[4]->activate();
+  case 1: // simple sort
+  case 3: // unsorted
+    b[1]->activate();   
+    b[2]->activate();
+    b[3]->deactivate(); 
+    if(format == 2 || format == 3) // pdf or svg
+      b[4]->deactivate();
+    else
+      b[4]->activate();
     break;
-  case 2:
-    b[1]->activate();   b[2]->activate();
-    b[3]->activate();   b[4]->activate();
+  case 2: // bsp sort
+    b[1]->activate();   
+    b[2]->activate();
+    b[3]->activate();   
+    if(format == 2 || format == 3) // pdf or svg
+      b[4]->deactivate();
+    else
+      b[4]->activate();
     break;
   }
 }
@@ -376,6 +389,7 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX)
     {"Raster image", 0, 0, 0},
     {"Vector simple sort", 0, 0, 0},
     {"Vector accurate sort", 0, 0, 0},
+    {"Vector unsorted", 0, 0, 0},
     {0}
   };
 
@@ -412,7 +426,9 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX)
   dialog->b[2]->value(CTX.print.eps_occlusion_culling);
   dialog->b[3]->value(CTX.print.eps_best_root);
   dialog->b[4]->value(CTX.print.eps_ps3shading);
-  activate_gl2ps_choices(CTX.print.eps_quality, dialog->b);
+
+  activate_gl2ps_choices(format, CTX.print.eps_quality, dialog->b);
+
   dialog->window->show();
 
   while(dialog->window->shown()){
@@ -422,7 +438,7 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX)
       if (!o) break;
 
       if (o == dialog->c){
-	activate_gl2ps_choices(dialog->c->value(), dialog->b);
+	activate_gl2ps_choices(format, dialog->c->value(), dialog->b);
       }
       if (o == dialog->ok) {
 	opt_print_eps_quality(0, GMSH_SET | GMSH_GUI, dialog->c->value());
@@ -432,6 +448,7 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX)
 	opt_print_eps_best_root(0, GMSH_SET | GMSH_GUI, dialog->b[3]->value());
 	opt_print_eps_ps3shading(0, GMSH_SET | GMSH_GUI, dialog->b[4]->value());
 	CreateOutputFile(name, 
+			 (format == 3) ? FORMAT_SVG :
 			 (format == 2) ? (TeX ? FORMAT_PDFTEX : FORMAT_PDF) : 
 			 (format == 1) ? (TeX ? FORMAT_EPSTEX : FORMAT_EPS) : 
 			 FORMAT_PS);
diff --git a/Geo/gmshEdge.cpp b/Geo/gmshEdge.cpp
index 478650250a56d7299ced3905062769dd49e0b40a..e5a954f34a3547b7af80359a001afc95f0946098 100644
--- a/Geo/gmshEdge.cpp
+++ b/Geo/gmshEdge.cpp
@@ -145,5 +145,8 @@ int gmshEdge::minimumMeshSegments () const
 
 int gmshEdge::minimumDrawSegments () const
 {
-  return CTX.geom.circle_points;
+  if(geomType() == Line)
+    return GEdge::minimumDrawSegments () ;
+  else
+    return CTX.geom.circle_points;
 }
diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp
index e023b841559c7318ec9e17025d277ffd0ee29853..4981a1ea8f5ee547c819bfe8d59286329d035a53 100644
--- a/Graphics/CreateFile.cpp
+++ b/Graphics/CreateFile.cpp
@@ -1,4 +1,4 @@
-// $Id: CreateFile.cpp,v 1.82 2006-07-14 12:17:06 geuzaine Exp $
+// $Id: CreateFile.cpp,v 1.83 2006-07-24 14:05:50 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -68,6 +68,7 @@ int GuessFileFormatFromFileName(char *name)
   else if(!strcmp(ext, ".epstex"))  return FORMAT_EPSTEX;
   else if(!strcmp(ext, ".pdftex"))  return FORMAT_PDFTEX;
   else if(!strcmp(ext, ".jpegtex")) return FORMAT_JPEGTEX;
+  else if(!strcmp(ext, ".svg"))     return FORMAT_SVG;
   else if(!strcmp(ext, ".ppm"))     return FORMAT_PPM;
   else if(!strcmp(ext, ".yuv"))     return FORMAT_YUV;
   else if(!strcmp(ext, ".gref"))    return FORMAT_GREF;
@@ -91,6 +92,7 @@ char *GetStringForFileFormat(int format)
   case FORMAT_EPSTEX: return "EPS";
   case FORMAT_PDF: return "PDF";
   case FORMAT_PDFTEX: return "PDF";
+  case FORMAT_SVG: return "SVG";
   default: return "";
   }
 }
@@ -151,13 +153,16 @@ void CreateOutputFile(char *name, int format)
 	return;
       }
 
+      PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE);
+
+      int old_bg_gradient = CTX.bg_gradient;
+      if(format == FORMAT_GIF && CTX.print.gif_transparent)
+	CTX.bg_gradient = 0;
       if(format == FORMAT_JPEGTEX || format == FORMAT_PNGTEX)
 	CTX.print.gl_fonts = 0;
-
-      PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE);
       buffer.Fill(CTX.batch);
-
       CTX.print.gl_fonts = 1;
+      CTX.bg_gradient = old_bg_gradient;
 
       Msg(INFO, "Writing %s file '%s'", GetStringForFileFormat(format), name);
       if(format == FORMAT_PPM){
@@ -194,6 +199,7 @@ void CreateOutputFile(char *name, int format)
   case FORMAT_EPSTEX:
   case FORMAT_PDF:
   case FORMAT_PDFTEX:
+  case FORMAT_SVG:
     {
       FILE *fp;
       if(!(fp = fopen(name, "wb"))) {
@@ -210,10 +216,16 @@ void CreateOutputFile(char *name, int format)
       case FORMAT_PS:
 	psformat = GL2PS_PS;
 	break;
+      case FORMAT_SVG:
+	psformat = GL2PS_SVG;
+	break;
       default:
 	psformat = GL2PS_EPS;
 	break;
       }
+
+      int old_bg_gradient = CTX.bg_gradient;
+      if(!CTX.print.eps_background) CTX.bg_gradient = 0;
       
       PixelBuffer buffer(width, height, GL_RGB, GL_FLOAT);
       
@@ -224,9 +236,12 @@ void CreateOutputFile(char *name, int format)
 	CTX.print.gl_fonts = 1;
       }
       
-      int pssort = (CTX.print.eps_quality == 2) ? GL2PS_BSP_SORT : GL2PS_SIMPLE_SORT;
+      int pssort = 
+	(CTX.print.eps_quality == 3) ? GL2PS_NO_SORT :
+	(CTX.print.eps_quality == 2) ? GL2PS_BSP_SORT : 
+	GL2PS_SIMPLE_SORT;
       int psoptions =
-	GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | GL2PS_NO_BLENDING |
+	GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT |
 	(CTX.print.eps_occlusion_culling ? GL2PS_OCCLUSION_CULL : 0) |
 	(CTX.print.eps_best_root ? GL2PS_BEST_ROOT : 0) |
 	(CTX.print.eps_background ? GL2PS_DRAW_BACKGROUND : 0) |
@@ -237,13 +252,13 @@ void CreateOutputFile(char *name, int format)
       
       Msg(INFO, "Writing %s file '%s'", GetStringForFileFormat(format), name);
       
-      GLint size3d = 0;
+      GLint buffsize = 0;
       int res = GL2PS_OVERFLOW;
       while(res == GL2PS_OVERFLOW) {
-	size3d += 2048 * 2048;
+	buffsize += 2048 * 2048;
 	gl2psBeginPage(CTX.base_filename, "Gmsh", viewport, 
 		       psformat, pssort, psoptions, GL_RGBA, 0, NULL, 
-		       15, 20, 10, size3d, fp, name);
+		       15, 20, 10, buffsize, fp, name);
 	if(CTX.print.eps_quality == 0){
 	  double modelview[16], projection[16];
 	  glGetDoublev(GL_PROJECTION_MATRIX, projection);
@@ -269,6 +284,8 @@ void CreateOutputFile(char *name, int format)
 	res = gl2psEndPage();
       }
 
+      CTX.bg_gradient = old_bg_gradient;
+
       Msg(INFO, "Wrote %s file '%s'", GetStringForFileFormat(format), name);
       Msg(STATUS2N, "Wrote '%s'", name);
       fclose(fp);
@@ -283,14 +300,20 @@ void CreateOutputFile(char *name, int format)
 	return;
       }
       Msg(INFO, "Writing TEX file '%s'", name);
-      gl2psBeginPage(CTX.base_filename, "Gmsh", viewport,
-		     GL2PS_TEX, GL2PS_NO_SORT, GL2PS_SILENT, GL_RGBA, 0, NULL, 
-		     0, 0, 0, 1000, fp, name);
-      CTX.print.gl_fonts = 0;
-      PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE);
-      buffer.Fill(CTX.batch);
-      CTX.print.gl_fonts = 1;
-      gl2psEndPage();
+
+      GLint buffsize = 0;
+      int res = GL2PS_OVERFLOW;
+      while(res == GL2PS_OVERFLOW) {
+	buffsize += 2048 * 2048;
+	gl2psBeginPage(CTX.base_filename, "Gmsh", viewport,
+		       GL2PS_TEX, GL2PS_NO_SORT, GL2PS_NONE, GL_RGBA, 0, NULL, 
+		       0, 0, 0, buffsize, fp, name);
+	PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE);
+	CTX.print.gl_fonts = 0;
+	buffer.Fill(CTX.batch);
+	CTX.print.gl_fonts = 1;
+	res = gl2psEndPage();
+      }
       Msg(INFO, "Wrote TEX file '%s'", name);
       Msg(STATUS2N, "Wrote '%s'", name);
       fclose(fp);
@@ -303,4 +326,5 @@ void CreateOutputFile(char *name, int format)
   }
 
   CTX.print.format = oldformat;
+  Draw();
 }
diff --git a/Graphics/Geom.cpp b/Graphics/Geom.cpp
index 6eff60b973fd438bc78738d3661b51bcb3434776..fc5c431287e96182bc4b1da59e2dc76f21e737bd 100644
--- a/Graphics/Geom.cpp
+++ b/Graphics/Geom.cpp
@@ -1,4 +1,4 @@
-// $Id: Geom.cpp,v 1.100 2006-07-14 12:17:06 geuzaine Exp $
+// $Id: Geom.cpp,v 1.101 2006-07-24 14:05:50 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -39,7 +39,7 @@ extern GModel *GMODEL;
 
 // Points
 
-void Draw_Geo_Vertex(GVertex *v)
+void drawGeoVertex(GVertex *v)
 {
   if(!(v->drawAttributes.Visible & VIS_GEOM))
     return;
@@ -105,7 +105,7 @@ void Draw_Geo_Vertex(GVertex *v)
 
 // Curves
 
-void Draw_Geo_Edge(GEdge *c)
+void drawGeoEdge(GEdge *c)
 {
   if(c->tag() < 0 || !(c->drawAttributes.Visible & VIS_GEOM))
     return;
@@ -532,7 +532,7 @@ void Draw_NonPlane_Surface(Surface * s)
   }
 }
 
-void Draw_Geo_Face(GFace *s)
+void drawGeoFace(GFace *s)
 {
   if(!(s->drawAttributes.Visible & VIS_GEOM))
     return;
@@ -573,7 +573,7 @@ void Draw_Geo_Face(GFace *s)
 
 // Volumes
 
-void Draw_Geo_Region(GRegion *v)
+void drawGeoRegion(GRegion *v)
 {
 }
 
@@ -585,19 +585,19 @@ void Draw_Geom()
   
   if(CTX.geom.points || CTX.geom.points_num)
     for(GModel::viter it = GMODEL->firstVertex(); it != GMODEL->lastVertex(); it++)
-      Draw_Geo_Vertex(*it);
+      drawGeoVertex(*it);
 
   if(CTX.geom.lines || CTX.geom.lines_num || CTX.geom.tangents)
     for(GModel::eiter it = GMODEL->firstEdge(); it != GMODEL->lastEdge(); it++)
-      Draw_Geo_Edge(*it);
+      drawGeoEdge(*it);
 
   if(CTX.geom.surfaces || CTX.geom.surfaces_num || CTX.geom.normals)
     for(GModel::fiter it = GMODEL->firstFace(); it != GMODEL->lastFace(); it++)
-      Draw_Geo_Face(*it);
+      drawGeoFace(*it);
 
   if(CTX.geom.volumes || CTX.geom.volumes_num)
     for(GModel::riter it = GMODEL->firstRegion(); it != GMODEL->lastRegion(); it++)
-      Draw_Geo_Region(*it);
+      drawGeoRegion(*it);
 }
 
 // Highlight routines (Note: in Gmsh < 1.61, we used to draw permanent
diff --git a/Graphics/gl2ps.cpp b/Graphics/gl2ps.cpp
index 86d290e4e245c84ddfa1ff62ae62c5efaa740b9c..4dbfc499722aa05faf3c4299b70115a999812682 100644
--- a/Graphics/gl2ps.cpp
+++ b/Graphics/gl2ps.cpp
@@ -1,4 +1,4 @@
-/* $Id: gl2ps.cpp,v 1.104 2006-02-27 18:39:45 geuzaine Exp $ */
+/* $Id: gl2ps.cpp,v 1.105 2006-07-24 14:05:50 geuzaine Exp $ */
 /*
  * GL2PS, an OpenGL to PostScript Printing Library
  * Copyright (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>
@@ -47,6 +47,8 @@
  *   Olivier Couet <couet@mail.cern.ch>
  *   Shai Ayal <shaiay@gmail.com>
  *   Fabian Wenzel <wenzel@tu-harburg.de>
+ *   Ian D. Gay <gay@sfu.ca>
+ *   Cosmin Truta and Baiju Devani <cosmin@cs.toronto.edu>
  *
  * For the latest info about gl2ps, see http://www.geuz.org/gl2ps/.
  * Please report all bugs and problems to <gl2ps@geuz.org>.
@@ -61,6 +63,14 @@
 #include <time.h>
 #include <float.h>
 
+#if defined(GL2PS_HAVE_ZLIB)
+#include <zlib.h>
+#endif
+
+#if defined(GL2PS_HAVE_LIBPNG)
+#include <png.h>
+#endif
+
 /********************************************************************* 
  *
  * Private definitions, data structures and prototypes
@@ -78,7 +88,7 @@
 
 /* Primitive types */
 
-#define GL2PS_NOTYPE          -1
+#define GL2PS_NO_TYPE          -1
 #define GL2PS_TEXT             1
 #define GL2PS_POINT            2
 #define GL2PS_LINE             3
@@ -88,6 +98,7 @@
 #define GL2PS_IMAGEMAP         7
 #define GL2PS_IMAGEMAP_WRITTEN 8
 #define GL2PS_IMAGEMAP_VISIBLE 9
+#define GL2PS_SPECIAL          10
 
 /* BSP tree primitive comparison */
 
@@ -102,21 +113,24 @@
 #define GL2PS_POINT_INFRONT    1
 #define GL2PS_POINT_BACK       2
 
-/* Pass through options */
-
-#define GL2PS_BEGIN_POLYGON_OFFSET_FILL 1
-#define GL2PS_END_POLYGON_OFFSET_FILL   2
-#define GL2PS_BEGIN_POLYGON_BOUNDARY    3
-#define GL2PS_END_POLYGON_BOUNDARY      4
-#define GL2PS_BEGIN_LINE_STIPPLE        5
-#define GL2PS_END_LINE_STIPPLE          6
-#define GL2PS_SET_POINT_SIZE            7
-#define GL2PS_SET_LINE_WIDTH            8
-#define GL2PS_BEGIN_BLEND               9
-#define GL2PS_END_BLEND                10
-#define GL2PS_SRC_BLEND                11
-#define GL2PS_DST_BLEND                12
-#define GL2PS_DRAW_IMAGEMAP_TOKEN      13
+/* Internal feedback buffer pass-through tokens */
+
+#define GL2PS_BEGIN_OFFSET_TOKEN   1
+#define GL2PS_END_OFFSET_TOKEN     2
+#define GL2PS_BEGIN_BOUNDARY_TOKEN 3
+#define GL2PS_END_BOUNDARY_TOKEN   4
+#define GL2PS_BEGIN_STIPPLE_TOKEN  5
+#define GL2PS_END_STIPPLE_TOKEN    6
+#define GL2PS_POINT_SIZE_TOKEN     7
+#define GL2PS_LINE_WIDTH_TOKEN     8
+#define GL2PS_BEGIN_BLEND_TOKEN    9
+#define GL2PS_END_BLEND_TOKEN      10
+#define GL2PS_SRC_BLEND_TOKEN      11
+#define GL2PS_DST_BLEND_TOKEN      12
+#define GL2PS_IMAGEMAP_TOKEN       13
+#define GL2PS_DRAW_PIXELS_TOKEN    14
+#define GL2PS_TEXT_TOKEN           15
+#define GL2PS_SPECIAL_TOKEN        16
 
 typedef enum {
   T_UNDEFINED    = -1,
@@ -163,15 +177,17 @@ typedef struct {
 typedef struct {
   GLshort fontsize;
   char *str, *fontname;
+  /* Note: for a 'special' string, 'alignment' holds the format
+     (PostScript, PDF, etc.) of the special string */
   GLint alignment;
   GLfloat angle;
 } GL2PSstring;
 
-/* FIXME: in the case of an image map, "type" indicates if this image
-   map has already been written to the PostScript file or not, and
-   "format" indicates if this image map is visible or not */
 typedef struct {
   GLsizei width, height;
+  /* Note: for an imagemap, 'type' indicates if it has already been
+     written to the file or not, and 'format' indicates if it is
+     visible or not */
   GLenum format, type;
   GLfloat *pixels;
 } GL2PSimage;
@@ -197,7 +213,7 @@ typedef struct {
 } GL2PSprimitive;
 
 typedef struct {
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   Bytef *dest, *src, *start;
   uLongf destLen, srcLen;
 #else
@@ -221,7 +237,7 @@ typedef struct {
   GL2PSrgba *colormap, lastrgba, threshold, bgcolor;
   GLushort lastpattern;
   GL2PSvertex lastvertex;
-  GL2PSlist *primitives;
+  GL2PSlist *primitives, *auxprimitives;
   FILE *stream;
   GL2PScompress *compress;
   GLboolean header;
@@ -267,7 +283,7 @@ typedef struct {
 
 static GL2PScontext *gl2ps = NULL;
 
-/* Need to forward declare this one */
+/* Need to forward-declare this one */
 
 static GLint gl2psPrintPrimitives(void);
 
@@ -277,7 +293,7 @@ static GLint gl2psPrintPrimitives(void);
  *
  *********************************************************************/
 
-static void gl2psMsg(GLint level, char *fmt, ...)
+static void gl2psMsg(GLint level, const char *fmt, ...)
 {
   va_list args;
 
@@ -325,9 +341,19 @@ static void gl2psFree(void *ptr)
   free(ptr);
 }
 
+static size_t gl2psWriteBigEndian(unsigned long data, size_t bytes)
+{
+  size_t i;
+  size_t size = sizeof(unsigned long);
+  for(i = 1; i <= bytes; ++i){
+    fputc(0xff & (data >> (size-i) * 8), gl2ps->stream);
+  }
+  return bytes;
+}
+
 /* zlib compression helper routines */
 
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
 
 static void gl2psSetupCompress(void)
 {
@@ -413,7 +439,7 @@ static int gl2psPrintf(const char* fmt, ...)
   int ret;
   va_list args;
 
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   unsigned int oldsize = 0;
   static char buf[1000];
   if(gl2ps->options & GL2PS_COMPRESS){
@@ -430,72 +456,68 @@ static int gl2psPrintf(const char* fmt, ...)
     va_start(args, fmt);
     ret = vfprintf(gl2ps->stream, fmt, args);
     va_end(args);
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   }
 #endif
   return ret;
 }
 
-static size_t gl2psWriteBigEndian(unsigned long data, size_t bytes)
+static void gl2psPrintGzipHeader()
 {
-  size_t i;
-  size_t size = sizeof(unsigned long);
-  for(i = 1; i <= bytes; ++i){
-    fputc(0xff & (data >> (size-i) * 8), gl2ps->stream);
+#if defined(GL2PS_HAVE_ZLIB)
+  char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */
+                  8, /* compression method: Z_DEFLATED */
+                  0, /* flags */
+                  0, 0, 0, 0, /* time */
+                  2, /* extra flags: max compression */
+                  '\x03'}; /* OS code: 0x03 (Unix) */
+
+  if(gl2ps->options & GL2PS_COMPRESS){
+    gl2psSetupCompress();
+    /* add the gzip file header */
+    fwrite(tmp, 10, 1, gl2ps->stream);
   }
-  return bytes;
+#endif  
 }
 
-static void gl2psAssignTriangleProperties(GL2PStriangle *t)
+static void gl2psPrintGzipFooter()
 {
-  /* int i; */
-
-  t->prop = T_VAR_COLOR;
+#if defined(GL2PS_HAVE_ZLIB)
+  int n;
+  uLong crc, len;
+  char tmp[8];
 
-  /* Uncommenting the following lines activates an even more fine
-     grained distinction between triangle types - please don't delete,
-     a remarkable amount of PDF handling code inside this file depends
-     on it if activated */
-  /*
-  t->prop = T_CONST_COLOR;    
-  for(i = 0; i < 3; ++i){
-    if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || 
-       !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){
-      t->prop = T_VAR_COLOR;
-      break;
+  if(gl2ps->options & GL2PS_COMPRESS){
+    if(Z_OK != gl2psDeflate()){
+      gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
     }
+    else{
+      /* determine the length of the header in the zlib stream */
+      n = 2; /* CMF+FLG */
+      if(gl2ps->compress->dest[1] & (1<<5)){
+        n += 4; /* DICTID */
+      }
+      /* write the data, without the zlib header and footer */
+      fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), 
+             1, gl2ps->stream);
+      /* add the gzip file footer */
+      crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen);
+      for(n = 0; n < 4; ++n){
+        tmp[n] = (char)(crc & 0xff);
+        crc >>= 8;
+      }
+      len = gl2ps->compress->srcLen;
+      for(n = 4; n < 8; ++n){
+        tmp[n] = (char)(len & 0xff);
+        len >>= 8;
+      }
+      fwrite(tmp, 8, 1, gl2ps->stream);
+    }
+    gl2psFreeCompress();
+    gl2psFree(gl2ps->compress);
+    gl2ps->compress = NULL;
   }
-  */
-
-  if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || 
-     !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){
-    t->prop |= T_VAR_ALPHA;
-  }
-  else{
-    if(t->vertex[0].rgba[3] < 1)
-      t->prop |= T_ALPHA_LESS_1;
-    else
-      t->prop |= T_ALPHA_1;
-  }
-}
-
-static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p,
-                                           GLboolean assignprops)
-{
-  t->vertex[0] = p->verts[0];
-  t->vertex[1] = p->verts[1];
-  t->vertex[2] = p->verts[2];
-  if(GL_TRUE == assignprops)
-    gl2psAssignTriangleProperties(t);
-}
-
-static void gl2psInitTriangle(GL2PStriangle *t)
-{
-  int i;
-  GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} };
-  for(i = 0; i < 3; i++)
-    t->vertex[i] = vertex;
-  t->prop = T_UNDEFINED;
+#endif 
 }
 
 /* The list handling routines */
@@ -606,7 +628,133 @@ static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data))
   }
 }
 
-/* Helper for pixmaps and strings */
+#if defined(GL2PS_HAVE_LIBPNG)
+
+static void gl2psListRead(GL2PSlist *list, int index, void *data)
+{
+  if((index < 0) || (index >= list->n))
+    gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead");
+  memcpy(data, &list->array[index * list->size], list->size);
+}
+
+static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len)
+{
+  static const char cb64[] = 
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  out[0] = cb64[ in[0] >> 2 ];
+  out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
+  out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | 
+                                            ((in[2] & 0xc0) >> 6) ] : '=');
+  out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
+}
+
+static void gl2psListEncodeBase64(GL2PSlist *list)
+{
+  unsigned char *buffer, in[3], out[4];
+  int i, n, index, len;
+
+  n = list->n * list->size;
+  buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned int));
+  memcpy(buffer, list->array, n * sizeof(unsigned int));
+  gl2psListReset(list);
+
+  index = 0;
+  while(index < n) {
+    len = 0;
+    for(i = 0; i < 3; i++) {
+      in[i] = buffer[index++];
+      if(index < n)
+        len++;
+      else
+        in[i] = 0;
+    }
+    if(len) {
+      gl2psEncodeBase64Block(in, out, len);
+      for(i = 0; i < 4; i++)
+        gl2psListAdd(list, &out[i]);
+    }
+  }
+  gl2psFree(buffer);
+}
+
+#endif
+
+/* Helpers for rgba colors */
+
+static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2)
+{
+  if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) ||
+     !GL2PS_ZERO(rgba1[1] - rgba2[1]) ||
+     !GL2PS_ZERO(rgba1[2] - rgba2[2]))
+    return GL_FALSE;
+  return GL_TRUE;
+}
+  
+static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim)
+{
+  int i;
+
+  for(i = 1; i < prim->numverts; i++){
+    if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){
+      return GL_FALSE;
+    }
+  }
+  return GL_TRUE;
+}
+
+static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[],
+                                         GL2PSrgba threshold)
+{
+  int i;
+
+  if(n < 2) return GL_TRUE;
+  
+  for(i = 1; i < n; i++){
+    if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] ||
+       fabs(rgba[0][1] - rgba[i][1]) > threshold[1] ||
+       fabs(rgba[0][2] - rgba[i][2]) > threshold[2])
+      return GL_FALSE;
+  }
+  
+  return GL_TRUE;
+}
+
+static void gl2psSetLastColor(GL2PSrgba rgba)
+{
+  int i;        
+  for(i = 0; i < 3; ++i){
+    gl2ps->lastrgba[i] = rgba[i];
+  }
+}
+
+static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y,
+                           GLfloat *red, GLfloat *green, GLfloat *blue)
+{
+  
+  GLsizei width = im->width;
+  GLsizei height = im->height;
+  GLfloat *pixels = im->pixels;
+  GLfloat *pimag;
+
+  /* OpenGL image is from down to up, PS image is up to down */  
+  switch(im->format){
+  case GL_RGBA:
+    pimag = pixels + 4 * (width * (height - 1 - y) + x);
+    break;
+  case GL_RGB:
+  default:
+    pimag = pixels + 3 * (width * (height - 1 - y) + x);
+    break;
+  }
+  *red = *pimag; pimag++;
+  *green = *pimag; pimag++;
+  *blue = *pimag; pimag++;
+
+  return (im->format == GL_RGBA) ? *pimag : 1.0F;
+}
+
+/* Helper routines for pixmaps */
 
 static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im)
 {
@@ -642,117 +790,166 @@ static void gl2psFreePixmap(GL2PSimage *im)
   gl2psFree(im);
 }
 
-static GL2PSstring *gl2psCopyText(GL2PSstring *t)
+#if defined(GL2PS_HAVE_LIBPNG)
+
+#if !defined(png_jmpbuf)
+#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length)
 {
-  GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
-  text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char));
-  strcpy(text->str, t->str); 
-  text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char));
-  strcpy(text->fontname, t->fontname);
-  text->fontsize = t->fontsize;
-  text->alignment = t->alignment;
-  text->angle = t->angle;
-  
-  return text;
+  unsigned int i;
+  GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr);
+  for(i = 0; i < length; i++) 
+    gl2psListAdd(png, &data[i]);
 }
 
-static void gl2psFreeText(GL2PSstring *text)
+static void gl2psUserFlushPNG(png_structp png_ptr)
 {
-  if(!text)
-    return;
-  gl2psFree(text->str);
-  gl2psFree(text->fontname);
-  gl2psFree(text);
 }
 
-static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p)
+static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png)
 {
-  GL2PSprimitive *prim;
+  png_structp png_ptr;
+  png_infop info_ptr;
+  unsigned char *row_data;
+  GLfloat dr, dg, db;
+  int row, col;
 
-  if(!p){
-    gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive");
-    return NULL;
+  if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
+    return;
+  
+  if(!(info_ptr = png_create_info_struct(png_ptr))){
+    png_destroy_write_struct(&png_ptr, NULL);
+    return;
   }
-
-  prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
   
-  prim->type = p->type;
-  prim->numverts = p->numverts;
-  prim->boundary = p->boundary;
-  prim->offset = p->offset;
-  prim->pattern = p->pattern;
-  prim->factor = p->factor;
-  prim->culled = p->culled;
-  prim->width = p->width;
-  prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex));
-  memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex));
-
-  switch(prim->type){
-  case GL2PS_PIXMAP :
-    prim->data.image = gl2psCopyPixmap(p->data.image);
-    break;
-  case GL2PS_TEXT :
-    prim->data.text = gl2psCopyText(p->data.text);
-    break;
-  default:
-    break;
+  if(setjmp(png_jmpbuf(png_ptr))) {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return;
+  }
+  
+  png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG);
+  png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
+  png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, 
+               PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 
+               PNG_FILTER_TYPE_BASE);
+  png_write_info(png_ptr, info_ptr);
+
+  row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char));
+  for(row = 0; row < pixmap->height; row++){
+    for(col = 0; col < pixmap->width; col++){
+      gl2psGetRGB(pixmap, col, row, &dr, &dg, &db);
+      row_data[3*col] = (unsigned char)(255. * dr);
+      row_data[3*col+1] = (unsigned char)(255. * dg);
+      row_data[3*col+2] = (unsigned char)(255. * db);
+    }
+    png_write_row(png_ptr, (png_bytep)row_data);
   }
+  gl2psFree(row_data);
 
-  return prim;
+  png_write_end(png_ptr, info_ptr);
+  png_destroy_write_struct(&png_ptr, &info_ptr);
 }
 
-/* Helpers for rgba colors and PDF blending */
+#endif
 
-static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2)
+/* Helper routines for text strings */
+
+static GLint gl2psAddText(GLint type, const char *str, const char *fontname, 
+                          GLshort fontsize, GLint alignment, GLfloat angle)
 {
-  if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) ||
-     !GL2PS_ZERO(rgba1[1] - rgba2[1]) ||
-     !GL2PS_ZERO(rgba1[2] - rgba2[2]))
-    return GL_FALSE;
-  return GL_TRUE;
+  GLfloat pos[4];
+  GL2PSprimitive *prim;
+  GLboolean valid;
+
+  if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED;
+
+  if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS;
+
+  glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
+  if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
+
+  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
+
+  prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
+  prim->type = type;
+  prim->boundary = 0;
+  prim->numverts = 1;
+  prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
+  prim->verts[0].xyz[0] = pos[0];
+  prim->verts[0].xyz[1] = pos[1];
+  prim->verts[0].xyz[2] = pos[2];
+  prim->culled = 0;
+  prim->offset = 0;
+  prim->pattern = 0;
+  prim->factor = 0;
+  prim->width = 1;
+  glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
+  prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
+  prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char));
+  strcpy(prim->data.text->str, str); 
+  prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char));
+  strcpy(prim->data.text->fontname, fontname);
+  prim->data.text->fontsize = fontsize;
+  prim->data.text->alignment = alignment;
+  prim->data.text->angle = angle;
+
+  gl2psListAdd(gl2ps->auxprimitives, &prim);
+  if(type == GL2PS_TEXT)
+    glPassThrough(GL2PS_TEXT_TOKEN);
+  else
+    glPassThrough(GL2PS_SPECIAL_TOKEN);
+    
+  return GL2PS_SUCCESS;
 }
-  
-static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim)
-{
-  int i;
 
-  for(i = 1; i < prim->numverts; i++){
-    if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){
-      return GL_FALSE;
-    }
-  }
-  return GL_TRUE;
+static GL2PSstring *gl2psCopyText(GL2PSstring *t)
+{
+  GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
+  text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char));
+  strcpy(text->str, t->str); 
+  text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char));
+  strcpy(text->fontname, t->fontname);
+  text->fontsize = t->fontsize;
+  text->alignment = t->alignment;
+  text->angle = t->angle;
+  
+  return text;
 }
 
-static void gl2psSetLastColor(GL2PSrgba rgba)
+static void gl2psFreeText(GL2PSstring *text)
 {
-  int i;        
-  for(i = 0; i < 3; ++i){
-    gl2ps->lastrgba[i] = rgba[i];
-  }
+  if(!text)
+    return;
+  gl2psFree(text->str);
+  gl2psFree(text->fontname);
+  gl2psFree(text);
 }
 
-/* returns TRUE if gl2ps supports the argument combination: only two
-   blending modes have been implemented so far */
+/* Helpers for blending modes */
 
 static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor)
 {
+  /* returns TRUE if gl2ps supports the argument combination: only two
+     blending modes have been implemented so far */
+
   if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || 
       (sfactor == GL_ONE && dfactor == GL_ZERO) )
     return GL_TRUE;
   return GL_FALSE;
 }
 
-/* Transforms vertex depending on the actual blending function -
-   currently the vertex v is considered as source vertex and his alpha
-   value is changed to 1.0 if source blending GL_ONE is active. This
-   might be extended in the future */
-
 static void gl2psAdaptVertexForBlending(GL2PSvertex *v)
 {
+  /* Transforms vertex depending on the actual blending function -
+     currently the vertex v is considered as source vertex and his
+     alpha value is changed to 1.0 if source blending GL_ONE is
+     active. This might be extended in the future */
+
   if(!v || !gl2ps)
     return;
-  
+
   if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
     v->rgba[3] = 1.0F;
     return;
@@ -767,30 +964,95 @@ static void gl2psAdaptVertexForBlending(GL2PSvertex *v)
   }
 }
 
-static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y,
-                           GLfloat *red, GLfloat *green, GLfloat *blue)
+static void gl2psAssignTriangleProperties(GL2PStriangle *t)
+{
+  /* int i; */
+
+  t->prop = T_VAR_COLOR;
+
+  /* Uncommenting the following lines activates an even more fine
+     grained distinction between triangle types - please don't delete,
+     a remarkable amount of PDF handling code inside this file depends
+     on it if activated */
+  /*
+  t->prop = T_CONST_COLOR;    
+  for(i = 0; i < 3; ++i){
+    if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || 
+       !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){
+      t->prop = T_VAR_COLOR;
+      break;
+    }
+  }
+  */
+
+  if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || 
+     !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){
+    t->prop |= T_VAR_ALPHA;
+  }
+  else{
+    if(t->vertex[0].rgba[3] < 1)
+      t->prop |= T_ALPHA_LESS_1;
+    else
+      t->prop |= T_ALPHA_1;
+  }
+}
+
+static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p,
+                                           GLboolean assignprops)
+{
+  t->vertex[0] = p->verts[0];
+  t->vertex[1] = p->verts[1];
+  t->vertex[2] = p->verts[2];
+  if(GL_TRUE == assignprops)
+    gl2psAssignTriangleProperties(t);
+}
+
+static void gl2psInitTriangle(GL2PStriangle *t)
+{
+  int i;
+  GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} };
+  for(i = 0; i < 3; i++)
+    t->vertex[i] = vertex;
+  t->prop = T_UNDEFINED;
+}
+
+/* Miscellaneous helper routines */
+
+static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p)
 {
+  GL2PSprimitive *prim;
+
+  if(!p){
+    gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive");
+    return NULL;
+  }
+
+  prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
   
-  GLsizei width = im->width;
-  GLsizei height = im->height;
-  GLfloat *pixels = im->pixels;
-  GLfloat *pimag;
+  prim->type = p->type;
+  prim->numverts = p->numverts;
+  prim->boundary = p->boundary;
+  prim->offset = p->offset;
+  prim->pattern = p->pattern;
+  prim->factor = p->factor;
+  prim->culled = p->culled;
+  prim->width = p->width;
+  prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex));
+  memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex));
 
-  /* OpenGL image is from down to up, PS image is up to down */  
-  switch(im->format){
-  case GL_RGBA:
-    pimag = pixels + 4 * (width * (height - 1 - y) + x);
+  switch(prim->type){
+  case GL2PS_PIXMAP :
+    prim->data.image = gl2psCopyPixmap(p->data.image);
+    break;
+  case GL2PS_TEXT :
+  case GL2PS_SPECIAL :
+    prim->data.text = gl2psCopyText(p->data.text);
     break;
-  case GL_RGB:
   default:
-    pimag = pixels + 3 * (width * (height - 1 - y) + x);
     break;
   }
-  *red = *pimag; pimag++;
-  *green = *pimag; pimag++;
-  *blue = *pimag; pimag++;
 
-  return (im->format == GL_RGBA) ? *pimag : 1.0F;
+  return prim;
 }
 
 static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2)
@@ -844,9 +1106,9 @@ static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c)
     c[2] = c[2] / norm;
   }
   else{
-    /* FIXME: the plane is still wrong, despite our tests in
-       gl2psGetPlane... Let's return a dummy value for now (this is a
-       hack: we should do more tests in GetPlane) */
+    /* The plane is still wrong despite our tests in gl2psGetPlane.
+       Let's return a dummy value for now (this is a hack: we should
+       do more intelligent tests in GetPlane) */
     c[0] = c[1] = 0.0F;
     c[2] = 1.0F;
   }
@@ -902,6 +1164,7 @@ static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane)
   case GL2PS_POINT :
   case GL2PS_PIXMAP :
   case GL2PS_TEXT :
+  case GL2PS_SPECIAL :
   case GL2PS_IMAGEMAP:
     plane[0] = plane[1] = 0.0F;
     plane[2] = 1.0F;
@@ -957,7 +1220,7 @@ static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane,
     case 2 : child->type = GL2PS_LINE; break; 
     case 3 : child->type = GL2PS_TRIANGLE; break; 
     case 4 : child->type = GL2PS_QUADRANGLE; break;    
-    default: child->type = GL2PS_NOTYPE; break;
+    default: child->type = GL2PS_NO_TYPE; break;
     }
   }
 
@@ -1217,7 +1480,7 @@ static void gl2psFreePrimitive(void *data)
   
   q = *(GL2PSprimitive**)data;
   gl2psFree(q->verts);
-  if(q->type == GL2PS_TEXT){
+  if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){
     gl2psFreeText(q->data.text);
   }
   else if(q->type == GL2PS_PIXMAP){
@@ -1623,7 +1886,7 @@ static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent,
     case 2 : child->type = GL2PS_LINE; break;
     case 3 : child->type = GL2PS_TRIANGLE; break;
     case 4 : child->type = GL2PS_QUADRANGLE; break;
-    default: child->type = GL2PS_NOTYPE; break; /* FIXME */
+    default: child->type = GL2PS_NO_TYPE; break; /* FIXME */
     }
   }
   child->boundary = 0; /* FIXME: not done! */
@@ -1732,7 +1995,9 @@ static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree)
   /* FIXME: until we consider the actual extent of text strings and
      pixmaps, never cull them. Otherwise the whole string/pixmap gets
      culled as soon as the reference point is hidden */
-  if(prim->type == GL2PS_PIXMAP || prim->type == GL2PS_TEXT){
+  if(prim->type == GL2PS_PIXMAP || 
+     prim->type == GL2PS_TEXT || 
+     prim->type == GL2PS_SPECIAL){
     return 1;
   }
 
@@ -1941,7 +2206,7 @@ static void gl2psParseFeedbackBuffer(GLint used)
   char flag;
   GLushort pattern = 0;
   GLboolean boundary;
-  GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0;
+  GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0;
   GLfloat lwidth = 1.0F, psize = 1.0F;
   GLfloat *current;
   GL2PSvertex vertices[3];
@@ -2018,14 +2283,14 @@ static void gl2psParseFeedbackBuffer(GLint used)
       break;      
     case GL_PASS_THROUGH_TOKEN :
       switch((GLint)current[1]){
-      case GL2PS_BEGIN_POLYGON_OFFSET_FILL : offset = 1; break;
-      case GL2PS_END_POLYGON_OFFSET_FILL : offset = 0; break;
-      case GL2PS_BEGIN_POLYGON_BOUNDARY : boundary = GL_TRUE; break;
-      case GL2PS_END_POLYGON_BOUNDARY : boundary = GL_FALSE; break;
-      case GL2PS_END_LINE_STIPPLE : pattern = factor = 0; break;
-      case GL2PS_BEGIN_BLEND : gl2ps->blending = GL_TRUE; break;
-      case GL2PS_END_BLEND : gl2ps->blending = GL_FALSE; break;
-      case GL2PS_BEGIN_LINE_STIPPLE : 
+      case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break;
+      case GL2PS_END_OFFSET_TOKEN : offset = 0; break;
+      case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break;
+      case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break;
+      case GL2PS_END_STIPPLE_TOKEN : pattern = factor = 0; break;
+      case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break;
+      case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break;
+      case GL2PS_BEGIN_STIPPLE_TOKEN : 
         current += 2;
         used -= 2; 
         pattern = (GLushort)current[1]; 
@@ -2033,27 +2298,27 @@ static void gl2psParseFeedbackBuffer(GLint used)
         used -= 2; 
         factor = (GLint)current[1]; 
         break;
-      case GL2PS_SRC_BLEND : 
+      case GL2PS_SRC_BLEND_TOKEN : 
         current += 2; 
         used -= 2; 
         gl2ps->blendfunc[0] = (GLint)current[1];
         break;
-      case GL2PS_DST_BLEND : 
+      case GL2PS_DST_BLEND_TOKEN : 
         current += 2; 
         used -= 2; 
         gl2ps->blendfunc[1] = (GLint)current[1];
         break;
-      case GL2PS_SET_POINT_SIZE : 
+      case GL2PS_POINT_SIZE_TOKEN : 
         current += 2; 
         used -= 2; 
         psize = current[1];
         break;
-      case GL2PS_SET_LINE_WIDTH : 
+      case GL2PS_LINE_WIDTH_TOKEN : 
         current += 2; 
         used -= 2; 
         lwidth = current[1];
         break;
-      case GL2PS_DRAW_IMAGEMAP_TOKEN :
+      case GL2PS_IMAGEMAP_TOKEN :
         prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive));
         prim->type = GL2PS_IMAGEMAP;
         prim->boundary = 0;
@@ -2117,6 +2382,15 @@ static void gl2psParseFeedbackBuffer(GLint used)
         current++; used--;
         gl2psListAdd(gl2ps->primitives, &prim);
         break;
+      case GL2PS_DRAW_PIXELS_TOKEN :
+      case GL2PS_TEXT_TOKEN :
+      case GL2PS_SPECIAL_TOKEN :
+        if(auxindex < gl2psListNbr(gl2ps->auxprimitives))
+          gl2psListAdd(gl2ps->primitives, 
+                       gl2psListPointer(gl2ps->auxprimitives, auxindex++));
+        else
+          gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer");
+        break;
       }
       current += 2; 
       used -= 2; 
@@ -2128,6 +2402,8 @@ static void gl2psParseFeedbackBuffer(GLint used)
       break;
     }
   }
+
+  gl2psListReset(gl2ps->auxprimitives);
 }
 
 /********************************************************************* 
@@ -2152,7 +2428,8 @@ static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im)
   GLuint width = (GLuint)im->width;
   GLuint height = (GLuint)im->height;
 
-  /* FIXME: should we define an option for these? */
+  /* FIXME: should we define an option for these? Or just keep the
+     8-bit per component case? */
   int greyscale = 0; /* set to 1 to output greyscale image */
   int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */
 
@@ -2367,24 +2644,10 @@ static void gl2psPrintPostScriptHeader(void)
 {
   time_t now;
 
-#ifdef GL2PS_HAVE_ZLIB
-  /* since compression is not part of the PostScript standard, we
-     simply generate a gzipped PostScript file ("ps.gz" or
-     "eps.gz") */
-  
-  char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */
-                  8, /* compression method: Z_DEFLATED */
-                  0, /* flags */
-                  0, 0, 0, 0, /* time */
-                  2, /* extra flags: max compression */
-                  '\x03'}; /* OS code: 0x03 (Unix) */
-
-  if(gl2ps->options & GL2PS_COMPRESS){
-    gl2psSetupCompress();
-    /* add the gzip file header */
-    fwrite(tmp, 10, 1, gl2ps->stream);
-  }
-#endif  
+  /* Since compression is not part of the PostScript standard,
+     compressed PostScript files are just gzipped PostScript files
+     ("ps.gz" or "eps.gz") */
+  gl2psPrintGzipHeader();
 
   time(&now);
 
@@ -2396,14 +2659,14 @@ static void gl2psPrintPostScriptHeader(void)
   }
 
   gl2psPrintf("%%%%Title: %s\n"
-              "%%%%Creator: GL2PS %d.%d.%d, (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>\n"
+              "%%%%Creator: GL2PS %d.%d.%d%s, (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>\n"
               "%%%%For: %s\n"
               "%%%%CreationDate: %s"
               "%%%%LanguageLevel: 3\n"
               "%%%%DocumentData: Clean7Bit\n"
               "%%%%Pages: 1\n",
               gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION,
-              gl2ps->producer, ctime(&now));
+              GL2PS_EXTRA_VERSION, gl2ps->producer, ctime(&now));
 
   if(gl2ps->format == GL2PS_PS){
     gl2psPrintf("%%%%Orientation: %s\n"
@@ -2640,10 +2903,39 @@ static void gl2psEndPostScriptLine(void)
   }
 }
 
+static void gl2psParseStipplePattern(GLushort pattern, GLint factor, 
+                                     int *nb, int array[10])
+{
+  int i, n, on[5] = {0, 0, 0, 0, 0}, off[5] = {0, 0, 0, 0, 0};
+  char tmp[16];
+
+  /* extract the 16 bits from the OpenGL stipple pattern */
+  for(n = 15; n >= 0; n--){
+    tmp[n] = (char)(pattern & 0x01);
+    pattern >>= 1;
+  }
+  /* compute the on/off pixel sequence (since the PostScript
+     specification allows for at most 11 elements in the on/off array,
+     we limit ourselves to 5 couples of on/off states) */
+  n = 0;
+  for(i = 0; i < 5; i++){
+    while(n < 16 && !tmp[n]){ off[i]++; n++; }
+    while(n < 16 && tmp[n]){ on[i]++; n++; }
+    if(n >= 15) break;
+  }
+  /* store the on/off array from right to left, starting with off
+     pixels (the longest possible array is: [on4 off4 on3 off3 on2
+     off2 on1 off1 on0 off0]) */
+  *nb = 0;
+  for(n = i; n >= 0; n--){
+    array[(*nb)++] = factor * on[n];
+    array[(*nb)++] = factor * off[n];
+  }
+}
+
 static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, char *str)
 {
-  int len = 0, i, n, on[5] = {0, 0, 0, 0, 0}, off[5] = {0, 0, 0, 0, 0};
-  char tmp[16];
+  int len = 0, i, n, array[10];
 
   if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
     return 0;
@@ -2656,27 +2948,11 @@ static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, char *str)
     len += gl2psPrintf("[] 0 %s\n", str);
   }
   else{
-    /* extract the 16 bits from the stipple pattern */
-    for(n = 15; n >= 0; n--){
-      tmp[n] = (char)(pattern & 0x01);
-      pattern >>= 1;
-    }
-    /* compute the on/off pixel sequence (since the PostScript
-       specification allows for at most 11 elements in the on/off
-       array, we limit ourselves to 5 couples of on/off states) */
-    n = 0;
-    for(i = 0; i < 5; i++){
-      while(n < 16 && !tmp[n]){ off[i]++; n++; }
-      while(n < 16 && tmp[n]){ on[i]++; n++; }
-      if(n >= 15) break;
-    }
-    /* print the on/off array from right to left, starting with off
-       pixels (the longest possible array is: [on4 off4 on3 off3 on2
-       off2 on1 off1 on0 off0]) */
+    gl2psParseStipplePattern(pattern, factor, &n, array);
     len += gl2psPrintf("[");
-    for(n = i; n >= 0; n--){
-      len += gl2psPrintf("%d %d", factor * on[n], factor * off[n]);
-      if(n) len += gl2psPrintf(" ");
+    for(i = 0; i < n; i++){
+      if(i) len += gl2psPrintf(" ");
+      len += gl2psPrintf("%d", array[i]);
     }
     len += gl2psPrintf("] 0 %s\n", str);
   }
@@ -2704,7 +2980,7 @@ static void gl2psPrintPostScriptPrimitive(void *data)
   case GL2PS_POINT :
     gl2psPrintPostScriptColor(prim->verts[0].rgba);
     gl2psPrintf("%g %g %g P\n", 
-                prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5*prim->width);
+                prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width);
     break;
   case GL2PS_LINE :
     if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
@@ -2811,20 +3087,20 @@ static void gl2psPrintPostScriptPrimitive(void *data)
       break;
     }
     break;
+  case GL2PS_SPECIAL :
+    /* alignment contains the format for which the special output text
+       is intended */
+    if(prim->data.text->alignment == GL2PS_PS ||
+       prim->data.text->alignment == GL2PS_EPS)
+      gl2psPrintf("%s\n", prim->data.text->str);
+    break;
   default :
-    gl2psMsg(GL2PS_ERROR, "Unknown type of primitive to print");
     break;
   }
 }
 
 static void gl2psPrintPostScriptFooter(void)
 {
-#ifdef GL2PS_HAVE_ZLIB
-  int n;
-  uLong crc, len;
-  char tmp[8];
-#endif
-  
   gl2psPrintf("grestore\n"
               "showpage\n"
               "cleartomark\n"
@@ -2832,39 +3108,8 @@ static void gl2psPrintPostScriptFooter(void)
               "%%%%Trailer\n"
               "end\n"
               "%%%%EOF\n");
-  
-#ifdef GL2PS_HAVE_ZLIB
-  if(gl2ps->options & GL2PS_COMPRESS){
-    if(Z_OK != gl2psDeflate()){
-      gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
-    }
-    else{
-      /* determine the length of the header in the zlib stream */
-      n = 2; /* CMF+FLG */
-      if(gl2ps->compress->dest[1] & (1<<5)){
-        n += 4; /* DICTID */
-      }
-      /* write the data, without the zlib header and footer */
-      fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), 
-             1, gl2ps->stream);
-      /* add the gzip file footer */
-      crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen);
-      for(n = 0; n < 4; ++n){
-        tmp[n] = (char)(crc & 0xff);
-        crc >>= 8;
-      }
-      len = gl2ps->compress->srcLen;
-      for(n = 4; n < 8; ++n){
-        tmp[n] = (char)(len & 0xff);
-        len >>= 8;
-      }
-      fwrite(tmp, 8, 1, gl2ps->stream);
-    }
-    gl2psFreeCompress();
-    gl2psFree(gl2ps->compress);
-    gl2ps->compress = NULL;
-  }
-#endif 
+
+  gl2psPrintGzipFooter();
 }
 
 static void gl2psPrintPostScriptBeginViewport(GLint viewport[4])
@@ -2892,7 +3137,7 @@ static void gl2psPrintPostScriptBeginViewport(GLint viewport[4])
       rgba[0] = gl2ps->colormap[index][0];
       rgba[1] = gl2ps->colormap[index][1];
       rgba[2] = gl2ps->colormap[index][2];
-      rgba[3] = 0.0F;
+      rgba[3] = 1.0F;
     }
     gl2psPrintf("%g %g %g C\n"
                 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
@@ -3031,6 +3276,12 @@ static void gl2psPrintTeXPrimitive(void *data)
       fprintf(gl2ps->stream, "}");
     fprintf(gl2ps->stream, "}}\n");
     break;
+  case GL2PS_SPECIAL :
+    /* alignment contains the format for which the special output text
+       is intended */
+    if (prim->data.text->alignment == GL2PS_TEX)
+      fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
+    break;
   default :
     break;
   }
@@ -3044,11 +3295,17 @@ static void gl2psPrintTeXFooter(void)
 
 static void gl2psPrintTeXBeginViewport(GLint viewport[4])
 {
+  glRenderMode(GL_FEEDBACK);
+  
+  if(gl2ps->header){
+    gl2psPrintTeXHeader();
+    gl2ps->header = GL_FALSE;
+  }
 }
 
 static GLint gl2psPrintTeXEndViewport(void)
 {
-  return 0;
+  return gl2psPrintPrimitives();
 }
 
 static void gl2psPrintTeXFinalPrimitive(void)
@@ -3076,7 +3333,7 @@ static GL2PSbackend gl2psTEX = {
 
 static int gl2psPrintPDFCompressorType(void)
 {
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   if(gl2ps->options & GL2PS_COMPRESS){
     return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n");
   }
@@ -3177,7 +3434,7 @@ static void gl2psPDFgroupListInit(void)
   int i;
   GL2PSprimitive *p = NULL;
   GL2PSpdfgroup gro;
-  int lasttype = GL2PS_NOTYPE;
+  int lasttype = GL2PS_NO_TYPE;
   GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F};
   GLushort lastpattern = 0;
   GLint lastfactor = 0;
@@ -3642,10 +3899,10 @@ static int gl2psPrintPDFInfo(void)
                  "<<\n"
                  "/Title (%s)\n"
                  "/Creator (%s)\n"
-                 "/Producer (GL2PS %d.%d.%d, "
+                 "/Producer (GL2PS %d.%d.%d%s, "
                  "(C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>)\n",
-                 gl2ps->title, gl2ps->producer,
-                 GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION);
+                 gl2ps->title, gl2ps->producer, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
+                 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION);
   
   if(!newtime){
     offs += fprintf(gl2ps->stream, 
@@ -3737,7 +3994,7 @@ static void gl2psPrintPDFHeader(void)
 
   gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); 
 
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   if(gl2ps->options & GL2PS_COMPRESS){
     gl2psSetupCompress();
   }
@@ -3779,7 +4036,7 @@ static int gl2psClosePDFDataStream(void)
 {
   int offs = 0;
  
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   if(gl2ps->options & GL2PS_COMPRESS){
     if(Z_OK != gl2psDeflate())
       gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
@@ -3897,6 +4154,9 @@ static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex,
   double dmax = ~1UL;
   char edgeflag = 0;
 
+  /* FIXME: temp bux fix for 64 bit archs: */
+  if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
+
   offs += (*action)(edgeflag, 1);
 
   /* The Shader stream in PDF requires to be in a 'big-endian'
@@ -3937,6 +4197,9 @@ static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex,
   unsigned long imap;
   double dmax = ~1UL;
 
+  /* FIXME: temp bux fix for 64 bit archs: */
+  if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
+
   imap = (unsigned long)((vertex->rgba[0]) * dmax);
   offs += (*action)(imap, 1);
     
@@ -3959,8 +4222,11 @@ static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex,
   int offs = 0;
   unsigned long imap;
   double dmax = ~1UL;
-        
-  if(sigbyte!=8 && sigbyte!=16)
+
+  /* FIXME: temp bux fix for 64 bit archs: */
+  if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
+
+  if(sigbyte != 8 && sigbyte != 16)
     sigbyte = 8;
         
   sigbyte /= 8;
@@ -4071,14 +4337,14 @@ static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles,
                   xmin, xmax, ymin, ymax,
                   (gray) ? "" : "0 1 0 1");
   
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   if(gl2ps->options & GL2PS_COMPRESS){
     gl2psAllocCompress(vertexbytes * size * 3);
 
     for(i = 0; i < size; ++i)
       gl2psPrintPDFShaderStreamData(&triangles[i],
                                     xmax-xmin, ymax-ymin, xmin, ymin, 
-                                    gl2psWriteBigEndianCompress,gray);
+                                    gl2psWriteBigEndianCompress, gray);
 
     if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
       offs += gl2psPrintPDFCompressorType();
@@ -4107,7 +4373,7 @@ static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles,
     for(i = 0; i < size; ++i)
       offs += gl2psPrintPDFShaderStreamData(&triangles[i],
                                             xmax-xmin, ymax-ymin, xmin, ymin,
-                                            gl2psWriteBigEndian,gray);
+                                            gl2psWriteBigEndian, gray);
   }
   
   offs += fprintf(gl2ps->stream,
@@ -4261,7 +4527,7 @@ static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray)
                     childobj);
   }
   
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   if(gl2ps->options & GL2PS_COMPRESS){
     gl2psAllocCompress((int)(im->width * im->height * sigbytes));
     
@@ -4379,6 +4645,12 @@ static int gl2psPDFgroupListWriteObjects(int entryoffs)
       gl2ps->xreflist[gro->fontobjno] = offs;
       offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno);
       break;
+    case GL2PS_SPECIAL :
+      /* alignment contains the format for which the special output text
+         is intended */
+      if(p->data.text->alignment == GL2PS_PDF)
+        offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str);
+      break;
     default:
       break;
     } 
@@ -4443,7 +4715,7 @@ static void gl2psPrintPDFFooter(void)
   gl2psListDelete(gl2ps->pdfprimlist);
   gl2psPDFgroupListDelete();
   
-#ifdef GL2PS_HAVE_ZLIB
+#if defined(GL2PS_HAVE_ZLIB)
   if(gl2ps->options & GL2PS_COMPRESS){
     gl2psFreeCompress();
     gl2psFree(gl2ps->compress);
@@ -4479,7 +4751,7 @@ static void gl2psPrintPDFBeginViewport(GLint viewport[4])
       rgba[0] = gl2ps->colormap[index][0];
       rgba[1] = gl2ps->colormap[index][1];
       rgba[2] = gl2ps->colormap[index][2];
-      rgba[3] = 0.0F;
+      rgba[3] = 1.0F;
     }
     offs += gl2psPrintPDFFillColor(rgba);
     offs += gl2psPrintf("%d %d %d %d re\n"
@@ -4529,11 +4801,19 @@ static GL2PSbackend gl2psPDF = {
  *
  *********************************************************************/
 
-/* FIXME: this is just a canvas, still far from being usable in any
-   way. One big problem is that it seems like there is no easy way to
-   do Gouraud shading in SVG!? Another is horrible rendering
-   performance (that could be partially fixed by using 'path' instead
-   of 'polygon') */
+static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, 
+                                       GL2PSxyz *xyz, GL2PSrgba *rgba)
+{
+  int i, j;
+
+  for(i = 0; i < n; i++){
+    xyz[i][0] = verts[i].xyz[0];
+    xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1];
+    xyz[i][2] = 0.0F;
+    for(j = 0; j < 4; j++)
+      rgba[i][j] = verts[i].rgba[j];
+  }
+}
 
 static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32])
 {
@@ -4546,119 +4826,332 @@ static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32])
   sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc);
 }
 
-static void gl2psSVGGetCoords(int n, GL2PSvertex *verts, GL2PSxyz *xyz)
+static void gl2psPrintSVGHeader(void)
+{
+  char col[32];
+  time_t now;
+
+  /* Compressed SVG files (.svgz) are simply gzipped SVG files */
+  gl2psPrintGzipHeader();
+
+  time(&now);
+
+  gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
+  gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
+  gl2psPrintf("     xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
+  gl2psPrintf("     viewBox=\"%d %d %d %d\">\n",
+              (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : 
+              (int)gl2ps->viewport[0],
+              (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] :
+              (int)gl2ps->viewport[1],
+              (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : 
+              (int)gl2ps->viewport[2],
+              (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] :
+              (int)gl2ps->viewport[3]);
+  gl2psPrintf("<title>\n");
+  gl2psPrintf("%s\n", gl2ps->title);
+  gl2psPrintf("</title>\n");
+  gl2psPrintf("<desc>\n");
+  gl2psPrintf("Creator: GL2PS %d.%d.%d%s\n"
+              "For: %s\n"
+              "CreationDate: %s",
+              GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION,
+              GL2PS_EXTRA_VERSION, gl2ps->producer, ctime(&now));
+  gl2psPrintf("</desc>\n");
+  gl2psPrintf("<defs>\n");
+  gl2psPrintf("</defs>\n");
+
+  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
+    gl2psSVGGetColorString(gl2ps->bgcolor, col);
+    gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
+                (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 
+                (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], 
+                (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], 
+                (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
+  }
+}
+
+static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3])
 {
   int i;
+  GL2PSxyz xyz2[3];
+  GL2PSrgba rgba2[3];
+  char col[32];
+
+  /* Apparently there is no easy way to do Gouraud shading in SVG
+     without explicitly pre-defining gradients, so for now we just do
+     recursive subdivision */
+
+  if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){
+    gl2psSVGGetColorString(rgba[0], col);
+    gl2psPrintf("<polygon fill=\"%s\" ", col);
+    if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
+    gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1], 
+                xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]);
+  }
+  else{
+    /* subdivide into 4 subtriangles */
+    for(i = 0; i < 3; i++){
+      xyz2[0][i] = xyz[0][i]; 
+      xyz2[1][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
+      xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
+    }
+    for(i = 0; i < 4; i++){
+      rgba2[0][i] = rgba[0][i]; 
+      rgba2[1][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
+      rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
+    }
+    gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
+    for(i = 0; i < 3; i++){
+      xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
+      xyz2[1][i] = xyz[1][i]; 
+      xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]);
+    }
+    for(i = 0; i < 4; i++){
+      rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
+      rgba2[1][i] = rgba[1][i]; 
+      rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]);
+    }
+    gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
+    for(i = 0; i < 3; i++){
+      xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
+      xyz2[1][i] = xyz[2][i]; 
+      xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]);
+    }
+    for(i = 0; i < 4; i++){
+      rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
+      rgba2[1][i] = rgba[2][i]; 
+      rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]);
+    }
+    gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
+    for(i = 0; i < 3; i++){
+      xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
+      xyz2[1][i] = 0.5 * (xyz[1][i] + xyz[2][i]); 
+      xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
+    }
+    for(i = 0; i < 4; i++){
+      rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
+      rgba2[1][i] = 0.5 * (rgba[1][i] + rgba[2][i]); 
+      rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
+    }
+    gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
+  }
+}
 
+static void gl2psPrintSVGDash(GLushort pattern, GLint factor)
+{
+  int i, n, array[10];
+
+  if(!pattern || !factor) return; /* solid line */
+
+  gl2psParseStipplePattern(pattern, factor, &n, array);
+  gl2psPrintf("stroke-dasharray=\"");
   for(i = 0; i < n; i++){
-    xyz[i][0] = verts[i].xyz[0];
-    xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1];
+    if(i) gl2psPrintf(",");
+    gl2psPrintf("%d", array[i]);
   }
+  gl2psPrintf("\" ");
 }
 
-static void gl2psPrintSVGHeader(void)
+static void gl2psEndSVGLine(void)
 {
-  time_t now;
-  time(&now);
+  int i;
+  if(gl2ps->lastvertex.rgba[0] >= 0.){
+    gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], 
+                gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]);
+    for(i = 0; i < 3; i++)
+      gl2ps->lastvertex.xyz[i] = -1.;
+    for(i = 0; i < 4; i++)
+      gl2ps->lastvertex.rgba[i] = -1.;
+  }
+}
 
-  fprintf(gl2ps->stream, 
-          "<svg viewBox=\"%d %d %d %d\" xmlns=\"http://www.w3.org/2000/svg\">\n",
-          (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : 
-          (int)gl2ps->viewport[0],
-          (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] :
-          (int)gl2ps->viewport[1],
-          (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : 
-          (int)gl2ps->viewport[2],
-          (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] :
-          (int)gl2ps->viewport[3]);
-  fprintf(gl2ps->stream, "<title>\n");
-  fprintf(gl2ps->stream, "%s\n",gl2ps->title);
-  fprintf(gl2ps->stream, "</title>\n");
-  fprintf(gl2ps->stream, "<desc>\n");
-  fprintf(gl2ps->stream, 
-          "Creator: GL2PS %d.%d.%d\n"
-          "For: %s\n"
-          "CreationDate: %s",
-          GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION,
-          gl2ps->producer, ctime(&now));
-  fprintf(gl2ps->stream, "</desc>\n");
-  fprintf(gl2ps->stream, "<defs>\n");
-  fprintf(gl2ps->stream, "</defs>\n");
+static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap)
+{
+#if defined(GL2PS_HAVE_LIBPNG)
+  GL2PSlist *png;
+  unsigned char c;
+  int i;
+
+  /* The only image types supported by the SVG standard are JPEG, PNG
+     and SVG. Here we choose PNG, and since we want to embed the image
+     directly in the SVG stream (and not link to an external image
+     file), we need to encode the pixmap into PNG in memory, then
+     encode it into base64. */
+
+  png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, 
+                        sizeof(unsigned char));
+  gl2psConvertPixmapToPNG(pixmap, png);
+  c = '\0'; /* need to base64-encode a null-terminated string */
+  gl2psListAdd(png, &c); 
+  gl2psListEncodeBase64(png);
+  gl2psPrintf("<image x=\"%g\" y=\"%g\" width=\"%d\" height=\"%d\"\n",
+              x, y - pixmap->height, pixmap->width, pixmap->height);
+  gl2psPrintf("xlink:href=\"data:image/png;base64,");
+  for(i = 0; i < gl2psListNbr(png); i++){
+    gl2psListRead(png, i, &c);
+    gl2psPrintf("%c", c);
+  }
+  gl2psPrintf("\"/>\n");
+  gl2psListDelete(png);
+#else
+  gl2psMsg(GL2PS_WARNING, "GL2PS has to be compiled with PNG support in "
+           "order to embed images in SVG streams");
+#endif
 }
 
 static void gl2psPrintSVGPrimitive(void *data)
 {
   GL2PSprimitive *prim;
   GL2PSxyz xyz[4];
+  GL2PSrgba rgba[4];
   char col[32];
+  int newline;
 
   prim = *(GL2PSprimitive**)data;
 
   if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
 
-  gl2psSVGGetCoords(prim->numverts, prim->verts, xyz);
+  /* We try to draw connected lines as a single path to get nice line
+     joins and correct stippling. So if the primitive to print is not
+     a line we must first finish the current line (if any): */
+  if(prim->type != GL2PS_LINE) gl2psEndSVGLine();
+
+  gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba);
 
   switch(prim->type){
   case GL2PS_POINT :
-    /* FIXME */
+    gl2psSVGGetColorString(rgba[0], col);
+    gl2psPrintf("<circle fill=\"%s\" ", col);
+    if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
+    gl2psPrintf("cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
+                xyz[0][0], xyz[0][1], 0.5 * prim->width);
     break;
   case GL2PS_LINE :
-    gl2psSVGGetColorString(prim->verts[0].rgba, col);
-    fprintf(gl2ps->stream,
-            "<line stroke=\"%s\" stroke-width=\"%d\" "
-            "x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
-            col, (int)(prim->width),
-            xyz[0][0], xyz[0][1], xyz[1][0], xyz[1][1]);
+    if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
+       !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
+       gl2ps->lastlinewidth != prim->width ||
+       gl2ps->lastpattern != prim->pattern ||
+       gl2ps->lastfactor != prim->factor){
+      /* End the current line if the new segment does not start where
+         the last one ended, or if the color, the width or the
+         stippling have changed (we will need to use multi-point
+         gradients for smooth-shaded lines) */
+      gl2psEndSVGLine();
+      newline = 1;
+    }
+    else{
+      newline = 0;
+    }
+    gl2ps->lastvertex = prim->verts[1];
+    gl2psSetLastColor(prim->verts[0].rgba);
+    gl2ps->lastlinewidth = prim->width;
+    gl2ps->lastpattern = prim->pattern;
+    gl2ps->lastfactor = prim->factor;
+    if(newline){
+      gl2psSVGGetColorString(rgba[0], col);
+      gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ", 
+                  col, prim->width);
+      if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]);
+      gl2psPrintSVGDash(prim->pattern, prim->factor);
+      gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]);
+    }
+    else{
+      gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]);
+    }
     break;
   case GL2PS_TRIANGLE :
-    gl2psSVGGetColorString(prim->verts[0].rgba, col);
-    fprintf(gl2ps->stream, 
-            "<polygon fill=\"%s\" points=\"%g,%g %g,%g %g,%g\"/>\n",
-            col, xyz[0][0], xyz[0][1], xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]);
+    gl2psPrintSVGSmoothTriangle(xyz, rgba);
     break;
   case GL2PS_QUADRANGLE :
     gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
     break;
   case GL2PS_PIXMAP :
-    /* FIXME */
-    break;
-  case GL2PS_IMAGEMAP :
-    /* FIXME */
+    gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image);
     break;
   case GL2PS_TEXT :
     gl2psSVGGetColorString(prim->verts[0].rgba, col);
-    fprintf(gl2ps->stream,
-            "<text x=\"%g\" y=\"%g\" fill=\"%s\" "
-            "font-size=\"%d\" font-family=\"%s\">%s</text>\n",
-            xyz[0][0], xyz[0][1], col,
-            prim->data.text->fontsize,
-            prim->data.text->fontname,
-            prim->data.text->str);
+    gl2psPrintf("<text fill=\"%s\" x=\"%g\" y=\"%g\" "
+                "font-size=\"%d\" font-family=\"%s\">%s</text>\n",
+                col, xyz[0][0], xyz[0][1],
+                prim->data.text->fontsize,
+                prim->data.text->fontname,
+                prim->data.text->str);
+    break;
+  case GL2PS_SPECIAL :
+    /* alignment contains the format for which the special output text
+       is intended */
+    if(prim->data.text->alignment == GL2PS_SVG)
+      gl2psPrintf("%s\n", prim->data.text->str);
     break;
   default :
-    gl2psMsg(GL2PS_ERROR, "Unknown type of primitive to print");
     break;
   }
 }
 
 static void gl2psPrintSVGFooter(void)
 {
-  fprintf(gl2ps->stream, "</svg>\n");
+  gl2psPrintf("</svg>\n");  
+  
+  gl2psPrintGzipFooter();
 }
 
 static void gl2psPrintSVGBeginViewport(GLint viewport[4])
 {
-  /* FIXME */
+  GLint index;
+  char col[32];
+  GLfloat rgba[4];
+  int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
+
+  glRenderMode(GL_FEEDBACK);
+  
+  if(gl2ps->header){
+    gl2psPrintSVGHeader();
+    gl2ps->header = GL_FALSE;
+  }
+
+  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
+    if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
+      glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
+    }
+    else{
+      glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
+      rgba[0] = gl2ps->colormap[index][0];
+      rgba[1] = gl2ps->colormap[index][1];
+      rgba[2] = gl2ps->colormap[index][2];
+      rgba[3] = 1.0F;
+    }
+    gl2psSVGGetColorString(rgba, col);
+    gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, 
+                x, gl2ps->viewport[3] - y, 
+                x + w, gl2ps->viewport[3] - y, 
+                x + w, gl2ps->viewport[3] - (y + h), 
+                x, gl2ps->viewport[3] - (y + h));
+  }
+
+  gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h);
+  gl2psPrintf("  <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", 
+              x, gl2ps->viewport[3] - y, 
+              x + w, gl2ps->viewport[3] - y, 
+              x + w, gl2ps->viewport[3] - (y + h), 
+              x, gl2ps->viewport[3] - (y + h));
+  gl2psPrintf("</clipPath>\n");
+  gl2psPrintf("<g stroke=\"none\" clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h);
 }
 
 static GLint gl2psPrintSVGEndViewport(void)
 {
-  /* FIXME */
-  return 0;
+  GLint res;
+
+  res = gl2psPrintPrimitives();
+  gl2psPrintf("</g>\n");
+  return res;
 }
 
 static void gl2psPrintSVGFinalPrimitive(void)
 {
+  /* End any remaining line, if any */
+  gl2psEndSVGLine();
 }
 
 /* definition of the SVG backend */
@@ -4690,23 +5183,6 @@ static void gl2psPrintPGFColor(GL2PSrgba rgba)
 
 static void gl2psPrintPGFHeader(void)
 {
-  char name[256];
-  int i;
-  
-  if(gl2ps->filename && strlen(gl2ps->filename) < 256){
-    for(i = strlen(gl2ps->filename)-1; i >= 0; i--){
-      if(gl2ps->filename[i] == '.'){
-        strncpy(name, gl2ps->filename, i);
-        name[i] = '\0';
-        break;
-      }
-    }
-    if(i <= 0) strcpy(name, gl2ps->filename);
-  }
-  else{
-    strcpy(name, "untitled");
-  }
-  
   fprintf(gl2ps->stream, "\\begin{pgfpicture}\n");
   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
     gl2psPrintPGFColor(gl2ps->bgcolor);
@@ -4721,8 +5197,7 @@ static void gl2psPrintPGFHeader(void)
 
 static void gl2psPrintPGFDash(GLushort pattern, GLint factor)
 {
-  int i, n, on[5] = {0, 0, 0, 0, 0}, off[5] = {0, 0, 0, 0, 0};
-  char tmp[16];
+  int i, n, array[10];
 
   if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
     return;
@@ -4735,28 +5210,9 @@ static void gl2psPrintPGFDash(GLushort pattern, GLint factor)
     fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n");
   }
   else{
-    /* extract the 16 bits from the stipple pattern */
-    for(n = 15; n >= 0; n--){
-      tmp[n] = (char)(pattern & 0x01);
-      pattern >>= 1;
-    }
-    /* compute the on/off pixel sequence (since the PostScript
-       specification allows for at most 11 elements in the on/off
-       array, we limit ourselves to 5 couples of on/off states) */
-    n = 0;
-    for(i = 0; i < 5; i++){
-      while(n < 16 && !tmp[n]){ off[i]++; n++; }
-      while(n < 16 && tmp[n]){ on[i]++; n++; }
-      if(n >= 15) break;
-    }
-    /* print the on/off array from right to left, starting with off
-       pixels (the longest possible array is: [on4 off4 on3 off3 on2
-       off2 on1 off1 on0 off0]) */
+    gl2psParseStipplePattern(pattern, factor, &n, array);
     fprintf(gl2ps->stream, "\\pgfsetdash{");
-    for(n = i; n >= 0; n--){
-      fprintf(gl2ps->stream, "{%dpt}{%dpt}",
-              (int)(factor * on[n]), (int)(factor * off[n]));
-    }
+    for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]);
     fprintf(gl2ps->stream, "}{0pt}\n");
   }
 }
@@ -4841,6 +5297,12 @@ static void gl2psPrintPGFPrimitive(void *data)
 
     fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n");
     break;
+  case GL2PS_SPECIAL :
+    /* alignment contains the format for which the special output text
+       is intended */
+    if (prim->data.text->alignment == GL2PS_PGF)
+      fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
+    break;
   default :
     break;
   }
@@ -4874,7 +5336,7 @@ static void gl2psPrintPGFBeginViewport(GLint viewport[4])
       rgba[0] = gl2ps->colormap[index][0];
       rgba[1] = gl2ps->colormap[index][1];
       rgba[2] = gl2ps->colormap[index][2];
-      rgba[3] = 0.0F;
+      rgba[3] = 1.0F;
     }
     gl2psPrintPGFColor(rgba);
     fprintf(gl2ps->stream, 
@@ -4961,16 +5423,14 @@ static GLint gl2psPrintPrimitives(void)
 
   used = glRenderMode(GL_RENDER);
 
-  if(gl2ps->format != GL2PS_TEX){
-    /* only report the overflow if we actually parse the buffer! */
-    if(used < 0){
-      gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow");
-      return GL2PS_OVERFLOW;
-    }
-    if(used > 0)
-      gl2psParseFeedbackBuffer(used);
+  if(used < 0){
+    gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow");
+    return GL2PS_OVERFLOW;
   }
 
+  if(used > 0)
+    gl2psParseFeedbackBuffer(used);
+
   gl2psRescaleAndOffset();
 
   if(gl2ps->header){
@@ -5110,9 +5570,9 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
     return GL2PS_ERROR;
   }
 
-  gl2ps->threshold[0] = nr ? 1.0F/(GLfloat)nr : 0.032F;
-  gl2ps->threshold[1] = ng ? 1.0F/(GLfloat)ng : 0.017F;
-  gl2ps->threshold[2] = nb ? 1.0F/(GLfloat)nb : 0.050F;
+  gl2ps->threshold[0] = nr ? 1.0F/(GLfloat)nr : 0.064F;
+  gl2ps->threshold[1] = ng ? 1.0F/(GLfloat)ng : 0.034F;
+  gl2ps->threshold[2] = nb ? 1.0F/(GLfloat)nb : 0.100F;
   gl2ps->colormode = colormode;
   gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048;
   for(i = 0; i < 3; i++){
@@ -5132,7 +5592,9 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
   gl2ps->pdfgrouplist = NULL;
   gl2ps->xreflist = NULL;
   
-  gl2ps->blending = glIsEnabled(GL_BLEND);
+  /* get default blending mode from current OpenGL state (enabled by
+     default for SVG) */
+  gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND);
   glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]);
   glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]);
 
@@ -5155,7 +5617,7 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
     gl2ps->bgcolor[0] = gl2ps->colormap[index][0];
     gl2ps->bgcolor[1] = gl2ps->colormap[index][1];
     gl2ps->bgcolor[2] = gl2ps->colormap[index][2];
-    gl2ps->bgcolor[3] = 0.0F;
+    gl2ps->bgcolor[3] = 1.0F;
   }
   else{
     gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage");
@@ -5192,6 +5654,7 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
   }
 
   gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
+  gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*));
   gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat));
   glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback);
   glRenderMode(GL_FEEDBACK);  
@@ -5213,6 +5676,7 @@ GL2PSDLL_API GLint gl2psEndPage(void)
   fflush(gl2ps->stream);
 
   gl2psListDelete(gl2ps->primitives);
+  gl2psListDelete(gl2ps->auxprimitives);
   gl2psFreeImagemap(gl2ps->imagemap_head);
   gl2psFree(gl2ps->colormap);
   gl2psFree(gl2ps->title);
@@ -5248,51 +5712,17 @@ GL2PSDLL_API GLint gl2psEndViewport(void)
 GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, 
                                 GLshort fontsize, GLint alignment, GLfloat angle)
 {
-  GLfloat pos[4];
-  GL2PSprimitive *prim;
-  GLboolean valid;
-
-  if(!gl2ps || !str) return GL2PS_UNINITIALIZED;
-
-  if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS;
-
-  glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
-  if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
-
-  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
-
-  prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
-  prim->type = GL2PS_TEXT;
-  prim->boundary = 0;
-  prim->numverts = 1;
-  prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
-  prim->verts[0].xyz[0] = pos[0];
-  prim->verts[0].xyz[1] = pos[1];
-  prim->verts[0].xyz[2] = pos[2];
-  prim->culled = 0;
-  prim->offset = 0;
-  prim->pattern = 0;
-  prim->factor = 0;
-  prim->width = 1;
-  glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
-  prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
-  prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char));
-  strcpy(prim->data.text->str, str); 
-  prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char));
-  strcpy(prim->data.text->fontname, fontname);
-  prim->data.text->fontsize = fontsize;
-  prim->data.text->alignment = alignment;
-  prim->data.text->angle = angle;
-
-  gl2psListAdd(gl2ps->primitives, &prim);
+  return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle);
+}
 
-  return GL2PS_SUCCESS;
+GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize)
+{
+  return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F);
 }
 
-GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname,
-                             GLshort fontsize)
+GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str)
 {
-  return gl2psTextOpt(str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F);
+  return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F);
 }
 
 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
@@ -5370,7 +5800,8 @@ GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
     break;
   }
 
-  gl2psListAdd(gl2ps->primitives, &prim);
+  gl2psListAdd(gl2ps->auxprimitives, &prim);
+  glPassThrough(GL2PS_DRAW_PIXELS_TOKEN);
 
   return GL2PS_SUCCESS;
 }
@@ -5386,12 +5817,12 @@ GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height,
   if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
   
   size = height + height * ((width-1)/8);
-  glPassThrough(GL2PS_DRAW_IMAGEMAP_TOKEN);
+  glPassThrough(GL2PS_IMAGEMAP_TOKEN);
   glBegin(GL_POINTS);
   glVertex3f(position[0], position[1],position[2]);
   glEnd();
-  glPassThrough(width);
-  glPassThrough(height);
+  glPassThrough((GLfloat)width);
+  glPassThrough((GLfloat)height);
   for(i = 0; i < size; i += sizeoffloat){
     float *value = (float*)imagemap;
     glPassThrough(*value);
@@ -5408,22 +5839,22 @@ GL2PSDLL_API GLint gl2psEnable(GLint mode)
 
   switch(mode){
   case GL2PS_POLYGON_OFFSET_FILL :
-    glPassThrough(GL2PS_BEGIN_POLYGON_OFFSET_FILL);
+    glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN);
     glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]);
     glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]);
     break;
   case GL2PS_POLYGON_BOUNDARY :
-    glPassThrough(GL2PS_BEGIN_POLYGON_BOUNDARY);
+    glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN);
     break;
   case GL2PS_LINE_STIPPLE :
-    glPassThrough(GL2PS_BEGIN_LINE_STIPPLE);
+    glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN);
     glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp);
     glPassThrough((GLfloat)tmp);
     glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp);
     glPassThrough((GLfloat)tmp);
     break;
   case GL2PS_BLEND :
-    glPassThrough(GL2PS_BEGIN_BLEND);
+    glPassThrough(GL2PS_BEGIN_BLEND_TOKEN);
     break;
   default :
     gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode);
@@ -5439,16 +5870,16 @@ GL2PSDLL_API GLint gl2psDisable(GLint mode)
 
   switch(mode){
   case GL2PS_POLYGON_OFFSET_FILL :
-    glPassThrough(GL2PS_END_POLYGON_OFFSET_FILL);
+    glPassThrough(GL2PS_END_OFFSET_TOKEN);
     break;
   case GL2PS_POLYGON_BOUNDARY :
-    glPassThrough(GL2PS_END_POLYGON_BOUNDARY);
+    glPassThrough(GL2PS_END_BOUNDARY_TOKEN);
     break;
   case GL2PS_LINE_STIPPLE :
-    glPassThrough(GL2PS_END_LINE_STIPPLE);
+    glPassThrough(GL2PS_END_STIPPLE_TOKEN);
     break;
   case GL2PS_BLEND :
-    glPassThrough(GL2PS_END_BLEND);
+    glPassThrough(GL2PS_END_BLEND_TOKEN);
     break;
   default :
     gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode);
@@ -5462,7 +5893,7 @@ GL2PSDLL_API GLint gl2psPointSize(GLfloat value)
 {
   if(!gl2ps) return GL2PS_UNINITIALIZED;
 
-  glPassThrough(GL2PS_SET_POINT_SIZE);
+  glPassThrough(GL2PS_POINT_SIZE_TOKEN);
   glPassThrough(value);
   
   return GL2PS_SUCCESS;
@@ -5472,7 +5903,7 @@ GL2PSDLL_API GLint gl2psLineWidth(GLfloat value)
 {
   if(!gl2ps) return GL2PS_UNINITIALIZED;
 
-  glPassThrough(GL2PS_SET_LINE_WIDTH);
+  glPassThrough(GL2PS_LINE_WIDTH_TOKEN);
   glPassThrough(value);
 
   return GL2PS_SUCCESS;
@@ -5485,9 +5916,9 @@ GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor)
   if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor))
     return GL2PS_WARNING;
 
-  glPassThrough(GL2PS_SRC_BLEND);
+  glPassThrough(GL2PS_SRC_BLEND_TOKEN);
   glPassThrough((GLfloat)sfactor);
-  glPassThrough(GL2PS_DST_BLEND);
+  glPassThrough(GL2PS_DST_BLEND_TOKEN);
   glPassThrough((GLfloat)dfactor);
 
   return GL2PS_SUCCESS;
diff --git a/Graphics/gl2ps.h b/Graphics/gl2ps.h
index 9924e721fd6b35fc037aac513eac0bd1bbaa0c16..fd503a00820d22df2c3a08b0894a639b11a26608 100644
--- a/Graphics/gl2ps.h
+++ b/Graphics/gl2ps.h
@@ -1,4 +1,4 @@
-/* $Id: gl2ps.h,v 1.64 2006-02-27 18:38:13 geuzaine Exp $ */
+/* $Id: gl2ps.h,v 1.65 2006-07-24 14:05:50 geuzaine Exp $ */
 /*
  * GL2PS, an OpenGL to PostScript Printing Library
  * Copyright (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>
@@ -38,7 +38,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-/* Define GL2PSDLL at compile time to build a Windows dll */
+/* Define GL2PSDLL at compile time to build a Windows DLL */
 
 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
 #  if defined(_MSC_VER)
@@ -58,26 +58,27 @@
 #  define GL2PSDLL_API
 #endif
 
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(HAVE_OPENGL_GL_H)
 #  include <OpenGL/gl.h>
 #else
 #  include <GL/gl.h>
 #endif
 
-/* Support for compressed PostScript/PDF */
+/* Support for compressed PostScript/PDF and for embedded PNG images in SVG */
 
-#if defined(HAVE_ZLIB) || defined(HAVE_LIBZ) || defined(GL2PS_HAVE_ZLIB)
-#  include <zlib.h>
-#  if !defined(GL2PS_HAVE_ZLIB)
-#    define GL2PS_HAVE_ZLIB
+#if defined(HAVE_ZLIB) || defined(HAVE_LIBZ)
+#  define GL2PS_HAVE_ZLIB
+#  if defined(HAVE_LIBPNG) || defined(HAVE_PNG)
+#    define GL2PS_HAVE_LIBPNG
 #  endif
 #endif
 
 /* Version number */
 
 #define GL2PS_MAJOR_VERSION 1
-#define GL2PS_MINOR_VERSION 2
-#define GL2PS_PATCH_VERSION 8
+#define GL2PS_MINOR_VERSION 3
+#define GL2PS_PATCH_VERSION 0
+#define GL2PS_EXTRA_VERSION "-cvs"
 
 #define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \
                        0.01 * GL2PS_MINOR_VERSION + \
@@ -168,6 +169,7 @@ GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname,
                              GLshort fontsize);
 GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, 
                                 GLshort fontsize, GLint align, GLfloat angle);
+GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str);
 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
                                    GLint xorig, GLint yorig,
                                    GLenum format, GLenum type, const void *pixels);
diff --git a/Mesh/Read_Mesh.cpp b/Mesh/Read_Mesh.cpp
index 7e4962da0dedfff4bf0d080a3003feebf4d990ab..8892e98254a60c4a49d93b4a435fc446baa26806 100644
--- a/Mesh/Read_Mesh.cpp
+++ b/Mesh/Read_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: Read_Mesh.cpp,v 1.105 2006-04-16 19:02:37 geuzaine Exp $
+// $Id: Read_Mesh.cpp,v 1.106 2006-07-24 14:05:50 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -98,7 +98,7 @@ void addVerticesInCurve(void *a, void *b)
     }
   }
 
-  // find starting element (or use the first one for closed curve)
+  // find starting element (or use the first one for a closed curve)
   std::map<int, nodex*>::const_iterator beg = nodes.begin();
   std::map<int, nodex*>::const_iterator end = nodes.end();
   int start = 0;
@@ -500,7 +500,7 @@ void Read_Mesh_MSH(Mesh * M, FILE * fp)
 	    Free_SimplexBase(&simp, 0);
 	  }
 	  // we don't insert the vertices in the list of vertices at
-	  // this point, since we need the list to ordered (and
+	  // this point, since we need the list to be ordered (and
 	  // consistent!), and simply doing a List_Insert and sorting
 	  // according to node numbers is not enough (in addition to
 	  // being slow): see addVerticesInCurve() below.
diff --git a/Plugin/ExtractElements.cpp b/Plugin/ExtractElements.cpp
index 8e4bc07bd690915fed7f7add539736b64a4794bb..47f2bf9ecbcd2bdcec03605edeaaa5b2b8cfb216 100644
--- a/Plugin/ExtractElements.cpp
+++ b/Plugin/ExtractElements.cpp
@@ -1,4 +1,4 @@
-// $Id: ExtractElements.cpp,v 1.5 2006-03-10 17:03:21 geuzaine Exp $
+// $Id: ExtractElements.cpp,v 1.6 2006-07-24 14:05:50 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -113,7 +113,7 @@ static void extract(List_T *inList, int inNb,
     }
     d /= (double)nbNod;
     // We use '>=' and '<' so that we can do segmentation without
-    // worrying about roudoff errors
+    // worrying about roundoff errors
     if(d >= MinVal && d < MaxVal){
       for(int j = 0; j < nb; j++)
 	List_Add(outList, List_Pointer_Fast(inList, i + j));