From bbe072e547ef4a2d7f13675710509af9060b1f09 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Tue, 16 Sep 2003 23:50:59 +0000
Subject: [PATCH] New native PDF support

---
 Fltk/Callbacks.cpp      |   34 +-
 Graphics/CreateFile.cpp |   23 +-
 Graphics/gl2ps.cpp      | 1113 ++++++++++++++++++++++++++++++++++++---
 Graphics/gl2ps.h        |   55 +-
 Mesh/Mesh.h             |    2 +
 5 files changed, 1148 insertions(+), 79 deletions(-)

diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index f7ca355a30..a0b8dd76b7 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.182 2003-07-21 23:31:16 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.183 2003-09-16 23:50:58 geuzaine Exp $
 //
 // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle
 //
@@ -469,6 +469,34 @@ void _save_epstex_accurate(char *name)
   CreateOutputFile(name, FORMAT_EPSTEX);
   CTX.print.eps_quality = old;
 }
+void _save_pdf_simple(char *name)
+{
+  int old = CTX.print.eps_quality;
+  CTX.print.eps_quality = 1;
+  CreateOutputFile(name, FORMAT_PDF);
+  CTX.print.eps_quality = old;
+}
+void _save_pdf_accurate(char *name)
+{
+  int old = CTX.print.eps_quality;
+  CTX.print.eps_quality = 2;
+  CreateOutputFile(name, FORMAT_PDF);
+  CTX.print.eps_quality = old;
+}
+void _save_pdftex_simple(char *name)
+{
+  int old = CTX.print.eps_quality;
+  CTX.print.eps_quality = 1;
+  CreateOutputFile(name, FORMAT_PDFTEX);
+  CTX.print.eps_quality = old;
+}
+void _save_pdftex_accurate(char *name)
+{
+  int old = CTX.print.eps_quality;
+  CTX.print.eps_quality = 2;
+  CreateOutputFile(name, FORMAT_PDFTEX);
+  CTX.print.eps_quality = old;
+}
 void _save_jpegtex(char *name)
 {
   CreateOutputFile(name, FORMAT_JPEGTEX);
@@ -563,6 +591,8 @@ void file_save_as_cb(CALLBACK_ARGS)
     {"PostScript accurate (*.ps)", _save_ps_accurate},
     {"Encapsulated PostScript fast (*.eps)", _save_eps_simple},
     {"Encapsulated PostScript accurate (*.eps)", _save_eps_accurate},
+    {"PDF fast (*.pdf)", _save_pdf_simple},
+    {"PDF accurate (*.pdf)", _save_pdf_accurate},
     {"PPM (*.ppm)", _save_ppm},
 #if defined(HAVE_LIBJPEG)
     {"LaTeX JPEG part (*.jpg)", _save_jpegtex},
@@ -572,6 +602,8 @@ void file_save_as_cb(CALLBACK_ARGS)
 #endif
     {"LaTeX EPS part fast (*.eps)", _save_epstex_simple},
     {"LaTeX EPS part accurate (*.eps)", _save_epstex_accurate},
+    {"LaTeX PDF part fast (*.pdf)", _save_pdftex_simple},
+    {"LaTeX PDF part accurate (*.pdf)", _save_pdftex_accurate},
     {"LaTeX TeX part (*.tex)", _save_tex},
     {"UCB YUV (*.yuv)", _save_yuv}
   };
diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp
index ad846bdb37..a1069d4393 100644
--- a/Graphics/CreateFile.cpp
+++ b/Graphics/CreateFile.cpp
@@ -1,4 +1,4 @@
-// $Id: CreateFile.cpp,v 1.44 2003-09-01 23:53:00 geuzaine Exp $
+// $Id: CreateFile.cpp,v 1.45 2003-09-16 23:50:58 geuzaine Exp $
 //
 // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle
 //
@@ -92,12 +92,16 @@ void CreateOutputFile(char *name, int format)
       CreateOutputFile(name, FORMAT_PS);
     else if(!strcmp(ext, ".eps"))
       CreateOutputFile(name, FORMAT_EPS);
+    else if(!strcmp(ext, ".pdf"))
+      CreateOutputFile(name, FORMAT_PDF);
     else if(!strcmp(ext, ".tex"))
       CreateOutputFile(name, FORMAT_TEX);
     else if(!strcmp(ext, ".pstex"))
       CreateOutputFile(name, FORMAT_PSTEX);
     else if(!strcmp(ext, ".epstex"))
       CreateOutputFile(name, FORMAT_EPSTEX);
+    else if(!strcmp(ext, ".pdftex"))
+      CreateOutputFile(name, FORMAT_PDFTEX);
     else if(!strcmp(ext, ".jpegtex"))
       CreateOutputFile(name, FORMAT_JPEGTEX);
     else if(!strcmp(ext, ".ppm"))
@@ -189,11 +193,18 @@ void CreateOutputFile(char *name, int format)
   case FORMAT_PSTEX:
   case FORMAT_EPS:
   case FORMAT_EPSTEX:
+  case FORMAT_PDF:
+  case FORMAT_PDFTEX:
     if(!(fp = fopen(name, "w"))) {
       Msg(GERROR, "Unable to open file '%s'", name);
       return;
     }
-    psformat = (format == FORMAT_PS || format == FORMAT_PSTEX) ? GL2PS_PS : GL2PS_EPS;
+    if(format == FORMAT_PDF || format == FORMAT_PDFTEX)
+      psformat = GL2PS_PDF;
+    else if(format == FORMAT_PS || format == FORMAT_PSTEX)
+      psformat = GL2PS_PS;
+    else
+      psformat = GL2PS_EPS;
     pssort = (CTX.print.eps_quality == 1) ? GL2PS_SIMPLE_SORT : GL2PS_BSP_SORT;
     psoptions =
       GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | 
@@ -201,7 +212,8 @@ void CreateOutputFile(char *name, int format)
       (CTX.print.eps_best_root ? GL2PS_BEST_ROOT : 0) |
       (CTX.print.eps_background ? GL2PS_DRAW_BACKGROUND : 0) |
       (format == FORMAT_PSTEX ? GL2PS_NO_TEXT : 0) |
-      (format == FORMAT_EPSTEX ? GL2PS_NO_TEXT : 0);
+      (format == FORMAT_EPSTEX ? GL2PS_NO_TEXT : 0) |
+      (format == FORMAT_PDFTEX ? GL2PS_NO_TEXT : 0);
 
     size3d = 0;
     res = GL2PS_OVERFLOW;
@@ -215,7 +227,10 @@ void CreateOutputFile(char *name, int format)
       CTX.print.gl_fonts = 1;
       res = gl2psEndPage();
     }
-    Msg(INFO, "PS/EPS creation complete '%s'", name);
+    if(psformat == GL2PS_PDF)
+      Msg(INFO, "PDF creation complete '%s'", name);
+    else
+      Msg(INFO, "PS/EPS creation complete '%s'", name);
     Msg(STATUS2, "Wrote '%s'", name);
     fclose(fp);
     break;
diff --git a/Graphics/gl2ps.cpp b/Graphics/gl2ps.cpp
index 5247674324..57b05c6adc 100644
--- a/Graphics/gl2ps.cpp
+++ b/Graphics/gl2ps.cpp
@@ -2,7 +2,7 @@
  * GL2PS, an OpenGL to PostScript Printing Library
  * Copyright (C) 1999-2003 Christophe Geuzaine 
  *
