gl2ps.cc

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

Generated on Mon May 27 17:50:29 2013 for Geant4 by  doxygen 1.4.7