gl2ps.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id$
00002 /*
00003  * GL2PS, an OpenGL to PostScript Printing Library
00004  * Copyright (C) 1999-2009 C. Geuzaine
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of either:
00008  *
00009  * a) the GNU Library General Public License as published by the Free
00010  * Software Foundation, either version 2 of the License, or (at your
00011  * option) any later version; or
00012  *
00013  * b) the GL2PS License as published by Christophe Geuzaine, either
00014  * version 2 of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See either
00019  * the GNU Library General Public License or the GL2PS License for
00020  * more details.
00021  *
00022  * You should have received a copy of the GNU Library General Public
00023  * License along with this library in the file named "COPYING.LGPL";
00024  * if not, write to the Free Software Foundation, Inc., 675 Mass Ave,
00025  * Cambridge, MA 02139, USA.
00026  *
00027  * You should have received a copy of the GL2PS License with this
00028  * library in the file named "COPYING.GL2PS"; if not, I will be glad
00029  * to provide one.
00030  *
00031  * Contributors:
00032  *   Michael Sweet <mike@easysw.com>
00033  *   Marc Ume <marc.ume@digitalgraphics.be>
00034  *   Jean-Francois Remacle <remacle@gce.ucl.ac.be>
00035  *   Bart Kaptein <B.L.Kaptein@lumc.nl>
00036  *   Quy Nguyen-Dai <quy@nguyendai.org>
00037  *   Sam Buss <sbuss@ucsd.edu>
00038  *   Shane Hill <Shane.Hill@dsto.defence.gov.au>
00039  *   Romain Boman <r_boman@yahoo.fr>
00040  *   Rouben Rostamian <rostamian@umbc.edu>
00041  *   Diego Santa Cruz <Diego.SantaCruz@epfl.ch>
00042  *   Shahzad Muzaffar <Shahzad.Muzaffar@cern.ch>
00043  *   Lassi Tuura <lassi.tuura@cern.ch>
00044  *   Guy Barrand <barrand@lal.in2p3.fr>
00045  *   Prabhu Ramachandran <prabhu@aero.iitm.ernet.in>
00046  *   Micha Bieber <bieber@traits.de>
00047  *   Olivier Couet <couet@mail.cern.ch>
00048  *   Shai Ayal <shaiay@gmail.com>
00049  *   Fabian Wenzel <wenzel@tu-harburg.de>
00050  *   Ian D. Gay <gay@sfu.ca>
00051  *   Cosmin Truta <cosmin@cs.toronto.edu>
00052  *   Baiju Devani <b.devani@gmail.com>
00053  *   Alexander Danilov <danilov@lanl.gov>
00054  *
00055  * For the latest info about gl2ps, see http://www.geuz.org/gl2ps/.
00056  * Please report all bugs and problems to <gl2ps@geuz.org>.
00057  */
00058 
00059 #include "gl2ps.h"
00060 
00061 #include <math.h>
00062 #include <string.h>
00063 #include <sys/types.h>
00064 #include <stdarg.h>
00065 #include <time.h>
00066 #include <float.h>
00067 
00068 #if defined(GL2PS_HAVE_ZLIB)
00069 #include <zlib.h>
00070 #endif
00071 
00072 #if defined(GL2PS_HAVE_LIBPNG)
00073 #include <png.h>
00074 #endif
00075 
00076 /********************************************************************* 
00077  *
00078  * Private definitions, data structures and prototypes
00079  *
00080  *********************************************************************/
00081 
00082 /* Magic numbers (assuming that the order of magnitude of window
00083    coordinates is 10^3) */
00084 
00085 #define GL2PS_EPSILON       5.0e-3F
00086 #define GL2PS_ZSCALE        1000.0F
00087 #define GL2PS_ZOFFSET       5.0e-2F
00088 #define GL2PS_ZOFFSET_LARGE 20.0F
00089 #define GL2PS_ZERO(arg)     (fabs(arg) < 1.e-20)
00090 
00091 /* Primitive types */
00092 
00093 #define GL2PS_NO_TYPE          -1
00094 #define GL2PS_TEXT             1
00095 #define GL2PS_POINT            2
00096 #define GL2PS_LINE             3
00097 #define GL2PS_QUADRANGLE       4
00098 #define GL2PS_TRIANGLE         5
00099 #define GL2PS_PIXMAP           6
00100 #define GL2PS_IMAGEMAP         7
00101 #define GL2PS_IMAGEMAP_WRITTEN 8
00102 #define GL2PS_IMAGEMAP_VISIBLE 9
00103 #define GL2PS_SPECIAL          10
00104 
00105 /* BSP tree primitive comparison */
00106 
00107 #define GL2PS_COINCIDENT  1
00108 #define GL2PS_IN_FRONT_OF 2
00109 #define GL2PS_IN_BACK_OF  3
00110 #define GL2PS_SPANNING    4
00111 
00112 /* 2D BSP tree primitive comparison */
00113 
00114 #define GL2PS_POINT_COINCIDENT 0
00115 #define GL2PS_POINT_INFRONT    1
00116 #define GL2PS_POINT_BACK       2
00117 
00118 /* Internal feedback buffer pass-through tokens */
00119 
00120 #define GL2PS_BEGIN_OFFSET_TOKEN   1
00121 #define GL2PS_END_OFFSET_TOKEN     2
00122 #define GL2PS_BEGIN_BOUNDARY_TOKEN 3
00123 #define GL2PS_END_BOUNDARY_TOKEN   4
00124 #define GL2PS_BEGIN_STIPPLE_TOKEN  5
00125 #define GL2PS_END_STIPPLE_TOKEN    6
00126 #define GL2PS_POINT_SIZE_TOKEN     7
00127 #define GL2PS_LINE_WIDTH_TOKEN     8
00128 #define GL2PS_BEGIN_BLEND_TOKEN    9
00129 #define GL2PS_END_BLEND_TOKEN      10
00130 #define GL2PS_SRC_BLEND_TOKEN      11
00131 #define GL2PS_DST_BLEND_TOKEN      12
00132 #define GL2PS_IMAGEMAP_TOKEN       13
00133 #define GL2PS_DRAW_PIXELS_TOKEN    14
00134 #define GL2PS_TEXT_TOKEN           15
00135 
00136 typedef enum {
00137   T_UNDEFINED    = -1,
00138   T_CONST_COLOR  = 1,
00139   T_VAR_COLOR    = 1<<1,
00140   T_ALPHA_1      = 1<<2,
00141   T_ALPHA_LESS_1 = 1<<3,
00142   T_VAR_ALPHA    = 1<<4
00143 } GL2PS_TRIANGLE_PROPERTY;
00144 
00145 typedef GLfloat GL2PSxyz[3];
00146 typedef GLfloat GL2PSplane[4];
00147 
00148 typedef struct _GL2PSbsptree2d GL2PSbsptree2d;
00149 
00150 struct _GL2PSbsptree2d {
00151   GL2PSplane plane;
00152   GL2PSbsptree2d *front, *back;
00153 };
00154 
00155 typedef struct {
00156   GLint nmax, size, incr, n;
00157   char *array;
00158 } GL2PSlist;
00159 
00160 typedef struct _GL2PSbsptree GL2PSbsptree;
00161 
00162 struct _GL2PSbsptree {
00163   GL2PSplane plane;
00164   GL2PSlist *primitives;
00165   GL2PSbsptree *front, *back;
00166 };
00167 
00168 typedef struct {
00169   GL2PSxyz xyz;
00170   GL2PSrgba rgba;
00171 } GL2PSvertex;
00172 
00173 typedef struct {
00174   GL2PSvertex vertex[3];
00175   int prop;
00176 } GL2PStriangle;
00177 
00178 typedef struct {
00179   GLshort fontsize;
00180   char *str, *fontname;
00181   /* Note: for a 'special' string, 'alignment' holds the format
00182      (PostScript, PDF, etc.) of the special string */
00183   GLint alignment;
00184   GLfloat angle;
00185 } GL2PSstring;
00186 
00187 typedef struct {
00188   GLsizei width, height;
00189   /* Note: for an imagemap, 'type' indicates if it has already been
00190      written to the file or not, and 'format' indicates if it is
00191      visible or not */
00192   GLenum format, type;
00193   GLfloat *pixels;
00194 } GL2PSimage;
00195 
00196 typedef struct _GL2PSimagemap GL2PSimagemap;
00197 
00198 struct _GL2PSimagemap {
00199   GL2PSimage *image;
00200   GL2PSimagemap *next;
00201 };
00202 
00203 typedef struct {
00204   GLshort type, numverts;
00205   GLushort pattern;
00206   char boundary, offset, culled;
00207   GLint factor;
00208   GLfloat width;
00209   GL2PSvertex *verts;
00210   union {
00211     GL2PSstring *text;
00212     GL2PSimage *image;
00213   } data;
00214 } GL2PSprimitive;
00215 
00216 typedef struct {
00217 #if defined(GL2PS_HAVE_ZLIB)
00218   Bytef *dest, *src, *start;
00219   uLongf destLen, srcLen;
00220 #else
00221   int dummy;
00222 #endif
00223 } GL2PScompress;
00224 
00225 typedef struct{
00226   GL2PSlist* ptrlist;
00227   int gsno, fontno, imno, shno, maskshno, trgroupno;
00228   int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno;
00229 } GL2PSpdfgroup;
00230 
00231 typedef struct {
00232   /* General */
00233   GLint format, sort, options, colorsize, colormode, buffersize;
00234   char *title, *producer, *filename;
00235   GLboolean boundary, blending;
00236   GLfloat *feedback, offset[2], lastlinewidth;
00237   GLint viewport[4], blendfunc[2], lastfactor;
00238   GL2PSrgba *colormap, lastrgba, threshold, bgcolor;
00239   GLushort lastpattern;
00240   GL2PSvertex lastvertex;
00241   GL2PSlist *primitives, *auxprimitives;
00242   FILE *stream;
00243   GL2PScompress *compress;
00244   GLboolean header;
00245 
00246   /* BSP-specific */
00247   GLint maxbestroot;
00248 
00249   /* Occlusion culling-specific */
00250   GLboolean zerosurfacearea;
00251   GL2PSbsptree2d *imagetree;
00252   GL2PSprimitive *primitivetoadd;
00253   
00254   /* PDF-specific */
00255   int streamlength;
00256   GL2PSlist *pdfprimlist, *pdfgrouplist;
00257   int *xreflist;
00258   int objects_stack; /* available objects */
00259   int extgs_stack; /* graphics state object number */
00260   int font_stack; /* font object number */
00261   int im_stack; /* image object number */
00262   int trgroupobjects_stack; /* xobject numbers */
00263   int shader_stack; /* shader object numbers */
00264   int mshader_stack; /* mask shader object numbers */
00265 
00266   /* for image map list */
00267   GL2PSimagemap *imagemap_head;
00268   GL2PSimagemap *imagemap_tail;
00269 } GL2PScontext;
00270 
00271 typedef struct {
00272   void  (*printHeader)(void);
00273   void  (*printFooter)(void);
00274   void  (*beginViewport)(GLint viewport[4]);
00275   GLint (*endViewport)(void);
00276   void  (*printPrimitive)(void *data);
00277   void  (*printFinalPrimitive)(void);
00278   const char *file_extension;
00279   const char *description;
00280 } GL2PSbackend;
00281 
00282 /* The gl2ps context. gl2ps is not thread safe (we should create a
00283    local GL2PScontext during gl2psBeginPage) */
00284 
00285 static GL2PScontext *gl2ps = NULL;
00286 
00287 /* Need to forward-declare this one */
00288 
00289 static GLint gl2psPrintPrimitives(void);
00290 
00291 /********************************************************************* 
00292  *
00293  * Utility routines
00294  *
00295  *********************************************************************/
00296 
00297 static void gl2psMsg(GLint level, const char *fmt, ...)
00298 {
00299   va_list args;
00300 
00301   if(!(gl2ps->options & GL2PS_SILENT)){
00302     switch(level){
00303     case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break;
00304     case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break;
00305     case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break;
00306     }
00307     va_start(args, fmt);
00308     vfprintf(stderr, fmt, args); 
00309     va_end(args);
00310     fprintf(stderr, "\n");
00311   }
00312   /* if(level == GL2PS_ERROR) exit(1); */
00313 }
00314 
00315 static void *gl2psMalloc(size_t size)
00316 {
00317   void *ptr;
00318 
00319   if(!size) return(NULL);
00320   ptr = malloc(size);
00321   if(!ptr){
00322     gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory");
00323     exit(1);
00324   }
00325   return(ptr);
00326 }
00327 
00328 static void *gl2psRealloc(void *ptr, size_t size)
00329 {
00330   if(!size) return(NULL);
00331   ptr = realloc(ptr, size);
00332   if(!ptr){
00333     gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory");
00334     exit(1);
00335   }
00336   return(ptr);
00337 }
00338 
00339 static void gl2psFree(void *ptr)
00340 {
00341   if(!ptr) return;
00342   free(ptr);
00343 }
00344 
00345 static size_t gl2psWriteBigEndian(unsigned long data, size_t bytes)
00346 {
00347   size_t i;
00348   size_t size = sizeof(unsigned long);
00349   for(i = 1; i <= bytes; ++i){
00350     fputc(0xff & (data >> (size-i) * 8), gl2ps->stream);
00351   }
00352   return bytes;
00353 }
00354 
00355 /* zlib compression helper routines */
00356 
00357 #if defined(GL2PS_HAVE_ZLIB)
00358 
00359 static void gl2psSetupCompress(void)
00360 {
00361   gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress));
00362   gl2ps->compress->src = NULL;
00363   gl2ps->compress->start = NULL;
00364   gl2ps->compress->dest = NULL;
00365   gl2ps->compress->srcLen = 0;
00366   gl2ps->compress->destLen = 0;
00367 }
00368 
00369 static void gl2psFreeCompress(void)
00370 {
00371   if(!gl2ps->compress)
00372     return;
00373   gl2psFree(gl2ps->compress->start);
00374   gl2psFree(gl2ps->compress->dest);
00375   gl2ps->compress->src = NULL;
00376   gl2ps->compress->start = NULL;
00377   gl2ps->compress->dest = NULL;
00378   gl2ps->compress->srcLen = 0;
00379   gl2ps->compress->destLen = 0;
00380 }
00381 
00382 static int gl2psAllocCompress(unsigned int srcsize)
00383 {
00384   gl2psFreeCompress();
00385   
00386   if(!gl2ps->compress || !srcsize)
00387     return GL2PS_ERROR;
00388   
00389   gl2ps->compress->srcLen = srcsize;
00390   gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
00391   gl2ps->compress->src = (Bytef*)gl2psMalloc(gl2ps->compress->srcLen);
00392   gl2ps->compress->start = gl2ps->compress->src;
00393   gl2ps->compress->dest = (Bytef*)gl2psMalloc(gl2ps->compress->destLen);
00394   
00395   return GL2PS_SUCCESS;
00396 }
00397 
00398 static void *gl2psReallocCompress(unsigned int srcsize)
00399 {
00400   if(!gl2ps->compress || !srcsize)
00401     return NULL;
00402   
00403   if(srcsize < gl2ps->compress->srcLen)
00404     return gl2ps->compress->start;
00405   
00406   gl2ps->compress->srcLen = srcsize;
00407   gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
00408   gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, 
00409                                               gl2ps->compress->srcLen);
00410   gl2ps->compress->start = gl2ps->compress->src;
00411   gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, 
00412                                                gl2ps->compress->destLen);
00413   
00414   return gl2ps->compress->start;
00415 }
00416 
00417 static size_t gl2psWriteBigEndianCompress(unsigned long data, size_t bytes)
00418 {
00419   size_t i;
00420   size_t size = sizeof(unsigned long);
00421   for(i = 1; i <= bytes; ++i){
00422     *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8));
00423     ++gl2ps->compress->src;
00424   }
00425   return bytes;
00426 }
00427 
00428 static int gl2psDeflate(void)
00429 {
00430   /* For compatibility with older zlib versions, we use compress(...)
00431      instead of compress2(..., Z_BEST_COMPRESSION) */
00432   return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, 
00433                   gl2ps->compress->start, gl2ps->compress->srcLen);  
00434 }
00435 
00436 #endif
00437 
00438 static int gl2psPrintf(const char* fmt, ...)
00439 {
00440   int ret;
00441   va_list args;
00442 
00443 #if defined(GL2PS_HAVE_ZLIB)
00444   unsigned int oldsize = 0;
00445   static char buf[1000];
00446   if(gl2ps->options & GL2PS_COMPRESS){
00447     va_start(args, fmt);
00448     ret = vsprintf(buf, fmt, args);
00449     va_end(args);
00450     oldsize = gl2ps->compress->srcLen;
00451     gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret);
00452     memcpy(gl2ps->compress->start+oldsize, buf, ret);
00453     ret = 0;
00454   }
00455   else{
00456 #endif
00457     va_start(args, fmt);
00458     ret = vfprintf(gl2ps->stream, fmt, args);
00459     va_end(args);
00460 #if defined(GL2PS_HAVE_ZLIB)
00461   }
00462 #endif
00463   return ret;
00464 }
00465 
00466 static void gl2psPrintGzipHeader()
00467 {
00468 #if defined(GL2PS_HAVE_ZLIB)
00469   char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */
00470                   8, /* compression method: Z_DEFLATED */
00471                   0, /* flags */
00472                   0, 0, 0, 0, /* time */
00473                   2, /* extra flags: max compression */
00474                   '\x03'}; /* OS code: 0x03 (Unix) */
00475 
00476   if(gl2ps->options & GL2PS_COMPRESS){
00477     gl2psSetupCompress();
00478     /* add the gzip file header */
00479     fwrite(tmp, 10, 1, gl2ps->stream);
00480   }
00481 #endif  
00482 }
00483 
00484 static void gl2psPrintGzipFooter()
00485 {
00486 #if defined(GL2PS_HAVE_ZLIB)
00487   int n;
00488   uLong crc, len;
00489   char tmp[8];
00490 
00491   if(gl2ps->options & GL2PS_COMPRESS){
00492     if(Z_OK != gl2psDeflate()){
00493       gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
00494     }
00495     else{
00496       /* determine the length of the header in the zlib stream */
00497       n = 2; /* CMF+FLG */
00498       if(gl2ps->compress->dest[1] & (1<<5)){
00499         n += 4; /* DICTID */
00500       }
00501       /* write the data, without the zlib header and footer */
00502       fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), 
00503              1, gl2ps->stream);
00504       /* add the gzip file footer */
00505       crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen);
00506       for(n = 0; n < 4; ++n){
00507         tmp[n] = (char)(crc & 0xff);
00508         crc >>= 8;
00509       }
00510       len = gl2ps->compress->srcLen;
00511       for(n = 4; n < 8; ++n){
00512         tmp[n] = (char)(len & 0xff);
00513         len >>= 8;
00514       }
00515       fwrite(tmp, 8, 1, gl2ps->stream);
00516     }
00517     gl2psFreeCompress();
00518     gl2psFree(gl2ps->compress);
00519     gl2ps->compress = NULL;
00520   }
00521 #endif 
00522 }
00523 
00524 /* The list handling routines */
00525 
00526 static void gl2psListRealloc(GL2PSlist *list, GLint n)
00527 {
00528   if(!list){
00529     gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list");
00530     return;
00531   }
00532   if(n <= 0) return;
00533   if(!list->array){
00534     list->nmax = n;
00535     list->array = (char*)gl2psMalloc(list->nmax * list->size);
00536   }
00537   else{
00538     if(n > list->nmax){
00539       list->nmax = ((n - 1) / list->incr + 1) * list->incr;
00540       list->array = (char*)gl2psRealloc(list->array,
00541                                         list->nmax * list->size);
00542     }
00543   }
00544 }
00545 
00546 static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size)
00547 {
00548   GL2PSlist *list;
00549 
00550   if(n < 0) n = 0;
00551   if(incr <= 0) incr = 1;
00552   list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist));
00553   list->nmax = 0;
00554   list->incr = incr;
00555   list->size = size;
00556   list->n = 0;
00557   list->array = NULL;
00558   gl2psListRealloc(list, n);
00559   return(list);
00560 }
00561 
00562 static void gl2psListReset(GL2PSlist *list)
00563 {
00564   if(!list) return;
00565   list->n = 0;
00566 }
00567 
00568 static void gl2psListDelete(GL2PSlist *list)
00569 {
00570   if(!list) return;  
00571   gl2psFree(list->array);
00572   gl2psFree(list);
00573 }
00574 
00575 static void gl2psListAdd(GL2PSlist *list, void *data)
00576 {
00577   if(!list){
00578     gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list");
00579     return;
00580   }
00581   list->n++;
00582   gl2psListRealloc(list, list->n);
00583   memcpy(&list->array[(list->n - 1) * list->size], data, list->size);
00584 }
00585 
00586 static int gl2psListNbr(GL2PSlist *list)
00587 {
00588   if(!list)
00589     return 0;
00590   return(list->n);
00591 }
00592 
00593 static void *gl2psListPointer(GL2PSlist *list, GLint index)
00594 {
00595   if(!list){
00596     gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list");
00597     return NULL;
00598   }
00599   if((index < 0) || (index >= list->n)){
00600     gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer");
00601     return NULL;
00602   }
00603   return(&list->array[index * list->size]);
00604 }
00605 
00606 static void gl2psListSort(GL2PSlist *list,
00607                           int (*fcmp)(const void *a, const void *b))
00608 {
00609   if(!list)
00610     return;
00611   qsort(list->array, list->n, list->size, fcmp);
00612 }
00613 
00614 static void gl2psListAction(GL2PSlist *list, void (*action)(void *data))
00615 {
00616   GLint i;
00617 
00618   for(i = 0; i < gl2psListNbr(list); i++){
00619     (*action)(gl2psListPointer(list, i));
00620   }
00621 }
00622 
00623 static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data))
00624 {
00625   GLint i;
00626 
00627   for(i = gl2psListNbr(list); i > 0; i--){
00628     (*action)(gl2psListPointer(list, i-1));
00629   }
00630 }
00631 
00632 #if defined(GL2PS_HAVE_LIBPNG)
00633 
00634 static void gl2psListRead(GL2PSlist *list, int index, void *data)
00635 {
00636   if((index < 0) || (index >= list->n))
00637     gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead");
00638   memcpy(data, &list->array[index * list->size], list->size);
00639 }
00640 
00641 static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len)
00642 {
00643   static const char cb64[] = 
00644     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00645 
00646   out[0] = cb64[ in[0] >> 2 ];
00647   out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
00648   out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=';
00649   out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '=';
00650 }
00651 
00652 static void gl2psListEncodeBase64(GL2PSlist *list)
00653 {
00654   unsigned char *buffer, in[3], out[4];
00655   int i, n, index, len;
00656 
00657   n = list->n * list->size;
00658   buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned char));
00659   memcpy(buffer, list->array, n * sizeof(unsigned char));
00660   gl2psListReset(list);
00661 
00662   index = 0;
00663   while(index < n) {
00664     len = 0;
00665     for(i = 0; i < 3; i++) {
00666       if(index < n){
00667         in[i] = buffer[index];
00668         len++;
00669       }
00670       else{
00671         in[i] = 0;
00672       }
00673       index++;
00674     }
00675     if(len) {
00676       gl2psEncodeBase64Block(in, out, len);
00677       for(i = 0; i < 4; i++)
00678         gl2psListAdd(list, &out[i]);
00679     }
00680   }
00681   gl2psFree(buffer);
00682 }
00683 
00684 #endif
00685 
00686 /* Helpers for rgba colors */
00687 
00688 static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2)
00689 {
00690   if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) ||
00691      !GL2PS_ZERO(rgba1[1] - rgba2[1]) ||
00692      !GL2PS_ZERO(rgba1[2] - rgba2[2]))
00693     return GL_FALSE;
00694   return GL_TRUE;
00695 }
00696   
00697 static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim)
00698 {
00699   int i;
00700 
00701   for(i = 1; i < prim->numverts; i++){
00702     if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){
00703       return GL_FALSE;
00704     }
00705   }
00706   return GL_TRUE;
00707 }
00708 
00709 static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[],
00710                                          GL2PSrgba threshold)
00711 {
00712   int i;
00713 
00714   if(n < 2) return GL_TRUE;
00715   
00716   for(i = 1; i < n; i++){
00717     if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] ||
00718        fabs(rgba[0][1] - rgba[i][1]) > threshold[1] ||
00719        fabs(rgba[0][2] - rgba[i][2]) > threshold[2])
00720       return GL_FALSE;
00721   }
00722   
00723   return GL_TRUE;
00724 }
00725 
00726 static void gl2psSetLastColor(GL2PSrgba rgba)
00727 {
00728   int i;        
00729   for(i = 0; i < 3; ++i){
00730     gl2ps->lastrgba[i] = rgba[i];
00731   }
00732 }
00733 
00734 static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y,
00735                            GLfloat *red, GLfloat *green, GLfloat *blue)
00736 {
00737   
00738   GLsizei width = im->width;
00739   GLsizei height = im->height;
00740   GLfloat *pixels = im->pixels;
00741   GLfloat *pimag;
00742 
00743   /* OpenGL image is from down to up, PS image is up to down */  
00744   switch(im->format){
00745   case GL_RGBA:
00746     pimag = pixels + 4 * (width * (height - 1 - y) + x);
00747     break;
00748   case GL_RGB:
00749   default:
00750     pimag = pixels + 3 * (width * (height - 1 - y) + x);
00751     break;
00752   }
00753   *red = *pimag; pimag++;
00754   *green = *pimag; pimag++;
00755   *blue = *pimag; pimag++;
00756 
00757   return (im->format == GL_RGBA) ? *pimag : 1.0F;
00758 }
00759 
00760 /* Helper routines for pixmaps */
00761 
00762 static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im)
00763 {
00764   int size;
00765   GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
00766   
00767   image->width = im->width;
00768   image->height = im->height;
00769   image->format = im->format;
00770   image->type = im->type;
00771 
00772   switch(image->format){
00773   case GL_RGBA:
00774     size = image->height * image->width * 4 * sizeof(GLfloat);
00775     break;
00776   case GL_RGB:
00777   default:
00778     size = image->height * image->width * 3 * sizeof(GLfloat);
00779     break;
00780   }
00781 
00782   image->pixels = (GLfloat*)gl2psMalloc(size);
00783   memcpy(image->pixels, im->pixels, size);
00784   
00785   return image;
00786 }
00787 
00788 static void gl2psFreePixmap(GL2PSimage *im)
00789 {
00790   if(!im)
00791     return;
00792   gl2psFree(im->pixels);
00793   gl2psFree(im);
00794 }
00795 
00796 #if defined(GL2PS_HAVE_LIBPNG)
00797 
00798 #if !defined(png_jmpbuf)
00799 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
00800 #endif
00801 
00802 static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length)
00803 {
00804   unsigned int i;
00805   GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr);
00806   for(i = 0; i < length; i++) 
00807     gl2psListAdd(png, &data[i]);
00808 }
00809 
00810 static void gl2psUserFlushPNG(png_structp png_ptr)
00811 {
00812 }
00813 
00814 static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png)
00815 {
00816   png_structp png_ptr;
00817   png_infop info_ptr;
00818   unsigned char *row_data;
00819   GLfloat dr, dg, db;
00820   int row, col;
00821 
00822   if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
00823     return;
00824   
00825   if(!(info_ptr = png_create_info_struct(png_ptr))){
00826     png_destroy_write_struct(&png_ptr, NULL);
00827     return;
00828   }
00829   
00830   if(setjmp(png_jmpbuf(png_ptr))) {
00831     png_destroy_write_struct(&png_ptr, &info_ptr);
00832     return;
00833   }
00834   
00835   png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG);
00836   png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
00837   png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, 
00838                PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 
00839                PNG_FILTER_TYPE_BASE);
00840   png_write_info(png_ptr, info_ptr);
00841 
00842   row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char));
00843   for(row = 0; row < pixmap->height; row++){
00844     for(col = 0; col < pixmap->width; col++){
00845       gl2psGetRGB(pixmap, col, row, &dr, &dg, &db);
00846       row_data[3*col] = (unsigned char)(255. * dr);
00847       row_data[3*col+1] = (unsigned char)(255. * dg);
00848       row_data[3*col+2] = (unsigned char)(255. * db);
00849     }
00850     png_write_row(png_ptr, (png_bytep)row_data);
00851   }
00852   gl2psFree(row_data);
00853 
00854   png_write_end(png_ptr, info_ptr);
00855   png_destroy_write_struct(&png_ptr, &info_ptr);
00856 }
00857 
00858 #endif
00859 
00860 /* Helper routines for text strings */
00861 
00862 static GLint gl2psAddText(GLint type, const char *str, const char *fontname, 
00863                           GLshort fontsize, GLint alignment, GLfloat angle)
00864 {
00865   GLfloat pos[4];
00866   GL2PSprimitive *prim;
00867   GLboolean valid;
00868 
00869   if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED;
00870 
00871   if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS;
00872 
00873   glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
00874   if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
00875 
00876   glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
00877 
00878   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
00879   prim->type = type;
00880   prim->boundary = 0;
00881   prim->numverts = 1;
00882   prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
00883   prim->verts[0].xyz[0] = pos[0];
00884   prim->verts[0].xyz[1] = pos[1];
00885   prim->verts[0].xyz[2] = pos[2];
00886   prim->culled = 0;
00887   prim->offset = 0;
00888   prim->pattern = 0;
00889   prim->factor = 0;
00890   prim->width = 1;
00891   glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
00892   prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
00893   prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char));
00894   strcpy(prim->data.text->str, str); 
00895   prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char));
00896   strcpy(prim->data.text->fontname, fontname);
00897   prim->data.text->fontsize = fontsize;
00898   prim->data.text->alignment = alignment;
00899   prim->data.text->angle = angle;
00900 
00901   gl2psListAdd(gl2ps->auxprimitives, &prim);
00902   glPassThrough(GL2PS_TEXT_TOKEN);
00903     
00904   return GL2PS_SUCCESS;
00905 }
00906 
00907 static GL2PSstring *gl2psCopyText(GL2PSstring *t)
00908 {
00909   GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
00910   text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char));
00911   strcpy(text->str, t->str); 
00912   text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char));
00913   strcpy(text->fontname, t->fontname);
00914   text->fontsize = t->fontsize;
00915   text->alignment = t->alignment;
00916   text->angle = t->angle;
00917   
00918   return text;
00919 }
00920 
00921 static void gl2psFreeText(GL2PSstring *text)
00922 {
00923   if(!text)
00924     return;
00925   gl2psFree(text->str);
00926   gl2psFree(text->fontname);
00927   gl2psFree(text);
00928 }
00929 
00930 /* Helpers for blending modes */
00931 
00932 static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor)
00933 {
00934   /* returns TRUE if gl2ps supports the argument combination: only two
00935      blending modes have been implemented so far */
00936 
00937   if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || 
00938       (sfactor == GL_ONE && dfactor == GL_ZERO) )
00939     return GL_TRUE;
00940   return GL_FALSE;
00941 }
00942 
00943 static void gl2psAdaptVertexForBlending(GL2PSvertex *v)
00944 {
00945   /* Transforms vertex depending on the actual blending function -
00946      currently the vertex v is considered as source vertex and his
00947      alpha value is changed to 1.0 if source blending GL_ONE is
00948      active. This might be extended in the future */
00949 
00950   if(!v || !gl2ps)
00951     return;
00952 
00953   if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
00954     v->rgba[3] = 1.0F;
00955     return;
00956   }
00957   
00958   switch(gl2ps->blendfunc[0]){
00959   case GL_ONE:
00960     v->rgba[3] = 1.0F;
00961     break;
00962   default:
00963     break;
00964   }
00965 }
00966 
00967 static void gl2psAssignTriangleProperties(GL2PStriangle *t)
00968 {
00969   /* int i; */
00970 
00971   t->prop = T_VAR_COLOR;
00972 
00973   /* Uncommenting the following lines activates an even more fine
00974      grained distinction between triangle types - please don't delete,
00975      a remarkable amount of PDF handling code inside this file depends
00976      on it if activated */
00977   /*
00978   t->prop = T_CONST_COLOR;    
00979   for(i = 0; i < 3; ++i){
00980     if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || 
00981        !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){
00982       t->prop = T_VAR_COLOR;
00983       break;
00984     }
00985   }
00986   */
00987 
00988   if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || 
00989      !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){
00990     t->prop |= T_VAR_ALPHA;
00991   }
00992   else{
00993     if(t->vertex[0].rgba[3] < 1)
00994       t->prop |= T_ALPHA_LESS_1;
00995     else
00996       t->prop |= T_ALPHA_1;
00997   }
00998 }
00999 
01000 static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p,
01001                                            GLboolean assignprops)
01002 {
01003   t->vertex[0] = p->verts[0];
01004   t->vertex[1] = p->verts[1];
01005   t->vertex[2] = p->verts[2];
01006   if(GL_TRUE == assignprops)
01007     gl2psAssignTriangleProperties(t);
01008 }
01009 
01010 static void gl2psInitTriangle(GL2PStriangle *t)
01011 {
01012   int i;
01013   GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} };
01014   for(i = 0; i < 3; i++)
01015     t->vertex[i] = vertex;
01016   t->prop = T_UNDEFINED;
01017 }
01018 
01019 /* Miscellaneous helper routines */
01020 
01021 static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p)
01022 {
01023   GL2PSprimitive *prim;
01024 
01025   if(!p){
01026     gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive");
01027     return NULL;
01028   }
01029 
01030   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
01031   
01032   prim->type = p->type;
01033   prim->numverts = p->numverts;
01034   prim->boundary = p->boundary;
01035   prim->offset = p->offset;
01036   prim->pattern = p->pattern;
01037   prim->factor = p->factor;
01038   prim->culled = p->culled;
01039   prim->width = p->width;
01040   prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex));
01041   memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex));
01042 
01043   switch(prim->type){
01044   case GL2PS_PIXMAP :
01045     prim->data.image = gl2psCopyPixmap(p->data.image);
01046     break;
01047   case GL2PS_TEXT :
01048   case GL2PS_SPECIAL :
01049     prim->data.text = gl2psCopyText(p->data.text);
01050     break;
01051   default:
01052     break;
01053   }
01054 
01055   return prim;
01056 }
01057 
01058 static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2)
01059 {
01060   if(!GL2PS_ZERO(p1[0] - p2[0]) ||
01061      !GL2PS_ZERO(p1[1] - p2[1]) ||
01062      !GL2PS_ZERO(p1[2] - p2[2]))
01063     return GL_FALSE;
01064   return GL_TRUE;
01065 }
01066 
01067 /********************************************************************* 
01068  *
01069  * 3D sorting routines 
01070  *
01071  *********************************************************************/
01072 
01073 static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane)
01074 {
01075   return(plane[0] * point[0] + 
01076          plane[1] * point[1] + 
01077          plane[2] * point[2] + 
01078          plane[3]);
01079 }
01080 
01081 static GLfloat gl2psPsca(GLfloat *a, GLfloat *b)
01082 {
01083   return(a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
01084 }
01085 
01086 static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c)
01087 {
01088   c[0] = a[1]*b[2] - a[2]*b[1];
01089   c[1] = a[2]*b[0] - a[0]*b[2];
01090   c[2] = a[0]*b[1] - a[1]*b[0];
01091 }
01092 
01093 static GLfloat gl2psNorm(GLfloat *a)
01094 {
01095   return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
01096 }
01097 
01098 static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c)
01099 {
01100   GLfloat norm;
01101 
01102   gl2psPvec(a, b, c);
01103   if(!GL2PS_ZERO(norm = gl2psNorm(c))){
01104     c[0] = c[0] / norm;
01105     c[1] = c[1] / norm;
01106     c[2] = c[2] / norm;
01107   }
01108   else{
01109     /* The plane is still wrong despite our tests in gl2psGetPlane.
01110        Let's return a dummy value for now (this is a hack: we should
01111        do more intelligent tests in GetPlane) */
01112     c[0] = c[1] = 0.0F;
01113     c[2] = 1.0F;
01114   }
01115 }
01116 
01117 static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane)
01118 {
01119   GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F};
01120 
01121   switch(prim->type){
01122   case GL2PS_TRIANGLE :
01123   case GL2PS_QUADRANGLE :
01124     v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; 
01125     v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; 
01126     v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; 
01127     w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0]; 
01128     w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1]; 
01129     w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2]; 
01130     if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) || 
01131        (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){
01132       plane[0] = plane[1] = 0.0F;
01133       plane[2] = 1.0F;
01134       plane[3] = -prim->verts[0].xyz[2];
01135     }
01136     else{
01137       gl2psGetNormal(v, w, plane);
01138       plane[3] = 
01139         - plane[0] * prim->verts[0].xyz[0] 
01140         - plane[1] * prim->verts[0].xyz[1] 
01141         - plane[2] * prim->verts[0].xyz[2];
01142     }
01143     break;
01144   case GL2PS_LINE :
01145     v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; 
01146     v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; 
01147     v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; 
01148     if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){
01149       plane[0] = plane[1] = 0.0F;
01150       plane[2] = 1.0F;
01151       plane[3] = -prim->verts[0].xyz[2];
01152     }
01153     else{
01154       if(GL2PS_ZERO(v[0]))      w[0] = 1.0F;
01155       else if(GL2PS_ZERO(v[1])) w[1] = 1.0F;
01156       else                      w[2] = 1.0F;
01157       gl2psGetNormal(v, w, plane);
01158       plane[3] = 
01159         - plane[0] * prim->verts[0].xyz[0] 
01160         - plane[1] * prim->verts[0].xyz[1] 
01161         - plane[2] * prim->verts[0].xyz[2];
01162     }
01163     break;
01164   case GL2PS_POINT :
01165   case GL2PS_PIXMAP :
01166   case GL2PS_TEXT :
01167   case GL2PS_SPECIAL :
01168   case GL2PS_IMAGEMAP:
01169     plane[0] = plane[1] = 0.0F;
01170     plane[2] = 1.0F;
01171     plane[3] = -prim->verts[0].xyz[2];
01172     break;
01173   default :
01174     gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree");
01175     plane[0] = plane[1] = plane[3] = 0.0F;
01176     plane[2] = 1.0F;
01177     break;
01178   }
01179 }
01180 
01181 static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane,
01182                          GL2PSvertex *c)
01183 {
01184   GL2PSxyz v;
01185   GLfloat sect, psca;
01186 
01187   v[0] = b->xyz[0] - a->xyz[0];
01188   v[1] = b->xyz[1] - a->xyz[1];
01189   v[2] = b->xyz[2] - a->xyz[2];
01190 
01191   if(!GL2PS_ZERO(psca = gl2psPsca(plane, v)))
01192     sect = -gl2psComparePointPlane(a->xyz, plane) / psca;
01193   else
01194     sect = 0.0F;
01195   
01196   c->xyz[0] = a->xyz[0] + v[0] * sect;
01197   c->xyz[1] = a->xyz[1] + v[1] * sect;
01198   c->xyz[2] = a->xyz[2] + v[2] * sect;
01199   
01200   c->rgba[0] = (1 - sect) * a->rgba[0] + sect * b->rgba[0];
01201   c->rgba[1] = (1 - sect) * a->rgba[1] + sect * b->rgba[1];
01202   c->rgba[2] = (1 - sect) * a->rgba[2] + sect * b->rgba[2];
01203   c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3];
01204 }
01205 
01206 static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane,
01207                                       GL2PSprimitive *child, GLshort numverts,
01208                                       GLshort *index0, GLshort *index1)
01209 {
01210   GLshort i;
01211 
01212   if(parent->type == GL2PS_IMAGEMAP){
01213     child->type = GL2PS_IMAGEMAP;
01214     child->data.image = parent->data.image;
01215   }
01216   else{
01217     if(numverts > 4){
01218       gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts);
01219       numverts = 4;
01220     }
01221     switch(numverts){
01222     case 1 : child->type = GL2PS_POINT; break; 
01223     case 2 : child->type = GL2PS_LINE; break; 
01224     case 3 : child->type = GL2PS_TRIANGLE; break; 
01225     case 4 : child->type = GL2PS_QUADRANGLE; break;    
01226     default: child->type = GL2PS_NO_TYPE; break;
01227     }
01228   }
01229 
01230   child->boundary = 0; /* FIXME: not done! */
01231   child->culled = parent->culled;
01232   child->offset = parent->offset;
01233   child->pattern = parent->pattern;
01234   child->factor = parent->factor;
01235   child->width = parent->width;
01236   child->numverts = numverts;
01237   child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
01238 
01239   for(i = 0; i < numverts; i++){
01240     if(index1[i] < 0){
01241       child->verts[i] = parent->verts[index0[i]];
01242     }
01243     else{
01244       gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], 
01245                    plane, &child->verts[i]);
01246     }
01247   }
01248 }
01249 
01250 static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, 
01251                           GLshort i, GLshort j)
01252 {
01253   GLint k;
01254 
01255   for(k = 0; k < *nb; k++){
01256     if((index0[k] == i && index1[k] == j) ||
01257        (index1[k] == i && index0[k] == j)) return;
01258   }
01259   index0[*nb] = i;
01260   index1[*nb] = j;
01261   (*nb)++;
01262 }
01263 
01264 static GLshort gl2psGetIndex(GLshort i, GLshort num)
01265 {
01266   return (i < num - 1) ? i + 1 : 0;
01267 }
01268 
01269 static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane)
01270 {
01271   GLint type = GL2PS_COINCIDENT;
01272   GLshort i, j;
01273   GLfloat d[5]; 
01274 
01275   for(i = 0; i < prim->numverts; i++){  
01276     d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
01277   }
01278 
01279   if(prim->numverts < 2){
01280     return 0;
01281   }
01282   else{
01283     for(i = 0; i < prim->numverts; i++){
01284       j = gl2psGetIndex(i, prim->numverts);
01285       if(d[j] > GL2PS_EPSILON){
01286         if(type == GL2PS_COINCIDENT)      type = GL2PS_IN_BACK_OF;
01287         else if(type != GL2PS_IN_BACK_OF) return 1; 
01288         if(d[i] < -GL2PS_EPSILON)         return 1;
01289       }
01290       else if(d[j] < -GL2PS_EPSILON){
01291         if(type == GL2PS_COINCIDENT)       type = GL2PS_IN_FRONT_OF;   
01292         else if(type != GL2PS_IN_FRONT_OF) return 1;
01293         if(d[i] > GL2PS_EPSILON)           return 1;
01294       }
01295     }
01296   }
01297   return 0;
01298 }
01299 
01300 static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, 
01301                                  GL2PSprimitive **front, GL2PSprimitive **back)
01302 {
01303   GLshort i, j, in = 0, out = 0;
01304   GLshort in0[5] = {0}, in1[5] = {0}, out0[5] = {0}, out1[5] = {0};
01305   GLint type;
01306   GLfloat d[5]; 
01307 
01308   type = GL2PS_COINCIDENT;
01309 
01310   for(i = 0; i < prim->numverts; i++){  
01311     d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
01312   }
01313 
01314   switch(prim->type){
01315   case GL2PS_POINT :
01316     if(d[0] > GL2PS_EPSILON)       type = GL2PS_IN_BACK_OF;
01317     else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF;
01318     else                           type = GL2PS_COINCIDENT;
01319     break;
01320   default :
01321     for(i = 0; i < prim->numverts; i++){
01322       j = gl2psGetIndex(i, prim->numverts);
01323       if(d[j] > GL2PS_EPSILON){
01324         if(type == GL2PS_COINCIDENT)      type = GL2PS_IN_BACK_OF;
01325         else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING; 
01326         if(d[i] < -GL2PS_EPSILON){
01327           gl2psAddIndex(in0, in1, &in, i, j);
01328           gl2psAddIndex(out0, out1, &out, i, j);
01329           type = GL2PS_SPANNING;
01330         }
01331         gl2psAddIndex(out0, out1, &out, j, -1);
01332       }
01333       else if(d[j] < -GL2PS_EPSILON){
01334         if(type == GL2PS_COINCIDENT)       type = GL2PS_IN_FRONT_OF;   
01335         else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING;
01336         if(d[i] > GL2PS_EPSILON){
01337           gl2psAddIndex(in0, in1, &in, i, j);
01338           gl2psAddIndex(out0, out1, &out, i, j);
01339           type = GL2PS_SPANNING;
01340         }
01341         gl2psAddIndex(in0, in1, &in, j, -1);
01342       }
01343       else{
01344         gl2psAddIndex(in0, in1, &in, j, -1);
01345         gl2psAddIndex(out0, out1, &out, j, -1);
01346       }
01347     }
01348     break;
01349   }
01350 
01351   if(type == GL2PS_SPANNING){
01352     *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
01353     *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
01354     gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1);
01355     gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1);
01356   }
01357 
01358   return type;
01359 }
01360 
01361 static void gl2psDivideQuad(GL2PSprimitive *quad, 
01362                             GL2PSprimitive **t1, GL2PSprimitive **t2)
01363 {
01364   *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
01365   *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
01366   (*t1)->type = (*t2)->type = GL2PS_TRIANGLE;
01367   (*t1)->numverts = (*t2)->numverts = 3;
01368   (*t1)->culled = (*t2)->culled = quad->culled;
01369   (*t1)->offset = (*t2)->offset = quad->offset;
01370   (*t1)->pattern = (*t2)->pattern = quad->pattern;
01371   (*t1)->factor = (*t2)->factor = quad->factor;
01372   (*t1)->width = (*t2)->width = quad->width;
01373   (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex));
01374   (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex));
01375   (*t1)->verts[0] = quad->verts[0];
01376   (*t1)->verts[1] = quad->verts[1];
01377   (*t1)->verts[2] = quad->verts[2];
01378   (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0);
01379   (*t2)->verts[0] = quad->verts[0];
01380   (*t2)->verts[1] = quad->verts[2];
01381   (*t2)->verts[2] = quad->verts[3];
01382   (*t2)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 4) ? 2 : 0);
01383 }
01384 
01385 static int gl2psCompareDepth(const void *a, const void *b)
01386 {
01387   GL2PSprimitive *q, *w;
01388   GLfloat dq = 0.0F, dw = 0.0F, diff;
01389   int i;
01390   
01391   q = *(GL2PSprimitive**)a;
01392   w = *(GL2PSprimitive**)b;
01393 
01394   for(i = 0; i < q->numverts; i++){
01395     dq += q->verts[i].xyz[2]; 
01396   }
01397   dq /= (GLfloat)q->numverts;
01398 
01399   for(i = 0; i < w->numverts; i++){
01400     dw += w->verts[i].xyz[2]; 
01401   }
01402   dw /= (GLfloat)w->numverts;
01403 
01404   diff = dq - dw;
01405   if(diff > 0.){
01406     return -1;
01407   }
01408   else if(diff < 0.){
01409     return 1;
01410   }
01411   else{
01412     return 0;
01413   }
01414 }
01415 
01416 static int gl2psTrianglesFirst(const void *a, const void *b)
01417 {
01418   GL2PSprimitive *q, *w;
01419 
01420   q = *(GL2PSprimitive**)a;
01421   w = *(GL2PSprimitive**)b;
01422   return(q->type < w->type ? 1 : -1);
01423 }
01424 
01425 static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root)
01426 {
01427   GLint i, j, count, best = 1000000, index = 0;
01428   GL2PSprimitive *prim1, *prim2;
01429   GL2PSplane plane;
01430   GLint maxp;
01431 
01432   if(!gl2psListNbr(primitives)){
01433     gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list");
01434     return 0;
01435   }
01436 
01437   *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0);
01438 
01439   if(gl2ps->options & GL2PS_BEST_ROOT){
01440     maxp = gl2psListNbr(primitives);
01441     if(maxp > gl2ps->maxbestroot){
01442       maxp = gl2ps->maxbestroot;
01443     }
01444     for(i = 0; i < maxp; i++){
01445       prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i);
01446       gl2psGetPlane(prim1, plane);
01447       count = 0;
01448       for(j = 0; j < gl2psListNbr(primitives); j++){
01449         if(j != i){
01450           prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j);
01451           count += gl2psTestSplitPrimitive(prim2, plane); 
01452         }
01453         if(count > best) break;
01454       }
01455       if(count < best){
01456         best = count;
01457         index = i;
01458         *root = prim1;
01459         if(!count) return index;
01460       }
01461     }
01462     /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */
01463     return index;
01464   }
01465   else{
01466     return 0;
01467   }
01468 }
01469 
01470 static void gl2psFreeImagemap(GL2PSimagemap *list){
01471   GL2PSimagemap *next;
01472   while(list != NULL){
01473     next = list->next;
01474     gl2psFree(list->image->pixels);
01475     gl2psFree(list->image);
01476     gl2psFree(list);
01477     list = next;
01478   }
01479 }
01480 
01481 static void gl2psFreePrimitive(void *data)
01482 {
01483   GL2PSprimitive *q;
01484   
01485   q = *(GL2PSprimitive**)data;
01486   gl2psFree(q->verts);
01487   if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){
01488     gl2psFreeText(q->data.text);
01489   }
01490   else if(q->type == GL2PS_PIXMAP){
01491     gl2psFreePixmap(q->data.image);
01492   }
01493   gl2psFree(q);
01494 }
01495 
01496 static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list)
01497 {
01498   GL2PSprimitive *t1, *t2;
01499 
01500   if(prim->type != GL2PS_QUADRANGLE){
01501     gl2psListAdd(list, &prim);
01502   }
01503   else{
01504     gl2psDivideQuad(prim, &t1, &t2);
01505     gl2psListAdd(list, &t1);
01506     gl2psListAdd(list, &t2);
01507     gl2psFreePrimitive(&prim);
01508   }
01509   
01510 }
01511 
01512 static void gl2psFreeBspTree(GL2PSbsptree **tree)
01513 {
01514   if(*tree){
01515     if((*tree)->back) gl2psFreeBspTree(&(*tree)->back);
01516     if((*tree)->primitives){
01517       gl2psListAction((*tree)->primitives, gl2psFreePrimitive);
01518       gl2psListDelete((*tree)->primitives);
01519     }
01520     if((*tree)->front) gl2psFreeBspTree(&(*tree)->front);
01521     gl2psFree(*tree);
01522     *tree = NULL;
01523   }
01524 }
01525 
01526 static GLboolean gl2psGreater(GLfloat f1, GLfloat f2)
01527 {
01528   if(f1 > f2) return GL_TRUE;
01529   else return GL_FALSE;
01530 }
01531 
01532 static GLboolean gl2psLess(GLfloat f1, GLfloat f2)
01533 {
01534   if(f1 < f2) return GL_TRUE;
01535   else return GL_FALSE;
01536 }
01537 
01538 static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives)
01539 {
01540   GL2PSprimitive *prim, *frontprim = NULL, *backprim = NULL;
01541   GL2PSlist *frontlist, *backlist;
01542   GLint i, index;
01543 
01544   tree->front = NULL;
01545   tree->back = NULL;
01546   tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
01547   index = gl2psFindRoot(primitives, &prim);
01548   gl2psGetPlane(prim, tree->plane);
01549   gl2psAddPrimitiveInList(prim, tree->primitives);
01550 
01551   frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
01552   backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
01553 
01554   for(i = 0; i < gl2psListNbr(primitives); i++){
01555     if(i != index){
01556       prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i);
01557       switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){
01558       case GL2PS_COINCIDENT:
01559         gl2psAddPrimitiveInList(prim, tree->primitives);
01560         break;
01561       case GL2PS_IN_BACK_OF:
01562         gl2psAddPrimitiveInList(prim, backlist);
01563         break;
01564       case GL2PS_IN_FRONT_OF:
01565         gl2psAddPrimitiveInList(prim, frontlist);
01566         break;
01567       case GL2PS_SPANNING:
01568         gl2psAddPrimitiveInList(backprim, backlist);
01569         gl2psAddPrimitiveInList(frontprim, frontlist);
01570         gl2psFreePrimitive(&prim);
01571         break;
01572       }
01573     }
01574   }
01575 
01576   if(gl2psListNbr(tree->primitives)){
01577     gl2psListSort(tree->primitives, gl2psTrianglesFirst);
01578   }
01579 
01580   if(gl2psListNbr(frontlist)){
01581     gl2psListSort(frontlist, gl2psTrianglesFirst);
01582     tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
01583     gl2psBuildBspTree(tree->front, frontlist);
01584   }
01585   else{
01586     gl2psListDelete(frontlist);
01587   }
01588 
01589   if(gl2psListNbr(backlist)){
01590     gl2psListSort(backlist, gl2psTrianglesFirst);
01591     tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
01592     gl2psBuildBspTree(tree->back, backlist);
01593   }
01594   else{
01595     gl2psListDelete(backlist);
01596   }
01597 
01598   gl2psListDelete(primitives);
01599 }
01600 
01601 static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon,
01602                                  GLboolean (*compare)(GLfloat f1, GLfloat f2),
01603                                  void (*action)(void *data), int inverse)
01604 {
01605   GLfloat result;
01606 
01607   if(!tree) return;
01608 
01609   result = gl2psComparePointPlane(eye, tree->plane);
01610 
01611   if(GL_TRUE == compare(result, epsilon)){
01612     gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
01613     if(inverse){
01614       gl2psListActionInverse(tree->primitives, action);
01615     }
01616     else{
01617       gl2psListAction(tree->primitives, action);
01618     }
01619     gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
01620   }
01621   else if(GL_TRUE == compare(-epsilon, result)){ 
01622     gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
01623     if(inverse){
01624       gl2psListActionInverse(tree->primitives, action);
01625     }
01626     else{
01627       gl2psListAction(tree->primitives, action);
01628     }
01629     gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
01630   }
01631   else{
01632     gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
01633     gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
01634   }
01635 }
01636 
01637 static void gl2psRescaleAndOffset()
01638 {
01639   GL2PSprimitive *prim;
01640   GLfloat minZ, maxZ, rangeZ, scaleZ;
01641   GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ;
01642   int i, j;
01643 
01644   if(!gl2psListNbr(gl2ps->primitives))
01645     return;
01646 
01647   /* get z-buffer range */
01648   prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, 0);
01649   minZ = maxZ = prim->verts[0].xyz[2];
01650   for(i = 1; i < prim->numverts; i++){
01651     if(prim->verts[i].xyz[2] < minZ) minZ = prim->verts[i].xyz[2];
01652     if(prim->verts[i].xyz[2] > maxZ) maxZ = prim->verts[i].xyz[2];
01653   }
01654   for(i = 1; i < gl2psListNbr(gl2ps->primitives); i++){
01655     prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i);
01656     for(j = 0; j < prim->numverts; j++){
01657       if(prim->verts[j].xyz[2] < minZ) minZ = prim->verts[j].xyz[2];
01658       if(prim->verts[j].xyz[2] > maxZ) maxZ = prim->verts[j].xyz[2];
01659     }
01660   }
01661   rangeZ = (maxZ - minZ);
01662 
01663   /* rescale z-buffer coordinate in [0,GL2PS_ZSCALE], to make it of
01664      the same order of magnitude as the x and y coordinates */
01665   scaleZ = GL2PS_ZERO(rangeZ) ? GL2PS_ZSCALE : (GL2PS_ZSCALE / rangeZ);
01666   /* avoid precision loss (we use floats!) */
01667   if(scaleZ > 100000.F) scaleZ = 100000.F;
01668 
01669   /* apply offsets */
01670   for(i = 0; i < gl2psListNbr(gl2ps->primitives); i++){
01671     prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i);
01672     for(j = 0; j < prim->numverts; j++){
01673       prim->verts[j].xyz[2] = (prim->verts[j].xyz[2] - minZ) * scaleZ;
01674     }
01675     if((gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET) &&
01676        (prim->type == GL2PS_LINE)){
01677       if(gl2ps->sort == GL2PS_SIMPLE_SORT){
01678         prim->verts[0].xyz[2] -= GL2PS_ZOFFSET_LARGE;
01679         prim->verts[1].xyz[2] -= GL2PS_ZOFFSET_LARGE;
01680       }
01681       else{
01682         prim->verts[0].xyz[2] -= GL2PS_ZOFFSET;
01683         prim->verts[1].xyz[2] -= GL2PS_ZOFFSET;
01684       }
01685     }
01686     else if(prim->offset && (prim->type == GL2PS_TRIANGLE)){
01687       factor = gl2ps->offset[0];
01688       units = gl2ps->offset[1];
01689       area = 
01690         (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * 
01691         (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) - 
01692         (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * 
01693         (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]);
01694       if(!GL2PS_ZERO(area)){
01695         dZdX = 
01696           ((prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) *
01697            (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) -
01698            (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) *
01699            (prim->verts[2].xyz[2] - prim->verts[1].xyz[2])) / area;
01700         dZdY = 
01701           ((prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) *
01702            (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) -
01703            (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) *
01704            (prim->verts[1].xyz[2] - prim->verts[0].xyz[2])) / area;
01705         maxdZ = (GLfloat)sqrt(dZdX * dZdX + dZdY * dZdY);
01706       }
01707       else{
01708         maxdZ = 0.0F;
01709       }
01710       dZ = factor * maxdZ + units;
01711       prim->verts[0].xyz[2] += dZ;
01712       prim->verts[1].xyz[2] += dZ;
01713       prim->verts[2].xyz[2] += dZ;
01714     }
01715   }
01716 }
01717 
01718 /********************************************************************* 
01719  *
01720  * 2D sorting routines (for occlusion culling) 
01721  *
01722  *********************************************************************/
01723 
01724 static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane)
01725 {
01726   GLfloat n; 
01727 
01728   plane[0] = b[1] - a[1];
01729   plane[1] = a[0] - b[0];
01730   n = (GLfloat)sqrt(plane[0]*plane[0] + plane[1]*plane[1]);
01731   plane[2] = 0.0F;
01732   if(!GL2PS_ZERO(n)){
01733     plane[0] /= n;
01734     plane[1] /= n;
01735     plane[3] = -plane[0]*a[0]-plane[1]*a[1]; 
01736     return 1;
01737   }
01738   else{
01739     plane[0] = -1.0F;
01740     plane[1] = 0.0F;
01741     plane[3] = a[0];
01742     return 0;
01743   }
01744 }
01745 
01746 static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree)
01747 {
01748   if(*tree){
01749     if((*tree)->back)  gl2psFreeBspImageTree(&(*tree)->back);
01750     if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front);
01751     gl2psFree(*tree);
01752     *tree = NULL;
01753   }
01754 }
01755 
01756 static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane)
01757 {
01758   GLfloat pt_dis;
01759 
01760   pt_dis = gl2psComparePointPlane(point, plane);
01761   if(pt_dis > GL2PS_EPSILON)        return GL2PS_POINT_INFRONT;
01762   else if(pt_dis < -GL2PS_EPSILON)  return GL2PS_POINT_BACK;
01763   else                              return GL2PS_POINT_COINCIDENT;
01764 }
01765 
01766 static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim,
01767                                          GL2PSbsptree2d **tree)
01768 {
01769   GLint ret = 0;
01770   GLint i;
01771   GLint offset = 0;
01772   GL2PSbsptree2d *head = NULL, *cur = NULL;
01773 
01774   if((*tree == NULL) && (prim->numverts > 2)){
01775     /* don't cull if transparent
01776     for(i = 0; i < prim->numverts - 1; i++)
01777       if(prim->verts[i].rgba[3] < 1.0F) return;
01778     */
01779     head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
01780     for(i = 0; i < prim->numverts-1; i++){
01781       if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz,
01782                                   prim->verts[i+1].xyz,
01783                                   head->plane)){
01784         if(prim->numverts-i > 3){
01785           offset++;
01786         }
01787         else{
01788           gl2psFree(head);
01789           return;
01790         }
01791       }
01792       else{
01793         break;
01794       }
01795     }
01796     head->back = NULL;
01797     head->front = NULL;
01798     for(i = 2+offset; i < prim->numverts; i++){
01799       ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane);
01800       if(ret != GL2PS_POINT_COINCIDENT) break;
01801     }
01802     switch(ret){
01803     case GL2PS_POINT_INFRONT :
01804       cur = head;
01805       for(i = 1+offset; i < prim->numverts-1; i++){
01806         if(cur->front == NULL){
01807           cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
01808         }
01809         if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
01810                                    prim->verts[i+1].xyz,
01811                                    cur->front->plane)){
01812           cur = cur->front;
01813           cur->front = NULL;
01814           cur->back = NULL;
01815         }
01816       }
01817       if(cur->front == NULL){
01818         cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
01819       }
01820       if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
01821                                  prim->verts[offset].xyz,
01822                                  cur->front->plane)){
01823         cur->front->front = NULL;
01824         cur->front->back = NULL;
01825       }
01826       else{
01827         gl2psFree(cur->front);
01828         cur->front = NULL;
01829       }
01830       break;
01831     case GL2PS_POINT_BACK :
01832       for(i = 0; i < 4; i++){
01833         head->plane[i] = -head->plane[i];
01834       }
01835       cur = head;
01836       for(i = 1+offset; i < prim->numverts-1; i++){
01837         if(cur->front == NULL){
01838           cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
01839         }
01840         if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz,
01841                                    prim->verts[i].xyz,
01842                                    cur->front->plane)){
01843           cur = cur->front;
01844           cur->front = NULL;
01845           cur->back = NULL;
01846         }
01847       }
01848       if(cur->front == NULL){
01849         cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
01850       }
01851       if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz,
01852                                  prim->verts[i].xyz,
01853                                  cur->front->plane)){
01854         cur->front->front = NULL;
01855         cur->front->back = NULL;
01856       }
01857       else{
01858         gl2psFree(cur->front);
01859         cur->front = NULL;
01860       }
01861       break;
01862     default:
01863       gl2psFree(head);
01864       return;
01865     }
01866     (*tree) = head;
01867   }
01868 }
01869 
01870 static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane)
01871 {
01872   GLint i;
01873   GLint pos;
01874 
01875   pos = gl2psCheckPoint(prim->verts[0].xyz, plane);
01876   for(i = 1; i < prim->numverts; i++){
01877     pos |= gl2psCheckPoint(prim->verts[i].xyz, plane);
01878     if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING;
01879   }
01880   if(pos & GL2PS_POINT_INFRONT)   return GL2PS_IN_FRONT_OF;
01881   else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF;
01882   else                            return GL2PS_COINCIDENT;
01883 }
01884 
01885 static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent,
01886                                                    GLshort numverts,
01887                                                    GL2PSvertex *vertx)
01888 {
01889   GLint i;
01890   GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
01891 
01892   if(parent->type == GL2PS_IMAGEMAP){
01893     child->type = GL2PS_IMAGEMAP;
01894     child->data.image = parent->data.image;
01895   }
01896   else {
01897     switch(numverts){
01898     case 1 : child->type = GL2PS_POINT; break;
01899     case 2 : child->type = GL2PS_LINE; break;
01900     case 3 : child->type = GL2PS_TRIANGLE; break;
01901     case 4 : child->type = GL2PS_QUADRANGLE; break;
01902     default: child->type = GL2PS_NO_TYPE; break; /* FIXME */
01903     }
01904   }
01905   child->boundary = 0; /* FIXME: not done! */
01906   child->culled = parent->culled;
01907   child->offset = parent->offset;
01908   child->pattern = parent->pattern;
01909   child->factor = parent->factor;
01910   child->width = parent->width;
01911   child->numverts = numverts;
01912   child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
01913   for(i = 0; i < numverts; i++){
01914     child->verts[i] = vertx[i];
01915   }
01916   return child;
01917 }
01918 
01919 static void gl2psSplitPrimitive2D(GL2PSprimitive *prim,
01920                                   GL2PSplane plane, 
01921                                   GL2PSprimitive **front, 
01922                                   GL2PSprimitive **back)
01923 {
01924   /* cur will hold the position of the current vertex
01925      prev will hold the position of the previous vertex
01926      prev0 will hold the position of the vertex number 0
01927      v1 and v2 represent the current and previous vertices, respectively
01928      flag is set if the current vertex should be checked against the plane */
01929   GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1;
01930   
01931   /* list of vertices that will go in front and back primitive */
01932   GL2PSvertex *front_list = NULL, *back_list = NULL;
01933   
01934   /* number of vertices in front and back list */
01935   GLshort front_count = 0, back_count = 0;
01936 
01937   for(i = 0; i <= prim->numverts; i++){
01938     v1 = i;
01939     if(v1 == prim->numverts){
01940       if(prim->numverts < 3) break;
01941       v1 = 0;
01942       v2 = prim->numverts - 1;
01943       cur = prev0;
01944     }
01945     else if(flag){
01946       cur = gl2psCheckPoint(prim->verts[v1].xyz, plane);
01947       if(i == 0){
01948         prev0 = cur;
01949       }
01950     } 
01951     if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) &&
01952        (i < prim->numverts)){
01953       if(cur == GL2PS_POINT_INFRONT){
01954         front_count++;
01955         front_list = (GL2PSvertex*)gl2psRealloc(front_list,
01956                                                 sizeof(GL2PSvertex)*front_count);
01957         front_list[front_count-1] = prim->verts[v1];
01958       }
01959       else if(cur == GL2PS_POINT_BACK){
01960         back_count++;
01961         back_list = (GL2PSvertex*)gl2psRealloc(back_list,
01962                                                sizeof(GL2PSvertex)*back_count);
01963         back_list[back_count-1] = prim->verts[v1];
01964       }
01965       else{
01966         front_count++;
01967         front_list = (GL2PSvertex*)gl2psRealloc(front_list,
01968                                                 sizeof(GL2PSvertex)*front_count);
01969         front_list[front_count-1] = prim->verts[v1];
01970         back_count++;
01971         back_list = (GL2PSvertex*)gl2psRealloc(back_list,
01972                                                sizeof(GL2PSvertex)*back_count);
01973         back_list[back_count-1] = prim->verts[v1];
01974       }
01975       flag = 1;
01976     }
01977     else if((prev != cur) && (cur != 0) && (prev != 0)){
01978       if(v1 != 0){
01979         v2 = v1-1;
01980         i--;
01981       }
01982       front_count++;
01983       front_list = (GL2PSvertex*)gl2psRealloc(front_list,
01984                                               sizeof(GL2PSvertex)*front_count);
01985       gl2psCutEdge(&prim->verts[v2], &prim->verts[v1],
01986                    plane, &front_list[front_count-1]);
01987       back_count++;
01988       back_list = (GL2PSvertex*)gl2psRealloc(back_list,
01989                                              sizeof(GL2PSvertex)*back_count);
01990       back_list[back_count-1] = front_list[front_count-1];
01991       flag = 0;
01992     }
01993     prev = cur;
01994   }
01995   *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list);
01996   *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list);
01997   gl2psFree(front_list);
01998   gl2psFree(back_list);
01999 }
02000 
02001 static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree)
02002 {
02003   GLint ret = 0;
02004   GL2PSprimitive *frontprim = NULL, *backprim = NULL;
02005   
02006   /* FIXME: until we consider the actual extent of text strings and
02007      pixmaps, never cull them. Otherwise the whole string/pixmap gets
02008      culled as soon as the reference point is hidden */
02009   if(prim->type == GL2PS_PIXMAP || 
02010      prim->type == GL2PS_TEXT || 
02011      prim->type == GL2PS_SPECIAL){
02012     return 1;
02013   }
02014 
02015   if(*tree == NULL){
02016     if((prim->type != GL2PS_IMAGEMAP) && (GL_FALSE == gl2ps->zerosurfacearea)){
02017       gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree);
02018     }
02019     return 1;
02020   }
02021   else{
02022     switch(gl2psCheckPrimitive(prim, (*tree)->plane)){
02023     case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back);
02024     case GL2PS_IN_FRONT_OF: 
02025       if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front);
02026       else                       return 0;
02027     case GL2PS_SPANNING:
02028       gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim);
02029       ret = gl2psAddInBspImageTree(backprim, &(*tree)->back);
02030       if((*tree)->front != NULL){
02031         if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){
02032           ret = 1;
02033         }
02034       }
02035       gl2psFree(frontprim->verts);
02036       gl2psFree(frontprim);
02037       gl2psFree(backprim->verts);
02038       gl2psFree(backprim);
02039       return ret;
02040     case GL2PS_COINCIDENT:
02041       if((*tree)->back != NULL){
02042         gl2ps->zerosurfacearea = GL_TRUE;
02043         ret = gl2psAddInBspImageTree(prim, &(*tree)->back);
02044         gl2ps->zerosurfacearea = GL_FALSE;
02045         if(ret) return ret;
02046       }
02047       if((*tree)->front != NULL){
02048         gl2ps->zerosurfacearea = GL_TRUE;
02049         ret = gl2psAddInBspImageTree(prim, &(*tree)->front);
02050         gl2ps->zerosurfacearea = GL_FALSE;
02051         if(ret) return ret;
02052       }
02053       if(prim->type == GL2PS_LINE) return 1;
02054       else                         return 0;
02055     }
02056   }
02057   return 0;
02058 }
02059 
02060 static void gl2psAddInImageTree(void *data)
02061 {
02062   GL2PSprimitive *prim = *(GL2PSprimitive **)data;
02063   gl2ps->primitivetoadd = prim;
02064   if(prim->type == GL2PS_IMAGEMAP && prim->data.image->format == GL2PS_IMAGEMAP_VISIBLE){
02065     prim->culled = 1;
02066   }
02067   else if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){
02068     prim->culled = 1;
02069   }
02070   else if(prim->type == GL2PS_IMAGEMAP){
02071     prim->data.image->format = GL2PS_IMAGEMAP_VISIBLE;
02072   }
02073 }
02074 
02075 /* Boundary construction */
02076 
02077 static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list)
02078 {
02079   GL2PSprimitive *b;
02080   GLshort i;
02081   GL2PSxyz c;
02082 
02083   c[0] = c[1] = c[2] = 0.0F;
02084   for(i = 0; i < prim->numverts; i++){
02085     c[0] += prim->verts[i].xyz[0];
02086     c[1] += prim->verts[i].xyz[1];
02087   }
02088   c[0] /= prim->numverts;
02089   c[1] /= prim->numverts;
02090 
02091   for(i = 0; i < prim->numverts; i++){
02092     if(prim->boundary & (GLint)pow(2., i)){
02093       b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
02094       b->type = GL2PS_LINE;
02095       b->offset = prim->offset;
02096       b->pattern = prim->pattern;
02097       b->factor = prim->factor;
02098       b->culled = prim->culled;
02099       b->width = prim->width;
02100       b->boundary = 0;
02101       b->numverts = 2;
02102       b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex));
02103 
02104 #if 0 /* FIXME: need to work on boundary offset... */
02105       v[0] = c[0] - prim->verts[i].xyz[0];
02106       v[1] = c[1] - prim->verts[i].xyz[1];
02107       v[2] = 0.0F;
02108       norm = gl2psNorm(v);
02109       v[0] /= norm;
02110       v[1] /= norm;
02111       b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0];
02112       b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1];
02113       b->verts[0].xyz[2] = prim->verts[i].xyz[2];
02114       v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
02115       v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
02116       norm = gl2psNorm(v);
02117       v[0] /= norm;
02118       v[1] /= norm;
02119       b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0];
02120       b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1];
02121       b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
02122 #else
02123       b->verts[0].xyz[0] = prim->verts[i].xyz[0];
02124       b->verts[0].xyz[1] = prim->verts[i].xyz[1];
02125       b->verts[0].xyz[2] = prim->verts[i].xyz[2];
02126       b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
02127       b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
02128       b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
02129 #endif
02130 
02131       b->verts[0].rgba[0] = 0.0F;
02132       b->verts[0].rgba[1] = 0.0F;
02133       b->verts[0].rgba[2] = 0.0F;
02134       b->verts[0].rgba[3] = 0.0F;
02135       b->verts[1].rgba[0] = 0.0F;
02136       b->verts[1].rgba[1] = 0.0F;
02137       b->verts[1].rgba[2] = 0.0F;
02138       b->verts[1].rgba[3] = 0.0F;
02139       gl2psListAdd(list, &b);
02140     }
02141   }
02142 
02143 }
02144 
02145 static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree)
02146 {
02147   GLint i;
02148   GL2PSprimitive *prim;
02149 
02150   if(!tree) return;
02151   gl2psBuildPolygonBoundary(tree->back);
02152   for(i = 0; i < gl2psListNbr(tree->primitives); i++){
02153     prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i);
02154     if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives);
02155   }
02156   gl2psBuildPolygonBoundary(tree->front);
02157 }
02158 
02159 /********************************************************************* 
02160  *
02161  * Feedback buffer parser
02162  *
02163  *********************************************************************/
02164 
02165 static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, 
02166                                   GL2PSvertex *verts, GLint offset, 
02167                                   GLushort pattern, GLint factor,
02168                                   GLfloat width, char boundary)
02169 {
02170   GL2PSprimitive *prim;
02171 
02172   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
02173   prim->type = type;
02174   prim->numverts = numverts;
02175   prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
02176   memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex));
02177   prim->boundary = boundary;
02178   prim->offset = offset;
02179   prim->pattern = pattern;
02180   prim->factor = factor;
02181   prim->width = width;
02182   prim->culled = 0;
02183 
02184   /* FIXME: here we should have an option to split stretched
02185      tris/quads to enhance SIMPLE_SORT */
02186 
02187   gl2psListAdd(gl2ps->primitives, &prim);
02188 }
02189 
02190 static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p)
02191 {
02192   GLint i;
02193 
02194   v->xyz[0] = p[0];
02195   v->xyz[1] = p[1];
02196   v->xyz[2] = p[2];
02197 
02198   if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){
02199     i = (GLint)(p[3] + 0.5);
02200     v->rgba[0] = gl2ps->colormap[i][0];
02201     v->rgba[1] = gl2ps->colormap[i][1];
02202     v->rgba[2] = gl2ps->colormap[i][2];
02203     v->rgba[3] = gl2ps->colormap[i][3];
02204     return 4;
02205   }
02206   else{
02207     v->rgba[0] = p[3];
02208     v->rgba[1] = p[4];
02209     v->rgba[2] = p[5];
02210     v->rgba[3] = p[6];
02211     return 7;
02212   }
02213 }
02214 
02215 static void gl2psParseFeedbackBuffer(GLint used)
02216 {
02217   char flag;
02218   GLushort pattern = 0;
02219   GLboolean boundary;
02220   GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0;
02221   GLfloat lwidth = 1.0F, psize = 1.0F;
02222   GLfloat *current;
02223   GL2PSvertex vertices[3];
02224   GL2PSprimitive *prim;
02225   GL2PSimagemap *node;
02226 
02227   current = gl2ps->feedback;
02228   boundary = gl2ps->boundary = GL_FALSE;
02229 
02230   while(used > 0){
02231 
02232     if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE;
02233     
02234     switch((GLint)*current){
02235     case GL_POINT_TOKEN :
02236       current ++;
02237       used --;
02238       i = gl2psGetVertex(&vertices[0], current);
02239       current += i;
02240       used    -= i;
02241       gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, 
02242                             pattern, factor, psize, 0);
02243       break;
02244     case GL_LINE_TOKEN :
02245     case GL_LINE_RESET_TOKEN :
02246       current ++;
02247       used --;
02248       i = gl2psGetVertex(&vertices[0], current);
02249       current += i;
02250       used    -= i;
02251       i = gl2psGetVertex(&vertices[1], current);
02252       current += i;
02253       used    -= i;
02254       gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, 
02255                             pattern, factor, lwidth, 0);
02256       break;
02257     case GL_POLYGON_TOKEN :
02258       count = (GLint)current[1];
02259       current += 2;
02260       used -= 2;
02261       v = vtot = 0;
02262       while(count > 0 && used > 0){
02263         i = gl2psGetVertex(&vertices[v], current);
02264         gl2psAdaptVertexForBlending(&vertices[v]);
02265         current += i;
02266         used    -= i;
02267         count --;
02268         vtot++;
02269         if(v == 2){
02270           if(GL_TRUE == boundary){
02271             if(!count && vtot == 2) flag = 1|2|4;
02272             else if(!count) flag = 2|4;
02273             else if(vtot == 2) flag = 1|2;
02274             else flag = 2;
02275           }
02276           else
02277             flag = 0;
02278           gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices, offset,
02279                                 pattern, factor, 1, flag);
02280           vertices[1] = vertices[2];
02281         }
02282         else
02283           v ++;
02284       }
02285       break;      
02286     case GL_BITMAP_TOKEN :
02287     case GL_DRAW_PIXEL_TOKEN :
02288     case GL_COPY_PIXEL_TOKEN :
02289       current ++;
02290       used --;
02291       i = gl2psGetVertex(&vertices[0], current);
02292       current += i;
02293       used    -= i;
02294       break;      
02295     case GL_PASS_THROUGH_TOKEN :
02296       switch((GLint)current[1]){
02297       case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break;
02298       case GL2PS_END_OFFSET_TOKEN : offset = 0; break;
02299       case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break;
02300       case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break;
02301       case GL2PS_END_STIPPLE_TOKEN : pattern = factor = 0; break;
02302       case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break;
02303       case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break;
02304       case GL2PS_BEGIN_STIPPLE_TOKEN : 
02305         current += 2;
02306         used -= 2; 
02307         pattern = (GLushort)current[1]; 
02308         current += 2;
02309         used -= 2; 
02310         factor = (GLint)current[1]; 
02311         break;
02312       case GL2PS_SRC_BLEND_TOKEN : 
02313         current += 2; 
02314         used -= 2; 
02315         gl2ps->blendfunc[0] = (GLint)current[1];
02316         break;
02317       case GL2PS_DST_BLEND_TOKEN : 
02318         current += 2; 
02319         used -= 2; 
02320         gl2ps->blendfunc[1] = (GLint)current[1];
02321         break;
02322       case GL2PS_POINT_SIZE_TOKEN : 
02323         current += 2; 
02324         used -= 2; 
02325         psize = current[1];
02326         break;
02327       case GL2PS_LINE_WIDTH_TOKEN : 
02328         current += 2; 
02329         used -= 2; 
02330         lwidth = current[1];
02331         break;
02332       case GL2PS_IMAGEMAP_TOKEN :
02333         prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive));
02334         prim->type = GL2PS_IMAGEMAP;
02335         prim->boundary = 0;
02336         prim->numverts = 4;
02337         prim->verts = (GL2PSvertex *)gl2psMalloc(4 * sizeof(GL2PSvertex));
02338         prim->culled = 0;
02339         prim->offset = 0;
02340         prim->pattern = 0;
02341         prim->factor = 0;
02342         prim->width = 1;
02343         
02344         node = (GL2PSimagemap*)gl2psMalloc(sizeof(GL2PSimagemap));
02345         node->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
02346         node->image->type = 0;
02347         node->image->format = 0;
02348         node->next = NULL;
02349         
02350         if(gl2ps->imagemap_head == NULL)
02351           gl2ps->imagemap_head = node;
02352         else
02353           gl2ps->imagemap_tail->next = node;
02354         gl2ps->imagemap_tail = node;
02355         prim->data.image = node->image;
02356         
02357         current += 2; used -= 2;
02358         i = gl2psGetVertex(&prim->verts[0], &current[1]);
02359         current += i; used -= i;
02360         
02361         node->image->width = (GLint)current[2];
02362         current += 2; used -= 2;
02363         node->image->height = (GLint)current[2];
02364         prim->verts[0].xyz[0] = prim->verts[0].xyz[0] - (int)(node->image->width / 2) + 0.5;
02365         prim->verts[0].xyz[1] = prim->verts[0].xyz[1] - (int)(node->image->height / 2) + 0.5;
02366         for(i = 1; i < 4; i++){
02367           for(v = 0; v < 3; v++){
02368             prim->verts[i].xyz[v] = prim->verts[0].xyz[v];
02369             prim->verts[i].rgba[v] = prim->verts[0].rgba[v];
02370           }
02371           prim->verts[i].rgba[v] = prim->verts[0].rgba[v];
02372         }
02373         prim->verts[1].xyz[0] = prim->verts[1].xyz[0] + node->image->width;
02374         prim->verts[2].xyz[0] = prim->verts[1].xyz[0];
02375         prim->verts[2].xyz[1] = prim->verts[2].xyz[1] + node->image->height;
02376         prim->verts[3].xyz[1] = prim->verts[2].xyz[1];
02377 
02378         sizeoffloat = sizeof(GLfloat);
02379         v = 2 * sizeoffloat;
02380         vtot = node->image->height + node->image->height * 
02381           ((node->image->width - 1) / 8);
02382         node->image->pixels = (GLfloat*)gl2psMalloc(v + vtot);
02383         node->image->pixels[0] = prim->verts[0].xyz[0];
02384         node->image->pixels[1] = prim->verts[0].xyz[1];
02385         
02386         for(i = 0; i < vtot; i += sizeoffloat){
02387           current += 2; used -= 2;
02388           if((vtot - i) >= 4)
02389             memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), sizeoffloat);
02390           else
02391             memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), vtot - i);
02392         }
02393         current++; used--;
02394         gl2psListAdd(gl2ps->primitives, &prim);
02395         break;
02396       case GL2PS_DRAW_PIXELS_TOKEN :
02397       case GL2PS_TEXT_TOKEN :
02398         if(auxindex < gl2psListNbr(gl2ps->auxprimitives))
02399           gl2psListAdd(gl2ps->primitives, 
02400                        gl2psListPointer(gl2ps->auxprimitives, auxindex++));
02401         else
02402           gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer");
02403         break;
02404       }
02405       current += 2; 
02406       used -= 2; 
02407       break;      
02408     default :
02409       gl2psMsg(GL2PS_WARNING, "Unknown token in buffer");
02410       current ++;
02411       used --;
02412       break;
02413     }
02414   }
02415 
02416   gl2psListReset(gl2ps->auxprimitives);
02417 }
02418 
02419 /********************************************************************* 
02420  *
02421  * PostScript routines
02422  *
02423  *********************************************************************/
02424 
02425 static void gl2psWriteByte(unsigned char byte)
02426 {
02427   unsigned char h = byte / 16;
02428   unsigned char l = byte % 16;
02429   gl2psPrintf("%x%x", h, l);
02430 }
02431 
02432 static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im)
02433 {
02434   GLuint nbhex, nbyte, nrgb, nbits;
02435   GLuint row, col, ibyte, icase;
02436   GLfloat dr, dg, db, fgrey;
02437   unsigned char red = 0, green = 0, blue = 0, b, grey;
02438   GLuint width = (GLuint)im->width;
02439   GLuint height = (GLuint)im->height;
02440 
02441   /* FIXME: should we define an option for these? Or just keep the
02442      8-bit per component case? */
02443   int greyscale = 0; /* set to 1 to output greyscale image */
02444   int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */
02445 
02446   if((width <= 0) || (height <= 0)) return;
02447 
02448   gl2psPrintf("gsave\n");
02449   gl2psPrintf("%.2f %.2f translate\n", x, y); 
02450   gl2psPrintf("%d %d scale\n", width, height); 
02451 
02452   if(greyscale){ /* greyscale */
02453     gl2psPrintf("/picstr %d string def\n", width); 
02454     gl2psPrintf("%d %d %d\n", width, height, 8); 
02455     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); 
02456     gl2psPrintf("{ currentfile picstr readhexstring pop }\n");
02457     gl2psPrintf("image\n");
02458     for(row = 0; row < height; row++){
02459       for(col = 0; col < width; col++){ 
02460         gl2psGetRGB(im, col, row, &dr, &dg, &db);
02461         fgrey = (0.30 * dr + 0.59 * dg + 0.11 * db);
02462         grey = (unsigned char)(255. * fgrey);
02463         gl2psWriteByte(grey);
02464       }
02465       gl2psPrintf("\n");
02466     }
02467     nbhex = width * height * 2; 
02468     gl2psPrintf("%%%% nbhex digit          :%d\n", nbhex); 
02469   }
02470   else if(nbit == 2){ /* color, 2 bits for r and g and b; rgbs following each other */
02471     nrgb = width  * 3;
02472     nbits = nrgb * nbit;
02473     nbyte = nbits / 8;
02474     if((nbyte * 8) != nbits) nbyte++;
02475     gl2psPrintf("/rgbstr %d string def\n", nbyte);
02476     gl2psPrintf("%d %d %d\n", width, height, nbit);
02477     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
02478     gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
02479     gl2psPrintf("false 3\n");
02480     gl2psPrintf("colorimage\n");
02481     for(row = 0; row < height; row++){
02482       icase = 1;
02483       col = 0;
02484       b = 0;
02485       for(ibyte = 0; ibyte < nbyte; ibyte++){
02486         if(icase == 1) {
02487           if(col < width) {
02488             gl2psGetRGB(im, col, row, &dr, &dg, &db);
02489           } 
02490           else {
02491             dr = dg = db = 0;
02492           }
02493           col++;
02494           red = (unsigned char)(3. * dr);
02495           green = (unsigned char)(3. * dg);
02496           blue = (unsigned char)(3. * db);
02497           b = red;
02498           b = (b<<2) + green;
02499           b = (b<<2) + blue;
02500           if(col < width) {
02501             gl2psGetRGB(im, col, row, &dr, &dg, &db);
02502           } 
02503           else {
02504             dr = dg = db = 0;
02505           }
02506           col++;
02507           red = (unsigned char)(3. * dr);
02508           green = (unsigned char)(3. * dg);
02509           blue = (unsigned char)(3. * db);
02510           b = (b<<2) + red;
02511           gl2psWriteByte(b);
02512           b = 0;
02513           icase++;
02514         } 
02515         else if(icase == 2) {
02516           b = green;
02517           b = (b<<2) + blue;
02518           if(col < width) {
02519             gl2psGetRGB(im, col, row, &dr, &dg, &db);
02520           }
02521           else {
02522             dr = dg = db = 0;
02523           }
02524           col++;
02525           red = (unsigned char)(3. * dr);
02526           green = (unsigned char)(3. * dg);
02527           blue = (unsigned char)(3. * db);
02528           b = (b<<2) + red;
02529           b = (b<<2) + green;
02530           gl2psWriteByte(b);
02531           b = 0;
02532           icase++;
02533         } 
02534         else if(icase == 3) {
02535           b = blue;
02536           if(col < width) {
02537             gl2psGetRGB(im, col, row, &dr, &dg, &db);
02538           }
02539           else {
02540             dr = dg = db = 0;
02541           }
02542           col++;
02543           red = (unsigned char)(3. * dr);
02544           green = (unsigned char)(3. * dg);
02545           blue = (unsigned char)(3. * db);
02546           b = (b<<2) + red;
02547           b = (b<<2) + green;
02548           b = (b<<2) + blue;
02549           gl2psWriteByte(b);
02550           b = 0;
02551           icase = 1;
02552         }
02553       }
02554       gl2psPrintf("\n");
02555     }
02556   }
02557   else if(nbit == 4){ /* color, 4 bits for r and g and b; rgbs following each other */
02558     nrgb = width  * 3;
02559     nbits = nrgb * nbit;
02560     nbyte = nbits / 8;
02561     if((nbyte * 8) != nbits) nbyte++; 
02562     gl2psPrintf("/rgbstr %d string def\n", nbyte);
02563     gl2psPrintf("%d %d %d\n", width, height, nbit);
02564     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
02565     gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
02566     gl2psPrintf("false 3\n");
02567     gl2psPrintf("colorimage\n");
02568     for(row = 0; row < height; row++){
02569       col = 0;
02570       icase = 1;
02571       for(ibyte = 0; ibyte < nbyte; ibyte++){
02572         if(icase == 1) {
02573           if(col < width) {
02574             gl2psGetRGB(im, col, row, &dr, &dg, &db);
02575           } 
02576           else {
02577             dr = dg = db = 0;
02578           }
02579           col++;
02580           red = (unsigned char)(15. * dr);
02581           green = (unsigned char)(15. * dg);
02582           gl2psPrintf("%x%x", red, green);
02583           icase++;
02584         } 
02585         else if(icase == 2) {
02586           blue = (unsigned char)(15. * db);
02587           if(col < width) {
02588             gl2psGetRGB(im, col, row, &dr, &dg, &db);
02589           } 
02590           else {
02591             dr = dg = db = 0;
02592           }
02593           col++;
02594           red = (unsigned char)(15. * dr);
02595           gl2psPrintf("%x%x", blue, red);
02596           icase++;
02597         }
02598         else if(icase == 3) {
02599           green = (unsigned char)(15. * dg);
02600           blue = (unsigned char)(15. * db);
02601           gl2psPrintf("%x%x", green, blue);
02602           icase = 1;
02603         }
02604       }
02605       gl2psPrintf("\n");
02606     }
02607   }
02608   else{ /* 8 bit for r and g and b */
02609     nbyte = width * 3;
02610     gl2psPrintf("/rgbstr %d string def\n", nbyte);
02611     gl2psPrintf("%d %d %d\n", width, height, 8);
02612     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); 
02613     gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
02614     gl2psPrintf("false 3\n");
02615     gl2psPrintf("colorimage\n");
02616     for(row = 0; row < height; row++){
02617       for(col = 0; col < width; col++){
02618         gl2psGetRGB(im, col, row, &dr, &dg, &db);
02619         red = (unsigned char)(255. * dr);
02620         gl2psWriteByte(red);
02621         green = (unsigned char)(255. * dg);
02622         gl2psWriteByte(green);
02623         blue = (unsigned char)(255. * db);
02624         gl2psWriteByte(blue);
02625       }
02626       gl2psPrintf("\n");
02627     }
02628   }
02629   
02630   gl2psPrintf("grestore\n");
02631 }
02632 
02633 static void gl2psPrintPostScriptImagemap(GLfloat x, GLfloat y,
02634                                          GLsizei width, GLsizei height,
02635                                          const unsigned char *imagemap){
02636   int i, size;
02637   
02638   if((width <= 0) || (height <= 0)) return;
02639   
02640   size = height + height * (width - 1) / 8;
02641   
02642   gl2psPrintf("gsave\n");
02643   gl2psPrintf("%.2f %.2f translate\n", x, y);
02644   gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height); 
02645   gl2psPrintf("[ %d 0 0 -%d 0 %d ] {<", width, height);
02646   for(i = 0; i < size; i++){
02647     gl2psWriteByte(*imagemap);
02648     imagemap++;
02649   }
02650   gl2psPrintf(">} imagemask\ngrestore\n");
02651 }
02652 
02653 static void gl2psPrintPostScriptHeader(void)
02654 {
02655   time_t now;
02656 
02657   /* Since compression is not part of the PostScript standard,
02658      compressed PostScript files are just gzipped PostScript files
02659      ("ps.gz" or "eps.gz") */
02660   gl2psPrintGzipHeader();
02661 
02662   time(&now);
02663 
02664   if(gl2ps->format == GL2PS_PS){
02665     gl2psPrintf("%%!PS-Adobe-3.0\n");
02666   }
02667   else{
02668     gl2psPrintf("%%!PS-Adobe-3.0 EPSF-3.0\n");
02669   }
02670 
02671   gl2psPrintf("%%%%Title: %s\n"
02672               "%%%%Creator: GL2PS %d.%d.%d%s, %s\n"
02673               "%%%%For: %s\n"
02674               "%%%%CreationDate: %s"
02675               "%%%%LanguageLevel: 3\n"
02676               "%%%%DocumentData: Clean7Bit\n"
02677               "%%%%Pages: 1\n",
02678               gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, 
02679               GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
02680               gl2ps->producer, ctime(&now));
02681 
02682   if(gl2ps->format == GL2PS_PS){
02683     gl2psPrintf("%%%%Orientation: %s\n"
02684                 "%%%%DocumentMedia: Default %d %d 0 () ()\n",
02685                 (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait",
02686                 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] :
02687                 (int)gl2ps->viewport[2], 
02688                 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : 
02689                 (int)gl2ps->viewport[3]);
02690   }
02691 
02692   gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n"
02693               "%%%%EndComments\n",
02694               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : 
02695               (int)gl2ps->viewport[0],
02696               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] :
02697               (int)gl2ps->viewport[1],
02698               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : 
02699               (int)gl2ps->viewport[2],
02700               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] :
02701               (int)gl2ps->viewport[3]);
02702 
02703   /* RGB color: r g b C (replace C by G in output to change from rgb to gray)
02704      Grayscale: r g b G
02705      Font choose: size fontname FC
02706      Text string: (string) x y size fontname S??
02707      Rotated text string: (string) angle x y size fontname S??R
02708      Point primitive: x y size P
02709      Line width: width W
02710      Line start: x y LS
02711      Line joining last point: x y L
02712      Line end: x y LE
02713      Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T
02714      Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */
02715 
02716   gl2psPrintf("%%%%BeginProlog\n"
02717               "/gl2psdict 64 dict def gl2psdict begin\n"
02718               "0 setlinecap 0 setlinejoin\n"
02719               "/tryPS3shading %s def %% set to false to force subdivision\n"
02720               "/rThreshold %g def %% red component subdivision threshold\n"
02721               "/gThreshold %g def %% green component subdivision threshold\n"
02722               "/bThreshold %g def %% blue component subdivision threshold\n",
02723               (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true",
02724               gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]);
02725 
02726   gl2psPrintf("/BD { bind def } bind def\n"
02727               "/C  { setrgbcolor } BD\n"
02728               "/G  { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n"
02729               "/W  { setlinewidth } BD\n");
02730 
02731   gl2psPrintf("/FC { findfont exch /SH exch def SH scalefont setfont } BD\n"
02732               "/SW { dup stringwidth pop } BD\n"
02733               "/S  { FC moveto show } BD\n"
02734               "/SBC{ FC moveto SW -2 div 0 rmoveto show } BD\n"
02735               "/SBR{ FC moveto SW neg 0 rmoveto show } BD\n"
02736               "/SCL{ FC moveto 0 SH -2 div rmoveto show } BD\n"
02737               "/SCC{ FC moveto SW -2 div SH -2 div rmoveto show } BD\n"
02738               "/SCR{ FC moveto SW neg SH -2 div rmoveto show } BD\n"
02739               "/STL{ FC moveto 0 SH neg rmoveto show } BD\n"
02740               "/STC{ FC moveto SW -2 div SH neg rmoveto show } BD\n"
02741               "/STR{ FC moveto SW neg SH neg rmoveto show } BD\n");
02742 
02743   /* rotated text routines: same nameanem with R appended */
02744 
02745   gl2psPrintf("/FCT { FC translate 0 0 } BD\n"
02746               "/SR  { gsave FCT moveto rotate show grestore } BD\n"  
02747               "/SBCR{ gsave FCT moveto rotate SW -2 div 0 rmoveto show grestore } BD\n"
02748               "/SBRR{ gsave FCT moveto rotate SW neg 0 rmoveto show grestore } BD\n"
02749               "/SCLR{ gsave FCT moveto rotate 0 SH -2 div rmoveto show grestore} BD\n");
02750   gl2psPrintf("/SCCR{ gsave FCT moveto rotate SW -2 div SH -2 div rmoveto show grestore} BD\n"
02751               "/SCRR{ gsave FCT moveto rotate SW neg SH -2 div rmoveto show grestore} BD\n"
02752               "/STLR{ gsave FCT moveto rotate 0 SH neg rmoveto show grestore } BD\n"
02753               "/STCR{ gsave FCT moveto rotate SW -2 div SH neg rmoveto show grestore } BD\n"
02754               "/STRR{ gsave FCT moveto rotate SW neg SH neg rmoveto show grestore } BD\n");
02755 
02756   gl2psPrintf("/P  { newpath 0.0 360.0 arc closepath fill } BD\n"
02757               "/LS { newpath moveto } BD\n"
02758               "/L  { lineto } BD\n"
02759               "/LE { lineto stroke } BD\n"
02760               "/T  { newpath moveto lineto lineto closepath fill } BD\n");
02761   
02762   /* Smooth-shaded triangle with PostScript level 3 shfill operator:
02763         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */
02764 
02765   gl2psPrintf("/STshfill {\n"
02766               "      /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n"
02767               "      /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n"
02768               "      /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n"
02769               "      gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n"
02770               "      /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n"
02771               "      shfill grestore } BD\n");
02772 
02773   /* Flat-shaded triangle with middle color:
02774         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */
02775 
02776   gl2psPrintf(/* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */
02777               "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */
02778               /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */
02779               "      3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */
02780               /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */
02781               "      3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */
02782               /* stack : x3 y3 x2 y2 x1 y1 r g b */
02783               " C T } BD\n");
02784 
02785   /* Split triangle in four sub-triangles (at sides middle points) and call the
02786      STnoshfill procedure on each, interpolating the colors in RGB space:
02787         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit
02788      (in procedure comments key: (Vi) = xi yi ri gi bi) */
02789 
02790   gl2psPrintf("/STsplit {\n"
02791               "      4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */
02792               "      4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */
02793               "      4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */
02794               "      4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */
02795               "      4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */
02796               "      5 copy 5 copy 25 15 roll\n");
02797 
02798   /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */
02799 
02800   gl2psPrintf("      9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */
02801               "      9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */
02802               "      9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */
02803               "      9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */
02804               "      9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */
02805               "      5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n");
02806 
02807   /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */
02808 
02809   gl2psPrintf("      4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */
02810               "      4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */
02811               "      4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */
02812               "      4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */
02813               "      4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */
02814               "      5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n");
02815   
02816   /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */
02817 
02818   gl2psPrintf("      STnoshfill STnoshfill STnoshfill STnoshfill } BD\n");
02819   
02820   /* Gouraud shaded triangle using recursive subdivision until the difference
02821      between corner colors does not exceed the thresholds:
02822         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill  */
02823 
02824   gl2psPrintf("/STnoshfill {\n"
02825               "      2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */
02826               "      { STsplit }\n"
02827               "      { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */
02828               "        { STsplit }\n"
02829               "        { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */
02830               "          { STsplit }\n"
02831               "          { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */
02832               "            { STsplit }\n"
02833               "            { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */
02834               "              { STsplit }\n"
02835               "              { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */
02836               "                { STsplit }\n"
02837               "                { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */
02838   gl2psPrintf("                  { STsplit }\n"
02839               "                  { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */
02840               "                    { STsplit }\n"
02841               "                    { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */
02842               "                      { STsplit }\n"
02843               "                      { Tm }\n" /* all colors sufficiently similar */
02844               "                      ifelse }\n"
02845               "                    ifelse }\n"
02846               "                  ifelse }\n"
02847               "                ifelse }\n"
02848               "              ifelse }\n"
02849               "            ifelse }\n"
02850               "          ifelse }\n"
02851               "        ifelse }\n"
02852               "      ifelse } BD\n");
02853   
02854   gl2psPrintf("tryPS3shading\n"
02855               "{ /shfill where\n"
02856               "  { /ST { STshfill } BD }\n"
02857               "  { /ST { STnoshfill } BD }\n"
02858               "  ifelse }\n"
02859               "{ /ST { STnoshfill } BD }\n"
02860               "ifelse\n");
02861 
02862   gl2psPrintf("end\n"
02863               "%%%%EndProlog\n"
02864               "%%%%BeginSetup\n"
02865               "/DeviceRGB setcolorspace\n"
02866               "gl2psdict begin\n"
02867               "%%%%EndSetup\n"
02868               "%%%%Page: 1 1\n"
02869               "%%%%BeginPageSetup\n");
02870   
02871   if(gl2ps->options & GL2PS_LANDSCAPE){
02872     gl2psPrintf("%d 0 translate 90 rotate\n",
02873                 (int)gl2ps->viewport[3]);
02874   }
02875 
02876   gl2psPrintf("%%%%EndPageSetup\n"
02877               "mark\n"
02878               "gsave\n"
02879               "1.0 1.0 scale\n");
02880           
02881   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
02882     gl2psPrintf("%g %g %g C\n"
02883                 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
02884                 "closepath fill\n",
02885                 gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2], 
02886                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], 
02887                 (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], 
02888                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
02889   }
02890 }
02891 
02892 static void gl2psPrintPostScriptColor(GL2PSrgba rgba)
02893 {
02894   if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
02895     gl2psSetLastColor(rgba);
02896     gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]);
02897   }
02898 }
02899 
02900 static void gl2psResetPostScriptColor(void)
02901 {
02902   gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.;
02903 }
02904 
02905 static void gl2psEndPostScriptLine(void)
02906 {
02907   int i;
02908   if(gl2ps->lastvertex.rgba[0] >= 0.){
02909     gl2psPrintf("%g %g LE\n", gl2ps->lastvertex.xyz[0], gl2ps->lastvertex.xyz[1]);
02910     for(i = 0; i < 3; i++)
02911       gl2ps->lastvertex.xyz[i] = -1.;
02912     for(i = 0; i < 4; i++)
02913       gl2ps->lastvertex.rgba[i] = -1.;
02914   }
02915 }
02916 
02917 static void gl2psParseStipplePattern(GLushort pattern, GLint factor, 
02918                                      int *nb, int array[10])
02919 {
02920   int i, n;
02921   int on[8] = {0, 0, 0, 0, 0, 0, 0, 0};
02922   int off[8] = {0, 0, 0, 0, 0, 0, 0, 0};
02923   char tmp[16];
02924 
02925   /* extract the 16 bits from the OpenGL stipple pattern */
02926   for(n = 15; n >= 0; n--){
02927     tmp[n] = (char)(pattern & 0x01);
02928     pattern >>= 1;
02929   }
02930   /* compute the on/off pixel sequence */
02931   n = 0;
02932   for(i = 0; i < 8; i++){
02933     while(n < 16 && !tmp[n]){ off[i]++; n++; }
02934     while(n < 16 && tmp[n]){ on[i]++; n++; }
02935     if(n >= 15){ i++; break; }
02936   }
02937 
02938   /* store the on/off array from right to left, starting with off
02939      pixels. The PostScript specification allows for at most 11
02940      elements in the on/off array, so we limit ourselves to 5 on/off
02941      couples (our longest possible array is thus [on4 off4 on3 off3
02942      on2 off2 on1 off1 on0 off0]) */
02943   *nb = 0;
02944   for(n = i - 1; n >= 0; n--){
02945     array[(*nb)++] = factor * on[n];
02946     array[(*nb)++] = factor * off[n];
02947     if(*nb == 10) break;
02948   }
02949 }
02950 
02951 static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, const char *str)
02952 {
02953   int len = 0, i, n, array[10];
02954 
02955   if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
02956     return 0;
02957   
02958   gl2ps->lastpattern = pattern;
02959   gl2ps->lastfactor = factor;
02960   
02961   if(!pattern || !factor){
02962     /* solid line */
02963     len += gl2psPrintf("[] 0 %s\n", str);
02964   }
02965   else{
02966     gl2psParseStipplePattern(pattern, factor, &n, array);
02967     len += gl2psPrintf("[");
02968     for(i = 0; i < n; i++){
02969       if(i) len += gl2psPrintf(" ");
02970       len += gl2psPrintf("%d", array[i]);
02971     }
02972     len += gl2psPrintf("] 0 %s\n", str);
02973   }
02974   
02975   return len;
02976 }
02977 
02978 static void gl2psPrintPostScriptPrimitive(void *data)
02979 {
02980   int newline;
02981   GL2PSprimitive *prim;
02982 
02983   prim = *(GL2PSprimitive**)data;
02984 
02985   if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
02986 
02987   /* Every effort is made to draw lines as connected segments (i.e.,
02988      using a single PostScript path): this is the only way to get nice
02989      line joins and to not restart the stippling for every line
02990      segment. So if the primitive to print is not a line we must first
02991      finish the current line (if any): */
02992   if(prim->type != GL2PS_LINE) gl2psEndPostScriptLine();
02993 
02994   switch(prim->type){
02995   case GL2PS_POINT :
02996     gl2psPrintPostScriptColor(prim->verts[0].rgba);
02997     gl2psPrintf("%g %g %g P\n", 
02998                 prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width);
02999     break;
03000   case GL2PS_LINE :
03001     if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
03002        !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
03003        gl2ps->lastlinewidth != prim->width ||
03004        gl2ps->lastpattern != prim->pattern ||
03005        gl2ps->lastfactor != prim->factor){
03006       /* End the current line if the new segment does not start where
03007          the last one ended, or if the color, the width or the
03008          stippling have changed (multi-stroking lines with changing
03009          colors is necessary until we use /shfill for lines;
03010          unfortunately this means that at the moment we can screw up
03011          line stippling for smooth-shaded lines) */
03012       gl2psEndPostScriptLine();
03013       newline = 1;
03014     }
03015     else{
03016       newline = 0;
03017     }
03018     if(gl2ps->lastlinewidth != prim->width){
03019       gl2ps->lastlinewidth = prim->width;
03020       gl2psPrintf("%g W\n", gl2ps->lastlinewidth);
03021     }
03022     gl2psPrintPostScriptDash(prim->pattern, prim->factor, "setdash");
03023     gl2psPrintPostScriptColor(prim->verts[0].rgba);
03024     gl2psPrintf("%g %g %s\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1],
03025                 newline ? "LS" : "L");
03026     gl2ps->lastvertex = prim->verts[1];
03027     break;
03028   case GL2PS_TRIANGLE :
03029     if(!gl2psVertsSameColor(prim)){
03030       gl2psResetPostScriptColor();
03031       gl2psPrintf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n",
03032                   prim->verts[2].xyz[0], prim->verts[2].xyz[1],
03033                   prim->verts[2].rgba[0], prim->verts[2].rgba[1],
03034                   prim->verts[2].rgba[2], prim->verts[1].xyz[0],
03035                   prim->verts[1].xyz[1], prim->verts[1].rgba[0],
03036                   prim->verts[1].rgba[1], prim->verts[1].rgba[2],
03037                   prim->verts[0].xyz[0], prim->verts[0].xyz[1],
03038                   prim->verts[0].rgba[0], prim->verts[0].rgba[1],
03039                   prim->verts[0].rgba[2]);
03040     }
03041     else{
03042       gl2psPrintPostScriptColor(prim->verts[0].rgba);
03043       gl2psPrintf("%g %g %g %g %g %g T\n",
03044                   prim->verts[2].xyz[0], prim->verts[2].xyz[1],
03045                   prim->verts[1].xyz[0], prim->verts[1].xyz[1],
03046                   prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
03047     }
03048     break;
03049   case GL2PS_QUADRANGLE :
03050     gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
03051     break;
03052   case GL2PS_PIXMAP :
03053     gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1],
03054                                prim->data.image);
03055     break;
03056   case GL2PS_IMAGEMAP :
03057     if(prim->data.image->type != GL2PS_IMAGEMAP_WRITTEN){
03058       gl2psPrintPostScriptColor(prim->verts[0].rgba);
03059       gl2psPrintPostScriptImagemap(prim->data.image->pixels[0],
03060                                    prim->data.image->pixels[1],
03061                                    prim->data.image->width, prim->data.image->height,
03062                                    (const unsigned char*)(&(prim->data.image->pixels[2])));
03063       prim->data.image->type = GL2PS_IMAGEMAP_WRITTEN;
03064     }
03065     break;
03066   case GL2PS_TEXT :
03067     gl2psPrintPostScriptColor(prim->verts[0].rgba);
03068     gl2psPrintf("(%s) ", prim->data.text->str);
03069     if(prim->data.text->angle)
03070       gl2psPrintf("%g ", prim->data.text->angle);
03071     gl2psPrintf("%g %g %d /%s ",
03072                 prim->verts[0].xyz[0], prim->verts[0].xyz[1],
03073                 prim->data.text->fontsize, prim->data.text->fontname);
03074     switch(prim->data.text->alignment){
03075     case GL2PS_TEXT_C:
03076       gl2psPrintf(prim->data.text->angle ? "SCCR\n" : "SCC\n");
03077       break;
03078     case GL2PS_TEXT_CL:
03079       gl2psPrintf(prim->data.text->angle ? "SCLR\n" : "SCL\n");
03080       break;
03081     case GL2PS_TEXT_CR:
03082       gl2psPrintf(prim->data.text->angle ? "SCRR\n" : "SCR\n");
03083       break;
03084     case GL2PS_TEXT_B:
03085       gl2psPrintf(prim->data.text->angle ? "SBCR\n" : "SBC\n");
03086       break;
03087     case GL2PS_TEXT_BR:
03088       gl2psPrintf(prim->data.text->angle ? "SBRR\n" : "SBR\n");
03089       break;
03090     case GL2PS_TEXT_T:
03091       gl2psPrintf(prim->data.text->angle ? "STCR\n" : "STC\n");
03092       break;
03093     case GL2PS_TEXT_TL:
03094       gl2psPrintf(prim->data.text->angle ? "STLR\n" : "STL\n");
03095       break;
03096     case GL2PS_TEXT_TR:
03097       gl2psPrintf(prim->data.text->angle ? "STRR\n" : "STR\n");
03098       break;
03099     case GL2PS_TEXT_BL:
03100     default:
03101       gl2psPrintf(prim->data.text->angle ? "SR\n" : "S\n");
03102       break;
03103     }
03104     break;
03105   case GL2PS_SPECIAL :
03106     /* alignment contains the format for which the special output text
03107        is intended */
03108     if(prim->data.text->alignment == GL2PS_PS ||
03109        prim->data.text->alignment == GL2PS_EPS)
03110       gl2psPrintf("%s\n", prim->data.text->str);
03111     break;
03112   default :
03113     break;
03114   }
03115 }
03116 
03117 static void gl2psPrintPostScriptFooter(void)
03118 {
03119   gl2psPrintf("grestore\n"
03120               "showpage\n"
03121               "cleartomark\n"
03122               "%%%%PageTrailer\n"
03123               "%%%%Trailer\n"
03124               "end\n"
03125               "%%%%EOF\n");
03126 
03127   gl2psPrintGzipFooter();
03128 }
03129 
03130 static void gl2psPrintPostScriptBeginViewport(GLint viewport[4])
03131 {
03132   GLint index;
03133   GLfloat rgba[4];
03134   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
03135 
03136   glRenderMode(GL_FEEDBACK);
03137 
03138   if(gl2ps->header){
03139     gl2psPrintPostScriptHeader();
03140     gl2ps->header = GL_FALSE;
03141   }
03142 
03143   gl2psPrintf("gsave\n"
03144               "1.0 1.0 scale\n");
03145 
03146   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
03147     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
03148       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
03149     }
03150     else{
03151       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
03152       rgba[0] = gl2ps->colormap[index][0];
03153       rgba[1] = gl2ps->colormap[index][1];
03154       rgba[2] = gl2ps->colormap[index][2];
03155       rgba[3] = 1.0F;
03156     }
03157     gl2psPrintf("%g %g %g C\n"
03158                 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
03159                 "closepath fill\n",
03160                 rgba[0], rgba[1], rgba[2], 
03161                 x, y, x+w, y, x+w, y+h, x, y+h);
03162   }
03163     
03164   gl2psPrintf("newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
03165               "closepath clip\n",
03166               x, y, x+w, y, x+w, y+h, x, y+h);
03167   
03168 }
03169 
03170 static GLint gl2psPrintPostScriptEndViewport(void)
03171 {
03172   GLint res;
03173 
03174   res = gl2psPrintPrimitives();
03175   gl2psPrintf("grestore\n");
03176   return res;
03177 }
03178 
03179 static void gl2psPrintPostScriptFinalPrimitive(void)
03180 {
03181   /* End any remaining line, if any */
03182   gl2psEndPostScriptLine();
03183 }
03184 
03185 /* definition of the PostScript and Encapsulated PostScript backends */
03186 
03187 static GL2PSbackend gl2psPS = {
03188   gl2psPrintPostScriptHeader,
03189   gl2psPrintPostScriptFooter,
03190   gl2psPrintPostScriptBeginViewport,
03191   gl2psPrintPostScriptEndViewport,
03192   gl2psPrintPostScriptPrimitive,
03193   gl2psPrintPostScriptFinalPrimitive,
03194   "ps",
03195   "Postscript"
03196 };
03197 
03198 static GL2PSbackend gl2psEPS = {
03199   gl2psPrintPostScriptHeader,
03200   gl2psPrintPostScriptFooter,
03201   gl2psPrintPostScriptBeginViewport,
03202   gl2psPrintPostScriptEndViewport,
03203   gl2psPrintPostScriptPrimitive,
03204   gl2psPrintPostScriptFinalPrimitive,
03205   "eps",
03206   "Encapsulated Postscript"
03207 };
03208 
03209 /********************************************************************* 
03210  *
03211  * LaTeX routines
03212  *
03213  *********************************************************************/
03214 
03215 static void gl2psPrintTeXHeader(void)
03216 {
03217   char name[256];
03218   time_t now;
03219   int i;
03220 
03221   if(gl2ps->filename && strlen(gl2ps->filename) < 256){
03222     for(i = strlen(gl2ps->filename)-1; i >= 0; i--){
03223       if(gl2ps->filename[i] == '.'){
03224         strncpy(name, gl2ps->filename, i);
03225         name[i] = '\0';
03226         break;
03227       }
03228     }
03229     if(i <= 0) strcpy(name, gl2ps->filename);
03230   }
03231   else{
03232     strcpy(name, "untitled");
03233   }
03234 
03235   time(&now);
03236 
03237   fprintf(gl2ps->stream, 
03238           "%% Title: %s\n"
03239           "%% Creator: GL2PS %d.%d.%d%s, %s\n"
03240           "%% For: %s\n"
03241           "%% CreationDate: %s",
03242           gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
03243           GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
03244           gl2ps->producer, ctime(&now));
03245 
03246   fprintf(gl2ps->stream, 
03247           "\\setlength{\\unitlength}{1pt}\n"
03248           "\\begin{picture}(0,0)\n"
03249           "\\includegraphics{%s}\n"
03250           "\\end{picture}%%\n"
03251           "%s\\begin{picture}(%d,%d)(0,0)\n",
03252           name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "",
03253           (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
03254 }
03255 
03256 static void gl2psPrintTeXPrimitive(void *data)
03257 {
03258   GL2PSprimitive *prim;
03259 
03260   prim = *(GL2PSprimitive**)data;
03261 
03262   switch(prim->type){
03263   case GL2PS_TEXT :
03264     fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", 
03265             prim->data.text->fontsize);
03266     fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)",
03267             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
03268     switch(prim->data.text->alignment){
03269     case GL2PS_TEXT_C:
03270       fprintf(gl2ps->stream, "{");
03271       break;
03272     case GL2PS_TEXT_CL:
03273       fprintf(gl2ps->stream, "[l]{");
03274       break;
03275     case GL2PS_TEXT_CR:
03276       fprintf(gl2ps->stream, "[r]{");
03277       break;
03278     case GL2PS_TEXT_B:
03279       fprintf(gl2ps->stream, "[b]{");
03280       break;
03281     case GL2PS_TEXT_BR:
03282       fprintf(gl2ps->stream, "[br]{");
03283       break;
03284     case GL2PS_TEXT_T:
03285       fprintf(gl2ps->stream, "[t]{");
03286       break;
03287     case GL2PS_TEXT_TL:
03288       fprintf(gl2ps->stream, "[tl]{");
03289       break;
03290     case GL2PS_TEXT_TR:
03291       fprintf(gl2ps->stream, "[tr]{");
03292       break;
03293     case GL2PS_TEXT_BL:
03294     default:
03295       fprintf(gl2ps->stream, "[bl]{");
03296       break;
03297     }
03298     if(prim->data.text->angle)
03299       fprintf(gl2ps->stream, "\\rotatebox{%g}{", prim->data.text->angle);
03300     fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}",
03301             prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2],
03302             prim->data.text->str);
03303     if(prim->data.text->angle)
03304       fprintf(gl2ps->stream, "}");
03305     fprintf(gl2ps->stream, "}}\n");
03306     break;
03307   case GL2PS_SPECIAL :
03308     /* alignment contains the format for which the special output text
03309        is intended */
03310     if (prim->data.text->alignment == GL2PS_TEX)
03311       fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
03312     break;
03313   default :
03314     break;
03315   }
03316 }
03317 
03318 static void gl2psPrintTeXFooter(void)
03319 {
03320   fprintf(gl2ps->stream, "\\end{picture}%s\n",
03321           (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : "");
03322 }
03323 
03324 static void gl2psPrintTeXBeginViewport(GLint /*viewport*/[4])
03325 {
03326   glRenderMode(GL_FEEDBACK);
03327   
03328   if(gl2ps->header){
03329     gl2psPrintTeXHeader();
03330     gl2ps->header = GL_FALSE;
03331   }
03332 }
03333 
03334 static GLint gl2psPrintTeXEndViewport(void)
03335 {
03336   return gl2psPrintPrimitives();
03337 }
03338 
03339 static void gl2psPrintTeXFinalPrimitive(void)
03340 {
03341 }
03342 
03343 /* definition of the LaTeX backend */
03344 
03345 static GL2PSbackend gl2psTEX = {
03346   gl2psPrintTeXHeader,
03347   gl2psPrintTeXFooter,
03348   gl2psPrintTeXBeginViewport,
03349   gl2psPrintTeXEndViewport,
03350   gl2psPrintTeXPrimitive,
03351   gl2psPrintTeXFinalPrimitive,
03352   "tex",
03353   "LaTeX text"
03354 };
03355 
03356 /********************************************************************* 
03357  *
03358  * PDF routines
03359  *
03360  *********************************************************************/
03361 
03362 static int gl2psPrintPDFCompressorType(void)
03363 {
03364 #if defined(GL2PS_HAVE_ZLIB)
03365   if(gl2ps->options & GL2PS_COMPRESS){
03366     return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n");
03367   }
03368 #endif
03369   return 0;
03370 }
03371 
03372 static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba)
03373 {
03374   int i, offs = 0;
03375 
03376   gl2psSetLastColor(rgba);
03377   for(i = 0; i < 3; ++i){
03378     if(GL2PS_ZERO(rgba[i]))
03379       offs += gl2psPrintf("%.0f ", 0.);
03380     else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */
03381       offs += gl2psPrintf("%f ", rgba[i]);
03382     else
03383       offs += gl2psPrintf("%g ", rgba[i]);
03384   }
03385   offs += gl2psPrintf("RG\n");
03386   return offs;
03387 }
03388 
03389 static int gl2psPrintPDFFillColor(GL2PSrgba rgba)
03390 {
03391   int i, offs = 0;
03392   
03393   for(i = 0; i < 3; ++i){
03394     if(GL2PS_ZERO(rgba[i]))
03395       offs += gl2psPrintf("%.0f ", 0.);
03396     else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */
03397       offs += gl2psPrintf("%f ", rgba[i]);
03398     else
03399       offs += gl2psPrintf("%g ", rgba[i]);
03400   }
03401   offs += gl2psPrintf("rg\n");
03402   return offs;
03403 }
03404 
03405 static int gl2psPrintPDFLineWidth(GLfloat lw)
03406 {
03407   if(GL2PS_ZERO(lw))
03408     return gl2psPrintf("%.0f w\n", 0.);
03409   else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */
03410     return gl2psPrintf("%f w\n", lw);
03411   else
03412     return gl2psPrintf("%g w\n", lw);
03413 }
03414 
03415 static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y)
03416 {
03417   gl2ps->streamlength += 
03418     gl2psPrintf("BT\n"
03419                 "/F%d %d Tf\n"
03420                 "%f %f Td\n"
03421                 "(%s) Tj\n"
03422                 "ET\n", 
03423                 cnt, text->fontsize, x, y, text->str);  
03424 }
03425 
03426 static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y)
03427 {
03428   gl2ps->streamlength += 
03429     gl2psPrintf("q\n"
03430                 "%d 0 0 %d %f %f cm\n"
03431                 "/Im%d Do\n"
03432                 "Q\n",
03433                 (int)image->width, (int)image->height, x, y, cnt);
03434 }
03435 
03436 static void gl2psPDFstacksInit(void)
03437 {
03438   gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1; 
03439   gl2ps->extgs_stack = 0;   
03440   gl2ps->font_stack = 0;    
03441   gl2ps->im_stack = 0;      
03442   gl2ps->trgroupobjects_stack = 0;    
03443   gl2ps->shader_stack = 0;  
03444   gl2ps->mshader_stack = 0; 
03445 }
03446 
03447 static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro)
03448 {
03449   if(!gro)
03450     return;
03451   
03452   gro->ptrlist = NULL;
03453   gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno 
03454     = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno 
03455     = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1;
03456 }
03457 
03458 /* Build up group objects and assign name and object numbers */
03459 
03460 static void gl2psPDFgroupListInit(void)
03461 {
03462   int i;
03463   GL2PSprimitive *p = NULL;
03464   GL2PSpdfgroup gro;
03465   int lasttype = GL2PS_NO_TYPE;
03466   GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F};
03467   GLushort lastpattern = 0;
03468   GLint lastfactor = 0;
03469   GLfloat lastwidth = 1;
03470   GL2PStriangle lastt, tmpt;
03471   int lastTriangleWasNotSimpleWithSameColor = 0;
03472 
03473   if(!gl2ps->pdfprimlist)
03474     return;
03475 
03476   gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup));
03477   gl2psInitTriangle(&lastt);
03478 
03479   for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){  
03480     p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i);
03481     switch(p->type){
03482     case GL2PS_PIXMAP:
03483       gl2psPDFgroupObjectInit(&gro);
03484       gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
03485       gro.imno = gl2ps->im_stack++;
03486       gl2psListAdd(gro.ptrlist, &p);
03487       gl2psListAdd(gl2ps->pdfgrouplist, &gro);
03488       break;
03489     case GL2PS_TEXT:
03490       gl2psPDFgroupObjectInit(&gro);
03491       gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
03492       gro.fontno = gl2ps->font_stack++;
03493       gl2psListAdd(gro.ptrlist, &p);
03494       gl2psListAdd(gl2ps->pdfgrouplist, &gro);
03495       break;
03496     case GL2PS_LINE:
03497       if(lasttype != p->type || lastwidth != p->width || 
03498          lastpattern != p->pattern || lastfactor != p->factor ||
03499          !gl2psSameColor(p->verts[0].rgba, lastrgba)){
03500         gl2psPDFgroupObjectInit(&gro);
03501         gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
03502         gl2psListAdd(gro.ptrlist, &p);
03503         gl2psListAdd(gl2ps->pdfgrouplist, &gro);
03504       }
03505       else{
03506         gl2psListAdd(gro.ptrlist, &p);
03507       }
03508       lastpattern = p->pattern;
03509       lastfactor = p->factor;
03510       lastwidth = p->width;
03511       lastrgba[0] = p->verts[0].rgba[0];
03512       lastrgba[1] = p->verts[0].rgba[1];
03513       lastrgba[2] = p->verts[0].rgba[2];
03514       break;
03515     case GL2PS_POINT:
03516       if(lasttype != p->type || lastwidth != p->width || 
03517          !gl2psSameColor(p->verts[0].rgba, lastrgba)){
03518         gl2psPDFgroupObjectInit(&gro);
03519         gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*));
03520         gl2psListAdd(gro.ptrlist, &p);
03521         gl2psListAdd(gl2ps->pdfgrouplist, &gro);
03522       }
03523       else{
03524         gl2psListAdd(gro.ptrlist, &p);
03525       }
03526       lastwidth = p->width;
03527       lastrgba[0] = p->verts[0].rgba[0];
03528       lastrgba[1] = p->verts[0].rgba[1];
03529       lastrgba[2] = p->verts[0].rgba[2];
03530       break;
03531     case GL2PS_TRIANGLE:
03532       gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE);
03533       lastTriangleWasNotSimpleWithSameColor = 
03534         !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) ||
03535         !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba);
03536       if(lasttype == p->type && tmpt.prop == lastt.prop && 
03537          lastTriangleWasNotSimpleWithSameColor){
03538         /* TODO Check here for last alpha */
03539         gl2psListAdd(gro.ptrlist, &p);
03540       }
03541       else{
03542         gl2psPDFgroupObjectInit(&gro);
03543         gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
03544         gl2psListAdd(gro.ptrlist, &p);
03545         gl2psListAdd(gl2ps->pdfgrouplist, &gro);
03546       }
03547       lastt = tmpt;
03548       break;
03549     default:
03550       break;
03551     } 
03552     lasttype = p->type;
03553   }
03554 }
03555 
03556 static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro)
03557 {
03558   GL2PStriangle t;
03559   GL2PSprimitive *prim = NULL;
03560   
03561   if(!gro)
03562     return;
03563 
03564   if(!gl2psListNbr(gro->ptrlist))
03565     return;
03566 
03567   prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
03568 
03569   if(prim->type != GL2PS_TRIANGLE)
03570     return;
03571 
03572   gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
03573   
03574   if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){        
03575     gro->gsno = gl2ps->extgs_stack++; 
03576     gro->gsobjno = gl2ps->objects_stack ++;
03577   }
03578   else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){              
03579     gro->gsno = gl2ps->extgs_stack++;
03580     gro->gsobjno = gl2ps->objects_stack++;
03581     gro->trgroupno = gl2ps->trgroupobjects_stack++; 
03582     gro->trgroupobjno = gl2ps->objects_stack++;
03583     gro->maskshno = gl2ps->mshader_stack++;
03584     gro->maskshobjno = gl2ps->objects_stack++;
03585   }
03586   else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){          
03587     gro->shno = gl2ps->shader_stack++;
03588     gro->shobjno = gl2ps->objects_stack++;
03589   }
03590   else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){             
03591     gro->gsno = gl2ps->extgs_stack++;
03592     gro->gsobjno = gl2ps->objects_stack++;
03593     gro->shno = gl2ps->shader_stack++; 
03594     gro->shobjno = gl2ps->objects_stack++;
03595   }
03596   else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){                
03597     gro->gsno = gl2ps->extgs_stack++;
03598     gro->gsobjno = gl2ps->objects_stack++;
03599     gro->shno = gl2ps->shader_stack++; 
03600     gro->shobjno = gl2ps->objects_stack++;
03601     gro->trgroupno = gl2ps->trgroupobjects_stack++; 
03602     gro->trgroupobjno = gl2ps->objects_stack++;
03603     gro->maskshno = gl2ps->mshader_stack++;
03604     gro->maskshobjno = gl2ps->objects_stack++;
03605   }
03606 }
03607 
03608 /* Main stream data */
03609 
03610 static void gl2psPDFgroupListWriteMainStream(void)
03611 {
03612   int i, j, lastel;
03613   GL2PSprimitive *prim = NULL, *prev = NULL;
03614   GL2PSpdfgroup *gro;
03615   GL2PStriangle t;
03616 
03617   if(!gl2ps->pdfgrouplist)
03618     return;
03619 
03620   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
03621     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
03622 
03623     lastel = gl2psListNbr(gro->ptrlist) - 1;
03624     if(lastel < 0)
03625       continue;
03626 
03627     prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
03628 
03629     switch(prim->type){
03630     case GL2PS_POINT:
03631       gl2ps->streamlength += gl2psPrintf("1 J\n");
03632       gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
03633       gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
03634       for(j = 0; j <= lastel; ++j){  
03635         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
03636         gl2ps->streamlength +=
03637           gl2psPrintf("%f %f m %f %f l\n",
03638                       prim->verts[0].xyz[0], prim->verts[0].xyz[1],
03639                       prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
03640       }
03641       gl2ps->streamlength += gl2psPrintf("S\n"); 
03642       gl2ps->streamlength += gl2psPrintf("0 J\n");
03643       break;
03644     case GL2PS_LINE:
03645       /* We try to use as few paths as possible to draw lines, in
03646          order to get nice stippling even when the individual segments
03647          are smaller than the stipple */
03648       gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
03649       gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
03650       gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d");
03651       /* start new path */
03652       gl2ps->streamlength += 
03653         gl2psPrintf("%f %f m\n", 
03654                     prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
03655       
03656       for(j = 1; j <= lastel; ++j){
03657         prev = prim;
03658         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
03659         if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){
03660           /* the starting point of the new segment does not match the
03661              end point of the previous line, so we end the current
03662              path and start a new one */
03663           gl2ps->streamlength += 
03664             gl2psPrintf("%f %f l\n", 
03665                         prev->verts[1].xyz[0], prev->verts[1].xyz[1]);
03666           gl2ps->streamlength += 
03667             gl2psPrintf("%f %f m\n", 
03668                         prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
03669         }
03670         else{
03671           /* the two segements are connected, so we just append to the
03672              current path */
03673           gl2ps->streamlength += 
03674             gl2psPrintf("%f %f l\n",
03675                         prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
03676         }
03677       }
03678       /* end last path */
03679       gl2ps->streamlength += 
03680         gl2psPrintf("%f %f l\n", 
03681                     prim->verts[1].xyz[0], prim->verts[1].xyz[1]);
03682       gl2ps->streamlength += gl2psPrintf("S\n");
03683       break;
03684     case GL2PS_TRIANGLE:
03685       gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
03686       gl2psSortOutTrianglePDFgroup(gro);
03687       
03688       /* No alpha and const color: Simple PDF draw orders  */
03689       if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){         
03690         gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba);        
03691         for(j = 0; j <= lastel; ++j){  
03692           prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
03693           gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
03694           gl2ps->streamlength 
03695             += gl2psPrintf("%f %f m\n"
03696                            "%f %f l\n"
03697                            "%f %f l\n"
03698                            "h f\n",
03699                            t.vertex[0].xyz[0], t.vertex[0].xyz[1],
03700                            t.vertex[1].xyz[0], t.vertex[1].xyz[1],
03701                            t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
03702         }
03703       }
03704       /* Const alpha < 1 and const color: Simple PDF draw orders 
03705          and an extra extended Graphics State for the alpha const */
03706       else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){               
03707         gl2ps->streamlength += gl2psPrintf("q\n"
03708                                            "/GS%d gs\n",
03709                                            gro->gsno);
03710         gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
03711         for(j = 0; j <= lastel; ++j){  
03712           prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
03713           gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
03714           gl2ps->streamlength 
03715             += gl2psPrintf("%f %f m\n"
03716                            "%f %f l\n"
03717                            "%f %f l\n"
03718                            "h f\n",
03719                            t.vertex[0].xyz[0], t.vertex[0].xyz[1],
03720                            t.vertex[1].xyz[0], t.vertex[1].xyz[1],
03721                            t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
03722         }
03723         gl2ps->streamlength += gl2psPrintf("Q\n");
03724       }
03725       /* Variable alpha and const color: Simple PDF draw orders 
03726          and an extra extended Graphics State + Xobject + Shader 
03727          object for the alpha mask */
03728       else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){          
03729         gl2ps->streamlength += gl2psPrintf("q\n"
03730                                            "/GS%d gs\n"
03731                                            "/TrG%d Do\n",
03732                                            gro->gsno, gro->trgroupno);
03733         gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
03734         for(j = 0; j <= lastel; ++j){  
03735           prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
03736           gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
03737           gl2ps->streamlength 
03738             += gl2psPrintf("%f %f m\n"
03739                            "%f %f l\n"
03740                            "%f %f l\n"
03741                            "h f\n",
03742                            t.vertex[0].xyz[0], t.vertex[0].xyz[1],
03743                            t.vertex[1].xyz[0], t.vertex[1].xyz[1],
03744                            t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
03745         }
03746         gl2ps->streamlength += gl2psPrintf("Q\n");
03747       }
03748       /* Variable color and no alpha: Shader Object for the colored
03749          triangle(s) */
03750       else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){              
03751         gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno);
03752       }
03753       /* Variable color and const alpha < 1: Shader Object for the 
03754          colored triangle(s) and an extra extended Graphics State 
03755          for the alpha const */
03756       else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){         
03757         gl2ps->streamlength += gl2psPrintf("q\n"
03758                                            "/GS%d gs\n"
03759                                            "/Sh%d sh\n"
03760                                            "Q\n",
03761                                            gro->gsno, gro->shno);
03762       }
03763       /* Variable alpha and color: Shader Object for the colored 
03764          triangle(s) and an extra extended Graphics State 
03765          + Xobject + Shader object for the alpha mask */
03766       else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){            
03767         gl2ps->streamlength += gl2psPrintf("q\n"
03768                                            "/GS%d gs\n"
03769                                            "/TrG%d Do\n"
03770                                            "/Sh%d sh\n"
03771                                            "Q\n",
03772                                            gro->gsno, gro->trgroupno, gro->shno);
03773       }
03774       break;
03775     case GL2PS_PIXMAP:
03776       for(j = 0; j <= lastel; ++j){
03777         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
03778         gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], 
03779                          prim->verts[0].xyz[1]);
03780       }
03781       break;
03782     case GL2PS_TEXT:
03783       for(j = 0; j <= lastel; ++j){  
03784         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
03785         gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
03786         gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0],
03787                         prim->verts[0].xyz[1]);
03788       }
03789       break;
03790     default:
03791       break;
03792     } 
03793   }
03794 }
03795 
03796 /* Graphics State names */
03797 
03798 static int gl2psPDFgroupListWriteGStateResources(void)
03799 {
03800   GL2PSpdfgroup *gro;
03801   int offs = 0;
03802   int i;
03803 
03804   offs += fprintf(gl2ps->stream,
03805                   "/ExtGState\n" 
03806                   "<<\n"
03807                   "/GSa 7 0 R\n");
03808   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){  
03809     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 
03810     if(gro->gsno >= 0)
03811       offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno);
03812   }
03813   offs += fprintf(gl2ps->stream, ">>\n"); 
03814   return offs;
03815 }
03816 
03817 /* Main Shader names */
03818 
03819 static int gl2psPDFgroupListWriteShaderResources(void)
03820 {
03821   GL2PSpdfgroup *gro;
03822   int offs = 0;
03823   int i;
03824 
03825   offs += fprintf(gl2ps->stream,
03826                   "/Shading\n"
03827                   "<<\n");
03828   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){  
03829     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 
03830     if(gro->shno >= 0)
03831       offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno);
03832     if(gro->maskshno >= 0)
03833       offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno);
03834   }
03835   offs += fprintf(gl2ps->stream,">>\n");  
03836   return offs;
03837 }
03838 
03839 /* Images & Mask Shader XObject names */
03840 
03841 static int gl2psPDFgroupListWriteXObjectResources(void)
03842 {
03843   int i;
03844   GL2PSprimitive *p = NULL;
03845   GL2PSpdfgroup *gro;
03846   int offs = 0;
03847 
03848   offs += fprintf(gl2ps->stream,
03849                   "/XObject\n"
03850                   "<<\n");
03851 
03852   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){  
03853     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 
03854     if(!gl2psListNbr(gro->ptrlist))
03855       continue;
03856     p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
03857     switch(p->type){
03858     case GL2PS_PIXMAP:
03859       gro->imobjno = gl2ps->objects_stack++;
03860       if(GL_RGBA == p->data.image->format)  /* reserve one object for image mask */
03861         gl2ps->objects_stack++;
03862       offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno);
03863     case GL2PS_TRIANGLE:
03864       if(gro->trgroupno >=0)
03865         offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno);
03866       break;
03867     default:
03868       break;
03869     }
03870   }
03871   offs += fprintf(gl2ps->stream,">>\n");
03872   return offs;
03873 }
03874 
03875 /* Font names */
03876 
03877 static int gl2psPDFgroupListWriteFontResources(void)
03878 {
03879   int i;
03880   GL2PSpdfgroup *gro;
03881   int offs = 0;
03882 
03883   offs += fprintf(gl2ps->stream, "/Font\n<<\n");
03884 
03885   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){  
03886     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 
03887     if(gro->fontno < 0)
03888       continue;
03889     gro->fontobjno = gl2ps->objects_stack++;
03890     offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno);
03891   }
03892   offs += fprintf(gl2ps->stream, ">>\n");
03893 
03894   return offs;
03895 }
03896 
03897 static void gl2psPDFgroupListDelete(void)
03898 {
03899   int i;
03900   GL2PSpdfgroup *gro = NULL;
03901   
03902   if(!gl2ps->pdfgrouplist)
03903     return;
03904 
03905   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 
03906     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i);
03907     gl2psListDelete(gro->ptrlist);
03908   }
03909 
03910   gl2psListDelete(gl2ps->pdfgrouplist);
03911   gl2ps->pdfgrouplist = NULL;
03912 }
03913 
03914 /* Print 1st PDF object - file info */
03915 
03916 static int gl2psPrintPDFInfo(void)
03917 {
03918   int offs;
03919   time_t now;
03920   struct tm *newtime;
03921   
03922   time(&now);
03923   newtime = gmtime(&now);
03924   
03925   offs = fprintf(gl2ps->stream,
03926                  "1 0 obj\n"
03927                  "<<\n"
03928                  "/Title (%s)\n"
03929                  "/Creator (GL2PS %d.%d.%d%s, %s)\n"
03930                  "/Producer (%s)\n",
03931                  gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
03932                  GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
03933                  gl2ps->producer);
03934   
03935   if(!newtime){
03936     offs += fprintf(gl2ps->stream, 
03937                     ">>\n"
03938                     "endobj\n");
03939     return offs;
03940   }
03941   
03942   offs += fprintf(gl2ps->stream, 
03943                   "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n"
03944                   ">>\n"
03945                   "endobj\n",
03946                   newtime->tm_year+1900, 
03947                   newtime->tm_mon+1, 
03948                   newtime->tm_mday,
03949                   newtime->tm_hour,
03950                   newtime->tm_min,
03951                   newtime->tm_sec);
03952   return offs;
03953 }
03954 
03955 /* Create catalog and page structure - 2nd and 3th PDF object */
03956 
03957 static int gl2psPrintPDFCatalog(void)
03958 {
03959   return fprintf(gl2ps->stream, 
03960                  "2 0 obj\n"
03961                  "<<\n"
03962                  "/Type /Catalog\n"
03963                  "/Pages 3 0 R\n"
03964                  ">>\n"
03965                  "endobj\n");
03966 }
03967 
03968 static int gl2psPrintPDFPages(void)
03969 {
03970   return fprintf(gl2ps->stream, 
03971                  "3 0 obj\n"
03972                  "<<\n" 
03973                  "/Type /Pages\n"
03974                  "/Kids [6 0 R]\n"
03975                  "/Count 1\n"
03976                  ">>\n"
03977                  "endobj\n");
03978 }
03979 
03980 /* Open stream for data - graphical objects, fonts etc. PDF object 4 */
03981 
03982 static int gl2psOpenPDFDataStream(void)
03983 {
03984   int offs = 0;
03985   
03986   offs += fprintf(gl2ps->stream, 
03987                   "4 0 obj\n"
03988                   "<<\n" 
03989                   "/Length 5 0 R\n" );
03990   offs += gl2psPrintPDFCompressorType();
03991   offs += fprintf(gl2ps->stream, 
03992                   ">>\n"
03993                   "stream\n");
03994   return offs;
03995 }
03996 
03997 /* Stream setup - Graphics state, fill background if allowed */
03998 
03999 static int gl2psOpenPDFDataStreamWritePreface(void)
04000 {
04001   int offs;
04002 
04003   offs = gl2psPrintf("/GSa gs\n");
04004   
04005   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
04006     offs += gl2psPrintPDFFillColor(gl2ps->bgcolor);
04007     offs += gl2psPrintf("%d %d %d %d re\n",
04008                         (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
04009                         (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
04010     offs += gl2psPrintf("f\n");  
04011   }
04012   return offs;
04013 }
04014 
04015 /* Use the functions above to create the first part of the PDF*/
04016 
04017 static void gl2psPrintPDFHeader(void)
04018 {
04019   int offs = 0;
04020   gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
04021   gl2psPDFstacksInit();
04022 
04023   gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); 
04024 
04025 #if defined(GL2PS_HAVE_ZLIB)
04026   if(gl2ps->options & GL2PS_COMPRESS){
04027     gl2psSetupCompress();
04028   }
04029 #endif    
04030   gl2ps->xreflist[0] = 0;
04031   offs += fprintf(gl2ps->stream, "%%PDF-1.4\n");
04032   gl2ps->xreflist[1] = offs;
04033   
04034   offs += gl2psPrintPDFInfo();
04035   gl2ps->xreflist[2] = offs;
04036   
04037   offs += gl2psPrintPDFCatalog();
04038   gl2ps->xreflist[3] = offs;
04039   
04040   offs += gl2psPrintPDFPages();
04041   gl2ps->xreflist[4] = offs;
04042   
04043   offs += gl2psOpenPDFDataStream();
04044   gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */
04045   gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface();
04046 }
04047 
04048 /* The central primitive drawing */
04049 
04050 static void gl2psPrintPDFPrimitive(void *data)
04051 {
04052   GL2PSprimitive *prim = *(GL2PSprimitive**)data;
04053 
04054   if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) 
04055     return;
04056 
04057   prim = gl2psCopyPrimitive(prim); /* deep copy */
04058   gl2psListAdd(gl2ps->pdfprimlist, &prim);
04059 }
04060 
04061 /* close stream and ... */
04062 
04063 static int gl2psClosePDFDataStream(void)
04064 {
04065   int offs = 0;
04066  
04067 #if defined(GL2PS_HAVE_ZLIB)
04068   if(gl2ps->options & GL2PS_COMPRESS){
04069     if(Z_OK != gl2psDeflate())
04070       gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
04071     else
04072       fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream);
04073     gl2ps->streamlength += gl2ps->compress->destLen;
04074     
04075     offs += gl2ps->streamlength;
04076     gl2psFreeCompress();
04077   }
04078 #endif 
04079   
04080   offs += fprintf(gl2ps->stream, 
04081                   "endstream\n"
04082                   "endobj\n");
04083   return offs;
04084 }
04085 
04086 /* ... write the now known length object */
04087 
04088 static int gl2psPrintPDFDataStreamLength(int val)
04089 {
04090   return fprintf(gl2ps->stream,
04091                  "5 0 obj\n"
04092                  "%d\n"
04093                  "endobj\n", val);
04094 }
04095 
04096 /* Put the info created before in PDF objects */
04097 
04098 static int gl2psPrintPDFOpenPage(void)
04099 {
04100   int offs;
04101   
04102   /* Write fixed part */
04103   
04104   offs = fprintf(gl2ps->stream, 
04105                  "6 0 obj\n"
04106                  "<<\n" 
04107                  "/Type /Page\n"
04108                  "/Parent 3 0 R\n"
04109                  "/MediaBox [%d %d %d %d]\n",
04110                  (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
04111                  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
04112   
04113   if(gl2ps->options & GL2PS_LANDSCAPE)
04114     offs += fprintf(gl2ps->stream, "/Rotate -90\n");
04115   
04116   offs += fprintf(gl2ps->stream,
04117                   "/Contents 4 0 R\n"
04118                   "/Resources\n" 
04119                   "<<\n" 
04120                   "/ProcSet [/PDF /Text /ImageB /ImageC]  %%/ImageI\n");
04121   
04122   return offs;
04123 
04124   /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */
04125 }
04126 
04127 static int gl2psPDFgroupListWriteVariableResources(void)
04128 {
04129   int offs = 0;
04130   
04131   /* a) Graphics States for shader alpha masks*/
04132   offs += gl2psPDFgroupListWriteGStateResources();  
04133   
04134   /* b) Shader and shader masks */ 
04135   offs += gl2psPDFgroupListWriteShaderResources();  
04136  
04137   /* c) XObjects (Images & Shader Masks) */
04138   offs += gl2psPDFgroupListWriteXObjectResources();
04139   
04140   /* d) Fonts */
04141   offs += gl2psPDFgroupListWriteFontResources();
04142   
04143   /* End resources and page */
04144   offs += fprintf(gl2ps->stream,
04145                   ">>\n"
04146                   ">>\n"
04147                   "endobj\n");
04148   return offs;
04149 }
04150 
04151 /* Standard Graphics State */
04152 
04153 static int gl2psPrintPDFGSObject(void)
04154 {
04155   return fprintf(gl2ps->stream,
04156                  "7 0 obj\n"
04157                  "<<\n"
04158                  "/Type /ExtGState\n"
04159                  "/SA false\n"
04160                  "/SM 0.02\n"
04161                  "/OP false\n"
04162                  "/op false\n"
04163                  "/OPM 0\n"
04164                  "/BG2 /Default\n"
04165                  "/UCR2 /Default\n"
04166                  "/TR2 /Default\n"
04167                  ">>\n"
04168                  "endobj\n");
04169 }
04170 
04171 /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */
04172 
04173 static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, 
04174                                               size_t (*action)(unsigned long data, 
04175                                                                size_t size), 
04176                                               GLfloat dx, GLfloat dy, 
04177                                               GLfloat xmin, GLfloat ymin)
04178 {
04179   int offs = 0;
04180   unsigned long imap;
04181   GLfloat diff;
04182   double dmax = ~1UL;
04183   char edgeflag = 0;
04184 
04185   /* FIXME: temp bux fix for 64 bit archs: */
04186   if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
04187 
04188   offs += (*action)(edgeflag, 1);
04189 
04190   /* The Shader stream in PDF requires to be in a 'big-endian'
04191      order */
04192     
04193   if(GL2PS_ZERO(dx * dy)){
04194     offs += (*action)(0, 4);
04195     offs += (*action)(0, 4);
04196   }
04197   else{
04198     diff = (vertex->xyz[0] - xmin) / dx;
04199     if(diff > 1)
04200       diff = 1.0F;
04201     else if(diff < 0)
04202       diff = 0.0F;
04203     imap = (unsigned long)(diff * dmax);
04204     offs += (*action)(imap, 4);
04205       
04206     diff = (vertex->xyz[1] - ymin) / dy;
04207     if(diff > 1)
04208       diff = 1.0F;
04209     else if(diff < 0)
04210       diff = 0.0F;
04211     imap = (unsigned long)(diff * dmax);
04212     offs += (*action)(imap, 4);
04213   }
04214   
04215   return offs;
04216 }
04217 
04218 /* Put vertex' rgb value (8bit for every component) in shader stream */
04219 
04220 static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex,
04221                                             size_t (*action)(unsigned long data, 
04222                                                              size_t size))
04223 {
04224   int offs = 0;
04225   unsigned long imap;
04226   double dmax = ~1UL;
04227 
04228   /* FIXME: temp bux fix for 64 bit archs: */
04229   if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
04230 
04231   imap = (unsigned long)((vertex->rgba[0]) * dmax);
04232   offs += (*action)(imap, 1);
04233     
04234   imap = (unsigned long)((vertex->rgba[1]) * dmax);
04235   offs += (*action)(imap, 1);
04236     
04237   imap = (unsigned long)((vertex->rgba[2]) * dmax);
04238   offs += (*action)(imap, 1);
04239   
04240   return offs;
04241 }
04242 
04243 /* Put vertex' alpha (8/16bit) in shader stream */
04244 
04245 static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, 
04246                                               size_t (*action)(unsigned long data, 
04247                                                                size_t size),
04248                                               int sigbyte)
04249 {
04250   int offs = 0;
04251   unsigned long imap;
04252   double dmax = ~1UL;
04253 
04254   /* FIXME: temp bux fix for 64 bit archs: */
04255   if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
04256 
04257   if(sigbyte != 8 && sigbyte != 16)
04258     sigbyte = 8;
04259         
04260   sigbyte /= 8;
04261   
04262   imap = (unsigned long)((vertex->rgba[3]) * dmax);
04263   
04264   offs += (*action)(imap, sigbyte);
04265   
04266   return offs;
04267 }
04268 
04269 /* Put a triangles raw data in shader stream */
04270 
04271 static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle, 
04272                                          GLfloat dx, GLfloat dy, 
04273                                          GLfloat xmin, GLfloat ymin,
04274                                          size_t (*action)(unsigned long data, 
04275                                                           size_t size),
04276                                          int gray)
04277 {
04278   int i, offs = 0;
04279   GL2PSvertex v;
04280   
04281   if(gray && gray != 8 && gray != 16)
04282     gray = 8;
04283   
04284   for(i = 0; i < 3; ++i){
04285     offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action,
04286                                                dx, dy, xmin, ymin);
04287     if(gray){ 
04288       v = triangle->vertex[i];
04289       offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); 
04290     }
04291     else{
04292       offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action);
04293     }
04294   }
04295   
04296   return offs;
04297 }
04298 
04299 static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, 
04300                              GLfloat *ymin, GLfloat *ymax, 
04301                              GL2PStriangle *triangles, int cnt)
04302 {
04303   int i, j;
04304 
04305   *xmin = triangles[0].vertex[0].xyz[0];
04306   *xmax = triangles[0].vertex[0].xyz[0];
04307   *ymin = triangles[0].vertex[0].xyz[1];
04308   *ymax = triangles[0].vertex[0].xyz[1];
04309   
04310   for(i = 0; i < cnt; ++i){
04311     for(j = 0; j < 3; ++j){
04312       if(*xmin > triangles[i].vertex[j].xyz[0])
04313         *xmin = triangles[i].vertex[j].xyz[0];
04314       if(*xmax < triangles[i].vertex[j].xyz[0])
04315         *xmax = triangles[i].vertex[j].xyz[0];
04316       if(*ymin > triangles[i].vertex[j].xyz[1])
04317         *ymin = triangles[i].vertex[j].xyz[1];
04318       if(*ymax < triangles[i].vertex[j].xyz[1])
04319         *ymax = triangles[i].vertex[j].xyz[1];
04320     }
04321   }
04322 }
04323 
04324 /* Writes shaded triangle 
04325    gray == 0 means write RGB triangles
04326    gray == 8             8bit-grayscale (for alpha masks)
04327    gray == 16            16bit-grayscale (for alpha masks) */
04328 
04329 static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, 
04330                                int size, int gray)
04331 {
04332   int i, offs = 0, vertexbytes, done = 0;
04333   GLfloat xmin, xmax, ymin, ymax;
04334         
04335   switch(gray){
04336   case 0:
04337     vertexbytes = 1+4+4+1+1+1;
04338     break;
04339   case 8:
04340     vertexbytes = 1+4+4+1;
04341     break;
04342   case 16:
04343     vertexbytes = 1+4+4+2;
04344     break;
04345   default:
04346     gray = 8;
04347     vertexbytes = 1+4+4+1;
04348     break;
04349   }
04350   
04351   gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size);
04352   
04353   offs += fprintf(gl2ps->stream,
04354                   "%d 0 obj\n"
04355                   "<< "
04356                   "/ShadingType 4 "
04357                   "/ColorSpace %s "
04358                   "/BitsPerCoordinate 32 "
04359                   "/BitsPerComponent %d "
04360                   "/BitsPerFlag 8 "
04361                   "/Decode [%f %f %f %f 0 1 %s] ",
04362                   obj,
04363                   (gray) ? "/DeviceGray" : "/DeviceRGB", 
04364                   (gray) ? gray : 8,
04365                   xmin, xmax, ymin, ymax,
04366                   (gray) ? "" : "0 1 0 1");
04367   
04368 #if defined(GL2PS_HAVE_ZLIB)
04369   if(gl2ps->options & GL2PS_COMPRESS){
04370     gl2psAllocCompress(vertexbytes * size * 3);
04371 
04372     for(i = 0; i < size; ++i)
04373       gl2psPrintPDFShaderStreamData(&triangles[i],
04374                                     xmax-xmin, ymax-ymin, xmin, ymin, 
04375                                     gl2psWriteBigEndianCompress, gray);
04376 
04377     if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
04378       offs += gl2psPrintPDFCompressorType();
04379       offs += fprintf(gl2ps->stream,
04380                       "/Length %d "
04381                       ">>\n"
04382                       "stream\n",
04383                       (int)gl2ps->compress->destLen);
04384       offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, 
04385                                                 gl2ps->compress->destLen, 
04386                                                 1, gl2ps->stream);
04387       done = 1;
04388     }
04389     gl2psFreeCompress();
04390   }
04391 #endif
04392 
04393   if(!done){
04394     /* no compression, or too long after compression, or compress error
04395        -> write non-compressed entry */
04396     offs += fprintf(gl2ps->stream,
04397                     "/Length %d "
04398                     ">>\n"
04399                     "stream\n",
04400                     vertexbytes * 3 * size);
04401     for(i = 0; i < size; ++i)
04402       offs += gl2psPrintPDFShaderStreamData(&triangles[i],
04403                                             xmax-xmin, ymax-ymin, xmin, ymin,
04404                                             gl2psWriteBigEndian, gray);
04405   }
04406   
04407   offs += fprintf(gl2ps->stream,
04408                   "\nendstream\n"
04409                   "endobj\n");
04410   
04411   return offs;
04412 }
04413 
04414 /* Writes a XObject for a shaded triangle mask */
04415 
04416 static int gl2psPrintPDFShaderMask(int obj, int childobj)
04417 {
04418   int offs = 0, len;
04419   
04420   offs += fprintf(gl2ps->stream,
04421                   "%d 0 obj\n"
04422                   "<<\n"
04423                   "/Type /XObject\n"
04424                   "/Subtype /Form\n"
04425                   "/BBox [ %d %d %d %d ]\n"
04426                   "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n"
04427                   ">>\n",
04428                   obj,
04429                   (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
04430                   (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
04431   
04432   len = (childobj>0) 
04433     ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1
04434     : strlen("/TrSh0 sh\n"); 
04435   
04436   offs += fprintf(gl2ps->stream,
04437                   "/Length %d\n"
04438                   ">>\n"
04439                   "stream\n",
04440                   len);
04441   offs += fprintf(gl2ps->stream,
04442                   "/TrSh%d sh\n",
04443                   childobj);
04444   offs += fprintf(gl2ps->stream,
04445                   "endstream\n"
04446                   "endobj\n");
04447   
04448   return offs;
04449 }
04450 
04451 /* Writes a Extended graphics state for a shaded triangle mask if
04452    simplealpha ist true the childobj argument is ignored and a /ca
04453    statement will be written instead */
04454 
04455 static int gl2psPrintPDFShaderExtGS(int obj, int childobj)
04456 {
04457   int offs = 0;
04458   
04459   offs += fprintf(gl2ps->stream,
04460                   "%d 0 obj\n"
04461                   "<<\n",
04462                   obj);
04463   
04464   offs += fprintf(gl2ps->stream,
04465                   "/SMask << /S /Alpha /G %d 0 R >> ",
04466                   childobj);
04467   
04468   offs += fprintf(gl2ps->stream,
04469                   ">>\n"
04470                   "endobj\n");
04471   return offs;
04472 }
04473 
04474 /* a simple graphics state */
04475 
04476 static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha)
04477 {
04478   int offs = 0;
04479   
04480   offs += fprintf(gl2ps->stream,
04481                   "%d 0 obj\n"
04482                   "<<\n"
04483                   "/ca %g"
04484                   ">>\n"
04485                   "endobj\n",
04486                   obj, alpha);
04487   return offs;
04488 }
04489 
04490 /* Similar groups of functions for pixmaps and text */
04491 
04492 static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im,
04493                                          size_t (*action)(unsigned long data, 
04494                                                           size_t size), 
04495                                          int gray)
04496 {
04497   int x, y;
04498   GLfloat r, g, b, a;
04499 
04500   if(im->format != GL_RGBA && gray)
04501     return 0;
04502 
04503   if(gray && gray !=8 && gray != 16)
04504     gray = 8;
04505 
04506   gray /= 8;
04507   
04508   for(y = 0; y < im->height; ++y){
04509     for(x = 0; x < im->width; ++x){
04510       a = gl2psGetRGB(im, x, y, &r, &g, &b);
04511       if(im->format == GL_RGBA && gray){
04512         (*action)((unsigned long)(a*255) << 24, gray);
04513       }
04514       else{
04515         (*action)((unsigned long)(r*255) << 24, 1);
04516         (*action)((unsigned long)(g*255) << 24, 1);
04517         (*action)((unsigned long)(b*255) << 24, 1);
04518       }
04519     }
04520   }
04521 
04522   switch(gray){
04523   case 0: return 3 * im->width * im->height;
04524   case 1: return im->width * im->height;
04525   case 2: return 2 * im->width * im->height;
04526   default: return 3 * im->width * im->height;
04527   }
04528 }
04529 
04530 static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray)
04531 {
04532   int offs = 0, done = 0, sigbytes = 3;
04533 
04534   if(gray && gray !=8 && gray != 16)
04535     gray = 8;
04536   
04537   if(gray)
04538     sigbytes = gray / 8; 
04539   
04540   offs += fprintf(gl2ps->stream,
04541                   "%d 0 obj\n"
04542                   "<<\n"
04543                   "/Type /XObject\n"
04544                   "/Subtype /Image\n"
04545                   "/Width %d\n"
04546                   "/Height %d\n"
04547                   "/ColorSpace %s \n"
04548                   "/BitsPerComponent 8\n",
04549                   obj,
04550                   (int)im->width, (int)im->height,
04551                   (gray) ? "/DeviceGray" : "/DeviceRGB" );
04552   if(GL_RGBA == im->format && gray == 0){
04553     offs += fprintf(gl2ps->stream,
04554                     "/SMask %d 0 R\n",
04555                     childobj);
04556   }
04557   
04558 #if defined(GL2PS_HAVE_ZLIB)
04559   if(gl2ps->options & GL2PS_COMPRESS){
04560     gl2psAllocCompress((int)(im->width * im->height * sigbytes));
04561     
04562     gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray);
04563     
04564     if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
04565       offs += gl2psPrintPDFCompressorType();
04566       offs += fprintf(gl2ps->stream,
04567                       "/Length %d "
04568                       ">>\n"
04569                       "stream\n",
04570                       (int)gl2ps->compress->destLen);
04571       offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen,
04572                                                 1, gl2ps->stream);
04573       done = 1;
04574     }
04575     gl2psFreeCompress();
04576   }
04577 #endif
04578   
04579   if(!done){
04580     /* no compression, or too long after compression, or compress error
04581        -> write non-compressed entry */
04582     offs += fprintf(gl2ps->stream,
04583                     "/Length %d "
04584                     ">>\n"
04585                     "stream\n",
04586                     (int)(im->width * im->height * sigbytes));
04587     offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray);
04588   }
04589   
04590   offs += fprintf(gl2ps->stream,
04591                   "\nendstream\n"
04592                   "endobj\n");
04593   
04594   return offs;
04595 }
04596 
04597 static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber)
04598 {
04599   int offs = 0;
04600   
04601   offs += fprintf(gl2ps->stream,
04602                   "%d 0 obj\n"
04603                   "<<\n"
04604                   "/Type /Font\n"
04605                   "/Subtype /Type1\n"
04606                   "/Name /F%d\n"
04607                   "/BaseFont /%s\n"
04608                   "/Encoding /MacRomanEncoding\n"
04609                   ">>\n"
04610                   "endobj\n",
04611                   obj, fontnumber, s->fontname);
04612   return offs;
04613 }
04614 
04615 /* Write the physical objects */
04616 
04617 static int gl2psPDFgroupListWriteObjects(int entryoffs)
04618 {
04619   int i,j;
04620   GL2PSprimitive *p = NULL;
04621   GL2PSpdfgroup *gro;
04622   int offs = entryoffs;
04623   GL2PStriangle *triangles;
04624   int size = 0;
04625 
04626   if(!gl2ps->pdfgrouplist)
04627     return offs;
04628   
04629   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){  
04630     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 
04631     if(!gl2psListNbr(gro->ptrlist))
04632       continue;
04633     p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
04634     switch(p->type){
04635     case GL2PS_POINT:
04636       break;
04637     case GL2PS_LINE:
04638       break;
04639     case GL2PS_TRIANGLE:
04640       size = gl2psListNbr(gro->ptrlist);
04641       triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size);
04642       for(j = 0; j < size; ++j){  
04643         p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
04644         gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE);
04645       }
04646       if(triangles[0].prop & T_VAR_COLOR){
04647         gl2ps->xreflist[gro->shobjno] = offs;
04648         offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0);
04649       }
04650       if(triangles[0].prop & T_ALPHA_LESS_1){
04651         gl2ps->xreflist[gro->gsobjno] = offs;
04652         offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]);
04653       }
04654       if(triangles[0].prop & T_VAR_ALPHA){
04655         gl2ps->xreflist[gro->gsobjno] = offs;
04656         offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno);
04657         gl2ps->xreflist[gro->trgroupobjno] = offs;
04658         offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno);
04659         gl2ps->xreflist[gro->maskshobjno] = offs;
04660         offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8);
04661       }
04662       gl2psFree(triangles);
04663       break;
04664     case GL2PS_PIXMAP:
04665       gl2ps->xreflist[gro->imobjno] = offs;
04666       offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0);
04667       if(p->data.image->format == GL_RGBA){
04668         gl2ps->xreflist[gro->imobjno+1] = offs;
04669         offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8);
04670       }
04671       break;
04672     case GL2PS_TEXT:
04673       gl2ps->xreflist[gro->fontobjno] = offs;
04674       offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno);
04675       break;
04676     case GL2PS_SPECIAL :
04677       /* alignment contains the format for which the special output text
04678          is intended */
04679       if(p->data.text->alignment == GL2PS_PDF)
04680         offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str);
04681       break;
04682     default:
04683       break;
04684     } 
04685   }
04686   return offs;
04687 }
04688 
04689 /* All variable data has been written at this point and all required
04690    functioninality has been gathered, so we can write now file footer
04691    with cross reference table and trailer */
04692 
04693 static void gl2psPrintPDFFooter(void)
04694 {
04695   int i, offs;  
04696 
04697   gl2psPDFgroupListInit();
04698   gl2psPDFgroupListWriteMainStream();
04699  
04700   offs = gl2ps->xreflist[5] + gl2ps->streamlength; 
04701   offs += gl2psClosePDFDataStream();
04702   gl2ps->xreflist[5] = offs;
04703   
04704   offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength);
04705   gl2ps->xreflist[6] = offs;
04706   gl2ps->streamlength = 0;
04707   
04708   offs += gl2psPrintPDFOpenPage();
04709   offs += gl2psPDFgroupListWriteVariableResources();
04710   gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist,
04711                                        sizeof(int) * (gl2ps->objects_stack + 1));
04712   gl2ps->xreflist[7] = offs;
04713   
04714   offs += gl2psPrintPDFGSObject();
04715   gl2ps->xreflist[8] = offs;
04716   
04717   gl2ps->xreflist[gl2ps->objects_stack] = 
04718     gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]);
04719 
04720   /* Start cross reference table. The file has to been opened in
04721      binary mode to preserve the 20 digit string length! */
04722   fprintf(gl2ps->stream,
04723           "xref\n"
04724           "0 %d\n"
04725           "%010d 65535 f \n", gl2ps->objects_stack, 0);
04726   
04727   for(i = 1; i < gl2ps->objects_stack; ++i)
04728     fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]);
04729   
04730   fprintf(gl2ps->stream,
04731           "trailer\n"
04732           "<<\n" 
04733           "/Size %d\n"
04734           "/Info 1 0 R\n"
04735           "/Root 2 0 R\n"
04736           ">>\n"
04737           "startxref\n%d\n"
04738           "%%%%EOF\n",
04739           gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]);
04740   
04741   /* Free auxiliary lists and arrays */    
04742   gl2psFree(gl2ps->xreflist);
04743   gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive);
04744   gl2psListDelete(gl2ps->pdfprimlist);
04745   gl2psPDFgroupListDelete();
04746   
04747 #if defined(GL2PS_HAVE_ZLIB)
04748   if(gl2ps->options & GL2PS_COMPRESS){
04749     gl2psFreeCompress();
04750     gl2psFree(gl2ps->compress);
04751     gl2ps->compress = NULL;
04752   }
04753 #endif
04754 }
04755 
04756 /* PDF begin viewport */
04757 
04758 static void gl2psPrintPDFBeginViewport(GLint viewport[4])
04759 {
04760   int offs = 0;
04761   GLint index;
04762   GLfloat rgba[4];
04763   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
04764   
04765   glRenderMode(GL_FEEDBACK);
04766   
04767   if(gl2ps->header){
04768     gl2psPrintPDFHeader();
04769     gl2ps->header = GL_FALSE;
04770   }
04771 
04772   offs += gl2psPrintf("q\n");
04773   
04774   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
04775     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
04776       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
04777     }
04778     else{
04779       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
04780       rgba[0] = gl2ps->colormap[index][0];
04781       rgba[1] = gl2ps->colormap[index][1];
04782       rgba[2] = gl2ps->colormap[index][2];
04783       rgba[3] = 1.0F;
04784     }
04785     offs += gl2psPrintPDFFillColor(rgba);
04786     offs += gl2psPrintf("%d %d %d %d re\n"
04787                         "W\n"
04788                         "f\n",
04789                         x, y, w, h);
04790   }
04791   else{
04792     offs += gl2psPrintf("%d %d %d %d re\n"
04793                         "W\n"   
04794                         "n\n",
04795                         x, y, w, h);            
04796   }
04797   
04798   gl2ps->streamlength += offs;
04799 }
04800 
04801 static GLint gl2psPrintPDFEndViewport(void)
04802 {
04803   GLint res;
04804   
04805   res = gl2psPrintPrimitives();
04806   gl2ps->streamlength += gl2psPrintf("Q\n");
04807   return res;
04808 }
04809 
04810 static void gl2psPrintPDFFinalPrimitive(void)
04811 {
04812 }
04813 
04814 /* definition of the PDF backend */
04815 
04816 static GL2PSbackend gl2psPDF = {
04817   gl2psPrintPDFHeader,
04818   gl2psPrintPDFFooter,
04819   gl2psPrintPDFBeginViewport,
04820   gl2psPrintPDFEndViewport,
04821   gl2psPrintPDFPrimitive,
04822   gl2psPrintPDFFinalPrimitive,
04823   "pdf",
04824   "Portable Document Format"
04825 };
04826 
04827 /********************************************************************* 
04828  *
04829  * SVG routines
04830  *
04831  *********************************************************************/
04832 
04833 static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, 
04834                                        GL2PSxyz *xyz, GL2PSrgba *rgba)
04835 {
04836   int i, j;
04837 
04838   for(i = 0; i < n; i++){
04839     xyz[i][0] = verts[i].xyz[0];
04840     xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1];
04841     xyz[i][2] = 0.0F;
04842     for(j = 0; j < 4; j++)
04843       rgba[i][j] = verts[i].rgba[j];
04844   }
04845 }
04846 
04847 static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32])
04848 {
04849   int r = (int)(255. * rgba[0]);
04850   int g = (int)(255. * rgba[1]);
04851   int b = (int)(255. * rgba[2]);
04852   int rc = (r < 0) ? 0 : (r > 255) ? 255 : r;
04853   int gc = (g < 0) ? 0 : (g > 255) ? 255 : g;
04854   int bc = (b < 0) ? 0 : (b > 255) ? 255 : b;
04855   sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc);
04856 }
04857 
04858 static void gl2psPrintSVGHeader(void)
04859 {
04860   int x, y, width, height;
04861   char col[32];
04862   time_t now;
04863   
04864   time(&now);
04865   
04866   if (gl2ps->options & GL2PS_LANDSCAPE){
04867     x = (int)gl2ps->viewport[1];
04868     y = (int)gl2ps->viewport[0];
04869     width = (int)gl2ps->viewport[3];
04870     height = (int)gl2ps->viewport[2];
04871   }
04872   else{
04873     x = (int)gl2ps->viewport[0];
04874     y = (int)gl2ps->viewport[1];
04875     width = (int)gl2ps->viewport[2];
04876     height = (int)gl2ps->viewport[3];
04877   }
04878   
04879   /* Compressed SVG files (.svgz) are simply gzipped SVG files */
04880   gl2psPrintGzipHeader();
04881   
04882   gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
04883   gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
04884   gl2psPrintf("     xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
04885               "     width=\"%dpx\" height=\"%dpx\" viewBox=\"%d %d %d %d\">\n",
04886               width, height, x, y, width, height);
04887   gl2psPrintf("<title>%s</title>\n", gl2ps->title);
04888   gl2psPrintf("<desc>\n");
04889   gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n"
04890               "For: %s\n"
04891               "CreationDate: %s",
04892               GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION,
04893               GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now));
04894   gl2psPrintf("</desc>\n");
04895   gl2psPrintf("<defs>\n");
04896   gl2psPrintf("</defs>\n");
04897 
04898   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
04899     gl2psSVGGetColorString(gl2ps->bgcolor, col);
04900     gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
04901                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 
04902                 (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], 
04903                 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], 
04904                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
04905   }
04906 
04907   /* group all the primitives and disable antialiasing */
04908   gl2psPrintf("<g shape-rendering=\"crispEdges\">\n");
04909 }
04910 
04911 static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3])
04912 {
04913   int i;
04914   GL2PSxyz xyz2[3];
04915   GL2PSrgba rgba2[3];
04916   char col[32];
04917 
04918   /* Apparently there is no easy way to do Gouraud shading in SVG
04919      without explicitly pre-defining gradients, so for now we just do
04920      recursive subdivision */
04921 
04922   if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){
04923     gl2psSVGGetColorString(rgba[0], col);
04924     gl2psPrintf("<polygon fill=\"%s\" ", col);
04925     if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
04926     gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1], 
04927                 xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]);
04928   }
04929   else{
04930     /* subdivide into 4 subtriangles */
04931     for(i = 0; i < 3; i++){
04932       xyz2[0][i] = xyz[0][i]; 
04933       xyz2[1][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
04934       xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
04935     }
04936     for(i = 0; i < 4; i++){
04937       rgba2[0][i] = rgba[0][i]; 
04938       rgba2[1][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
04939       rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
04940     }
04941     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
04942     for(i = 0; i < 3; i++){
04943       xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
04944       xyz2[1][i] = xyz[1][i]; 
04945       xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]);
04946     }
04947     for(i = 0; i < 4; i++){
04948       rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
04949       rgba2[1][i] = rgba[1][i]; 
04950       rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]);
04951     }
04952     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
04953     for(i = 0; i < 3; i++){
04954       xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
04955       xyz2[1][i] = xyz[2][i]; 
04956       xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]);
04957     }
04958     for(i = 0; i < 4; i++){
04959       rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
04960       rgba2[1][i] = rgba[2][i]; 
04961       rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]);
04962     }
04963     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
04964     for(i = 0; i < 3; i++){
04965       xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
04966       xyz2[1][i] = 0.5 * (xyz[1][i] + xyz[2][i]); 
04967       xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
04968     }
04969     for(i = 0; i < 4; i++){
04970       rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
04971       rgba2[1][i] = 0.5 * (rgba[1][i] + rgba[2][i]); 
04972       rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
04973     }
04974     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
04975   }
04976 }
04977 
04978 static void gl2psPrintSVGDash(GLushort pattern, GLint factor)
04979 {
04980   int i, n, array[10];
04981 
04982   if(!pattern || !factor) return; /* solid line */
04983 
04984   gl2psParseStipplePattern(pattern, factor, &n, array);
04985   gl2psPrintf("stroke-dasharray=\"");
04986   for(i = 0; i < n; i++){
04987     if(i) gl2psPrintf(",");
04988     gl2psPrintf("%d", array[i]);
04989   }
04990   gl2psPrintf("\" ");
04991 }
04992 
04993 static void gl2psEndSVGLine(void)
04994 {
04995   int i;
04996   if(gl2ps->lastvertex.rgba[0] >= 0.){
04997     gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], 
04998                 gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]);
04999     for(i = 0; i < 3; i++)
05000       gl2ps->lastvertex.xyz[i] = -1.;
05001     for(i = 0; i < 4; i++)
05002       gl2ps->lastvertex.rgba[i] = -1.;
05003   }
05004 }
05005 
05006 static void gl2psPrintSVGPixmap(GLfloat /*x*/, GLfloat /*y*/, GL2PSimage * /*pixmap*/)
05007 {
05008 #if defined(GL2PS_HAVE_LIBPNG)
05009   GL2PSlist *png;
05010   unsigned char c;
05011   int i;
05012 
05013   /* The only image types supported by the SVG standard are JPEG, PNG
05014      and SVG. Here we choose PNG, and since we want to embed the image
05015      directly in the SVG stream (and not link to an external image
05016      file), we need to encode the pixmap into PNG in memory, then
05017      encode it into base64. */
05018 
05019   png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, 
05020                         sizeof(unsigned char));
05021   gl2psConvertPixmapToPNG(pixmap, png);
05022   gl2psListEncodeBase64(png);
05023   gl2psPrintf("<image x=\"%g\" y=\"%g\" width=\"%d\" height=\"%d\"\n",
05024               x, y - pixmap->height, pixmap->width, pixmap->height);
05025   gl2psPrintf("xlink:href=\"data:image/png;base64,");
05026   for(i = 0; i < gl2psListNbr(png); i++){
05027     gl2psListRead(png, i, &c);
05028     gl2psPrintf("%c", c);
05029   }
05030   gl2psPrintf("\"/>\n");
05031   gl2psListDelete(png);
05032 #else
05033   gl2psMsg(GL2PS_WARNING, "GL2PS has to be compiled with PNG support in "
05034            "order to embed images in SVG streams");
05035 #endif
05036 }
05037 
05038 static void gl2psPrintSVGPrimitive(void *data)
05039 {
05040   GL2PSprimitive *prim;
05041   GL2PSxyz xyz[4];
05042   GL2PSrgba rgba[4];
05043   char col[32];
05044   int newline;
05045 
05046   prim = *(GL2PSprimitive**)data;
05047 
05048   if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
05049 
05050   /* We try to draw connected lines as a single path to get nice line
05051      joins and correct stippling. So if the primitive to print is not
05052      a line we must first finish the current line (if any): */
05053   if(prim->type != GL2PS_LINE) gl2psEndSVGLine();
05054 
05055   gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba);
05056 
05057   switch(prim->type){
05058   case GL2PS_POINT :
05059     gl2psSVGGetColorString(rgba[0], col);
05060     gl2psPrintf("<circle fill=\"%s\" ", col);
05061     if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
05062     gl2psPrintf("cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
05063                 xyz[0][0], xyz[0][1], 0.5 * prim->width);
05064     break;
05065   case GL2PS_LINE :
05066     if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
05067        !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
05068        gl2ps->lastlinewidth != prim->width ||
05069        gl2ps->lastpattern != prim->pattern ||
05070        gl2ps->lastfactor != prim->factor){
05071       /* End the current line if the new segment does not start where
05072          the last one ended, or if the color, the width or the
05073          stippling have changed (we will need to use multi-point
05074          gradients for smooth-shaded lines) */
05075       gl2psEndSVGLine();
05076       newline = 1;
05077     }
05078     else{
05079       newline = 0;
05080     }
05081     gl2ps->lastvertex = prim->verts[1];
05082     gl2psSetLastColor(prim->verts[0].rgba);
05083     gl2ps->lastlinewidth = prim->width;
05084     gl2ps->lastpattern = prim->pattern;
05085     gl2ps->lastfactor = prim->factor;
05086     if(newline){
05087       gl2psSVGGetColorString(rgba[0], col);
05088       gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ", 
05089                   col, prim->width);
05090       if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]);
05091       gl2psPrintSVGDash(prim->pattern, prim->factor);
05092       gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]);
05093     }
05094     else{
05095       gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]);
05096     }
05097     break;
05098   case GL2PS_TRIANGLE :
05099     gl2psPrintSVGSmoothTriangle(xyz, rgba);
05100     break;
05101   case GL2PS_QUADRANGLE :
05102     gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
05103     break;
05104   case GL2PS_PIXMAP :
05105     gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image);
05106     break;
05107   case GL2PS_TEXT :
05108     gl2psSVGGetColorString(prim->verts[0].rgba, col);
05109     gl2psPrintf("<text fill=\"%s\" x=\"%g\" y=\"%g\" font-size=\"%d\" ",
05110                 col, xyz[0][0], xyz[0][1], prim->data.text->fontsize);
05111     if(!strcmp(prim->data.text->fontname, "Times-Roman"))
05112       gl2psPrintf("font-family=\"Times\">");
05113     else if(!strcmp(prim->data.text->fontname, "Times-Bold"))
05114       gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">");
05115     else if(!strcmp(prim->data.text->fontname, "Times-Italic"))
05116       gl2psPrintf("font-family=\"Times\" font-style=\"italic\">");
05117     else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic"))
05118       gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">");
05119     else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold"))
05120       gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">");
05121     else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique"))
05122       gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">");
05123     else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique"))
05124       gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">");
05125     else if(!strcmp(prim->data.text->fontname, "Courier-Bold"))
05126       gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">");
05127     else if(!strcmp(prim->data.text->fontname, "Courier-Oblique"))
05128       gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">");
05129     else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique"))
05130       gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">");
05131     else
05132       gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname);
05133     gl2psPrintf("%s</text>\n", prim->data.text->str);
05134     break;
05135   case GL2PS_SPECIAL :
05136     /* alignment contains the format for which the special output text
05137        is intended */
05138     if(prim->data.text->alignment == GL2PS_SVG)
05139       gl2psPrintf("%s\n", prim->data.text->str);
05140     break;
05141   default :
05142     break;
05143   }
05144 }
05145 
05146 static void gl2psPrintSVGFooter(void)
05147 {
05148   gl2psPrintf("</g>\n");
05149   gl2psPrintf("</svg>\n");  
05150   
05151   gl2psPrintGzipFooter();
05152 }
05153 
05154 static void gl2psPrintSVGBeginViewport(GLint viewport[4])
05155 {
05156   GLint index;
05157   char col[32];
05158   GLfloat rgba[4];
05159   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
05160 
05161   glRenderMode(GL_FEEDBACK);
05162   
05163   if(gl2ps->header){
05164     gl2psPrintSVGHeader();
05165     gl2ps->header = GL_FALSE;
05166   }
05167 
05168   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
05169     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
05170       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
05171     }
05172     else{
05173       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
05174       rgba[0] = gl2ps->colormap[index][0];
05175       rgba[1] = gl2ps->colormap[index][1];
05176       rgba[2] = gl2ps->colormap[index][2];
05177       rgba[3] = 1.0F;
05178     }
05179     gl2psSVGGetColorString(rgba, col);
05180     gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, 
05181                 x, gl2ps->viewport[3] - y, 
05182                 x + w, gl2ps->viewport[3] - y, 
05183                 x + w, gl2ps->viewport[3] - (y + h), 
05184                 x, gl2ps->viewport[3] - (y + h));
05185   }
05186 
05187   gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h);
05188   gl2psPrintf("  <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", 
05189               x, gl2ps->viewport[3] - y, 
05190               x + w, gl2ps->viewport[3] - y, 
05191               x + w, gl2ps->viewport[3] - (y + h), 
05192               x, gl2ps->viewport[3] - (y + h));
05193   gl2psPrintf("</clipPath>\n");
05194   gl2psPrintf("<g clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h);
05195 }
05196 
05197 static GLint gl2psPrintSVGEndViewport(void)
05198 {
05199   GLint res;
05200 
05201   res = gl2psPrintPrimitives();
05202   gl2psPrintf("</g>\n");
05203   return res;
05204 }
05205 
05206 static void gl2psPrintSVGFinalPrimitive(void)
05207 {
05208   /* End any remaining line, if any */
05209   gl2psEndSVGLine();
05210 }
05211 
05212 /* definition of the SVG backend */
05213 
05214 static GL2PSbackend gl2psSVG = {
05215   gl2psPrintSVGHeader,
05216   gl2psPrintSVGFooter,
05217   gl2psPrintSVGBeginViewport,
05218   gl2psPrintSVGEndViewport,
05219   gl2psPrintSVGPrimitive,
05220   gl2psPrintSVGFinalPrimitive,
05221   "svg",
05222   "Scalable Vector Graphics"
05223 };
05224 
05225 /*********************************************************************
05226  *
05227  * PGF routines
05228  *
05229  *********************************************************************/
05230 
05231 static void gl2psPrintPGFColor(GL2PSrgba rgba)
05232 {
05233   if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
05234     gl2psSetLastColor(rgba);
05235     fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]);
05236   }
05237 }
05238 
05239 static void gl2psPrintPGFHeader(void)
05240 {
05241   time_t now;
05242 
05243   time(&now);
05244 
05245   fprintf(gl2ps->stream, 
05246           "%% Title: %s\n"
05247           "%% Creator: GL2PS %d.%d.%d%s, %s\n"
05248           "%% For: %s\n"
05249           "%% CreationDate: %s",
05250           gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
05251           GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
05252           gl2ps->producer, ctime(&now));
05253 
05254   fprintf(gl2ps->stream, "\\begin{pgfpicture}\n");
05255   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
05256     gl2psPrintPGFColor(gl2ps->bgcolor);
05257     fprintf(gl2ps->stream,
05258             "\\pgfpathrectanglecorners{"
05259             "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n"
05260             "\\pgfusepath{fill}\n",
05261             (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
05262             (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
05263   }
05264 }
05265 
05266 static void gl2psPrintPGFDash(GLushort pattern, GLint factor)
05267 {
05268   int i, n, array[10];
05269 
05270   if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
05271     return;
05272 
05273   gl2ps->lastpattern = pattern;
05274   gl2ps->lastfactor = factor;
05275 
05276   if(!pattern || !factor){
05277     /* solid line */
05278     fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n");
05279   }
05280   else{
05281     gl2psParseStipplePattern(pattern, factor, &n, array);
05282     fprintf(gl2ps->stream, "\\pgfsetdash{");
05283     for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]);
05284     fprintf(gl2ps->stream, "}{0pt}\n");
05285   }
05286 }
05287 
05288 static const char *gl2psPGFTextAlignment(int align)
05289 {
05290   switch(align){
05291   case GL2PS_TEXT_C  : return "center";
05292   case GL2PS_TEXT_CL : return "west";
05293   case GL2PS_TEXT_CR : return "east";
05294   case GL2PS_TEXT_B  : return "south";
05295   case GL2PS_TEXT_BR : return "south east";
05296   case GL2PS_TEXT_T  : return "north";
05297   case GL2PS_TEXT_TL : return "north west";
05298   case GL2PS_TEXT_TR : return "north east";
05299   case GL2PS_TEXT_BL : 
05300   default            : return "south west";
05301   }
05302 }
05303 
05304 static void gl2psPrintPGFPrimitive(void *data)
05305 {
05306   GL2PSprimitive *prim;
05307 
05308   prim = *(GL2PSprimitive**)data;
05309 
05310   switch(prim->type){
05311   case GL2PS_POINT :
05312     /* Points in openGL are rectangular */
05313     gl2psPrintPGFColor(prim->verts[0].rgba);
05314     fprintf(gl2ps->stream, 
05315             "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}"
05316             "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n",
05317             prim->verts[0].xyz[0]-0.5*prim->width,
05318             prim->verts[0].xyz[1]-0.5*prim->width,
05319             prim->width,prim->width);
05320     break;
05321   case GL2PS_LINE :
05322     gl2psPrintPGFColor(prim->verts[0].rgba);
05323     if(gl2ps->lastlinewidth != prim->width){
05324       gl2ps->lastlinewidth = prim->width;
05325       fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth);
05326     }
05327     gl2psPrintPGFDash(prim->pattern, prim->factor);
05328     fprintf(gl2ps->stream, 
05329             "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
05330             "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
05331             "\\pgfusepath{stroke}\n",
05332             prim->verts[1].xyz[0], prim->verts[1].xyz[1],
05333             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
05334     break;
05335   case GL2PS_TRIANGLE :
05336     if(gl2ps->lastlinewidth != 0){
05337       gl2ps->lastlinewidth = 0;
05338       fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n");
05339     }
05340     gl2psPrintPGFColor(prim->verts[0].rgba);
05341     fprintf(gl2ps->stream, 
05342             "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
05343             "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
05344             "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
05345             "\\pgfpathclose\n"
05346             "\\pgfusepath{fill,stroke}\n",
05347             prim->verts[2].xyz[0], prim->verts[2].xyz[1],
05348             prim->verts[1].xyz[0], prim->verts[1].xyz[1],
05349             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
05350     break;
05351   case GL2PS_TEXT :
05352     fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n",
05353             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
05354 
05355     if(prim->data.text->angle)
05356       fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle);
05357 
05358     fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont",
05359             gl2psPGFTextAlignment(prim->data.text->alignment),
05360             prim->data.text->fontsize);
05361 
05362     fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}",
05363             prim->verts[0].rgba[0], prim->verts[0].rgba[1],
05364             prim->verts[0].rgba[2], prim->data.text->str);
05365 
05366     fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n");
05367     break;
05368   case GL2PS_SPECIAL :
05369     /* alignment contains the format for which the special output text
05370        is intended */
05371     if (prim->data.text->alignment == GL2PS_PGF)
05372       fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
05373     break;
05374   default :
05375     break;
05376   }
05377 }
05378 
05379 static void gl2psPrintPGFFooter(void)
05380 {
05381   fprintf(gl2ps->stream, "\\end{pgfpicture}\n");
05382 }
05383 
05384 static void gl2psPrintPGFBeginViewport(GLint viewport[4])
05385 {
05386   GLint index;
05387   GLfloat rgba[4];
05388   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
05389 
05390   glRenderMode(GL_FEEDBACK);
05391 
05392   if(gl2ps->header){
05393     gl2psPrintPGFHeader();
05394     gl2ps->header = GL_FALSE;
05395   }
05396 
05397   fprintf(gl2ps->stream, "\\begin{pgfscope}\n");
05398   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
05399     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
05400       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
05401     }
05402     else{
05403       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
05404       rgba[0] = gl2ps->colormap[index][0];
05405       rgba[1] = gl2ps->colormap[index][1];
05406       rgba[2] = gl2ps->colormap[index][2];
05407       rgba[3] = 1.0F;
05408     }
05409     gl2psPrintPGFColor(rgba);
05410     fprintf(gl2ps->stream, 
05411             "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
05412             "{\\pgfpoint{%dpt}{%dpt}}\n"
05413             "\\pgfusepath{fill}\n",
05414             x, y, w, h);
05415   }
05416   
05417   fprintf(gl2ps->stream, 
05418           "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
05419           "{\\pgfpoint{%dpt}{%dpt}}\n"
05420           "\\pgfusepath{clip}\n",
05421           x, y, w, h);
05422 }
05423 
05424 static GLint gl2psPrintPGFEndViewport(void)
05425 {
05426   GLint res;
05427   res = gl2psPrintPrimitives();
05428   fprintf(gl2ps->stream, "\\end{pgfscope}\n");
05429   return res;
05430 }
05431 
05432 static void gl2psPrintPGFFinalPrimitive(void)
05433 {
05434 }
05435 
05436 /* definition of the PGF backend */
05437 
05438 static GL2PSbackend gl2psPGF = {
05439   gl2psPrintPGFHeader,
05440   gl2psPrintPGFFooter,
05441   gl2psPrintPGFBeginViewport,
05442   gl2psPrintPGFEndViewport,
05443   gl2psPrintPGFPrimitive,
05444   gl2psPrintPGFFinalPrimitive,
05445   "tex",
05446   "PGF Latex Graphics"
05447 };
05448 
05449 /********************************************************************* 
05450  *
05451  * General primitive printing routine
05452  *
05453  *********************************************************************/
05454 
05455 /* Warning: the ordering of the backends must match the format
05456    #defines in gl2ps.h */
05457 
05458 static GL2PSbackend *gl2psbackends[] = {
05459   &gl2psPS,  /* 0 */
05460   &gl2psEPS, /* 1 */
05461   &gl2psTEX, /* 2 */
05462   &gl2psPDF, /* 3 */
05463   &gl2psSVG, /* 4 */
05464   &gl2psPGF  /* 5 */
05465 };
05466 
05467 static void gl2psComputeTightBoundingBox(void *data)
05468 {
05469   GL2PSprimitive *prim;
05470   int i;
05471 
05472   prim = *(GL2PSprimitive**)data;
05473 
05474   for(i = 0; i < prim->numverts; i++){
05475     if(prim->verts[i].xyz[0] < gl2ps->viewport[0])
05476       gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0];
05477     if(prim->verts[i].xyz[0] > gl2ps->viewport[2])
05478       gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F);
05479     if(prim->verts[i].xyz[1] < gl2ps->viewport[1])
05480       gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1];
05481     if(prim->verts[i].xyz[1] > gl2ps->viewport[3])
05482       gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F);
05483   }
05484 }  
05485 
05486 static GLint gl2psPrintPrimitives(void)
05487 {
05488   GL2PSbsptree *root;
05489   GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE};
05490   GLint used;
05491 
05492   used = glRenderMode(GL_RENDER);
05493 
05494   if(used < 0){
05495     gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow");
05496     return GL2PS_OVERFLOW;
05497   }
05498 
05499   if(used > 0)
05500     gl2psParseFeedbackBuffer(used);
05501 
05502   gl2psRescaleAndOffset();
05503 
05504   if(gl2ps->header){
05505     if(gl2psListNbr(gl2ps->primitives) && 
05506        (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){
05507       gl2ps->viewport[0] = gl2ps->viewport[1] = 100000;
05508       gl2ps->viewport[2] = gl2ps->viewport[3] = -100000;
05509       gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox);
05510     }
05511     (gl2psbackends[gl2ps->format]->printHeader)();
05512     gl2ps->header = GL_FALSE;
05513   }
05514 
05515   if(!gl2psListNbr(gl2ps->primitives)){
05516     /* empty feedback buffer and/or nothing else to print */
05517     return GL2PS_NO_FEEDBACK;
05518   }
05519 
05520   switch(gl2ps->sort){
05521   case GL2PS_NO_SORT :
05522     gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
05523     gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
05524     /* reset the primitive list, waiting for the next viewport */
05525     gl2psListReset(gl2ps->primitives);
05526     break;
05527   case GL2PS_SIMPLE_SORT :
05528     gl2psListSort(gl2ps->primitives, gl2psCompareDepth);
05529     if(gl2ps->options & GL2PS_OCCLUSION_CULL){
05530       gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree);
05531       gl2psFreeBspImageTree(&gl2ps->imagetree);
05532     }
05533     gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
05534     gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
05535     /* reset the primitive list, waiting for the next viewport */
05536     gl2psListReset(gl2ps->primitives);
05537     break;
05538   case GL2PS_BSP_SORT :
05539     root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
05540     gl2psBuildBspTree(root, gl2ps->primitives);
05541     if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root);
05542     if(gl2ps->options & GL2PS_OCCLUSION_CULL){
05543       gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess,
05544                            gl2psAddInImageTree, 1);
05545       gl2psFreeBspImageTree(&gl2ps->imagetree);
05546     }
05547     gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, 
05548                          gl2psbackends[gl2ps->format]->printPrimitive, 0);
05549     gl2psFreeBspTree(&root);
05550     /* reallocate the primitive list (it's been deleted by
05551        gl2psBuildBspTree) in case there is another viewport */
05552     gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
05553     break;
05554   }
05555   gl2psbackends[gl2ps->format]->printFinalPrimitive();
05556 
05557   return GL2PS_SUCCESS;
05558 }
05559 
05560 /********************************************************************* 
05561  *
05562  * Public routines
05563  *
05564  *********************************************************************/
05565 
05566 GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, 
05567                                   GLint viewport[4], GLint format, GLint sort,
05568                                   GLint options, GLint colormode,
05569                                   GLint colorsize, GL2PSrgba *colormap,
05570                                   GLint nr, GLint ng, GLint nb, GLint buffersize,
05571                                   FILE *stream, const char *filename)
05572 {
05573   GLint index;
05574   int i;
05575 
05576   if(gl2ps){
05577     gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state");
05578     return GL2PS_ERROR;
05579   }
05580 
05581   gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext));
05582 
05583   if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))){
05584     gl2ps->format = format;
05585   }
05586   else {
05587     gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format);
05588     gl2psFree(gl2ps);
05589     gl2ps = NULL;
05590     return GL2PS_ERROR;
05591   }
05592 
05593   switch(sort){
05594   case GL2PS_NO_SORT :
05595   case GL2PS_SIMPLE_SORT :
05596   case GL2PS_BSP_SORT :
05597     gl2ps->sort = sort;
05598     break;
05599   default :
05600     gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort);
05601     gl2psFree(gl2ps);
05602     gl2ps = NULL;
05603     return GL2PS_ERROR;
05604   }
05605 
05606   if(stream){
05607     gl2ps->stream = stream;
05608   }
05609   else{
05610     gl2psMsg(GL2PS_ERROR, "Bad file pointer");
05611     gl2psFree(gl2ps);
05612     gl2ps = NULL;
05613     return GL2PS_ERROR;
05614   }
05615 
05616   gl2ps->header = GL_TRUE;
05617   gl2ps->maxbestroot = 10;
05618   gl2ps->options = options;
05619   gl2ps->compress = NULL;
05620   gl2ps->imagemap_head = NULL;
05621   gl2ps->imagemap_tail = NULL;
05622 
05623   if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){
05624     glGetIntegerv(GL_VIEWPORT, gl2ps->viewport);
05625   }
05626   else{
05627     for(i = 0; i < 4; i++){
05628       gl2ps->viewport[i] = viewport[i];
05629     }
05630   }
05631 
05632   if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){
05633     gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)",
05634              gl2ps->viewport[0], gl2ps->viewport[1], 
05635              gl2ps->viewport[2], gl2ps->viewport[3]);
05636     gl2psFree(gl2ps);
05637     gl2ps = NULL;
05638     return GL2PS_ERROR;
05639   }
05640 
05641   gl2ps->threshold[0] = nr ? 1.0F / (GLfloat)nr : 0.064F;
05642   gl2ps->threshold[1] = ng ? 1.0F / (GLfloat)ng : 0.034F;
05643   gl2ps->threshold[2] = nb ? 1.0F / (GLfloat)nb : 0.100F;
05644   gl2ps->colormode = colormode;
05645   gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048;
05646   for(i = 0; i < 3; i++){
05647     gl2ps->lastvertex.xyz[i] = -1.0F;
05648   }
05649   for(i = 0; i < 4; i++){
05650     gl2ps->lastvertex.rgba[i] = -1.0F;
05651     gl2ps->lastrgba[i] = -1.0F;
05652   }
05653   gl2ps->lastlinewidth = -1.0F;
05654   gl2ps->lastpattern = 0;
05655   gl2ps->lastfactor = 0;
05656   gl2ps->imagetree = NULL;
05657   gl2ps->primitivetoadd = NULL;
05658   gl2ps->zerosurfacearea = GL_FALSE;  
05659   gl2ps->pdfprimlist = NULL;
05660   gl2ps->pdfgrouplist = NULL;
05661   gl2ps->xreflist = NULL;
05662   
05663   /* get default blending mode from current OpenGL state (enabled by
05664      default for SVG) */
05665   gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND);
05666   glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]);
05667   glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]);
05668 
05669   if(gl2ps->colormode == GL_RGBA){
05670     gl2ps->colorsize = 0;
05671     gl2ps->colormap = NULL;
05672     glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor);
05673   }
05674   else if(gl2ps->colormode == GL_COLOR_INDEX){
05675     if(!colorsize || !colormap){
05676       gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering");
05677       gl2psFree(gl2ps);
05678       gl2ps = NULL;
05679       return GL2PS_ERROR;
05680     }
05681     gl2ps->colorsize = colorsize;
05682     gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba));
05683     memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba));
05684     glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
05685     gl2ps->bgcolor[0] = gl2ps->colormap[index][0];
05686     gl2ps->bgcolor[1] = gl2ps->colormap[index][1];
05687     gl2ps->bgcolor[2] = gl2ps->colormap[index][2];
05688     gl2ps->bgcolor[3] = 1.0F;
05689   }
05690   else{
05691     gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage");
05692     gl2psFree(gl2ps);
05693     gl2ps = NULL;
05694     return GL2PS_ERROR;
05695   }
05696 
05697   if(!title){
05698     gl2ps->title = (char*)gl2psMalloc(sizeof(char));
05699     gl2ps->title[0] = '\0';
05700   }
05701   else{
05702     gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char));
05703     strcpy(gl2ps->title, title);
05704   }
05705     
05706   if(!producer){
05707     gl2ps->producer = (char*)gl2psMalloc(sizeof(char));
05708     gl2ps->producer[0] = '\0';
05709   }
05710   else{
05711     gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char));
05712     strcpy(gl2ps->producer, producer);
05713   }
05714   
05715   if(!filename){
05716     gl2ps->filename = (char*)gl2psMalloc(sizeof(char));
05717     gl2ps->filename[0] = '\0';
05718   }
05719   else{
05720     gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char));
05721     strcpy(gl2ps->filename, filename);
05722   }
05723 
05724   gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
05725   gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*));
05726   gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat));
05727   glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback);
05728   glRenderMode(GL_FEEDBACK);  
05729 
05730   return GL2PS_SUCCESS;
05731 }
05732 
05733 GL2PSDLL_API GLint gl2psEndPage(void)
05734 {
05735   GLint res;
05736 
05737   if(!gl2ps) return GL2PS_UNINITIALIZED;
05738 
05739   res = gl2psPrintPrimitives();
05740 
05741   if(res != GL2PS_OVERFLOW)
05742     (gl2psbackends[gl2ps->format]->printFooter)();
05743   
05744   fflush(gl2ps->stream);
05745 
05746   gl2psListDelete(gl2ps->primitives);
05747   gl2psListDelete(gl2ps->auxprimitives);
05748   gl2psFreeImagemap(gl2ps->imagemap_head);
05749   gl2psFree(gl2ps->colormap);
05750   gl2psFree(gl2ps->title);
05751   gl2psFree(gl2ps->producer);
05752   gl2psFree(gl2ps->filename);
05753   gl2psFree(gl2ps->feedback);
05754   gl2psFree(gl2ps);
05755   gl2ps = NULL;
05756 
05757   return res;
05758 }
05759 
05760 GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4])
05761 {
05762   if(!gl2ps) return GL2PS_UNINITIALIZED;
05763 
05764   (gl2psbackends[gl2ps->format]->beginViewport)(viewport);
05765   
05766   return GL2PS_SUCCESS;
05767 }
05768 
05769 GL2PSDLL_API GLint gl2psEndViewport(void)
05770 {
05771   GLint res;
05772 
05773   if(!gl2ps) return GL2PS_UNINITIALIZED;
05774 
05775   res = (gl2psbackends[gl2ps->format]->endViewport)();
05776 
05777   /* reset last used colors, line widths */
05778   gl2ps->lastlinewidth = -1.0F;
05779 
05780   return res;
05781 }
05782 
05783 GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, 
05784                                 GLshort fontsize, GLint alignment, GLfloat angle)
05785 {
05786   return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle);
05787 }
05788 
05789 GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize)
05790 {
05791   return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F);
05792 }
05793 
05794 GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str)
05795 {
05796   return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F);
05797 }
05798 
05799 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
05800                                    GLint xorig, GLint yorig,
05801                                    GLenum format, GLenum type, 
05802                                    const void *pixels)
05803 {
05804   int size, i;
05805   GLfloat pos[4], *piv;
05806   GL2PSprimitive *prim;
05807   GLboolean valid;
05808 
05809   if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED;
05810 
05811   if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
05812 
05813   if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS;
05814 
05815   if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){
05816     gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for "
05817              "GL_RGB/GL_RGBA, GL_FLOAT pixels");
05818     return GL2PS_ERROR;
05819   }
05820 
05821   glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
05822   if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
05823 
05824   glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
05825 
05826   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
05827   prim->type = GL2PS_PIXMAP;
05828   prim->boundary = 0;
05829   prim->numverts = 1;
05830   prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
05831   prim->verts[0].xyz[0] = pos[0] + xorig;
05832   prim->verts[0].xyz[1] = pos[1] + yorig;
05833   prim->verts[0].xyz[2] = pos[2];
05834   prim->culled = 0;
05835   prim->offset = 0;
05836   prim->pattern = 0;
05837   prim->factor = 0;
05838   prim->width = 1;
05839   glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
05840   prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
05841   prim->data.image->width = width;
05842   prim->data.image->height = height;
05843   prim->data.image->format = format;
05844   prim->data.image->type = type;
05845 
05846   switch(format){
05847   case GL_RGBA:
05848     if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
05849       /* special case: blending turned off */
05850       prim->data.image->format = GL_RGB;
05851       size = height * width * 3;
05852       prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
05853       piv = (GLfloat*)pixels;
05854       for(i = 0; i < size; ++i, ++piv){
05855         prim->data.image->pixels[i] = *piv;
05856         if(!((i+1)%3))
05857           ++piv;
05858       }   
05859     }
05860     else{
05861       size = height * width * 4;
05862       prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
05863       memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
05864     }
05865     break;
05866   case GL_RGB:
05867   default:
05868     size = height * width * 3;
05869     prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
05870     memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
05871     break;
05872   }
05873 
05874   gl2psListAdd(gl2ps->auxprimitives, &prim);
05875   glPassThrough(GL2PS_DRAW_PIXELS_TOKEN);
05876 
05877   return GL2PS_SUCCESS;
05878 }
05879 
05880 GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height,
05881                                      const GLfloat position[3],
05882                                      const unsigned char *imagemap){
05883   int size, i;
05884   int sizeoffloat = sizeof(GLfloat);
05885   
05886   if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED;
05887 
05888   if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
05889   
05890   size = height + height * ((width - 1) / 8);
05891   glPassThrough(GL2PS_IMAGEMAP_TOKEN);
05892   glBegin(GL_POINTS);
05893   glVertex3f(position[0], position[1],position[2]);
05894   glEnd();
05895   glPassThrough((GLfloat)width);
05896   glPassThrough((GLfloat)height);
05897   for(i = 0; i < size; i += sizeoffloat){
05898     float *value = (float*)imagemap;
05899     glPassThrough(*value);
05900     imagemap += sizeoffloat;
05901   }
05902   return GL2PS_SUCCESS;
05903 }
05904 
05905 GL2PSDLL_API GLint gl2psEnable(GLint mode)
05906 {
05907   GLint tmp;
05908 
05909   if(!gl2ps) return GL2PS_UNINITIALIZED;
05910 
05911   switch(mode){
05912   case GL2PS_POLYGON_OFFSET_FILL :
05913     glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN);
05914     glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]);
05915     glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]);
05916     break;
05917   case GL2PS_POLYGON_BOUNDARY :
05918     glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN);
05919     break;
05920   case GL2PS_LINE_STIPPLE :
05921     glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN);
05922     glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp);
05923     glPassThrough((GLfloat)tmp);
05924     glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp);
05925     glPassThrough((GLfloat)tmp);
05926     break;
05927   case GL2PS_BLEND :
05928     glPassThrough(GL2PS_BEGIN_BLEND_TOKEN);
05929     break;
05930   default :
05931     gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode);
05932     return GL2PS_WARNING;
05933   }
05934 
05935   return GL2PS_SUCCESS;
05936 }
05937 
05938 GL2PSDLL_API GLint gl2psDisable(GLint mode)
05939 {
05940   if(!gl2ps) return GL2PS_UNINITIALIZED;
05941 
05942   switch(mode){
05943   case GL2PS_POLYGON_OFFSET_FILL :
05944     glPassThrough(GL2PS_END_OFFSET_TOKEN);
05945     break;
05946   case GL2PS_POLYGON_BOUNDARY :
05947     glPassThrough(GL2PS_END_BOUNDARY_TOKEN);
05948     break;
05949   case GL2PS_LINE_STIPPLE :
05950     glPassThrough(GL2PS_END_STIPPLE_TOKEN);
05951     break;
05952   case GL2PS_BLEND :
05953     glPassThrough(GL2PS_END_BLEND_TOKEN);
05954     break;
05955   default :
05956     gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode);
05957     return GL2PS_WARNING;
05958   }
05959 
05960   return GL2PS_SUCCESS;
05961 }
05962 
05963 GL2PSDLL_API GLint gl2psPointSize(GLfloat value)
05964 {
05965   if(!gl2ps) return GL2PS_UNINITIALIZED;
05966 
05967   glPassThrough(GL2PS_POINT_SIZE_TOKEN);
05968   glPassThrough(value);
05969   
05970   return GL2PS_SUCCESS;
05971 }
05972 
05973 GL2PSDLL_API GLint gl2psLineWidth(GLfloat value)
05974 {
05975   if(!gl2ps) return GL2PS_UNINITIALIZED;
05976 
05977   glPassThrough(GL2PS_LINE_WIDTH_TOKEN);
05978   glPassThrough(value);
05979 
05980   return GL2PS_SUCCESS;
05981 }
05982 
05983 GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor)
05984 {
05985   if(!gl2ps) return GL2PS_UNINITIALIZED;
05986 
05987   if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor))
05988     return GL2PS_WARNING;
05989 
05990   glPassThrough(GL2PS_SRC_BLEND_TOKEN);
05991   glPassThrough((GLfloat)sfactor);
05992   glPassThrough(GL2PS_DST_BLEND_TOKEN);
05993   glPassThrough((GLfloat)dfactor);
05994 
05995   return GL2PS_SUCCESS;
05996 }
05997 
05998 GL2PSDLL_API GLint gl2psSetOptions(GLint options)
05999 {
06000   if(!gl2ps) return GL2PS_UNINITIALIZED;
06001 
06002   gl2ps->options = options;
06003 
06004   return GL2PS_SUCCESS;
06005 }
06006 
06007 GL2PSDLL_API GLint gl2psGetOptions(GLint *options)
06008 {
06009   if(!gl2ps) {
06010     *options = 0;
06011     return GL2PS_UNINITIALIZED;
06012   }
06013 
06014   *options = gl2ps->options;
06015 
06016   return GL2PS_SUCCESS;
06017 }
06018 
06019 GL2PSDLL_API const char *gl2psGetFileExtension(GLint format)
06020 {
06021   if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0])))
06022     return gl2psbackends[format]->file_extension;
06023   else
06024     return "Unknown format";
06025 }
06026 
06027 GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format)
06028 {
06029   if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0])))
06030     return gl2psbackends[format]->description;
06031   else
06032     return "Unknown format";
06033 }

Generated on Tue Jul 5 14:18:05 2011 for ROOT_528-00b_version by  doxygen 1.5.1