- * $Id: gl2ps.cpp,v 1.69 2003-07-04 15:11:55 geuzaine Exp $
+ * $Id: gl2ps.cpp,v 1.70 2003-09-16 23:50:58 geuzaine Exp $
  *
  * E-mail: geuz@geuz.org
  * URL: http://www.geuz.org/gl2ps/
@@ -35,12 +35,14 @@
  *   Shahzad Muzaffar <Shahzad.Muzaffar@cern.ch>
  *   Lassi Tuura <lassi.tuura@cern.ch>
  *   Guy Barrand <barrand@lal.in2p3.fr>
+ *   Micha Bieber <bieber@traits.de>
  */
 
 #include <string.h>
 #include <sys/types.h>
 #include <stdarg.h>
 #include <time.h>
+#include <float.h>
 #include "gl2ps.h"
 
 /* The gl2ps context. gl2ps is not thread safe (we should create a
@@ -48,7 +50,11 @@
 
 GL2PScontext *gl2ps = NULL;
 
-/* Some 'system' utility routines */
+/********************************************************************* 
+ *
+ * Utility routines
+ *
+ *********************************************************************/
 
 void gl2psMsg(GLint level, char *fmt, ...){
   va_list args;
@@ -94,6 +100,21 @@ void gl2psFree(void *ptr){
   free(ptr);
 }
 
+void gl2psWriteByte(FILE *stream, unsigned char byte){
+  unsigned char h = byte / 16;
+  unsigned char l = byte % 16;
+  fprintf(stream, "%x%x", h, l);
+}
+
+size_t gl2psWriteBigEndian(unsigned long data, size_t bytes, FILE* fp){
+  size_t i;
+  size_t size = sizeof(unsigned long);
+  for(i = 1; i <= bytes; ++i){
+    fputc(0xff & (data >> (size-i) * 8), fp);
+  }
+  return bytes;
+}
+
 /* The list handling routines */
 
 void gl2psListRealloc(GL2PSlist *list, GLint n){
@@ -141,7 +162,7 @@ void gl2psListAdd(GL2PSlist *list, void *data){
   memcpy(&list->array[(list->n - 1) * list->size], data, list->size);
 }
 
-GLint gl2psListNbr(GL2PSlist *list){
+int gl2psListNbr(GL2PSlist *list){
   return(list->n);
 }
 
@@ -176,7 +197,96 @@ void gl2psListActionInverse(GL2PSlist *list,
   }
 }
 
-/* The 3D sorting routines */
+/* Helper for pixmaps and strings */
+
+GL2PSimage* gl2psCopyPixmap(GL2PSimage* im){
+  int size;
+  GL2PSimage* image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
+  
+  image->width = im->width;
+  image->height = im->height;
+  image->format = im->format;
+  image->type = im->type;
+
+  /* FIXME: handle other types/formats */
+  size = image->height*image->width*3*sizeof(GLfloat);
+
+  image->pixels = (GLfloat*)gl2psMalloc(size);
+  memcpy(image->pixels, im->pixels, size);
+  
+  return image;
+}
+
+void gl2psFreePixmap(GL2PSimage* im){
+  if(!im)
+    return;
+  if(im->pixels)
+    gl2psFree(im->pixels);
+  gl2psFree(im);
+}
+
+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;
+  
+  return text;
+}
+
+void gl2psFreeText(GL2PSstring* text){
+  if(!text)
+    return;
+  if(text->str)
+    gl2psFree(text->str);
+  if(text->fontname)
+    gl2psFree(text->fontname);
+  gl2psFree(text);
+}
+
+/* Helpers for rgba colors */
+
+float gl2psColorDiff(GL2PSrgba rgba1, GL2PSrgba rgba2){
+  int i;	
+  float res = 0;
+  for(i = 0; i < 3; ++i){
+    res += (rgba1[i] - rgba2[i]) * (rgba1[i] - rgba2[i]);
+  }
+  return res;
+}
+
+GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2){
+  return !(rgba1[0] != rgba2[0] || 
+	   rgba1[1] != rgba2[1] ||
+	   rgba1[2] != rgba2[2]);
+}
+  
+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 0;
+    }
+  }
+  return 1;
+}
+
+void gl2psSetLastColor(GL2PSrgba rgba){
+  int i;	
+  for(i = 0; i < 3; ++i){
+    gl2ps->lastrgba[i] = rgba[i];
+  }
+}
+
+/********************************************************************* 
+ *
+ * 3D sorting routines 
+ *
+ *********************************************************************/
 
 GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane){
   return(plane[0] * point[0] + 
@@ -678,7 +788,11 @@ void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon,
   }
 }
 
-/* The 2D sorting routines (for occlusion culling) */
+/********************************************************************* 
+ *
+ * 2D sorting routines (for occlusion culling) 
+ *
+ *********************************************************************/
 
 GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane){  
   GLfloat n; 
@@ -1087,7 +1201,11 @@ void gl2psBuildPolygonBoundary(GL2PSbsptree *tree){
   gl2psBuildPolygonBoundary(tree->front);
 }
 
-/* The feedback buffer parser */
+/********************************************************************* 
+ *
+ * Feedback buffer parser
+ *
+ *********************************************************************/
 
 void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, 
 			   GL2PSvertex *verts, GLint offset, 
@@ -1298,34 +1416,11 @@ void gl2psParseFeedbackBuffer(GLint used){
   }
 }
 
-GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2){
-  return !(rgba1[0] != rgba2[0] || 
-	   rgba1[1] != rgba2[1] ||
-	   rgba1[2] != rgba2[2]);
-}
-  
-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 0;
-    }
-  }
-  return 1;
-}
-
-/* The PostScript routines. Other (vector) image formats should be
-   easy to generate by creating the three corresponding routines
-   (gl2psPrintXXXHeader, gl2psPrintXXXPrimitive, gl2psPrintXXXFooter,
-   gl2psPrintXXXBeginViewport and gl2psPrintXXXEndViewport) for the
-   new format. */
-
-void gl2psWriteByte(FILE *stream, unsigned char byte){
-  unsigned char h = byte / 16;
-  unsigned char l = byte % 16;
-  fprintf(stream, "%x%x", h, l);
-}
+/********************************************************************* 
+ *
+ * PostScript routines
+ *
+ *********************************************************************/
 
 void gl2psGetRGB(GLfloat *pixels, GLsizei width, GLsizei height, GLuint x, GLuint y,
 		 GLfloat *red, GLfloat *green, GLfloat *blue){
@@ -1353,12 +1448,12 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei
 
   fprintf(stream, "gsave\n");
   fprintf(stream, "%.2f %.2f translate\n", x, y); 
-  fprintf(stream, "%d %d scale\n", width, height); 
+  fprintf(stream, "%d %d scale\n", (int)width, (int)height); 
 
   if(greyscale){ /* greyscale, 8 bits per pixel */
-    fprintf(stream, "/picstr %d string def\n", width); 
-    fprintf(stream, "%d %d %d\n", width, height, 8); 
-    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height); 
+    fprintf(stream, "/picstr %d string def\n", (int)width); 
+    fprintf(stream, "%d %d %d\n", (int)width, (int)height, 8); 
+    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)width, (int)height, (int)height); 
     fprintf(stream, "{ currentfile picstr readhexstring pop }\n");
     fprintf(stream, "image\n");
     for(row = 0; row < height; row++){
@@ -1379,8 +1474,8 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei
     nbyte2 *=3;
     col_max = (nbyte2 * 4)/3;
     fprintf(stream, "/rgbstr %d string def\n", nbyte2); 
-    fprintf(stream, "%d %d %d\n", col_max, height, 2); 
-    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", col_max, height, height); 
+    fprintf(stream, "%d %d %d\n", (int)col_max, (int)height, 2); 
+    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)col_max, (int)height, (int)height); 
     fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n" );
     fprintf(stream, "false 3\n" );
     fprintf(stream, "colorimage\n" );
