gl2ps.c

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

Generated on Wed Sep 22 16:51:26 2010 for Body_Schema_Learning by  doxygen 1.6.1