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