@@ -1427,8 +1522,8 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei
     nbyte4 *=3;
     col_max = (nbyte4 * 2)/3;
     fprintf(stream, "/rgbstr %d string def\n", nbyte4);
-    fprintf(stream, "%d %d %d\n", col_max, height, 4);
-    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", col_max, height, height);
+    fprintf(stream, "%d %d %d\n", (int)col_max, (int)height, 4);
+    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)col_max, (int)height, (int)height);
     fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n");
     fprintf(stream, "false 3\n");
     fprintf(stream, "colorimage\n");
@@ -1452,8 +1547,8 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei
   else{ /* color, 8 bits for r and g and b; rgbs following each other */
     nbyte8 = width * 3;
     fprintf(stream, "/rgbstr %d string def\n", nbyte8);
-    fprintf(stream, "%d %d %d\n", width, height, 8);
-    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height); 
+    fprintf(stream, "%d %d %d\n", (int)width, (int)height, 8);
+    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)width, (int)height, (int)height); 
     fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n");
     fprintf(stream, "false 3\n");
     fprintf(stream, "colorimage\n");
@@ -1504,18 +1599,24 @@ void gl2psPrintPostScriptHeader(void){
 	    "%%%%Orientation: %s\n"
 	    "%%%%DocumentMedia: Default %d %d 0 () ()\n",
 	    (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait",
-	    (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[3] : gl2ps->viewport[2],
-	    (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[2] : gl2ps->viewport[3]);
+	    (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,
 	  "%%%%BoundingBox: %d %d %d %d\n"
 	  "%%%%Copyright: GNU LGPL (C) 1999-2003 Christophe Geuzaine <geuz@geuz.org>\n"
 	  "%%%%EndComments\n",
-	  (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[1] : gl2ps->viewport[0],
-	  (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[0] : gl2ps->viewport[1],
-	  (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[3] : gl2ps->viewport[2],
-	  (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[2] : gl2ps->viewport[3]);
+	  (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]);
 
   /* RGB color: r g b C (replace C by G in output to change from rgb to gray)
      Grayscale: r g b G
@@ -1661,7 +1762,7 @@ void gl2psPrintPostScriptHeader(void){
   if(gl2ps->options & GL2PS_LANDSCAPE){
     fprintf(gl2ps->stream,
 	    "%d 0 translate 90 rotate\n",
-	    gl2ps->viewport[3]);
+	    (int)gl2ps->viewport[3]);
   }
 
   fprintf(gl2ps->stream, 
@@ -1686,17 +1787,15 @@ void gl2psPrintPostScriptHeader(void){
 	    "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
 	    "closepath fill\n",
 	    rgba[0], rgba[1], rgba[2], 
-	    gl2ps->viewport[0], gl2ps->viewport[1], gl2ps->viewport[2], 
-	    gl2ps->viewport[1], gl2ps->viewport[2], gl2ps->viewport[3], 
-	    gl2ps->viewport[0], gl2ps->viewport[3]);
+	    (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]);
   }
 }
 
 void gl2psPrintPostScriptColor(GL2PSrgba rgba){
   if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
-    gl2ps->lastrgba[0] = rgba[0];
-    gl2ps->lastrgba[1] = rgba[1];
-    gl2ps->lastrgba[2] = rgba[2];
+    gl2psSetLastColor(rgba);
     fprintf(gl2ps->stream, "%g %g %g C\n", rgba[0], rgba[1], rgba[2]);
   }
 }
@@ -1843,7 +1942,11 @@ GLint gl2psPrintPostScriptEndViewport(void){
   return res;
 }
 
-/* The LaTeX routines */
+/********************************************************************* 
+ *
+ * LaTeX routines
+ *
+ *********************************************************************/
 
 void gl2psPrintTeXHeader(void){
   char name[256];
@@ -1870,7 +1973,7 @@ void gl2psPrintTeXHeader(void){
 	  "\\end{picture}%%\n"
 	  "%s\\begin{picture}(%d,%d)(0,0)\n",
 	  name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "",
-	  gl2ps->viewport[2], gl2ps->viewport[3]);
+	  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
 }
 
 void gl2psPrintTeXPrimitive(void *a, void *b){
@@ -1880,8 +1983,45 @@ void gl2psPrintTeXPrimitive(void *a, void *b){
 
   switch(prim->type){
   case GL2PS_TEXT :
+#if 0 /* old code: */
     fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)[lb]{%s}}\n",
 	    prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->text->str);
+#endif
+    fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", 
+	    prim->text->fontsize);
+    fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)",
+	    prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
+    switch (prim->text->alignment) {
+    case GL2PS_TEXT_CL:
+      fprintf(gl2ps->stream, "[l]");
+      break;
+    case GL2PS_TEXT_CR:
+      fprintf(gl2ps->stream, "[r]");
+      break;
+    case GL2PS_TEXT_B:
+      fprintf(gl2ps->stream, "[b]");
+      break;
+    case GL2PS_TEXT_BL:
+      fprintf(gl2ps->stream, "[bl]");
+      break;
+    case GL2PS_TEXT_BR:
+      fprintf(gl2ps->stream, "[br]");
+      break;
+    case GL2PS_TEXT_T:
+      fprintf(gl2ps->stream, "[t]");
+      break;
+    case GL2PS_TEXT_TL:
+      fprintf(gl2ps->stream, "[tl]");
+      break;
+    case GL2PS_TEXT_TR:
+      fprintf(gl2ps->stream, "[tr]");
+      break;
+    default:
+      break;
+    }
+    fprintf(gl2ps->stream, "{\\textcolor[rgb]{%f,%f,%f}{",
+	    prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2]);
+    fprintf(gl2ps->stream, "{%s}}}}\n", prim->text->str);
     break;
   default :
     break;
@@ -1900,7 +2040,807 @@ GLint gl2psPrintTeXEndViewport(void){
   return GL2PS_SUCCESS;
 }
 
-/* The general primitive printing routine */
+/********************************************************************* 
+ *
+ * PDF routines
+ *
+ *********************************************************************/
+
+int gl2psPrintPDFCompressorType(){
+  if(gl2ps->options & GL2PS_DEFLATE){	
+    return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n");
+  }	
+  return 0;
+}
+
+int gl2psPrintPDFStrokeColor(GL2PSrgba rgba){
+  int offs = 0;
+  int i;	
+  
+  gl2psSetLastColor(rgba);
+  for(i = 0; i < 3; ++i){
+    if(GL2PS_ZERO(rgba[i]))
+      offs += fprintf(gl2ps->stream, "%.0f ", 0.);
+    else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting*/
+      offs += fprintf(gl2ps->stream, "%f ", rgba[i]);
+    else
+      offs += fprintf(gl2ps->stream, "%g ", rgba[i]);
+  }
+  offs += fprintf(gl2ps->stream, "RG\n");
+  return offs;
+}
+
+int gl2psPrintPDFFillColor(GL2PSrgba rgba){
+  int offs = 0;
+  int i;	
+  
+  for(i = 0; i < 3; ++i){
+    if(GL2PS_ZERO(rgba[i]))
+      offs += fprintf(gl2ps->stream, "%.0f ", 0.);
+    else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting*/
+      offs += fprintf(gl2ps->stream, "%f ", rgba[i]);
+    else
+      offs += fprintf(gl2ps->stream, "%g ", rgba[i]);
+  }
+  offs += fprintf(gl2ps->stream, "rg\n");
+  return offs;
+}
+
+int gl2psPrintPDFLineWidth(float lw){
+  if(GL2PS_ZERO(lw))
+    return fprintf(gl2ps->stream, "%.0f w\n", 0.);
+  else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting*/
+    return fprintf(gl2ps->stream, "%f w\n", lw);
+  else
+    return fprintf(gl2ps->stream, "%g w\n", lw);
+}
+
+/* Print 1st PDF object - file info */
+
+int gl2psPrintPDFInfo(){
+  int offs;
+  time_t now;
+  struct tm *newtime;
+  
+  time(&now);
+  newtime = gmtime(&now);
+  
+  offs = fprintf(gl2ps->stream, 
+		 "1 0 obj\n"
+		 "<<\n"
+		 "/Title (%s)\n"
+		 "/Creator (%s)\n"
+		 "/Producer (GL2PS %d.%d.%d, an OpenGL to PostScript Printing Library)\n",
+		 gl2ps->title, gl2ps->producer, 
+		 GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION);
+  
+  if(!newtime){
+    offs += fprintf(gl2ps->stream, 
+		    ">>\n"
+		    "endobj\n");	
+    return offs;
+  }
+  
+  offs += fprintf(gl2ps->stream, 
+		  "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n"
+		  ">>\n"
+		  "endobj\n",
+		  newtime->tm_year+1900, 
+		  newtime->tm_mon+1, 
+		  newtime->tm_mday,
+		  newtime->tm_hour,
+		  newtime->tm_min,
+		  newtime->tm_sec);
+  return offs;
+}
+
+/* Create catalog and page structure - 2nd and 3th PDF object */
+
+int gl2psPrintPDFCatalog(){
+  return fprintf(gl2ps->stream, 
+		 "2 0 obj\n"
+		 "<<\n" 
+		 "/Type /Catalog\n"
+		 "/Pages 3 0 R\n"
+		 ">>\n"
+		 "endobj\n");
+}
+
+int gl2psPrintPDFPages(){
+  return fprintf(gl2ps->stream, 
+		 "3 0 obj\n"
+		 "<<\n" 
+		 "/Type /Pages\n"
+		 "/Kids [6 0 R]\n"
+		 "/Count 1\n"
+		 ">>\n"
+		 "endobj\n");
+}
+
+/* Open stream for data - graphical objects, fonts etc. PDF object 4*/
+
+int gl2psOpenPDFDataStream(){
+  int offs = 0;
+  
+  offs += fprintf(gl2ps->stream, 
+		  "4 0 obj\n"
+		  "<<\n" 
+		  "/Length 5 0 R\n" );
+  offs += gl2psPrintPDFCompressorType();
+  offs += fprintf(gl2ps->stream, 
+		  ">>\n"
+		  "stream\n");
+  return offs;
+}
+
+/* Stream setup - Graphics state, fill background if allowed */
+
+int gl2psOpenPDFDataStreamWritePreface(){
+  int offs;
+  GLint index;
+  GLfloat rgba[4];
+  
+  offs = fprintf(gl2ps->stream, "/GS1 gs\n");
+  
+  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] = 0.;
+    }
+    offs += gl2psPrintPDFFillColor(rgba);    
+    offs += fprintf(gl2ps->stream, "%d %d %d %d re\n",
+		    (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
+		    (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
+    offs += fprintf(gl2ps->stream, "f\n");  
+  }
+  return offs;
+}
+
+/* Use the functions above to create the first part of the PDF*/
+
+void gl2psPrintPDFHeader(){
+  int offs;
+  
+  /* tlist, tidxlist, ilist and slist contain triangles, indexes for
+     consecutive triangles, images and strings */
+  gl2ps->tlist = gl2psListCreate(0, 1, sizeof(GL2PStriangle));
+  gl2ps->tidxlist = gl2psListCreate(0, 1, sizeof(int));
+  gl2ps->ilist = gl2psListCreate(0, 1, sizeof(GL2PSimage));
+  gl2ps->slist = gl2psListCreate(0, 1, sizeof(GL2PSstring));
+  
+  gl2ps->lasttype = GL2PS_NOTYPE;
+  gl2ps->consec_cnt = 0;
+  gl2ps->consec_inner_cnt = 0;
+  
+  offs = fprintf(gl2ps->stream, "%%PDF-1.3\n");
+  gl2ps->cref[0] = offs;
+  
+  offs += gl2psPrintPDFInfo();   
+  gl2ps->cref[1] = offs;
+  
+  offs += gl2psPrintPDFCatalog();
+  gl2ps->cref[2] = offs;  
+  
+  offs += gl2psPrintPDFPages();
+  gl2ps->cref[3] = offs;  
+  
+  offs += gl2psOpenPDFDataStream();
+  gl2ps->cref[4] = offs; /* finished in gl2psPrintPDFFooter */
+  gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface();
+}
+
+
+int gl2psFlushPDFTriangles(){
+  int offs = 0;
+  if(gl2ps->lasttype == GL2PS_TRIANGLE){
+    gl2psListAdd(gl2ps->tidxlist,&gl2ps->consec_inner_cnt);
+    offs = fprintf(gl2ps->stream, "/Sh%d sh\n", gl2ps->consec_cnt++);
+    gl2ps->consec_inner_cnt = 0;
+    gl2ps->streamlength += offs;
+  }
+  return offs;
+}
+
+int gl2psFlushPDFLines(){
+  int offs = 0;
+  if(gl2ps->lasttype == GL2PS_LINE && !gl2ps->line_stroked){
+    offs = fprintf(gl2ps->stream, "S\n");
+    gl2ps->streamlength += offs;
+    gl2ps->line_stroked = 1;
+  }
+  return offs;
+}
+
+/* The central primitive drawing */
+
+void gl2psPrintPDFPrimitive(void *a, void *b){
+  GL2PSprimitive *prim;
+  GL2PStriangle t;
+  GL2PSimage* image;
+  GL2PSstring* str;
+
+  prim = *(GL2PSprimitive**)a;
+  
+  if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
+  
+  if(prim->type != GL2PS_TRIANGLE)
+    gl2psFlushPDFTriangles();
+  if(prim->type != GL2PS_LINE)
+    gl2psFlushPDFLines();
+  
+  switch(prim->type){
+  case GL2PS_PIXMAP :
+    image = gl2psCopyPixmap(prim->image);
+    gl2psListAdd(gl2ps->ilist, &image);
+    gl2ps->streamlength += fprintf(gl2ps->stream,
+				   "q\n"
+				   "%d 0 0 %d %f %f cm\n"
+				   "/Im%d Do\n"
+				   "Q\n",
+				   (int)prim->image->width, (int)prim->image->height,
+				   prim->verts[0].xyz[0], prim->verts[0].xyz[1],
+				   gl2psListNbr(gl2ps->ilist)-1);
+    break;
+  case GL2PS_TEXT :
+    str = gl2psCopyText(prim->text);
+    gl2psListAdd(gl2ps->slist, &str);		
+    gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
+    gl2ps->streamlength += fprintf(gl2ps->stream,			
+				   "BT\n"
+				   "/F%d %d Tf\n"
+				   "%f %f Td\n"
+				   "(%s) Tj\n"
+				   "ET\n",
+				   gl2psListNbr(gl2ps->slist)-1,
+				   prim->text->fontsize, prim->verts[0].xyz[0], 
+				   prim->verts[0].xyz[1], prim->text->str);
+    break;
+  case GL2PS_POINT :
+    if(gl2ps->lastlinewidth != prim->width){
+      gl2ps->lastlinewidth = prim->width;
+      gl2ps->streamlength += gl2psPrintPDFLineWidth(gl2ps->lastlinewidth);
+    }
+    gl2ps->streamlength += fprintf(gl2ps->stream, "1 J\n");
+    gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
+    gl2ps->streamlength += fprintf(gl2ps->stream, "%f %f m %f %f l S\n",
+				   prim->verts[0].xyz[0], prim->verts[0].xyz[1],
+				   prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
+    gl2ps->streamlength += fprintf(gl2ps->stream, "0 J\n");
+    break;
+  case GL2PS_LINE :
+    gl2ps->line_width_diff = gl2ps->lastlinewidth != prim->width;
+    gl2ps->line_rgb_diff = !GL2PS_ZERO(gl2psColorDiff(prim->verts[0].rgba, gl2ps->lastrgba));
+    
+    if(gl2ps->line_width_diff || gl2ps->line_rgb_diff || prim->dash){
+      gl2psFlushPDFLines();
+    }
+    if(gl2ps->line_width_diff){
+      gl2ps->lastlinewidth = prim->width;
+      gl2ps->streamlength += gl2psPrintPDFLineWidth(gl2ps->lastlinewidth);
+    }
+    if(gl2ps->line_rgb_diff){
+      gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
+    }
+    if(prim->dash){
+      gl2ps->streamlength += fprintf(gl2ps->stream, "[%d] 0 d\n", prim->dash);
+    }
+    gl2ps->streamlength += fprintf(gl2ps->stream, "%f %f m %f %f l \n",
+				   prim->verts[0].xyz[0], prim->verts[0].xyz[1],
+				   prim->verts[1].xyz[0], prim->verts[1].xyz[1]);
+    gl2ps->line_stroked = 0;
+    
+    if(prim->dash){
+      /* FIXME: use prim->dash */
+      gl2ps->streamlength += fprintf(gl2ps->stream, "S\n[] 0 d\n"); 
+      gl2ps->line_stroked = 1;
+    }
+    break;
+  case GL2PS_TRIANGLE :
+    t[0] = prim->verts[0];
+    t[1] = prim->verts[1];
+    t[2] = prim->verts[2];
+    
+    gl2psListAdd(gl2ps->tlist, t);		
+    ++gl2ps->consec_inner_cnt;
+    break;
+  case GL2PS_QUADRANGLE :
+    gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
+    break;
+  default :
+    gl2psMsg(GL2PS_ERROR, "Unknown type of primitive to print");
+    break;
+  }
+  gl2ps->lasttype = prim->type;
+}
+
+/* close stream and ... */
+
+int gl2psClosePDFDataStream(){
+  int offs = 0;
+  
+  offs += gl2psFlushPDFTriangles();
+  offs += gl2psFlushPDFLines();
+  
+  offs += fprintf(gl2ps->stream, 
+		  "endstream\n"
+		  "endobj\n");
+  return offs;
+}
+
+/* ... write the now known length object */
+
+int gl2psPrintPDFDataStreamLength(int val){
+  return fprintf(gl2ps->stream,
+		 "5 0 obj\n"
+		 "%d\n"
+		 "endobj\n", val);
+}
+
+/* Create named shader objects */
+
+int gl2psPrintPDFShaderResources(int firstObject, int size){
+  int offs = 0;
+  int i;
+  
+  offs += fprintf(gl2ps->stream,
+		  "/Shading\n"
+		  "<<\n");
+  
+  for(i = 0; i < size; ++i){
+    offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", i, firstObject+i);
+  }
+  offs += fprintf(gl2ps->stream, ">>\n");
+  
+  return offs;
+}
+
+/* Create named pixmap objects */
+
+int gl2psPrintPDFPixmapResources(int firstObject, int size){
+  int offs = 0;
+  int i;
+  
+  offs += fprintf(gl2ps->stream,
+		  "/XObject\n"
+		  "<<\n");
+  
+  for(i = 0; i < size; ++i){
+    offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", i, firstObject + i);
+  }
+  offs += fprintf(gl2ps->stream, ">>\n");
+  
+  return offs;
+}
+
+/* Create named font objects */
+
+int gl2psPrintPDFTextResources(int firstObject, int size){
+  int offs = 0;
+  int i;
+  
+  offs += fprintf(gl2ps->stream,
+		  "/Font\n"
+		  "<<\n");
+  
+  for(i = 0; i < size; ++i){
+    offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", i, firstObject + i);
+  }
+  offs += fprintf(gl2ps->stream, ">>\n");
+  
+  return offs;
+}
+
+/* Put the info created before in PDF objects */
+
+int gl2psPrintPDFSinglePage(){
+  int offs;
+	
+  offs = fprintf(gl2ps->stream, 
+		 "6 0 obj\n"
+		 "<<\n" 
+		 "/Type /Page\n"
+		 "/Parent 3 0 R\n"
+		 "/MediaBox [%d %d %d %d]\n",
+		 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 
+		 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
+  
+  if(gl2ps->options & GL2PS_LANDSCAPE)
+    offs += fprintf(gl2ps->stream, "/Rotate -90\n");
+  
+  offs += fprintf(gl2ps->stream, 
+		  "/Contents 4 0 R\n"
+		  "/Resources\n" 
+		  "<<\n" 
+		  "/ProcSet [/PDF /Text /ImageB /ImageC]  %%/ImageI\n"
+		  "/Length 5 0 R\n"
+		  "/ExtGState\n" 
+		  "<<\n"	
+		  "/GS1 7 0 R\n"
+		  ">>\n");
+  
+  offs += gl2psPrintPDFShaderResources(GL2PS_FIXED_XREF_ENTRIES + 1, 
+				       gl2psListNbr(gl2ps->tidxlist));
+  offs += gl2psPrintPDFPixmapResources(GL2PS_FIXED_XREF_ENTRIES + 1
+				       + gl2psListNbr(gl2ps->tidxlist),
+				       gl2psListNbr(gl2ps->ilist));
+  offs += gl2psPrintPDFTextResources(GL2PS_FIXED_XREF_ENTRIES + 1 
+				     + gl2psListNbr(gl2ps->tidxlist) 
+				     + gl2psListNbr(gl2ps->ilist), 
+				     gl2psListNbr(gl2ps->slist));
+  offs += fprintf(gl2ps->stream, 			
+		  ">>\n"
+		  ">>\n"
+		  "endobj\n");
+  
+  return offs;
+}
+
+/* Extended graphics state for shading */
+
+int gl2psPrintPDFExtGState(){
+  return fprintf(gl2ps->stream,
+		 "7 0 obj\n"
+		 "<<\n"
+		 "/Type /ExtGState\n"
+		 "/SA false\n"
+		 "/SM 0.02\n"
+		 "/OP false\n"
+		 "/op false\n"
+		 "/OPM 0\n"
+		 "/BG2 /Default\n"
+		 "/UCR2 /Default\n"
+		 "/TR2 /Default\n"
+		 ">>\n"
+		 "endobj\n");
+}
+
+/* Put a triangles uncompressed raw data in shader stream */
+
+int gl2psPrintPDFShaderStreamData(GL2PStriangle triangle){
+  int offs = 0;
+  int i;
+  unsigned long imap;
+  GLfloat  diff, dx, dy;
+  
+  char edgeflag = 0;
+  double dmax = ~1UL;
+  
+  dx = gl2ps->viewport[2]-gl2ps->viewport[0];
+  dy = gl2ps->viewport[3]-gl2ps->viewport[1];
+  
+  for(i = 0; i < 3; ++i){
+    offs += fwrite (&edgeflag, sizeof(char), 1, gl2ps->stream);
+
+    /* In unfiltered mode the Shader stream in PDF requires to be in a
+       'big-endian' order */
+    
+    if(fabs(dx*dy) < FLT_MIN){
+      offs += gl2psWriteBigEndian(0, 4, gl2ps->stream);
+      offs += gl2psWriteBigEndian(0, 4, gl2ps->stream);
+    }
+    else{
+      diff = (triangle[i].xyz[0] - gl2ps->viewport[0]) / dx;
+      if(diff>1)
+	diff = 1;
+      else if(diff < 0)
+	diff = 0;
+      imap = (unsigned long)(diff * dmax);
+      offs += gl2psWriteBigEndian(imap, 4, gl2ps->stream);
+      
+      diff = (triangle[i].xyz[1] - gl2ps->viewport[1]) / dy;
+      if(diff>1)
+	diff = 1;
+      else if(diff < 0)
+	diff = 0;
+      imap = (unsigned long)(diff * dmax);
+      offs += gl2psWriteBigEndian(imap, 4, gl2ps->stream);
+    }
+    
+    imap = (unsigned long)(triangle[i].rgba[0] * dmax);
+    offs += gl2psWriteBigEndian(imap, 1, gl2ps->stream);
+    
+    imap = (unsigned long)(triangle[i].rgba[1] * dmax);
+    offs += gl2psWriteBigEndian(imap, 1, gl2ps->stream);
+    
+    imap = (unsigned long)(triangle[i].rgba[2] * dmax);
+    offs += gl2psWriteBigEndian(imap, 1, gl2ps->stream);
+  }
+  return offs;
+}
+
+/* Writes shaded triangle */
+
+int gl2psPrintPDFShader(int obj, GL2PSlist* triangles, int idx, int cnt ){
+  int offs = 0;
+  int vertexbytes = 1+4+4+1+1+1;
+  int i;
+  
+  offs += fprintf(gl2ps->stream,
+		  "%d 0 obj\n"
+		  "<< "
+		  "/ShadingType 4 "
+		  "/ColorSpace /DeviceRGB "
+		  "/BitsPerCoordinate 32 "
+		  "/BitsPerComponent 8 "
+		  "/BitsPerFlag 8 "
+		  "/Decode [%d %d %d %d 0 1 0 1 0 1] ",
+		  obj,
+		  (int)gl2ps->viewport[0], (int)gl2ps->viewport[2],
+		  (int)gl2ps->viewport[1], (int)gl2ps->viewport[3]);
+  
+  offs += gl2psPrintPDFCompressorType();
+  
+  offs += fprintf(gl2ps->stream,
+		  "/Length %d "
+		  ">>\n"
+		  "stream\n",
+		  vertexbytes * 3 * cnt);
+  for(i = 0; i < cnt; ++i)
+    offs += gl2psPrintPDFShaderStreamData((GL2PSvertex*)gl2psListPointer(triangles, idx+i));
+  
+  offs += fprintf(gl2ps->stream,
+		  "\nendstream\n"
+		  "endobj\n");
+  return offs;
+}
+
+/* Writes all triangles and returns field of offsets for the PDF cross
+   reference table */
+
+int* gl2psPrintPDFShaderObjects(int firstObjnumber, int firstOffs){
+  int size;
+  int* offs;
+  int i;
+  int idx = 0;
+  int tmp;
+  
+  size = gl2psListNbr(gl2ps->tidxlist);
+  offs = (int*)gl2psMalloc(sizeof(int) * (size+1));
+  
+  offs[0] = firstOffs;
+  
+  for(i = 0; i < size; ++i){
+    tmp = *(int*)gl2psListPointer(gl2ps->tidxlist, i);
+    
+    firstOffs += gl2psPrintPDFShader(i+firstObjnumber, gl2ps->tlist, idx, tmp);
+    offs[i+1] = firstOffs;
+    idx += tmp;
+  }
+  return offs;
+}
+
+/* Similar groups of  functions for pixmaps and text */
+
+int gl2psPrintPDFPixmapStreamData(GL2PSimage* im){
+  int x,y;
+  GLfloat r,g,b;
+  
+  for(y = 0; y < im->height; ++y)
+    for(x = 0; x < im->width; ++x){
+      gl2psGetRGB(im->pixels, im->width, im->height, x, y, &r, &g, &b);
+      fputc((int)(r*255),gl2ps->stream);
+      fputc((int)(g*255),gl2ps->stream);
+      fputc((int)(b*255),gl2ps->stream);
+    }
+  return 3 * im->width * im->height;
+}
+
+int gl2psPrintPDFPixmap(int obj, GL2PSimage* im ){
+  int offs = 0;
+  
+  offs += fprintf(gl2ps->stream,
+		  "%d 0 obj\n"
+		  "<<\n"
+		  "/Type /XObject\n"
+		  "/Subtype /Image\n"
+		  "/Width %d\n"
+		  "/Height %d\n"
+		  "/ColorSpace /DeviceRGB\n"
+		  "/BitsPerComponent 8\n"
+		  "/Length %d\n"
+		  ">>\n"
+		  "stream\n",
+		  obj, (int)im->width, (int)im->height, 
+		  (int)(im->width * im->height * 3));
+  
+  offs += gl2psPrintPDFPixmapStreamData(im);
+  
+  offs += fprintf(gl2ps->stream,
+		  "\nendstream\n"
+		  "endobj\n");
+  return offs;
+}
+
+int* gl2psPrintPDFPixmapObjects(int firstObjnumber, int firstOffs){
+  int size;
+  int* offs;
+  int i;
+  
+  size = gl2psListNbr(gl2ps->ilist);
+  offs = (int*)gl2psMalloc(sizeof(int) * (size+1));
+  
+  offs[0] = firstOffs;
+  
+  for(i = 0; i < size; ++i){
+    firstOffs += gl2psPrintPDFPixmap(i+firstObjnumber, 
+				     *(GL2PSimage**)gl2psListPointer(gl2ps->ilist, i));
+    offs[i+1] = firstOffs;
+  }
+  return offs;
+}
+
+int gl2psPrintPDFText(int obj, GL2PSstring* s, int fontnumber ){
+  int offs = 0;
+  
+  offs += fprintf(gl2ps->stream,
+		  "%d 0 obj\n"
+		  "<<\n"
+		  "/Type /Font\n"
+		  "/Subtype /Type1\n"
+		  "/Name /F%d\n"
+		  "/BaseFont /%s\n"
+		  "/Encoding /MacRomanEncoding\n"
+		  ">>\n"
+		  "endobj\n",
+		  obj, fontnumber, s->fontname);
+  return offs;
+}
+
+int* gl2psPrintPDFTextObjects(int firstObjnumber, int firstOffs){
+  int size;
+  int* offs;
+  int i;
+  
+  size = gl2psListNbr(gl2ps->slist);
+  offs = (int*)gl2psMalloc(sizeof(int) * (size+1));
+  
+  offs[0] = firstOffs;
+  
+  for(i = 0; i < size; ++i){
+    firstOffs += gl2psPrintPDFText(i+firstObjnumber,
+				   *(GL2PSstring**)gl2psListPointer(gl2ps->slist, i),i);
+    offs[i+1] = firstOffs;
+  }
+  return offs;
+}
+
+/* All variable data is written at this point and all required
+   functioninality has been gathered: Writes file footer with cross
+   reference table and trailer */
+
+void gl2psPrintPDFFooter(){
+  int offs;
+  int i;
+  int *shader_offs, *image_offs, *text_offs;
+  int shader_size, image_size, text_size, objnumber, lastoffset;
+  
+  offs = gl2ps->cref[4] + gl2ps->streamlength; 
+  offs += gl2psClosePDFDataStream();
+  gl2ps->cref[4] = offs; 
+  
+  offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength);
+  gl2ps->cref[5] = offs;
+  gl2ps->streamlength = 0;
+  
+  offs += gl2psPrintPDFSinglePage();
+  gl2ps->cref[6] = offs;
+  
+  offs += gl2psPrintPDFExtGState();
+  
+  shader_size = gl2psListNbr(gl2ps->tidxlist);
+  image_size = gl2psListNbr(gl2ps->ilist);
+  text_size = gl2psListNbr(gl2ps->slist);
+  
+  shader_offs = gl2psPrintPDFShaderObjects(GL2PS_FIXED_XREF_ENTRIES + 1, offs);
+  image_offs = gl2psPrintPDFPixmapObjects(GL2PS_FIXED_XREF_ENTRIES + 1 + shader_size, 
+					  shader_offs[shader_size]);
+  text_offs = gl2psPrintPDFTextObjects(GL2PS_FIXED_XREF_ENTRIES + 1 + shader_size + image_size,
+				       image_offs[image_size]);
+  
+  lastoffset = text_offs[text_size];
+  objnumber = GL2PS_FIXED_XREF_ENTRIES + shader_size + image_size + text_size + 1;
+  
+  /* Start cross reference table. The file has to been opened in
+     binary mode to preserve the 20 digit string length! */
+  fprintf(gl2ps->stream,
+	  "xref\n"
+	  "0 %d\n"
+	  "%010d 65535 f \n", objnumber, 0); 
+  
+  for(i = 0; i < GL2PS_FIXED_XREF_ENTRIES; ++i){
+    fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->cref[i]); 
+  }
+  for(i = 0; i < shader_size; ++i){
+    fprintf(gl2ps->stream, "%010d 00000 n \n", shader_offs[i]); 
+  }
+  for(i = 0; i < image_size; ++i){
+    fprintf(gl2ps->stream, "%010d 00000 n \n", image_offs[i]); 
+  }
+  for(i = 0; i < text_size; ++i){
+    fprintf(gl2ps->stream, "%010d 00000 n \n", text_offs[i]); 
+  }
+  
+  fprintf(gl2ps->stream,
+	  "trailer\n"
+	  "<<\n" 
+	  "/Size %d\n"
+	  "/Info 1 0 R\n"
+	  "/Root 2 0 R\n"
+	  ">>\n"
+	  "startxref\n%d\n"
+	  "%%%%EOF\n",
+	  objnumber, lastoffset);
+  
+  /* Free auxiliary lists and arrays */
+  gl2psFree(shader_offs);
+  gl2psFree(image_offs);
+  gl2psFree(text_offs);
+  gl2psListDelete(gl2ps->tlist);
+  gl2psListDelete(gl2ps->tidxlist);
+  for(i = 0; i < gl2psListNbr(gl2ps->ilist); ++i)
+    gl2psFreePixmap(*(GL2PSimage**)gl2psListPointer(gl2ps->ilist,i));
+  gl2psListDelete(gl2ps->ilist);
+  for(i = 0; i < gl2psListNbr(gl2ps->slist); ++i)
+    gl2psFreeText(*(GL2PSstring**)gl2psListPointer(gl2ps->slist,i));
+  gl2psListDelete(gl2ps->slist);
+}
+
+/* PDF begin viewport */
+
+void gl2psPrintPDFBeginViewport(GLint viewport[4]){
+  int offs;
+  GLint index;
+  GLfloat rgba[4];
+  int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
+  
+  offs = 0;
+  
+  glRenderMode(GL_FEEDBACK);
+  
+  offs += fprintf(gl2ps->stream, "q\n");
+  
+  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] = 0.;
+    }
+    offs += fprintf(gl2ps->stream,
+		    "%f %f %f rg\n"
+		    "%d %d %d %d re\n"
+		    /* "W\n" */  
+		    "f\n",
+		    rgba[0], rgba[1], rgba[2],x, y, w, h);
+  }
+  gl2ps->streamlength += offs;
+}
+
+GLint gl2psPrintPDFEndViewport(){
+  GLint res;
+  GLint gl2psPrintPrimitives(void);
+  
+  res = gl2psPrintPrimitives();
+  gl2ps->streamlength += fprintf(gl2ps->stream, "Q\n");
+  
+  return res;
+}
+
+/********************************************************************* 
+ *
+ * General primitive printing routine
+ *
+ *********************************************************************/
 
 GLint gl2psPrintPrimitives(void){
   GL2PSbsptree *root;
@@ -1919,7 +2859,9 @@ GLint gl2psPrintPrimitives(void){
     return GL2PS_NO_FEEDBACK; /* Empty feedback buffer */
   }
 
-  if(gl2ps->format == GL2PS_PS || gl2ps->format == GL2PS_EPS){
+  if(gl2ps->format == GL2PS_PS || 
+     gl2ps->format == GL2PS_EPS ||
+     gl2ps->format == GL2PS_PDF){
     gl2psParseFeedbackBuffer(used);
   }
 
@@ -1935,6 +2877,9 @@ GLint gl2psPrintPrimitives(void){
   case GL2PS_EPS :
     pprim = gl2psPrintPostScriptPrimitive;
     break;
+  case GL2PS_PDF :
+    pprim = gl2psPrintPDFPrimitive;
+    break;
   }
   
   switch(gl2ps->sort){
@@ -1981,7 +2926,11 @@ GLint gl2psPrintPrimitives(void){
   return GL2PS_SUCCESS;
 }
 
-/* The public routines */
+/********************************************************************* 
+ *
+ * Public routines
+ *
+ *********************************************************************/
 
 GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, 
 				  GLint viewport[4], GLint format, GLint sort,
@@ -2057,6 +3006,14 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
     rewind(gl2ps->stream);
   }
 
+  /* only used for PDF output... */
+  gl2ps->lasttype = -1;
+  gl2ps->consec_cnt = 0;
+  gl2ps->consec_inner_cnt = 1;
+  gl2ps->line_width_diff = 1;
+  gl2ps->line_rgb_diff = 1;
+  gl2ps->line_stroked = 0;
+
   switch(gl2ps->format){
   case GL2PS_TEX :
     gl2psPrintTeXHeader();
@@ -2065,6 +3022,9 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
   case GL2PS_EPS :
     gl2psPrintPostScriptHeader();
     break;
+  case GL2PS_PDF :
+    gl2psPrintPDFHeader();
+    break;
   default :
     gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", gl2ps->format);
     gl2psFree(gl2ps);
@@ -2097,6 +3057,9 @@ GL2PSDLL_API GLint gl2psEndPage(void){
   case GL2PS_EPS :
     gl2psPrintPostScriptFooter();
     break;
+  case GL2PS_PDF :
+    gl2psPrintPDFFooter();
+    break;
   }
 
   fflush(gl2ps->stream);
@@ -2114,9 +3077,13 @@ GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]){
   if(!gl2ps) return GL2PS_UNINITIALIZED;
 
   switch(gl2ps->format){
+  case GL2PS_PS :
   case GL2PS_EPS :
     gl2psPrintPostScriptBeginViewport(viewport);
     break;
+  case GL2PS_PDF :
+    gl2psPrintPDFBeginViewport(viewport);
+    break;
   default :
     /* FIXME: handle other formats */
     break;
@@ -2131,9 +3098,13 @@ GL2PSDLL_API GLint gl2psEndViewport(void){
   if(!gl2ps) return GL2PS_UNINITIALIZED;
 
   switch(gl2ps->format){
+  case GL2PS_PS :
   case GL2PS_EPS :
     res = gl2psPrintPostScriptEndViewport();
     break;
+  case GL2PS_PDF :
+    res = gl2psPrintPDFEndViewport();
+    break;
   default :
     /* FIXME: handle other formats */
     res = GL2PS_SUCCESS;
@@ -2143,7 +3114,8 @@ GL2PSDLL_API GLint gl2psEndViewport(void){
   return res;
 }
 
-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 alignment, GL2PSrgba rgba){
   GLfloat pos[4];
   GL2PSprimitive *prim;
   GLboolean valid;
@@ -2169,19 +3141,32 @@ GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort font
   prim->culled = 0;
   prim->dash = 0;
   prim->width = 1;
-  glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
+  if(rgba){
+    prim->verts[0].rgba[0] = rgba[0];
+    prim->verts[0].rgba[1] = rgba[1];
+    prim->verts[0].rgba[2] = rgba[2];
+    prim->verts[0].rgba[3] = rgba[3];
+  }
+  else{
+    glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
+  }
   prim->text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
   prim->text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char));
   strcpy(prim->text->str, str); 
   prim->text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char));
   strcpy(prim->text->fontname, fontname);
   prim->text->fontsize = fontsize;
+  prim->text->alignment = alignment;
 
   gl2psListAdd(gl2ps->primitives, &prim);
 
   return GL2PS_SUCCESS;
 }
 
+GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize){
+  return gl2psTextOpt(str, fontname, fontsize, GL2PS_TEXT_BL, NULL);
+}
+
 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
 				   GLint xorig, GLint yorig,
 				   GLenum format, GLenum type, 
diff --git a/Graphics/gl2ps.h b/Graphics/gl2ps.h
index 74403c79c6..64eb67b348 100644
--- a/Graphics/gl2ps.h
+++ b/Graphics/gl2ps.h
@@ -2,7 +2,7 @@
  * GL2PS, an OpenGL to PostScript Printing Library
  * Copyright (C) 1999-2003 Christophe Geuzaine
  *
- * $Id: gl2ps.h,v 1.41 2003-07-03 18:59:52 geuzaine Exp $
+ * $Id: gl2ps.h,v 1.42 2003-09-16 23:50:58 geuzaine Exp $
  *
  * E-mail: geuz@geuz.org
  * URL: http://www.geuz.org/gl2ps/
@@ -55,9 +55,9 @@
 
 /* Version number */
 
-#define GL2PS_MAJOR_VERSION 0
-#define GL2PS_MINOR_VERSION 9
-#define GL2PS_PATCH_VERSION 2
+#define GL2PS_MAJOR_VERSION 1
+#define GL2PS_MINOR_VERSION 0
+#define GL2PS_PATCH_VERSION 0
 
 #define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \
                        0.01 * GL2PS_MINOR_VERSION + \
@@ -65,9 +65,10 @@
 
 /* Output file format */
 
-#define GL2PS_PS  1
-#define GL2PS_EPS 2
-#define GL2PS_TEX 3
+#define GL2PS_PS               1
+#define GL2PS_EPS              2
+#define GL2PS_TEX              3
+#define GL2PS_PDF              4
 
 /* Sorting algorithms */
 
@@ -88,6 +89,7 @@
 #define GL2PS_NO_PS3_SHADING       (1<<7)
 #define GL2PS_NO_PIXMAP            (1<<8)
 #define GL2PS_USE_CURRENT_VIEWPORT (1<<9)
+#define GL2PS_DEFLATE              (1<<10)
 
 /* Arguments for gl2psEnable/gl2psDisable */
 
@@ -102,6 +104,7 @@
 #define GL2PS_SIMPLE_OFFSET       0.05
 #define GL2PS_SIMPLE_OFFSET_LARGE 1.0
 #define GL2PS_ZERO(arg)           (fabs(arg)<1.e-20)
+#define GL2PS_FIXED_XREF_ENTRIES  7 
 
 /* Message levels and error codes */
 
@@ -115,6 +118,7 @@
 
 /* Primitive types */
 
+#define GL2PS_NOTYPE     -1
 #define GL2PS_TEXT       1
 #define GL2PS_POINT      2
 #define GL2PS_LINE       3
@@ -122,6 +126,18 @@
 #define GL2PS_TRIANGLE   5
 #define GL2PS_PIXMAP     6
 
+/* Text alignment */
+
+#define GL2PS_TEXT_C     1
+#define GL2PS_TEXT_CL    2
+#define GL2PS_TEXT_CR    3
+#define GL2PS_TEXT_B     4
+#define GL2PS_TEXT_BL    5
+#define GL2PS_TEXT_BR    6
+#define GL2PS_TEXT_T     7
+#define GL2PS_TEXT_TL    8
+#define GL2PS_TEXT_TR    9
+
 /* BSP tree primitive comparison */
 
 #define GL2PS_COINCIDENT  1
@@ -175,9 +191,12 @@ typedef struct {
   GL2PSrgba rgba;
 } GL2PSvertex;
 
+typedef GL2PSvertex GL2PStriangle[3];
+
 typedef struct {
   GLshort fontsize;
   char *str, *fontname;
+  GLint alignment;
 } GL2PSstring;
 
 typedef struct {
@@ -196,17 +215,31 @@ typedef struct {
 } GL2PSprimitive;
 
 typedef struct {
-  GLint format, sort, options, colorsize, colormode, buffersize, maxbestroot;
+  /* general */
+  GLint format, sort, options, colorsize, colormode, buffersize;
   const char *title, *producer, *filename;
-  GLboolean boundary, zerosurfacearea;
+  GLboolean boundary;
   GLfloat *feedback, offset[2];
   GLint viewport[4];
   GL2PSrgba *colormap, lastrgba, threshold;
   float lastlinewidth;
   GL2PSlist *primitives;
-  GL2PSbsptree2d *imagetree;
   FILE *stream;
+
+  /* BSP-specific */
+  GLint maxbestroot;
+
+  /* occlusion culling-specific */
+  GLboolean zerosurfacearea;
+  GL2PSbsptree2d *imagetree;
   GL2PSprimitive *primitivetoadd;
+  
+  /* PDF-specific */
+  int cref[GL2PS_FIXED_XREF_ENTRIES];
+  int streamlength;
+  GL2PSlist *tlist, *tidxlist, *ilist, *slist; 
+  int lasttype, consec_cnt, consec_inner_cnt;
+  int line_width_diff, line_rgb_diff, line_stroked;
 } GL2PScontext;
 
 /* public functions */
@@ -225,6 +258,8 @@ GL2PSDLL_API GLint gl2psEndPage(void);
 GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]);
 GL2PSDLL_API GLint gl2psEndViewport(void);
 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, GL2PSrgba color);
 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
 				   GLint xorig, GLint yorig,
 				   GLenum format, GLenum type, const void *pixels);
diff --git a/Mesh/Mesh.h b/Mesh/Mesh.h
index b2c4b24a34..5e29f74ef1 100644
--- a/Mesh/Mesh.h
+++ b/Mesh/Mesh.h
@@ -50,6 +50,8 @@
 #define FORMAT_EPSTEX  21
 #define FORMAT_PNG     22
 #define FORMAT_PNGTEX  23
+#define FORMAT_PDF     24
+#define FORMAT_PDFTEX  25
 
 #define CONV_VALUE    0.8
 
-- 
GitLab