1 /*
2  * GL2PS, an OpenGL to PostScript Printing Library
3  * Copyright (C) 1999-2009 C. Geuzaine
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of either:
7  *
8  * a) the GNU Library General Public License as published by the Free
9  * Software Foundation, either version 2 of the License, or (at your
10  * option) any later version; or
11  *
12  * b) the GL2PS License as published by Christophe Geuzaine, either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See either
18  * the GNU Library General Public License or the GL2PS License for
19  * more details.
20  *
21  * You should have received a copy of the GNU Library General Public
22  * License along with this library in the file named "COPYING.LGPL";
23  * if not, write to the Free Software Foundation, Inc., 675 Mass Ave,
24  * Cambridge, MA 02139, USA.
25  *
26  * You should have received a copy of the GL2PS License with this
27  * library in the file named "COPYING.GL2PS"; if not, I will be glad
28  * to provide one.
29  *
30  * Contributors:
31  *   Michael Sweet <mike@easysw.com>
32  *   Marc Ume <marc.ume@digitalgraphics.be>
33  *   Jean-Francois Remacle <remacle@gce.ucl.ac.be>
34  *   Bart Kaptein <B.L.Kaptein@lumc.nl>
35  *   Quy Nguyen-Dai <quy@nguyendai.org>
36  *   Sam Buss <sbuss@ucsd.edu>
37  *   Shane Hill <Shane.Hill@dsto.defence.gov.au>
38  *   Romain Boman <r_boman@yahoo.fr>
39  *   Rouben Rostamian <rostamian@umbc.edu>
40  *   Diego Santa Cruz <Diego.SantaCruz@epfl.ch>
41  *   Shahzad Muzaffar <Shahzad.Muzaffar@cern.ch>
42  *   Lassi Tuura <lassi.tuura@cern.ch>
43  *   Guy Barrand <barrand@lal.in2p3.fr>
44  *   Prabhu Ramachandran <prabhu@aero.iitm.ernet.in>
45  *   Micha Bieber <bieber@traits.de>
46  *   Olivier Couet <couet@mail.cern.ch>
47  *   Shai Ayal <shaiay@gmail.com>
48  *   Fabian Wenzel <wenzel@tu-harburg.de>
49  *   Ian D. Gay <gay@sfu.ca>
50  *   Cosmin Truta <cosmin@cs.toronto.edu>
51  *   Baiju Devani <b.devani@gmail.com>
52  *   Alexander Danilov <danilov@lanl.gov>
53  *
54  * For the latest info about gl2ps, see http://www.geuz.org/gl2ps/.
55  * Please report all bugs and problems to <gl2ps@geuz.org>.
56  */
57 
58 #include "gl2ps.h"
59 
60 #include <math.h>
61 #include <string.h>
62 #include <sys/types.h>
63 #include <stdarg.h>
64 #include <time.h>
65 #include <float.h>
66 
67 #if defined(GL2PS_HAVE_ZLIB)
68 #include <zlib.h>
69 #endif
70 
71 #if defined(GL2PS_HAVE_LIBPNG)
72 #include <png.h>
73 #endif
74 
75 /*********************************************************************
76  *
77  * Private definitions, data structures and prototypes
78  *
79  *********************************************************************/
80 
81 /* Magic numbers (assuming that the order of magnitude of window
82    coordinates is 10^3) */
83 
84 #define GL2PS_EPSILON       5.0e-3F
85 #define GL2PS_ZSCALE        1000.0F
86 #define GL2PS_ZOFFSET       5.0e-2F
87 #define GL2PS_ZOFFSET_LARGE 20.0F
88 #define GL2PS_ZERO(arg)     (fabs(arg) < 1.e-20)
89 
90 /* Primitive types */
91 
92 #define GL2PS_NO_TYPE          -1
93 #define GL2PS_TEXT             1
94 #define GL2PS_POINT            2
95 #define GL2PS_LINE             3
96 #define GL2PS_QUADRANGLE       4
97 #define GL2PS_TRIANGLE         5
98 #define GL2PS_PIXMAP           6
99 #define GL2PS_IMAGEMAP         7
100 #define GL2PS_IMAGEMAP_WRITTEN 8
101 #define GL2PS_IMAGEMAP_VISIBLE 9
102 #define GL2PS_SPECIAL          10
103 
104 /* BSP tree primitive comparison */
105 
106 #define GL2PS_COINCIDENT  1
107 #define GL2PS_IN_FRONT_OF 2
108 #define GL2PS_IN_BACK_OF  3
109 #define GL2PS_SPANNING    4
110 
111 /* 2D BSP tree primitive comparison */
112 
113 #define GL2PS_POINT_COINCIDENT 0
114 #define GL2PS_POINT_INFRONT    1
115 #define GL2PS_POINT_BACK       2
116 
117 /* Internal feedback buffer pass-through tokens */
118 
119 #define GL2PS_BEGIN_OFFSET_TOKEN   1
120 #define GL2PS_END_OFFSET_TOKEN     2
121 #define GL2PS_BEGIN_BOUNDARY_TOKEN 3
122 #define GL2PS_END_BOUNDARY_TOKEN   4
123 #define GL2PS_BEGIN_STIPPLE_TOKEN  5
124 #define GL2PS_END_STIPPLE_TOKEN    6
125 #define GL2PS_POINT_SIZE_TOKEN     7
126 #define GL2PS_LINE_WIDTH_TOKEN     8
127 #define GL2PS_BEGIN_BLEND_TOKEN    9
128 #define GL2PS_END_BLEND_TOKEN      10
129 #define GL2PS_SRC_BLEND_TOKEN      11
130 #define GL2PS_DST_BLEND_TOKEN      12
131 #define GL2PS_IMAGEMAP_TOKEN       13
132 #define GL2PS_DRAW_PIXELS_TOKEN    14
133 #define GL2PS_TEXT_TOKEN           15
134 
135 typedef enum {
136   T_UNDEFINED    = -1,
137   T_CONST_COLOR  = 1,
138   T_VAR_COLOR    = 1<<1,
139   T_ALPHA_1      = 1<<2,
140   T_ALPHA_LESS_1 = 1<<3,
141   T_VAR_ALPHA    = 1<<4
142 } GL2PS_TRIANGLE_PROPERTY;
143 
144 typedef GLfloat GL2PSxyz[3];
145 typedef GLfloat GL2PSplane[4];
146 
147 typedef struct _GL2PSbsptree2d GL2PSbsptree2d;
148 
149 struct _GL2PSbsptree2d {
150   GL2PSplane plane;
151   GL2PSbsptree2d *front, *back;
152 };
153 
154 typedef struct {
155   GLint nmax, size, incr, n;
156   char *array;
157 } GL2PSlist;
158 
159 typedef struct _GL2PSbsptree GL2PSbsptree;
160 
161 struct _GL2PSbsptree {
162   GL2PSplane plane;
163   GL2PSlist *primitives;
164   GL2PSbsptree *front, *back;
165 };
166 
167 typedef struct {
168   GL2PSxyz xyz;
169   GL2PSrgba rgba;
170 } GL2PSvertex;
171 
172 typedef struct {
173   GL2PSvertex vertex[3];
174   int prop;
175 } GL2PStriangle;
176 
177 typedef struct {
178   GLshort fontsize;
179   char *str, *fontname;
180   /* Note: for a 'special' string, 'alignment' holds the format
181      (PostScript, PDF, etc.) of the special string */
182   GLint alignment;
183   GLfloat angle;
184 } GL2PSstring;
185 
186 typedef struct {
187   GLsizei width, height;
188   /* Note: for an imagemap, 'type' indicates if it has already been
189      written to the file or not, and 'format' indicates if it is
190      visible or not */
191   GLenum format, type;
192   GLfloat *pixels;
193 } GL2PSimage;
194 
195 typedef struct _GL2PSimagemap GL2PSimagemap;
196 
197 struct _GL2PSimagemap {
198   GL2PSimage *image;
199   GL2PSimagemap *next;
200 };
201 
202 typedef struct {
203   GLshort type, numverts;
204   GLushort pattern;
205   char boundary, offset, culled;
206   GLint factor;
207   GLfloat width;
208   GL2PSvertex *verts;
209   union {
210     GL2PSstring *text;
211     GL2PSimage *image;
212   } data;
213 } GL2PSprimitive;
214 
215 typedef struct {
216 #if defined(GL2PS_HAVE_ZLIB)
217   Bytef *dest, *src, *start;
218   uLongf destLen, srcLen;
219 #else
220   int dummy;
221 #endif
222 } GL2PScompress;
223 
224 typedef struct{
225   GL2PSlist* ptrlist;
226   int gsno, fontno, imno, shno, maskshno, trgroupno;
227   int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno;
228 } GL2PSpdfgroup;
229 
230 typedef struct {
231   /* General */
232   GLint format, sort, options, colorsize, colormode, buffersize;
233   char *title, *producer, *filename;
234   GLboolean boundary, blending;
235   GLfloat *feedback, offset[2], lastlinewidth;
236   GLint viewport[4], blendfunc[2], lastfactor;
237   GL2PSrgba *colormap, lastrgba, threshold, bgcolor;
238   GLushort lastpattern;
239   GL2PSvertex lastvertex;
240   GL2PSlist *primitives, *auxprimitives;
241   FILE *stream;
242   GL2PScompress *compress;
243   GLboolean header;
244 
245   /* BSP-specific */
246   GLint maxbestroot;
247 
248   /* Occlusion culling-specific */
249   GLboolean zerosurfacearea;
250   GL2PSbsptree2d *imagetree;
251   GL2PSprimitive *primitivetoadd;
252 
253   /* PDF-specific */
254   int streamlength;
255   GL2PSlist *pdfprimlist, *pdfgrouplist;
256   int *xreflist;
257   int objects_stack; /* available objects */
258   int extgs_stack; /* graphics state object number */
259   int font_stack; /* font object number */
260   int im_stack; /* image object number */
261   int trgroupobjects_stack; /* xobject numbers */
262   int shader_stack; /* shader object numbers */
263   int mshader_stack; /* mask shader object numbers */
264 
265   /* for image map list */
266   GL2PSimagemap *imagemap_head;
267   GL2PSimagemap *imagemap_tail;
268 
269   /* image content bound (ca) */
270   int boundMinX, boundMaxX, boundMinY, boundMaxY;
271 
272 } GL2PScontext;
273 
274 typedef struct {
275   void  (*printHeader)(void);
276   void  (*printFooter)(void);
277   void  (*beginViewport)(GLint viewport[4]);
278   GLint (*endViewport)(void);
279   void  (*printPrimitive)(void *data);
280   void  (*printFinalPrimitive)(void);
281   const char *file_extension;
282   const char *description;
283 } GL2PSbackend;
284 
285 /* The gl2ps context. gl2ps is not thread safe (we should create a
286    local GL2PScontext during gl2psBeginPage) */
287 
288 static GL2PScontext *gl2ps = NULL;
289 
290 /* Need to forward-declare this one */
291 
292 static GLint gl2psPrintPrimitives(void);
293 
294 /*********************************************************************
295  *
296  * Utility routines
297  *
298  *********************************************************************/
299 
gl2psMsg(GLint level,const char * fmt,...)300 static void gl2psMsg(GLint level, const char *fmt, ...)
301 {
302   va_list args;
303 
304   if(!(gl2ps->options & GL2PS_SILENT)){
305     switch(level){
306     case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break;
307     case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break;
308     case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break;
309     }
310     va_start(args, fmt);
311     vfprintf(stderr, fmt, args);
312     va_end(args);
313     fprintf(stderr, "\n");
314   }
315   /* if(level == GL2PS_ERROR) exit(1); */
316 }
317 
gl2psMalloc(size_t size)318 static void *gl2psMalloc(size_t size)
319 {
320   void *ptr;
321 
322   if(!size) return(NULL);
323   ptr = malloc(size);
324   if(!ptr){
325     gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory");
326     exit(1);
327   }
328   return(ptr);
329 }
330 
gl2psRealloc(void * ptr,size_t size)331 static void *gl2psRealloc(void *ptr, size_t size)
332 {
333   if(!size) return(NULL);
334   ptr = realloc(ptr, size);
335   if(!ptr){
336     gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory");
337     exit(1);
338   }
339   return(ptr);
340 }
341 
gl2psFree(void * ptr)342 static void gl2psFree(void *ptr)
343 {
344   if(!ptr) return;
345   free(ptr);
346 }
347 
gl2psWriteBigEndian(unsigned long data,size_t bytes)348 static size_t gl2psWriteBigEndian(unsigned long data, size_t bytes)
349 {
350   size_t i;
351   size_t size = sizeof(unsigned long);
352   for(i = 1; i <= bytes; ++i){
353     fputc(0xff & (data >> (size-i) * 8), gl2ps->stream);
354   }
355   return bytes;
356 }
357 
358 /* zlib compression helper routines */
359 
360 #if defined(GL2PS_HAVE_ZLIB)
361 
gl2psSetupCompress(void)362 static void gl2psSetupCompress(void)
363 {
364   gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress));
365   gl2ps->compress->src = NULL;
366   gl2ps->compress->start = NULL;
367   gl2ps->compress->dest = NULL;
368   gl2ps->compress->srcLen = 0;
369   gl2ps->compress->destLen = 0;
370 }
371 
gl2psFreeCompress(void)372 static void gl2psFreeCompress(void)
373 {
374   if(!gl2ps->compress)
375     return;
376   gl2psFree(gl2ps->compress->start);
377   gl2psFree(gl2ps->compress->dest);
378   gl2ps->compress->src = NULL;
379   gl2ps->compress->start = NULL;
380   gl2ps->compress->dest = NULL;
381   gl2ps->compress->srcLen = 0;
382   gl2ps->compress->destLen = 0;
383 }
384 
gl2psAllocCompress(unsigned int srcsize)385 static int gl2psAllocCompress(unsigned int srcsize)
386 {
387   gl2psFreeCompress();
388 
389   if(!gl2ps->compress || !srcsize)
390     return GL2PS_ERROR;
391 
392   gl2ps->compress->srcLen = srcsize;
393   gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
394   gl2ps->compress->src = (Bytef*)gl2psMalloc(gl2ps->compress->srcLen);
395   gl2ps->compress->start = gl2ps->compress->src;
396   gl2ps->compress->dest = (Bytef*)gl2psMalloc(gl2ps->compress->destLen);
397 
398   return GL2PS_SUCCESS;
399 }
400 
gl2psReallocCompress(unsigned int srcsize)401 static void *gl2psReallocCompress(unsigned int srcsize)
402 {
403   if(!gl2ps->compress || !srcsize)
404     return NULL;
405 
406   if(srcsize < gl2ps->compress->srcLen)
407     return gl2ps->compress->start;
408 
409   gl2ps->compress->srcLen = srcsize;
410   gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
411   gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src,
412                                               gl2ps->compress->srcLen);
413   gl2ps->compress->start = gl2ps->compress->src;
414   gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest,
415                                                gl2ps->compress->destLen);
416 
417   return gl2ps->compress->start;
418 }
419 
gl2psWriteBigEndianCompress(unsigned long data,size_t bytes)420 static size_t gl2psWriteBigEndianCompress(unsigned long data, size_t bytes)
421 {
422   size_t i;
423   size_t size = sizeof(unsigned long);
424   for(i = 1; i <= bytes; ++i){
425     *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8));
426     ++gl2ps->compress->src;
427   }
428   return bytes;
429 }
430 
gl2psDeflate(void)431 static int gl2psDeflate(void)
432 {
433   /* For compatibility with older zlib versions, we use compress(...)
434      instead of compress2(..., Z_BEST_COMPRESSION) */
435   return compress(gl2ps->compress->dest, &gl2ps->compress->destLen,
436                   gl2ps->compress->start, gl2ps->compress->srcLen);
437 }
438 
439 #endif
440 
gl2psPrintf(const char * fmt,...)441 static int gl2psPrintf(const char* fmt, ...)
442 {
443   int ret;
444   va_list args;
445 
446 #if defined(GL2PS_HAVE_ZLIB)
447   unsigned int oldsize = 0;
448   static char buf[1000];
449   if(gl2ps->options & GL2PS_COMPRESS){
450     va_start(args, fmt);
451     ret = vsprintf(buf, fmt, args);
452     va_end(args);
453     oldsize = gl2ps->compress->srcLen;
454     gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret);
455     memcpy(gl2ps->compress->start+oldsize, buf, ret);
456     ret = 0;
457   }
458   else{
459 #endif
460     va_start(args, fmt);
461     ret = vfprintf(gl2ps->stream, fmt, args);
462     va_end(args);
463 #if defined(GL2PS_HAVE_ZLIB)
464   }
465 #endif
466   return ret;
467 }
468 
gl2psPrintGzipHeader()469 static void gl2psPrintGzipHeader()
470 {
471 #if defined(GL2PS_HAVE_ZLIB)
472   char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */
473                   8, /* compression method: Z_DEFLATED */
474                   0, /* flags */
475                   0, 0, 0, 0, /* time */
476                   2, /* extra flags: max compression */
477                   '\x03'}; /* OS code: 0x03 (Unix) */
478 
479   if(gl2ps->options & GL2PS_COMPRESS){
480     gl2psSetupCompress();
481     /* add the gzip file header */
482     fwrite(tmp, 10, 1, gl2ps->stream);
483   }
484 #endif
485 }
486 
gl2psPrintGzipFooter()487 static void gl2psPrintGzipFooter()
488 {
489 #if defined(GL2PS_HAVE_ZLIB)
490   int n;
491   uLong crc, len;
492   char tmp[8];
493 
494   if(gl2ps->options & GL2PS_COMPRESS){
495     if(Z_OK != gl2psDeflate()){
496       gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
497     }
498     else{
499       /* determine the length of the header in the zlib stream */
500       n = 2; /* CMF+FLG */
501       if(gl2ps->compress->dest[1] & (1<<5)){
502         n += 4; /* DICTID */
503       }
504       /* write the data, without the zlib header and footer */
505       fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4),
506              1, gl2ps->stream);
507       /* add the gzip file footer */
508       crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen);
509       for(n = 0; n < 4; ++n){
510         tmp[n] = (char)(crc & 0xff);
511         crc >>= 8;
512       }
513       len = gl2ps->compress->srcLen;
514       for(n = 4; n < 8; ++n){
515         tmp[n] = (char)(len & 0xff);
516         len >>= 8;
517       }
518       fwrite(tmp, 8, 1, gl2ps->stream);
519     }
520     gl2psFreeCompress();
521     gl2psFree(gl2ps->compress);
522     gl2ps->compress = NULL;
523   }
524 #endif
525 }
526 
527 /* The list handling routines */
528 
gl2psListRealloc(GL2PSlist * list,GLint n)529 static void gl2psListRealloc(GL2PSlist *list, GLint n)
530 {
531   if(!list){
532     gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list");
533     return;
534   }
535   if(n <= 0) return;
536   if(!list->array){
537     list->nmax = n;
538     list->array = (char*)gl2psMalloc(list->nmax * list->size);
539   }
540   else{
541     if(n > list->nmax){
542       list->nmax = ((n - 1) / list->incr + 1) * list->incr;
543       list->array = (char*)gl2psRealloc(list->array,
544                                         list->nmax * list->size);
545     }
546   }
547 }
548 
gl2psListCreate(GLint n,GLint incr,GLint size)549 static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size)
550 {
551   GL2PSlist *list;
552 
553   if(n < 0) n = 0;
554   if(incr <= 0) incr = 1;
555   list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist));
556   list->nmax = 0;
557   list->incr = incr;
558   list->size = size;
559   list->n = 0;
560   list->array = NULL;
561   gl2psListRealloc(list, n);
562   return(list);
563 }
564 
gl2psListReset(GL2PSlist * list)565 static void gl2psListReset(GL2PSlist *list)
566 {
567   if(!list) return;
568   list->n = 0;
569 }
570 
gl2psListDelete(GL2PSlist * list)571 static void gl2psListDelete(GL2PSlist *list)
572 {
573   if(!list) return;
574   gl2psFree(list->array);
575   gl2psFree(list);
576 }
577 
gl2psListAdd(GL2PSlist * list,void * data)578 static void gl2psListAdd(GL2PSlist *list, void *data)
579 {
580   if(!list){
581     gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list");
582     return;
583   }
584   list->n++;
585   gl2psListRealloc(list, list->n);
586   memcpy(&list->array[(list->n - 1) * list->size], data, list->size);
587 }
588 
gl2psListNbr(GL2PSlist * list)589 static int gl2psListNbr(GL2PSlist *list)
590 {
591   if(!list)
592     return 0;
593   return(list->n);
594 }
595 
gl2psListPointer(GL2PSlist * list,GLint index)596 static void *gl2psListPointer(GL2PSlist *list, GLint index)
597 {
598   if(!list){
599     gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list");
600     return NULL;
601   }
602   if((index < 0) || (index >= list->n)){
603     gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer");
604     return NULL;
605   }
606   return(&list->array[index * list->size]);
607 }
608 
gl2psListSort(GL2PSlist * list,int (* fcmp)(const void * a,const void * b))609 static void gl2psListSort(GL2PSlist *list,
610                           int (*fcmp)(const void *a, const void *b))
611 {
612   if(!list)
613     return;
614   qsort(list->array, list->n, list->size, fcmp);
615 }
616 
gl2psListAction(GL2PSlist * list,void (* action)(void * data))617 static void gl2psListAction(GL2PSlist *list, void (*action)(void *data))
618 {
619   GLint i;
620 
621   for(i = 0; i < gl2psListNbr(list); i++){
622     (*action)(gl2psListPointer(list, i));
623   }
624 }
625 
gl2psListActionInverse(GL2PSlist * list,void (* action)(void * data))626 static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data))
627 {
628   GLint i;
629 
630   for(i = gl2psListNbr(list); i > 0; i--){
631     (*action)(gl2psListPointer(list, i-1));
632   }
633 }
634 
635 #if defined(GL2PS_HAVE_LIBPNG)
636 
gl2psListRead(GL2PSlist * list,int index,void * data)637 static void gl2psListRead(GL2PSlist *list, int index, void *data)
638 {
639   if((index < 0) || (index >= list->n))
640     gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead");
641   memcpy(data, &list->array[index * list->size], list->size);
642 }
643 
gl2psEncodeBase64Block(unsigned char in[3],unsigned char out[4],int len)644 static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len)
645 {
646   static const char cb64[] =
647     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
648 
649   out[0] = cb64[ in[0] >> 2 ];
650   out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
651   out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=';
652   out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '=';
653 }
654 
gl2psListEncodeBase64(GL2PSlist * list)655 static void gl2psListEncodeBase64(GL2PSlist *list)
656 {
657   unsigned char *buffer, in[3], out[4];
658   int i, n, index, len;
659 
660   n = list->n * list->size;
661   buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned char));
662   memcpy(buffer, list->array, n * sizeof(unsigned char));
663   gl2psListReset(list);
664 
665   index = 0;
666   while(index < n) {
667     len = 0;
668     for(i = 0; i < 3; i++) {
669       if(index < n){
670         in[i] = buffer[index];
671         len++;
672       }
673       else{
674         in[i] = 0;
675       }
676       index++;
677     }
678     if(len) {
679       gl2psEncodeBase64Block(in, out, len);
680       for(i = 0; i < 4; i++)
681         gl2psListAdd(list, &out[i]);
682     }
683   }
684   gl2psFree(buffer);
685 }
686 
687 #endif
688 
689 /* Helpers for rgba colors */
690 
gl2psSameColor(GL2PSrgba rgba1,GL2PSrgba rgba2)691 static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2)
692 {
693   if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) ||
694      !GL2PS_ZERO(rgba1[1] - rgba2[1]) ||
695      !GL2PS_ZERO(rgba1[2] - rgba2[2]))
696     return GL_FALSE;
697   return GL_TRUE;
698 }
699 
gl2psVertsSameColor(const GL2PSprimitive * prim)700 static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim)
701 {
702   int i;
703 
704   for(i = 1; i < prim->numverts; i++){
705     if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){
706       return GL_FALSE;
707     }
708   }
709   return GL_TRUE;
710 }
711 
gl2psSameColorThreshold(int n,GL2PSrgba rgba[],GL2PSrgba threshold)712 static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[],
713                                          GL2PSrgba threshold)
714 {
715   int i;
716 
717   if(n < 2) return GL_TRUE;
718 
719   for(i = 1; i < n; i++){
720     if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] ||
721        fabs(rgba[0][1] - rgba[i][1]) > threshold[1] ||
722        fabs(rgba[0][2] - rgba[i][2]) > threshold[2])
723       return GL_FALSE;
724   }
725 
726   return GL_TRUE;
727 }
728 
gl2psSetLastColor(GL2PSrgba rgba)729 static void gl2psSetLastColor(GL2PSrgba rgba)
730 {
731   int i;
732   for(i = 0; i < 3; ++i){
733     gl2ps->lastrgba[i] = rgba[i];
734   }
735 }
736 
gl2psGetRGB(GL2PSimage * im,GLuint x,GLuint y,GLfloat * red,GLfloat * green,GLfloat * blue)737 static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y,
738                            GLfloat *red, GLfloat *green, GLfloat *blue)
739 {
740 
741   GLsizei width = im->width;
742   GLsizei height = im->height;
743   GLfloat *pixels = im->pixels;
744   GLfloat *pimag;
745 
746   /* OpenGL image is from down to up, PS image is up to down */
747   switch(im->format){
748   case GL_RGBA:
749     pimag = pixels + 4 * (width * (height - 1 - y) + x);
750     break;
751   case GL_RGB:
752   default:
753     pimag = pixels + 3 * (width * (height - 1 - y) + x);
754     break;
755   }
756   *red = *pimag; pimag++;
757   *green = *pimag; pimag++;
758   *blue = *pimag; pimag++;
759 
760   return (im->format == GL_RGBA) ? *pimag : 1.0F;
761 }
762 
763 /* Helper routines for pixmaps */
764 
gl2psCopyPixmap(GL2PSimage * im)765 static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im)
766 {
767   int size;
768   GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
769 
770   image->width = im->width;
771   image->height = im->height;
772   image->format = im->format;
773   image->type = im->type;
774 
775   switch(image->format){
776   case GL_RGBA:
777     size = image->height * image->width * 4 * sizeof(GLfloat);
778     break;
779   case GL_RGB:
780   default:
781     size = image->height * image->width * 3 * sizeof(GLfloat);
782     break;
783   }
784 
785   image->pixels = (GLfloat*)gl2psMalloc(size);
786   memcpy(image->pixels, im->pixels, size);
787 
788   return image;
789 }
790 
gl2psFreePixmap(GL2PSimage * im)791 static void gl2psFreePixmap(GL2PSimage *im)
792 {
793   if(!im)
794     return;
795   gl2psFree(im->pixels);
796   gl2psFree(im);
797 }
798 
799 #if defined(GL2PS_HAVE_LIBPNG)
800 
801 #if !defined(png_jmpbuf)
802 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
803 #endif
804 
gl2psUserWritePNG(png_structp png_ptr,png_bytep data,png_size_t length)805 static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length)
806 {
807   unsigned int i;
808   GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr);
809   for(i = 0; i < length; i++)
810     gl2psListAdd(png, &data[i]);
811 }
812 
gl2psUserFlushPNG(png_structp png_ptr)813 static void gl2psUserFlushPNG(png_structp png_ptr)
814 {
815 }
816 
gl2psConvertPixmapToPNG(GL2PSimage * pixmap,GL2PSlist * png)817 static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png)
818 {
819   png_structp png_ptr;
820   png_infop info_ptr;
821   unsigned char *row_data;
822   GLfloat dr, dg, db;
823   int row, col;
824 
825   if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
826     return;
827 
828   if(!(info_ptr = png_create_info_struct(png_ptr))){
829     png_destroy_write_struct(&png_ptr, NULL);
830     return;
831   }
832 
833   if(setjmp(png_jmpbuf(png_ptr))) {
834     png_destroy_write_struct(&png_ptr, &info_ptr);
835     return;
836   }
837 
838   png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG);
839   png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
840   png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8,
841                PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
842                PNG_FILTER_TYPE_BASE);
843   png_write_info(png_ptr, info_ptr);
844 
845   row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char));
846   for(row = 0; row < pixmap->height; row++){
847     for(col = 0; col < pixmap->width; col++){
848       gl2psGetRGB(pixmap, col, row, &dr, &dg, &db);
849       row_data[3*col] = (unsigned char)(255. * dr);
850       row_data[3*col+1] = (unsigned char)(255. * dg);
851       row_data[3*col+2] = (unsigned char)(255. * db);
852     }
853     png_write_row(png_ptr, (png_bytep)row_data);
854   }
855   gl2psFree(row_data);
856 
857   png_write_end(png_ptr, info_ptr);
858   png_destroy_write_struct(&png_ptr, &info_ptr);
859 }
860 
861 #endif
862 
863 /* Helper routines for text strings */
864 
gl2psAddText(GLint type,const char * str,const char * fontname,GLshort fontsize,GLint alignment,GLfloat angle)865 static GLint gl2psAddText(GLint type, const char *str, const char *fontname,
866                           GLshort fontsize, GLint alignment, GLfloat angle)
867 {
868   GLfloat pos[4];
869   GL2PSprimitive *prim;
870   GLboolean valid;
871 
872   if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED;
873 
874   if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS;
875 
876   glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
877   if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
878 
879   glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
880 
881   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
882   prim->type = type;
883   prim->boundary = 0;
884   prim->numverts = 1;
885   prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
886   prim->verts[0].xyz[0] = pos[0];
887   prim->verts[0].xyz[1] = pos[1];
888   prim->verts[0].xyz[2] = pos[2];
889   prim->culled = 0;
890   prim->offset = 0;
891   prim->pattern = 0;
892   prim->factor = 0;
893   prim->width = 1;
894   glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
895   prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
896   prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char));
897   strcpy(prim->data.text->str, str);
898   prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char));
899   strcpy(prim->data.text->fontname, fontname);
900   prim->data.text->fontsize = fontsize;
901   prim->data.text->alignment = alignment;
902   prim->data.text->angle = angle;
903 
904   gl2psListAdd(gl2ps->auxprimitives, &prim);
905   glPassThrough(GL2PS_TEXT_TOKEN);
906 
907   return GL2PS_SUCCESS;
908 }
909 
gl2psCopyText(GL2PSstring * t)910 static GL2PSstring *gl2psCopyText(GL2PSstring *t)
911 {
912   GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
913   text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char));
914   strcpy(text->str, t->str);
915   text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char));
916   strcpy(text->fontname, t->fontname);
917   text->fontsize = t->fontsize;
918   text->alignment = t->alignment;
919   text->angle = t->angle;
920 
921   return text;
922 }
923 
gl2psFreeText(GL2PSstring * text)924 static void gl2psFreeText(GL2PSstring *text)
925 {
926   if(!text)
927     return;
928   gl2psFree(text->str);
929   gl2psFree(text->fontname);
930   gl2psFree(text);
931 }
932 
933 /* Helpers for blending modes */
934 
gl2psSupportedBlendMode(GLenum sfactor,GLenum dfactor)935 static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor)
936 {
937   /* returns TRUE if gl2ps supports the argument combination: only two
938      blending modes have been implemented so far */
939 
940   if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) ||
941       (sfactor == GL_ONE && dfactor == GL_ZERO) )
942     return GL_TRUE;
943   return GL_FALSE;
944 }
945 
gl2psAdaptVertexForBlending(GL2PSvertex * v)946 static void gl2psAdaptVertexForBlending(GL2PSvertex *v)
947 {
948   /* Transforms vertex depending on the actual blending function -
949      currently the vertex v is considered as source vertex and his
950      alpha value is changed to 1.0 if source blending GL_ONE is
951      active. This might be extended in the future */
952 
953   if(!v || !gl2ps)
954     return;
955 
956   if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
957     v->rgba[3] = 1.0F;
958     return;
959   }
960 
961   switch(gl2ps->blendfunc[0]){
962   case GL_ONE:
963     v->rgba[3] = 1.0F;
964     break;
965   default:
966     break;
967   }
968 }
969 
gl2psAssignTriangleProperties(GL2PStriangle * t)970 static void gl2psAssignTriangleProperties(GL2PStriangle *t)
971 {
972   /* int i; */
973 
974   t->prop = T_VAR_COLOR;
975 
976   /* Uncommenting the following lines activates an even more fine
977      grained distinction between triangle types - please don't delete,
978      a remarkable amount of PDF handling code inside this file depends
979      on it if activated */
980   /*
981   t->prop = T_CONST_COLOR;
982   for(i = 0; i < 3; ++i){
983     if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) ||
984        !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){
985       t->prop = T_VAR_COLOR;
986       break;
987     }
988   }
989   */
990 
991   if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) ||
992      !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){
993     t->prop |= T_VAR_ALPHA;
994   }
995   else{
996     if(t->vertex[0].rgba[3] < 1)
997       t->prop |= T_ALPHA_LESS_1;
998     else
999       t->prop |= T_ALPHA_1;
1000   }
1001 }
1002 
gl2psFillTriangleFromPrimitive(GL2PStriangle * t,GL2PSprimitive * p,GLboolean assignprops)1003 static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p,
1004                                            GLboolean assignprops)
1005 {
1006   t->vertex[0] = p->verts[0];
1007   t->vertex[1] = p->verts[1];
1008   t->vertex[2] = p->verts[2];
1009   if(GL_TRUE == assignprops)
1010     gl2psAssignTriangleProperties(t);
1011 }
1012 
gl2psInitTriangle(GL2PStriangle * t)1013 static void gl2psInitTriangle(GL2PStriangle *t)
1014 {
1015   int i;
1016   GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} };
1017   for(i = 0; i < 3; i++)
1018     t->vertex[i] = vertex;
1019   t->prop = T_UNDEFINED;
1020 }
1021 
1022 /* Miscellaneous helper routines */
1023 
gl2psCopyPrimitive(GL2PSprimitive * p)1024 static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p)
1025 {
1026   GL2PSprimitive *prim;
1027 
1028   if(!p){
1029     gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive");
1030     return NULL;
1031   }
1032 
1033   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1034 
1035   prim->type = p->type;
1036   prim->numverts = p->numverts;
1037   prim->boundary = p->boundary;
1038   prim->offset = p->offset;
1039   prim->pattern = p->pattern;
1040   prim->factor = p->factor;
1041   prim->culled = p->culled;
1042   prim->width = p->width;
1043   prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex));
1044   memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex));
1045 
1046   switch(prim->type){
1047   case GL2PS_PIXMAP :
1048     prim->data.image = gl2psCopyPixmap(p->data.image);
1049     break;
1050   case GL2PS_TEXT :
1051   case GL2PS_SPECIAL :
1052     prim->data.text = gl2psCopyText(p->data.text);
1053     break;
1054   default:
1055     break;
1056   }
1057 
1058   return prim;
1059 }
1060 
gl2psSamePosition(GL2PSxyz p1,GL2PSxyz p2)1061 static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2)
1062 {
1063   if(!GL2PS_ZERO(p1[0] - p2[0]) ||
1064      !GL2PS_ZERO(p1[1] - p2[1]) ||
1065      !GL2PS_ZERO(p1[2] - p2[2]))
1066     return GL_FALSE;
1067   return GL_TRUE;
1068 }
1069 
1070 /*********************************************************************
1071  *
1072  * 3D sorting routines
1073  *
1074  *********************************************************************/
1075 
gl2psComparePointPlane(GL2PSxyz point,GL2PSplane plane)1076 static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane)
1077 {
1078   return(plane[0] * point[0] +
1079          plane[1] * point[1] +
1080          plane[2] * point[2] +
1081          plane[3]);
1082 }
1083 
gl2psPsca(GLfloat * a,GLfloat * b)1084 static GLfloat gl2psPsca(GLfloat *a, GLfloat *b)
1085 {
1086   return(a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
1087 }
1088 
gl2psPvec(GLfloat * a,GLfloat * b,GLfloat * c)1089 static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c)
1090 {
1091   c[0] = a[1]*b[2] - a[2]*b[1];
1092   c[1] = a[2]*b[0] - a[0]*b[2];
1093   c[2] = a[0]*b[1] - a[1]*b[0];
1094 }
1095 
gl2psNorm(GLfloat * a)1096 static GLfloat gl2psNorm(GLfloat *a)
1097 {
1098   return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
1099 }
1100 
gl2psGetNormal(GLfloat * a,GLfloat * b,GLfloat * c)1101 static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c)
1102 {
1103   GLfloat norm;
1104 
1105   gl2psPvec(a, b, c);
1106   if(!GL2PS_ZERO(norm = gl2psNorm(c))){
1107     c[0] = c[0] / norm;
1108     c[1] = c[1] / norm;
1109     c[2] = c[2] / norm;
1110   }
1111   else{
1112     /* The plane is still wrong despite our tests in gl2psGetPlane.
1113        Let's return a dummy value for now (this is a hack: we should
1114        do more intelligent tests in GetPlane) */
1115     c[0] = c[1] = 0.0F;
1116     c[2] = 1.0F;
1117   }
1118 }
1119 
gl2psGetPlane(GL2PSprimitive * prim,GL2PSplane plane)1120 static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane)
1121 {
1122   GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F};
1123 
1124   switch(prim->type){
1125   case GL2PS_TRIANGLE :
1126   case GL2PS_QUADRANGLE :
1127     v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0];
1128     v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1];
1129     v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2];
1130     w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0];
1131     w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1];
1132     w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2];
1133     if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) ||
1134        (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){
1135       plane[0] = plane[1] = 0.0F;
1136       plane[2] = 1.0F;
1137       plane[3] = -prim->verts[0].xyz[2];
1138     }
1139     else{
1140       gl2psGetNormal(v, w, plane);
1141       plane[3] =
1142         - plane[0] * prim->verts[0].xyz[0]
1143         - plane[1] * prim->verts[0].xyz[1]
1144         - plane[2] * prim->verts[0].xyz[2];
1145     }
1146     break;
1147   case GL2PS_LINE :
1148     v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0];
1149     v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1];
1150     v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2];
1151     if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){
1152       plane[0] = plane[1] = 0.0F;
1153       plane[2] = 1.0F;
1154       plane[3] = -prim->verts[0].xyz[2];
1155     }
1156     else{
1157       if(GL2PS_ZERO(v[0]))      w[0] = 1.0F;
1158       else if(GL2PS_ZERO(v[1])) w[1] = 1.0F;
1159       else                      w[2] = 1.0F;
1160       gl2psGetNormal(v, w, plane);
1161       plane[3] =
1162         - plane[0] * prim->verts[0].xyz[0]
1163         - plane[1] * prim->verts[0].xyz[1]
1164         - plane[2] * prim->verts[0].xyz[2];
1165     }
1166     break;
1167   case GL2PS_POINT :
1168   case GL2PS_PIXMAP :
1169   case GL2PS_TEXT :
1170   case GL2PS_SPECIAL :
1171   case GL2PS_IMAGEMAP:
1172     plane[0] = plane[1] = 0.0F;
1173     plane[2] = 1.0F;
1174     plane[3] = -prim->verts[0].xyz[2];
1175     break;
1176   default :
1177     gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree");
1178     plane[0] = plane[1] = plane[3] = 0.0F;
1179     plane[2] = 1.0F;
1180     break;
1181   }
1182 }
1183 
gl2psCutEdge(GL2PSvertex * a,GL2PSvertex * b,GL2PSplane plane,GL2PSvertex * c)1184 static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane,
1185                          GL2PSvertex *c)
1186 {
1187   GL2PSxyz v;
1188   GLfloat sect, psca;
1189 
1190   v[0] = b->xyz[0] - a->xyz[0];
1191   v[1] = b->xyz[1] - a->xyz[1];
1192   v[2] = b->xyz[2] - a->xyz[2];
1193 
1194   if(!GL2PS_ZERO(psca = gl2psPsca(plane, v)))
1195     sect = -gl2psComparePointPlane(a->xyz, plane) / psca;
1196   else
1197     sect = 0.0F;
1198 
1199   c->xyz[0] = a->xyz[0] + v[0] * sect;
1200   c->xyz[1] = a->xyz[1] + v[1] * sect;
1201   c->xyz[2] = a->xyz[2] + v[2] * sect;
1202 
1203   c->rgba[0] = (1 - sect) * a->rgba[0] + sect * b->rgba[0];
1204   c->rgba[1] = (1 - sect) * a->rgba[1] + sect * b->rgba[1];
1205   c->rgba[2] = (1 - sect) * a->rgba[2] + sect * b->rgba[2];
1206   c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3];
1207 }
1208 
gl2psCreateSplitPrimitive(GL2PSprimitive * parent,GL2PSplane plane,GL2PSprimitive * child,GLshort numverts,GLshort * index0,GLshort * index1)1209 static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane,
1210                                       GL2PSprimitive *child, GLshort numverts,
1211                                       GLshort *index0, GLshort *index1)
1212 {
1213   GLshort i;
1214 
1215   if(parent->type == GL2PS_IMAGEMAP){
1216     child->type = GL2PS_IMAGEMAP;
1217     child->data.image = parent->data.image;
1218   }
1219   else{
1220     if(numverts > 4){
1221       gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts);
1222       numverts = 4;
1223     }
1224     switch(numverts){
1225     case 1 : child->type = GL2PS_POINT; break;
1226     case 2 : child->type = GL2PS_LINE; break;
1227     case 3 : child->type = GL2PS_TRIANGLE; break;
1228     case 4 : child->type = GL2PS_QUADRANGLE; break;
1229     default: child->type = GL2PS_NO_TYPE; break;
1230     }
1231   }
1232 
1233   child->boundary = 0; /* FIXME: not done! */
1234   child->culled = parent->culled;
1235   child->offset = parent->offset;
1236   child->pattern = parent->pattern;
1237   child->factor = parent->factor;
1238   child->width = parent->width;
1239   child->numverts = numverts;
1240   child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
1241 
1242   for(i = 0; i < numverts; i++){
1243     if(index1[i] < 0){
1244       child->verts[i] = parent->verts[index0[i]];
1245     }
1246     else{
1247       gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]],
1248                    plane, &child->verts[i]);
1249     }
1250   }
1251 }
1252 
gl2psAddIndex(GLshort * index0,GLshort * index1,GLshort * nb,GLshort i,GLshort j)1253 static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb,
1254                           GLshort i, GLshort j)
1255 {
1256   GLint k;
1257 
1258   for(k = 0; k < *nb; k++){
1259     if((index0[k] == i && index1[k] == j) ||
1260        (index1[k] == i && index0[k] == j)) return;
1261   }
1262   index0[*nb] = i;
1263   index1[*nb] = j;
1264   (*nb)++;
1265 }
1266 
gl2psGetIndex(GLshort i,GLshort num)1267 static GLshort gl2psGetIndex(GLshort i, GLshort num)
1268 {
1269   return (i < num - 1) ? i + 1 : 0;
1270 }
1271 
gl2psTestSplitPrimitive(GL2PSprimitive * prim,GL2PSplane plane)1272 static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane)
1273 {
1274   GLint type = GL2PS_COINCIDENT;
1275   GLshort i, j;
1276   GLfloat d[5];
1277 
1278   for(i = 0; i < prim->numverts; i++){
1279     d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
1280   }
1281 
1282   if(prim->numverts < 2){
1283     return 0;
1284   }
1285   else{
1286     for(i = 0; i < prim->numverts; i++){
1287       j = gl2psGetIndex(i, prim->numverts);
1288       if(d[j] > GL2PS_EPSILON){
1289         if(type == GL2PS_COINCIDENT)      type = GL2PS_IN_BACK_OF;
1290         else if(type != GL2PS_IN_BACK_OF) return 1;
1291         if(d[i] < -GL2PS_EPSILON)         return 1;
1292       }
1293       else if(d[j] < -GL2PS_EPSILON){
1294         if(type == GL2PS_COINCIDENT)       type = GL2PS_IN_FRONT_OF;
1295         else if(type != GL2PS_IN_FRONT_OF) return 1;
1296         if(d[i] > GL2PS_EPSILON)           return 1;
1297       }
1298     }
1299   }
1300   return 0;
1301 }
1302 
gl2psSplitPrimitive(GL2PSprimitive * prim,GL2PSplane plane,GL2PSprimitive ** front,GL2PSprimitive ** back)1303 static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane,
1304                                  GL2PSprimitive **front, GL2PSprimitive **back)
1305 {
1306   GLshort i, j, in = 0, out = 0, in0[5], in1[5], out0[5], out1[5];
1307   GLint type;
1308   GLfloat d[5];
1309 
1310   type = GL2PS_COINCIDENT;
1311 
1312   for(i = 0; i < prim->numverts; i++){
1313     d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
1314   }
1315 
1316   switch(prim->type){
1317   case GL2PS_POINT :
1318     if(d[0] > GL2PS_EPSILON)       type = GL2PS_IN_BACK_OF;
1319     else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF;
1320     else                           type = GL2PS_COINCIDENT;
1321     break;
1322   default :
1323     for(i = 0; i < prim->numverts; i++){
1324       j = gl2psGetIndex(i, prim->numverts);
1325       if(d[j] > GL2PS_EPSILON){
1326         if(type == GL2PS_COINCIDENT)      type = GL2PS_IN_BACK_OF;
1327         else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING;
1328         if(d[i] < -GL2PS_EPSILON){
1329           gl2psAddIndex(in0, in1, &in, i, j);
1330           gl2psAddIndex(out0, out1, &out, i, j);
1331           type = GL2PS_SPANNING;
1332         }
1333         gl2psAddIndex(out0, out1, &out, j, -1);
1334       }
1335       else if(d[j] < -GL2PS_EPSILON){
1336         if(type == GL2PS_COINCIDENT)       type = GL2PS_IN_FRONT_OF;
1337         else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING;
1338         if(d[i] > GL2PS_EPSILON){
1339           gl2psAddIndex(in0, in1, &in, i, j);
1340           gl2psAddIndex(out0, out1, &out, i, j);
1341           type = GL2PS_SPANNING;
1342         }
1343         gl2psAddIndex(in0, in1, &in, j, -1);
1344       }
1345       else{
1346         gl2psAddIndex(in0, in1, &in, j, -1);
1347         gl2psAddIndex(out0, out1, &out, j, -1);
1348       }
1349     }
1350     break;
1351   }
1352 
1353   if(type == GL2PS_SPANNING){
1354     *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1355     *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1356     gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1);
1357     gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1);
1358   }
1359 
1360   return type;
1361 }
1362 
gl2psDivideQuad(GL2PSprimitive * quad,GL2PSprimitive ** t1,GL2PSprimitive ** t2)1363 static void gl2psDivideQuad(GL2PSprimitive *quad,
1364                             GL2PSprimitive **t1, GL2PSprimitive **t2)
1365 {
1366   *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1367   *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1368   (*t1)->type = (*t2)->type = GL2PS_TRIANGLE;
1369   (*t1)->numverts = (*t2)->numverts = 3;
1370   (*t1)->culled = (*t2)->culled = quad->culled;
1371   (*t1)->offset = (*t2)->offset = quad->offset;
1372   (*t1)->pattern = (*t2)->pattern = quad->pattern;
1373   (*t1)->factor = (*t2)->factor = quad->factor;
1374   (*t1)->width = (*t2)->width = quad->width;
1375   (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex));
1376   (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex));
1377   (*t1)->verts[0] = quad->verts[0];
1378   (*t1)->verts[1] = quad->verts[1];
1379   (*t1)->verts[2] = quad->verts[2];
1380   (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0);
1381   (*t2)->verts[0] = quad->verts[0];
1382   (*t2)->verts[1] = quad->verts[2];
1383   (*t2)->verts[2] = quad->verts[3];
1384   (*t2)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 4) ? 2 : 0);
1385 }
1386 
gl2psCompareDepth(const void * a,const void * b)1387 static int gl2psCompareDepth(const void *a, const void *b)
1388 {
1389   GL2PSprimitive *q, *w;
1390   GLfloat dq = 0.0F, dw = 0.0F, diff;
1391   int i;
1392 
1393   q = *(GL2PSprimitive**)a;
1394   w = *(GL2PSprimitive**)b;
1395 
1396   for(i = 0; i < q->numverts; i++){
1397     dq += q->verts[i].xyz[2];
1398   }
1399   dq /= (GLfloat)q->numverts;
1400 
1401   for(i = 0; i < w->numverts; i++){
1402     dw += w->verts[i].xyz[2];
1403   }
1404   dw /= (GLfloat)w->numverts;
1405 
1406   diff = dq - dw;
1407   if(diff > 0.){
1408     return -1;
1409   }
1410   else if(diff < 0.){
1411     return 1;
1412   }
1413   else{
1414     return 0;
1415   }
1416 }
1417 
gl2psTrianglesFirst(const void * a,const void * b)1418 static int gl2psTrianglesFirst(const void *a, const void *b)
1419 {
1420   GL2PSprimitive *q, *w;
1421 
1422   q = *(GL2PSprimitive**)a;
1423   w = *(GL2PSprimitive**)b;
1424   return(q->type < w->type ? 1 : -1);
1425 }
1426 
gl2psFindRoot(GL2PSlist * primitives,GL2PSprimitive ** root)1427 static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root)
1428 {
1429   GLint i, j, count, best = 1000000, index = 0;
1430   GL2PSprimitive *prim1, *prim2;
1431   GL2PSplane plane;
1432   GLint maxp;
1433 
1434   if(!gl2psListNbr(primitives)){
1435     gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list");
1436     return 0;
1437   }
1438 
1439   *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0);
1440 
1441   if(gl2ps->options & GL2PS_BEST_ROOT){
1442     maxp = gl2psListNbr(primitives);
1443     if(maxp > gl2ps->maxbestroot){
1444       maxp = gl2ps->maxbestroot;
1445     }
1446     for(i = 0; i < maxp; i++){
1447       prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i);
1448       gl2psGetPlane(prim1, plane);
1449       count = 0;
1450       for(j = 0; j < gl2psListNbr(primitives); j++){
1451         if(j != i){
1452           prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j);
1453           count += gl2psTestSplitPrimitive(prim2, plane);
1454         }
1455         if(count > best) break;
1456       }
1457       if(count < best){
1458         best = count;
1459         index = i;
1460         *root = prim1;
1461         if(!count) return index;
1462       }
1463     }
1464     /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */
1465     return index;
1466   }
1467   else{
1468     return 0;
1469   }
1470 }
1471 
gl2psFreeImagemap(GL2PSimagemap * list)1472 static void gl2psFreeImagemap(GL2PSimagemap *list){
1473   GL2PSimagemap *next;
1474   while(list != NULL){
1475     next = list->next;
1476     gl2psFree(list->image->pixels);
1477     gl2psFree(list->image);
1478     gl2psFree(list);
1479     list = next;
1480   }
1481 }
1482 
gl2psFreePrimitive(void * data)1483 static void gl2psFreePrimitive(void *data)
1484 {
1485   GL2PSprimitive *q;
1486 
1487   q = *(GL2PSprimitive**)data;
1488   gl2psFree(q->verts);
1489   if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){
1490     gl2psFreeText(q->data.text);
1491   }
1492   else if(q->type == GL2PS_PIXMAP){
1493     gl2psFreePixmap(q->data.image);
1494   }
1495   gl2psFree(q);
1496 }
1497 
gl2psAddPrimitiveInList(GL2PSprimitive * prim,GL2PSlist * list)1498 static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list)
1499 {
1500   GL2PSprimitive *t1, *t2;
1501 
1502   if(prim->type != GL2PS_QUADRANGLE){
1503     gl2psListAdd(list, &prim);
1504   }
1505   else{
1506     gl2psDivideQuad(prim, &t1, &t2);
1507     gl2psListAdd(list, &t1);
1508     gl2psListAdd(list, &t2);
1509     gl2psFreePrimitive(&prim);
1510   }
1511 
1512 }
1513 
gl2psFreeBspTree(GL2PSbsptree ** tree)1514 static void gl2psFreeBspTree(GL2PSbsptree **tree)
1515 {
1516   if(*tree){
1517     if((*tree)->back) gl2psFreeBspTree(&(*tree)->back);
1518     if((*tree)->primitives){
1519       gl2psListAction((*tree)->primitives, gl2psFreePrimitive);
1520       gl2psListDelete((*tree)->primitives);
1521     }
1522     if((*tree)->front) gl2psFreeBspTree(&(*tree)->front);
1523     gl2psFree(*tree);
1524     *tree = NULL;
1525   }
1526 }
1527 
gl2psGreater(GLfloat f1,GLfloat f2)1528 static GLboolean gl2psGreater(GLfloat f1, GLfloat f2)
1529 {
1530   if(f1 > f2) return GL_TRUE;
1531   else return GL_FALSE;
1532 }
1533 
gl2psLess(GLfloat f1,GLfloat f2)1534 static GLboolean gl2psLess(GLfloat f1, GLfloat f2)
1535 {
1536   if(f1 < f2) return GL_TRUE;
1537   else return GL_FALSE;
1538 }
1539 
gl2psBuildBspTree(GL2PSbsptree * tree,GL2PSlist * primitives)1540 static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives)
1541 {
1542   GL2PSprimitive *prim, *frontprim = NULL, *backprim = NULL;
1543   GL2PSlist *frontlist, *backlist;
1544   GLint i, index;
1545 
1546   tree->front = NULL;
1547   tree->back = NULL;
1548   tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
1549   index = gl2psFindRoot(primitives, &prim);
1550   gl2psGetPlane(prim, tree->plane);
1551   gl2psAddPrimitiveInList(prim, tree->primitives);
1552 
1553   frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
1554   backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
1555 
1556   for(i = 0; i < gl2psListNbr(primitives); i++){
1557     if(i != index){
1558       prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i);
1559       switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){
1560       case GL2PS_COINCIDENT:
1561         gl2psAddPrimitiveInList(prim, tree->primitives);
1562         break;
1563       case GL2PS_IN_BACK_OF:
1564         gl2psAddPrimitiveInList(prim, backlist);
1565         break;
1566       case GL2PS_IN_FRONT_OF:
1567         gl2psAddPrimitiveInList(prim, frontlist);
1568         break;
1569       case GL2PS_SPANNING:
1570         gl2psAddPrimitiveInList(backprim, backlist);
1571         gl2psAddPrimitiveInList(frontprim, frontlist);
1572         gl2psFreePrimitive(&prim);
1573         break;
1574       }
1575     }
1576   }
1577 
1578   if(gl2psListNbr(tree->primitives)){
1579     gl2psListSort(tree->primitives, gl2psTrianglesFirst);
1580   }
1581 
1582   if(gl2psListNbr(frontlist)){
1583     gl2psListSort(frontlist, gl2psTrianglesFirst);
1584     tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
1585     gl2psBuildBspTree(tree->front, frontlist);
1586   }
1587   else{
1588     gl2psListDelete(frontlist);
1589   }
1590 
1591   if(gl2psListNbr(backlist)){
1592     gl2psListSort(backlist, gl2psTrianglesFirst);
1593     tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
1594     gl2psBuildBspTree(tree->back, backlist);
1595   }
1596   else{
1597     gl2psListDelete(backlist);
1598   }
1599 
1600   gl2psListDelete(primitives);
1601 }
1602 
gl2psTraverseBspTree(GL2PSbsptree * tree,GL2PSxyz eye,GLfloat epsilon,GLboolean (* compare)(GLfloat f1,GLfloat f2),void (* action)(void * data),int inverse)1603 static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon,
1604                                  GLboolean (*compare)(GLfloat f1, GLfloat f2),
1605                                  void (*action)(void *data), int inverse)
1606 {
1607   GLfloat result;
1608 
1609   if(!tree) return;
1610 
1611   result = gl2psComparePointPlane(eye, tree->plane);
1612 
1613   if(GL_TRUE == compare(result, epsilon)){
1614     gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
1615     if(inverse){
1616       gl2psListActionInverse(tree->primitives, action);
1617     }
1618     else{
1619       gl2psListAction(tree->primitives, action);
1620     }
1621     gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
1622   }
1623   else if(GL_TRUE == compare(-epsilon, result)){
1624     gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
1625     if(inverse){
1626       gl2psListActionInverse(tree->primitives, action);
1627     }
1628     else{
1629       gl2psListAction(tree->primitives, action);
1630     }
1631     gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
1632   }
1633   else{
1634     gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
1635     gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
1636   }
1637 }
1638 
gl2psRescaleAndOffset()1639 static void gl2psRescaleAndOffset()
1640 {
1641   GL2PSprimitive *prim;
1642   GLfloat minZ, maxZ, rangeZ, scaleZ;
1643   GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ;
1644   int i, j;
1645 
1646   if(!gl2psListNbr(gl2ps->primitives))
1647     return;
1648 
1649   /* get z-buffer range */
1650   prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, 0);
1651   minZ = maxZ = prim->verts[0].xyz[2];
1652   for(i = 1; i < prim->numverts; i++){
1653     if(prim->verts[i].xyz[2] < minZ) minZ = prim->verts[i].xyz[2];
1654     if(prim->verts[i].xyz[2] > maxZ) maxZ = prim->verts[i].xyz[2];
1655   }
1656   for(i = 1; i < gl2psListNbr(gl2ps->primitives); i++){
1657     prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i);
1658     for(j = 0; j < prim->numverts; j++){
1659       if(prim->verts[j].xyz[2] < minZ) minZ = prim->verts[j].xyz[2];
1660       if(prim->verts[j].xyz[2] > maxZ) maxZ = prim->verts[j].xyz[2];
1661     }
1662   }
1663   rangeZ = (maxZ - minZ);
1664 
1665   /* rescale z-buffer coordinate in [0,GL2PS_ZSCALE], to make it of
1666      the same order of magnitude as the x and y coordinates */
1667   scaleZ = GL2PS_ZERO(rangeZ) ? GL2PS_ZSCALE : (GL2PS_ZSCALE / rangeZ);
1668   /* avoid precision loss (we use floats!) */
1669   if(scaleZ > 100000.F) scaleZ = 100000.F;
1670 
1671   /* apply offsets */
1672   for(i = 0; i < gl2psListNbr(gl2ps->primitives); i++){
1673     prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i);
1674     for(j = 0; j < prim->numverts; j++){
1675       prim->verts[j].xyz[2] = (prim->verts[j].xyz[2] - minZ) * scaleZ;
1676     }
1677     if((gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET) &&
1678        (prim->type == GL2PS_LINE)){
1679       if(gl2ps->sort == GL2PS_SIMPLE_SORT){
1680         prim->verts[0].xyz[2] -= GL2PS_ZOFFSET_LARGE;
1681         prim->verts[1].xyz[2] -= GL2PS_ZOFFSET_LARGE;
1682       }
1683       else{
1684         prim->verts[0].xyz[2] -= GL2PS_ZOFFSET;
1685         prim->verts[1].xyz[2] -= GL2PS_ZOFFSET;
1686       }
1687     }
1688     else if(prim->offset && (prim->type == GL2PS_TRIANGLE)){
1689       factor = gl2ps->offset[0];
1690       units = gl2ps->offset[1];
1691       area =
1692         (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) *
1693         (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) -
1694         (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) *
1695         (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]);
1696       if(!GL2PS_ZERO(area)){
1697       dZdX =
1698         ((prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) *
1699          (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) -
1700          (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) *
1701          (prim->verts[2].xyz[2] - prim->verts[1].xyz[2])) / area;
1702       dZdY =
1703         ((prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) *
1704          (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) -
1705          (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) *
1706          (prim->verts[1].xyz[2] - prim->verts[0].xyz[2])) / area;
1707       maxdZ = (GLfloat)sqrt(dZdX * dZdX + dZdY * dZdY);
1708       }
1709       else{
1710         maxdZ = 0.0F;
1711       }
1712       dZ = factor * maxdZ + units;
1713       prim->verts[0].xyz[2] += dZ;
1714       prim->verts[1].xyz[2] += dZ;
1715       prim->verts[2].xyz[2] += dZ;
1716     }
1717   }
1718 }
1719 
1720 /*********************************************************************
1721  *
1722  * 2D sorting routines (for occlusion culling)
1723  *
1724  *********************************************************************/
1725 
gl2psGetPlaneFromPoints(GL2PSxyz a,GL2PSxyz b,GL2PSplane plane)1726 static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane)
1727 {
1728   GLfloat n;
1729 
1730   plane[0] = b[1] - a[1];
1731   plane[1] = a[0] - b[0];
1732   n = (GLfloat)sqrt(plane[0]*plane[0] + plane[1]*plane[1]);
1733   plane[2] = 0.0F;
1734   if(!GL2PS_ZERO(n)){
1735     plane[0] /= n;
1736     plane[1] /= n;
1737     plane[3] = -plane[0]*a[0]-plane[1]*a[1];
1738     return 1;
1739   }
1740   else{
1741     plane[0] = -1.0F;
1742     plane[1] = 0.0F;
1743     plane[3] = a[0];
1744     return 0;
1745   }
1746 }
1747 
gl2psFreeBspImageTree(GL2PSbsptree2d ** tree)1748 static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree)
1749 {
1750   if(*tree){
1751     if((*tree)->back)  gl2psFreeBspImageTree(&(*tree)->back);
1752     if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front);
1753     gl2psFree(*tree);
1754     *tree = NULL;
1755   }
1756 }
1757 
gl2psCheckPoint(GL2PSxyz point,GL2PSplane plane)1758 static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane)
1759 {
1760   GLfloat pt_dis;
1761 
1762   pt_dis = gl2psComparePointPlane(point, plane);
1763   if(pt_dis > GL2PS_EPSILON)        return GL2PS_POINT_INFRONT;
1764   else if(pt_dis < -GL2PS_EPSILON)  return GL2PS_POINT_BACK;
1765   else                              return GL2PS_POINT_COINCIDENT;
1766 }
1767 
gl2psAddPlanesInBspTreeImage(GL2PSprimitive * prim,GL2PSbsptree2d ** tree)1768 static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim,
1769                                          GL2PSbsptree2d **tree)
1770 {
1771   GLint ret = 0;
1772   GLint i;
1773   GLint offset = 0;
1774   GL2PSbsptree2d *head = NULL, *cur = NULL;
1775 
1776   if((*tree == NULL) && (prim->numverts > 2)){
1777     /* don't cull if transparent
1778     for(i = 0; i < prim->numverts - 1; i++)
1779       if(prim->verts[i].rgba[3] < 1.0F) return;
1780     */
1781     head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1782     for(i = 0; i < prim->numverts-1; i++){
1783       if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz,
1784                                   prim->verts[i+1].xyz,
1785                                   head->plane)){
1786         if(prim->numverts-i > 3){
1787           offset++;
1788         }
1789         else{
1790           gl2psFree(head);
1791           return;
1792         }
1793       }
1794       else{
1795         break;
1796       }
1797     }
1798     head->back = NULL;
1799     head->front = NULL;
1800     for(i = 2+offset; i < prim->numverts; i++){
1801       ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane);
1802       if(ret != GL2PS_POINT_COINCIDENT) break;
1803     }
1804     switch(ret){
1805     case GL2PS_POINT_INFRONT :
1806       cur = head;
1807       for(i = 1+offset; i < prim->numverts-1; i++){
1808         if(cur->front == NULL){
1809           cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1810         }
1811         if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
1812                                    prim->verts[i+1].xyz,
1813                                    cur->front->plane)){
1814           cur = cur->front;
1815           cur->front = NULL;
1816           cur->back = NULL;
1817         }
1818       }
1819       if(cur->front == NULL){
1820         cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1821       }
1822       if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
1823                                  prim->verts[offset].xyz,
1824                                  cur->front->plane)){
1825         cur->front->front = NULL;
1826         cur->front->back = NULL;
1827       }
1828       else{
1829         gl2psFree(cur->front);
1830         cur->front = NULL;
1831       }
1832       break;
1833     case GL2PS_POINT_BACK :
1834       for(i = 0; i < 4; i++){
1835         head->plane[i] = -head->plane[i];
1836       }
1837       cur = head;
1838       for(i = 1+offset; i < prim->numverts-1; i++){
1839         if(cur->front == NULL){
1840           cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1841         }
1842         if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz,
1843                                    prim->verts[i].xyz,
1844                                    cur->front->plane)){
1845           cur = cur->front;
1846           cur->front = NULL;
1847           cur->back = NULL;
1848         }
1849       }
1850       if(cur->front == NULL){
1851         cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1852       }
1853       if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz,
1854                                  prim->verts[i].xyz,
1855                                  cur->front->plane)){
1856         cur->front->front = NULL;
1857         cur->front->back = NULL;
1858       }
1859       else{
1860         gl2psFree(cur->front);
1861         cur->front = NULL;
1862       }
1863       break;
1864     default:
1865       gl2psFree(head);
1866       return;
1867     }
1868     (*tree) = head;
1869   }
1870 }
1871 
gl2psCheckPrimitive(GL2PSprimitive * prim,GL2PSplane plane)1872 static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane)
1873 {
1874   GLint i;
1875   GLint pos;
1876 
1877   pos = gl2psCheckPoint(prim->verts[0].xyz, plane);
1878   for(i = 1; i < prim->numverts; i++){
1879     pos |= gl2psCheckPoint(prim->verts[i].xyz, plane);
1880     if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING;
1881   }
1882   if(pos & GL2PS_POINT_INFRONT)   return GL2PS_IN_FRONT_OF;
1883   else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF;
1884   else                            return GL2PS_COINCIDENT;
1885 }
1886 
gl2psCreateSplitPrimitive2D(GL2PSprimitive * parent,GLshort numverts,GL2PSvertex * vertx)1887 static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent,
1888                                                    GLshort numverts,
1889                                                    GL2PSvertex *vertx)
1890 {
1891   GLint i;
1892   GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1893 
1894   if(parent->type == GL2PS_IMAGEMAP){
1895     child->type = GL2PS_IMAGEMAP;
1896     child->data.image = parent->data.image;
1897   }
1898   else {
1899     switch(numverts){
1900     case 1 : child->type = GL2PS_POINT; break;
1901     case 2 : child->type = GL2PS_LINE; break;
1902     case 3 : child->type = GL2PS_TRIANGLE; break;
1903     case 4 : child->type = GL2PS_QUADRANGLE; break;
1904     default: child->type = GL2PS_NO_TYPE; break; /* FIXME */
1905     }
1906   }
1907   child->boundary = 0; /* FIXME: not done! */
1908   child->culled = parent->culled;
1909   child->offset = parent->offset;
1910   child->pattern = parent->pattern;
1911   child->factor = parent->factor;
1912   child->width = parent->width;
1913   child->numverts = numverts;
1914   child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
1915   for(i = 0; i < numverts; i++){
1916     child->verts[i] = vertx[i];
1917   }
1918   return child;
1919 }
1920 
gl2psSplitPrimitive2D(GL2PSprimitive * prim,GL2PSplane plane,GL2PSprimitive ** front,GL2PSprimitive ** back)1921 static void gl2psSplitPrimitive2D(GL2PSprimitive *prim,
1922                                   GL2PSplane plane,
1923                                   GL2PSprimitive **front,
1924                                   GL2PSprimitive **back)
1925 {
1926   /* cur will hold the position of the current vertex
1927      prev will hold the position of the previous vertex
1928      prev0 will hold the position of the vertex number 0
1929      v1 and v2 represent the current and previous vertices, respectively
1930      flag is set if the current vertex should be checked against the plane */
1931   GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1;
1932 
1933   /* list of vertices that will go in front and back primitive */
1934   GL2PSvertex *front_list = NULL, *back_list = NULL;
1935 
1936   /* number of vertices in front and back list */
1937   GLshort front_count = 0, back_count = 0;
1938 
1939   for(i = 0; i <= prim->numverts; i++){
1940     v1 = i;
1941     if(v1 == prim->numverts){
1942       if(prim->numverts < 3) break;
1943       v1 = 0;
1944       v2 = prim->numverts-1;
1945       cur = prev0;
1946     }
1947     else if(flag){
1948       cur = gl2psCheckPoint(prim->verts[v1].xyz, plane);
1949       if(i == 0){
1950         prev0 = cur;
1951       }
1952     }
1953     if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) &&
1954        (i < prim->numverts)){
1955       if(cur == GL2PS_POINT_INFRONT){
1956         front_count++;
1957         front_list = (GL2PSvertex*)gl2psRealloc(front_list,
1958                                                 sizeof(GL2PSvertex)*front_count);
1959         front_list[front_count-1] = prim->verts[v1];
1960       }
1961       else if(cur == GL2PS_POINT_BACK){
1962         back_count++;
1963         back_list = (GL2PSvertex*)gl2psRealloc(back_list,
1964                                                sizeof(GL2PSvertex)*back_count);
1965         back_list[back_count-1] = prim->verts[v1];
1966       }
1967       else{
1968         front_count++;
1969         front_list = (GL2PSvertex*)gl2psRealloc(front_list,
1970                                                 sizeof(GL2PSvertex)*front_count);
1971         front_list[front_count-1] = prim->verts[v1];
1972         back_count++;
1973         back_list = (GL2PSvertex*)gl2psRealloc(back_list,
1974                                                sizeof(GL2PSvertex)*back_count);
1975         back_list[back_count-1] = prim->verts[v1];
1976       }
1977       flag = 1;
1978     }
1979     else if((prev != cur) && (cur != 0) && (prev != 0)){
1980       if(v1 != 0){
1981         v2 = v1-1;
1982         i--;
1983       }
1984       front_count++;
1985       front_list = (GL2PSvertex*)gl2psRealloc(front_list,
1986                                               sizeof(GL2PSvertex)*front_count);
1987       gl2psCutEdge(&prim->verts[v2], &prim->verts[v1],
1988                    plane, &front_list[front_count-1]);
1989       back_count++;
1990       back_list = (GL2PSvertex*)gl2psRealloc(back_list,
1991                                              sizeof(GL2PSvertex)*back_count);
1992       back_list[back_count-1] = front_list[front_count-1];
1993       flag = 0;
1994     }
1995     prev = cur;
1996   }
1997   *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list);
1998   *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list);
1999   gl2psFree(front_list);
2000   gl2psFree(back_list);
2001 }
2002 
gl2psAddInBspImageTree(GL2PSprimitive * prim,GL2PSbsptree2d ** tree)2003 static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree)
2004 {
2005   GLint ret = 0;
2006   GL2PSprimitive *frontprim = NULL, *backprim = NULL;
2007 
2008   /* FIXME: until we consider the actual extent of text strings and
2009      pixmaps, never cull them. Otherwise the whole string/pixmap gets
2010      culled as soon as the reference point is hidden */
2011   if(prim->type == GL2PS_PIXMAP ||
2012      prim->type == GL2PS_TEXT ||
2013      prim->type == GL2PS_SPECIAL){
2014     return 1;
2015   }
2016 
2017   if(*tree == NULL){
2018     if((prim->type != GL2PS_IMAGEMAP) && (GL_FALSE == gl2ps->zerosurfacearea)){
2019       gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree);
2020     }
2021     return 1;
2022   }
2023   else{
2024     switch(gl2psCheckPrimitive(prim, (*tree)->plane)){
2025     case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back);
2026     case GL2PS_IN_FRONT_OF:
2027       if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front);
2028       else                       return 0;
2029     case GL2PS_SPANNING:
2030       gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim);
2031       ret = gl2psAddInBspImageTree(backprim, &(*tree)->back);
2032       if((*tree)->front != NULL){
2033         if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){
2034           ret = 1;
2035         }
2036       }
2037       gl2psFree(frontprim->verts);
2038       gl2psFree(frontprim);
2039       gl2psFree(backprim->verts);
2040       gl2psFree(backprim);
2041       return ret;
2042     case GL2PS_COINCIDENT:
2043       if((*tree)->back != NULL){
2044         gl2ps->zerosurfacearea = GL_TRUE;
2045         ret = gl2psAddInBspImageTree(prim, &(*tree)->back);
2046         gl2ps->zerosurfacearea = GL_FALSE;
2047         if(ret) return ret;
2048       }
2049       if((*tree)->front != NULL){
2050         gl2ps->zerosurfacearea = GL_TRUE;
2051         ret = gl2psAddInBspImageTree(prim, &(*tree)->front);
2052         gl2ps->zerosurfacearea = GL_FALSE;
2053         if(ret) return ret;
2054       }
2055       if(prim->type == GL2PS_LINE) return 1;
2056       else                         return 0;
2057     }
2058   }
2059   return 0;
2060 }
2061 
gl2psAddInImageTree(void * data)2062 static void gl2psAddInImageTree(void *data)
2063 {
2064   GL2PSprimitive *prim = *(GL2PSprimitive **)data;
2065   gl2ps->primitivetoadd = prim;
2066   if(prim->type == GL2PS_IMAGEMAP && prim->data.image->format == GL2PS_IMAGEMAP_VISIBLE){
2067     prim->culled = 1;
2068   }
2069   else if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){
2070     prim->culled = 1;
2071   }
2072   else if(prim->type == GL2PS_IMAGEMAP){
2073     prim->data.image->format = GL2PS_IMAGEMAP_VISIBLE;
2074   }
2075 }
2076 
2077 /* Boundary construction */
2078 
gl2psAddBoundaryInList(GL2PSprimitive * prim,GL2PSlist * list)2079 static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list)
2080 {
2081   GL2PSprimitive *b;
2082   GLshort i;
2083   GL2PSxyz c;
2084 
2085   c[0] = c[1] = c[2] = 0.0F;
2086   for(i = 0; i < prim->numverts; i++){
2087     c[0] += prim->verts[i].xyz[0];
2088     c[1] += prim->verts[i].xyz[1];
2089   }
2090   c[0] /= prim->numverts;
2091   c[1] /= prim->numverts;
2092 
2093   for(i = 0; i < prim->numverts; i++){
2094     if(prim->boundary & (GLint)pow(2., i)){
2095       b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
2096       b->type = GL2PS_LINE;
2097       b->offset = prim->offset;
2098       b->pattern = prim->pattern;
2099       b->factor = prim->factor;
2100       b->culled = prim->culled;
2101       b->width = prim->width;
2102       b->boundary = 0;
2103       b->numverts = 2;
2104       b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex));
2105 
2106 #if 0 /* FIXME: need to work on boundary offset... */
2107       v[0] = c[0] - prim->verts[i].xyz[0];
2108       v[1] = c[1] - prim->verts[i].xyz[1];
2109       v[2] = 0.0F;
2110       norm = gl2psNorm(v);
2111       v[0] /= norm;
2112       v[1] /= norm;
2113       b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0];
2114       b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1];
2115       b->verts[0].xyz[2] = prim->verts[i].xyz[2];
2116       v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
2117       v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
2118       norm = gl2psNorm(v);
2119       v[0] /= norm;
2120       v[1] /= norm;
2121       b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0];
2122       b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1];
2123       b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
2124 #else
2125       b->verts[0].xyz[0] = prim->verts[i].xyz[0];
2126       b->verts[0].xyz[1] = prim->verts[i].xyz[1];
2127       b->verts[0].xyz[2] = prim->verts[i].xyz[2];
2128       b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
2129       b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
2130       b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
2131 #endif
2132 
2133       b->verts[0].rgba[0] = 0.0F;
2134       b->verts[0].rgba[1] = 0.0F;
2135       b->verts[0].rgba[2] = 0.0F;
2136       b->verts[0].rgba[3] = 0.0F;
2137       b->verts[1].rgba[0] = 0.0F;
2138       b->verts[1].rgba[1] = 0.0F;
2139       b->verts[1].rgba[2] = 0.0F;
2140       b->verts[1].rgba[3] = 0.0F;
2141       gl2psListAdd(list, &b);
2142     }
2143   }
2144 
2145 }
2146 
gl2psBuildPolygonBoundary(GL2PSbsptree * tree)2147 static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree)
2148 {
2149   GLint i;
2150   GL2PSprimitive *prim;
2151 
2152   if(!tree) return;
2153   gl2psBuildPolygonBoundary(tree->back);
2154   for(i = 0; i < gl2psListNbr(tree->primitives); i++){
2155     prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i);
2156     if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives);
2157   }
2158   gl2psBuildPolygonBoundary(tree->front);
2159 }
2160 
2161 /*********************************************************************
2162  *
2163  * Feedback buffer parser
2164  *
2165  *********************************************************************/
2166 
gl2psAddPolyPrimitive(GLshort type,GLshort numverts,GL2PSvertex * verts,GLint offset,GLushort pattern,GLint factor,GLfloat width,char boundary)2167 static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts,
2168                                   GL2PSvertex *verts, GLint offset,
2169                                   GLushort pattern, GLint factor,
2170                                   GLfloat width, char boundary)
2171 {
2172   GL2PSprimitive *prim;
2173 
2174   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
2175   prim->type = type;
2176   prim->numverts = numverts;
2177   prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
2178   memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex));
2179   prim->boundary = boundary;
2180   prim->offset = offset;
2181   prim->pattern = pattern;
2182   prim->factor = factor;
2183   prim->width = width;
2184   prim->culled = 0;
2185 
2186   /* FIXME: here we should have an option to split stretched
2187      tris/quads to enhance SIMPLE_SORT */
2188 
2189   gl2psListAdd(gl2ps->primitives, &prim);
2190 }
2191 
gl2psGetVertex(GL2PSvertex * v,GLfloat * p)2192 static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p)
2193 {
2194   GLint i;
2195 
2196   v->xyz[0] = p[0];
2197   v->xyz[1] = p[1];
2198   v->xyz[2] = p[2];
2199 
2200   if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){
2201     i = (GLint)(p[3] + 0.5);
2202     v->rgba[0] = gl2ps->colormap[i][0];
2203     v->rgba[1] = gl2ps->colormap[i][1];
2204     v->rgba[2] = gl2ps->colormap[i][2];
2205     v->rgba[3] = gl2ps->colormap[i][3];
2206     return 4;
2207   }
2208   else{
2209     v->rgba[0] = p[3];
2210     v->rgba[1] = p[4];
2211     v->rgba[2] = p[5];
2212     v->rgba[3] = p[6];
2213     return 7;
2214   }
2215 }
2216 
gl2psParseFeedbackBuffer(GLint used)2217 static void gl2psParseFeedbackBuffer(GLint used)
2218 {
2219   char flag;
2220   GLushort pattern = 0;
2221   GLboolean boundary;
2222   GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0;
2223   GLfloat lwidth = 1.0F, psize = 1.0F;
2224   GLfloat *current;
2225   GL2PSvertex vertices[3];
2226   GL2PSprimitive *prim;
2227   GL2PSimagemap *node;
2228 
2229   current = gl2ps->feedback;
2230   boundary = gl2ps->boundary = GL_FALSE;
2231 
2232   while(used > 0){
2233 
2234     if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE;
2235 
2236     switch((GLint)*current){
2237     case GL_POINT_TOKEN :
2238       current ++;
2239       used --;
2240       i = gl2psGetVertex(&vertices[0], current);
2241       current += i;
2242       used    -= i;
2243       gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0,
2244                             pattern, factor, psize, 0);
2245       break;
2246     case GL_LINE_TOKEN :
2247     case GL_LINE_RESET_TOKEN :
2248       current ++;
2249       used --;
2250       i = gl2psGetVertex(&vertices[0], current);
2251       current += i;
2252       used    -= i;
2253       i = gl2psGetVertex(&vertices[1], current);
2254       current += i;
2255       used    -= i;
2256       gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0,
2257                             pattern, factor, lwidth, 0);
2258 
2259       // PATCH FOR BURRTOOLS
2260       if (vertices[0].xyz[0] < gl2ps->boundMinX) gl2ps->boundMinX = vertices[0].xyz[0];
2261       if (vertices[0].xyz[0] > gl2ps->boundMaxX) gl2ps->boundMaxX = vertices[0].xyz[0];
2262       if (vertices[0].xyz[1] < gl2ps->boundMinY) gl2ps->boundMinY = vertices[0].xyz[1];
2263       if (vertices[0].xyz[1] > gl2ps->boundMaxY) gl2ps->boundMaxY = vertices[0].xyz[1];
2264 
2265       if (vertices[1].xyz[0] < gl2ps->boundMinX) gl2ps->boundMinX = vertices[1].xyz[0];
2266       if (vertices[1].xyz[0] > gl2ps->boundMaxX) gl2ps->boundMaxX = vertices[1].xyz[0];
2267       if (vertices[1].xyz[1] < gl2ps->boundMinY) gl2ps->boundMinY = vertices[1].xyz[1];
2268       if (vertices[1].xyz[1] > gl2ps->boundMaxY) gl2ps->boundMaxY = vertices[1].xyz[1];
2269 
2270       break;
2271     case GL_POLYGON_TOKEN :
2272       count = (GLint)current[1];
2273       current += 2;
2274       used -= 2;
2275       v = vtot = 0;
2276       while(count > 0 && used > 0){
2277         i = gl2psGetVertex(&vertices[v], current);
2278 
2279         // PATCH FOR BURRTOOLS
2280         if (vertices[v].xyz[0] < gl2ps->boundMinX) gl2ps->boundMinX = vertices[v].xyz[0];
2281         if (vertices[v].xyz[0] > gl2ps->boundMaxX) gl2ps->boundMaxX = vertices[v].xyz[0];
2282         if (vertices[v].xyz[1] < gl2ps->boundMinY) gl2ps->boundMinY = vertices[v].xyz[1];
2283         if (vertices[v].xyz[1] > gl2ps->boundMaxY) gl2ps->boundMaxY = vertices[v].xyz[1];
2284 
2285         gl2psAdaptVertexForBlending(&vertices[v]);
2286         current += i;
2287         used    -= i;
2288         count --;
2289         vtot++;
2290         if(v == 2){
2291           if(GL_TRUE == boundary){
2292             if(!count && vtot == 2) flag = 1|2|4;
2293             else if(!count) flag = 2|4;
2294             else if(vtot == 2) flag = 1|2;
2295             else flag = 2;
2296           }
2297           else
2298             flag = 0;
2299           gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices, offset,
2300                                 pattern, factor, 1, flag);
2301           vertices[1] = vertices[2];
2302         }
2303         else
2304           v ++;
2305       }
2306       break;
2307     case GL_BITMAP_TOKEN :
2308     case GL_DRAW_PIXEL_TOKEN :
2309     case GL_COPY_PIXEL_TOKEN :
2310       current ++;
2311       used --;
2312       i = gl2psGetVertex(&vertices[0], current);
2313       current += i;
2314       used    -= i;
2315       break;
2316     case GL_PASS_THROUGH_TOKEN :
2317       switch((GLint)current[1]){
2318       case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break;
2319       case GL2PS_END_OFFSET_TOKEN : offset = 0; break;
2320       case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break;
2321       case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break;
2322       case GL2PS_END_STIPPLE_TOKEN : pattern = factor = 0; break;
2323       case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break;
2324       case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break;
2325       case GL2PS_BEGIN_STIPPLE_TOKEN :
2326         current += 2;
2327         used -= 2;
2328         pattern = (GLushort)current[1];
2329         current += 2;
2330         used -= 2;
2331         factor = (GLint)current[1];
2332         break;
2333       case GL2PS_SRC_BLEND_TOKEN :
2334         current += 2;
2335         used -= 2;
2336         gl2ps->blendfunc[0] = (GLint)current[1];
2337         break;
2338       case GL2PS_DST_BLEND_TOKEN :
2339         current += 2;
2340         used -= 2;
2341         gl2ps->blendfunc[1] = (GLint)current[1];
2342         break;
2343       case GL2PS_POINT_SIZE_TOKEN :
2344         current += 2;
2345         used -= 2;
2346         psize = current[1];
2347         break;
2348       case GL2PS_LINE_WIDTH_TOKEN :
2349         current += 2;
2350         used -= 2;
2351         lwidth = current[1];
2352         break;
2353       case GL2PS_IMAGEMAP_TOKEN :
2354         prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive));
2355         prim->type = GL2PS_IMAGEMAP;
2356         prim->boundary = 0;
2357         prim->numverts = 4;
2358         prim->verts = (GL2PSvertex *)gl2psMalloc(4 * sizeof(GL2PSvertex));
2359         prim->culled = 0;
2360         prim->offset = 0;
2361         prim->pattern = 0;
2362         prim->factor = 0;
2363         prim->width = 1;
2364 
2365         node = (GL2PSimagemap*)gl2psMalloc(sizeof(GL2PSimagemap));
2366         node->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
2367         node->image->type = 0;
2368         node->image->format = 0;
2369         node->next = NULL;
2370 
2371         if(gl2ps->imagemap_head == NULL)
2372           gl2ps->imagemap_head = node;
2373         else
2374           gl2ps->imagemap_tail->next = node;
2375         gl2ps->imagemap_tail = node;
2376         prim->data.image = node->image;
2377 
2378         current += 2; used -= 2;
2379         i = gl2psGetVertex(&prim->verts[0], &current[1]);
2380         current += i; used -= i;
2381 
2382         node->image->width = (GLint)current[2];
2383         current += 2; used -= 2;
2384         node->image->height = (GLint)current[2];
2385         prim->verts[0].xyz[0] = prim->verts[0].xyz[0] - (int)(node->image->width / 2) + 0.5;
2386         prim->verts[0].xyz[1] = prim->verts[0].xyz[1] - (int)(node->image->height / 2) + 0.5;
2387         for(i = 1; i < 4; i++){
2388           for(v = 0; v < 3; v++){
2389             prim->verts[i].xyz[v] = prim->verts[0].xyz[v];
2390             prim->verts[i].rgba[v] = prim->verts[0].rgba[v];
2391           }
2392           prim->verts[i].rgba[v] = prim->verts[0].rgba[v];
2393         }
2394         prim->verts[1].xyz[0] = prim->verts[1].xyz[0] + node->image->width;
2395         prim->verts[2].xyz[0] = prim->verts[1].xyz[0];
2396         prim->verts[2].xyz[1] = prim->verts[2].xyz[1] + node->image->height;
2397         prim->verts[3].xyz[1] = prim->verts[2].xyz[1];
2398 
2399         sizeoffloat = sizeof(GLfloat);
2400         v = 2 * sizeoffloat;
2401         vtot = node->image->height + node->image->height *
2402           ((node->image->width-1)/8);
2403         node->image->pixels = (GLfloat*)gl2psMalloc(v + vtot);
2404         node->image->pixels[0] = prim->verts[0].xyz[0];
2405         node->image->pixels[1] = prim->verts[0].xyz[1];
2406 
2407         for(i = 0; i < vtot; i += sizeoffloat){
2408           current += 2; used -= 2;
2409           if((vtot - i) >= 4)
2410             memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), sizeoffloat);
2411           else
2412             memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), vtot - i);
2413         }
2414         current++; used--;
2415         gl2psListAdd(gl2ps->primitives, &prim);
2416         break;
2417       case GL2PS_DRAW_PIXELS_TOKEN :
2418       case GL2PS_TEXT_TOKEN :
2419         if(auxindex < gl2psListNbr(gl2ps->auxprimitives))
2420           gl2psListAdd(gl2ps->primitives,
2421                        gl2psListPointer(gl2ps->auxprimitives, auxindex++));
2422         else
2423           gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer");
2424         break;
2425       }
2426       current += 2;
2427       used -= 2;
2428       break;
2429     default :
2430       gl2psMsg(GL2PS_WARNING, "Unknown token in buffer");
2431       current ++;
2432       used --;
2433       break;
2434     }
2435   }
2436 
2437   gl2psListReset(gl2ps->auxprimitives);
2438 }
2439 
2440 /*********************************************************************
2441  *
2442  * PostScript routines
2443  *
2444  *********************************************************************/
2445 
gl2psWriteByte(unsigned char byte)2446 static void gl2psWriteByte(unsigned char byte)
2447 {
2448   unsigned char h = byte / 16;
2449   unsigned char l = byte % 16;
2450   gl2psPrintf("%x%x", h, l);
2451 }
2452 
gl2psPrintPostScriptPixmap(GLfloat x,GLfloat y,GL2PSimage * im)2453 static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im)
2454 {
2455   GLuint nbhex, nbyte, nrgb, nbits;
2456   GLuint row, col, ibyte, icase;
2457   GLfloat dr, dg, db, fgrey;
2458   unsigned char red = 0, green = 0, blue = 0, b, grey;
2459   GLuint width = (GLuint)im->width;
2460   GLuint height = (GLuint)im->height;
2461 
2462   /* FIXME: should we define an option for these? Or just keep the
2463      8-bit per component case? */
2464   int greyscale = 0; /* set to 1 to output greyscale image */
2465   int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */
2466 
2467   if((width <= 0) || (height <= 0)) return;
2468 
2469   gl2psPrintf("gsave\n");
2470   gl2psPrintf("%.2f %.2f translate\n", x, y);
2471   gl2psPrintf("%d %d scale\n", width, height);
2472 
2473   if(greyscale){ /* greyscale */
2474     gl2psPrintf("/picstr %d string def\n", width);
2475     gl2psPrintf("%d %d %d\n", width, height, 8);
2476     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2477     gl2psPrintf("{ currentfile picstr readhexstring pop }\n");
2478     gl2psPrintf("image\n");
2479     for(row = 0; row < height; row++){
2480       for(col = 0; col < width; col++){
2481         gl2psGetRGB(im, col, row, &dr, &dg, &db);
2482         fgrey = (0.30 * dr + 0.59 * dg + 0.11 * db);
2483         grey = (unsigned char)(255. * fgrey);
2484         gl2psWriteByte(grey);
2485       }
2486       gl2psPrintf("\n");
2487     }
2488     nbhex = width * height * 2;
2489     gl2psPrintf("%%%% nbhex digit          :%d\n", nbhex);
2490   }
2491   else if(nbit == 2){ /* color, 2 bits for r and g and b; rgbs following each other */
2492     nrgb = width  * 3;
2493     nbits = nrgb * nbit;
2494     nbyte = nbits/8;
2495     if((nbyte * 8) != nbits) nbyte++;
2496     gl2psPrintf("/rgbstr %d string def\n", nbyte);
2497     gl2psPrintf("%d %d %d\n", width, height, nbit);
2498     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2499     gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
2500     gl2psPrintf("false 3\n");
2501     gl2psPrintf("colorimage\n");
2502     for(row = 0; row < height; row++){
2503       icase = 1;
2504       col = 0;
2505       b = 0;
2506       for(ibyte = 0; ibyte < nbyte; ibyte++){
2507         if(icase == 1) {
2508           if(col < width) {
2509             gl2psGetRGB(im, col, row, &dr, &dg, &db);
2510           }
2511           else {
2512             dr = dg = db = 0;
2513           }
2514           col++;
2515           red = (unsigned char)(3. * dr);
2516           green = (unsigned char)(3. * dg);
2517           blue = (unsigned char)(3. * db);
2518           b = red;
2519           b = (b<<2) + green;
2520           b = (b<<2) + blue;
2521           if(col < width) {
2522             gl2psGetRGB(im, col, row, &dr, &dg, &db);
2523           }
2524           else {
2525             dr = dg = db = 0;
2526           }
2527           col++;
2528           red = (unsigned char)(3. * dr);
2529           green = (unsigned char)(3. * dg);
2530           blue = (unsigned char)(3. * db);
2531           b = (b<<2) + red;
2532           gl2psWriteByte(b);
2533           b = 0;
2534           icase++;
2535         }
2536         else if(icase == 2) {
2537           b = green;
2538           b = (b<<2) + blue;
2539           if(col < width) {
2540             gl2psGetRGB(im, col, row, &dr, &dg, &db);
2541           }
2542           else {
2543             dr = dg = db = 0;
2544           }
2545           col++;
2546           red = (unsigned char)(3. * dr);
2547           green = (unsigned char)(3. * dg);
2548           blue = (unsigned char)(3. * db);
2549           b = (b<<2) + red;
2550           b = (b<<2) + green;
2551           gl2psWriteByte(b);
2552           b = 0;
2553           icase++;
2554         }
2555         else if(icase == 3) {
2556           b = blue;
2557           if(col < width) {
2558             gl2psGetRGB(im, col, row, &dr, &dg, &db);
2559           }
2560           else {
2561             dr = dg = db = 0;
2562           }
2563           col++;
2564           red = (unsigned char)(3. * dr);
2565           green = (unsigned char)(3. * dg);
2566           blue = (unsigned char)(3. * db);
2567           b = (b<<2) + red;
2568           b = (b<<2) + green;
2569           b = (b<<2) + blue;
2570           gl2psWriteByte(b);
2571           b = 0;
2572           icase = 1;
2573         }
2574       }
2575       gl2psPrintf("\n");
2576     }
2577   }
2578   else if(nbit == 4){ /* color, 4 bits for r and g and b; rgbs following each other */
2579     nrgb = width  * 3;
2580     nbits = nrgb * nbit;
2581     nbyte = nbits/8;
2582     if((nbyte * 8) != nbits) nbyte++;
2583     gl2psPrintf("/rgbstr %d string def\n", nbyte);
2584     gl2psPrintf("%d %d %d\n", width, height, nbit);
2585     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2586     gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
2587     gl2psPrintf("false 3\n");
2588     gl2psPrintf("colorimage\n");
2589     for(row = 0; row < height; row++){
2590       col = 0;
2591       icase = 1;
2592       for(ibyte = 0; ibyte < nbyte; ibyte++){
2593         if(icase == 1) {
2594           if(col < width) {
2595             gl2psGetRGB(im, col, row, &dr, &dg, &db);
2596           }
2597           else {
2598             dr = dg = db = 0;
2599           }
2600           col++;
2601           red = (unsigned char)(15. * dr);
2602           green = (unsigned char)(15. * dg);
2603           gl2psPrintf("%x%x", red, green);
2604           icase++;
2605         }
2606         else if(icase == 2) {
2607           blue = (unsigned char)(15. * db);
2608           if(col < width) {
2609             gl2psGetRGB(im, col, row, &dr, &dg, &db);
2610           }
2611           else {
2612             dr = dg = db = 0;
2613           }
2614           col++;
2615           red = (unsigned char)(15. * dr);
2616           gl2psPrintf("%x%x", blue, red);
2617           icase++;
2618         }
2619         else if(icase == 3) {
2620           green = (unsigned char)(15. * dg);
2621           blue = (unsigned char)(15. * db);
2622           gl2psPrintf("%x%x", green, blue);
2623           icase = 1;
2624         }
2625       }
2626       gl2psPrintf("\n");
2627     }
2628   }
2629   else{ /* 8 bit for r and g and b */
2630     nbyte = width * 3;
2631     gl2psPrintf("/rgbstr %d string def\n", nbyte);
2632     gl2psPrintf("%d %d %d\n", width, height, 8);
2633     gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2634     gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
2635     gl2psPrintf("false 3\n");
2636     gl2psPrintf("colorimage\n");
2637     for(row = 0; row < height; row++){
2638       for(col = 0; col < width; col++){
2639         gl2psGetRGB(im, col, row, &dr, &dg, &db);
2640         red = (unsigned char)(255. * dr);
2641         gl2psWriteByte(red);
2642         green = (unsigned char)(255. * dg);
2643         gl2psWriteByte(green);
2644         blue = (unsigned char)(255. * db);
2645         gl2psWriteByte(blue);
2646       }
2647       gl2psPrintf("\n");
2648     }
2649   }
2650 
2651   gl2psPrintf("grestore\n");
2652 }
2653 
gl2psPrintPostScriptImagemap(GLfloat x,GLfloat y,GLsizei width,GLsizei height,const unsigned char * imagemap)2654 static void gl2psPrintPostScriptImagemap(GLfloat x, GLfloat y,
2655                                          GLsizei width, GLsizei height,
2656                                          const unsigned char *imagemap){
2657   int i, size;
2658 
2659   if((width <= 0) || (height <= 0)) return;
2660 
2661   size = height + height * (width-1)/8;
2662 
2663   gl2psPrintf("gsave\n");
2664   gl2psPrintf("%.2f %.2f translate\n", x, y);
2665   gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height);
2666   gl2psPrintf("[ %d 0 0 -%d 0 %d ] {<", width, height);
2667   for(i = 0; i < size; i++){
2668     gl2psWriteByte(*imagemap);
2669     imagemap++;
2670   }
2671   gl2psPrintf(">} imagemask\ngrestore\n");
2672 }
2673 
gl2psPrintPostScriptHeader(void)2674 static void gl2psPrintPostScriptHeader(void)
2675 {
2676   time_t now;
2677 
2678   /* Since compression is not part of the PostScript standard,
2679      compressed PostScript files are just gzipped PostScript files
2680      ("ps.gz" or "eps.gz") */
2681   gl2psPrintGzipHeader();
2682 
2683   time(&now);
2684 
2685   if(gl2ps->format == GL2PS_PS){
2686     gl2psPrintf("%%!PS-Adobe-3.0\n");
2687   }
2688   else{
2689     gl2psPrintf("%%!PS-Adobe-3.0 EPSF-3.0\n");
2690   }
2691 
2692   gl2psPrintf("%%%%Title: %s\n"
2693               "%%%%Creator: GL2PS %d.%d.%d%s, %s\n"
2694               "%%%%For: %s\n"
2695               "%%%%CreationDate: %s"
2696               "%%%%LanguageLevel: 3\n"
2697               "%%%%DocumentData: Clean7Bit\n"
2698               "%%%%Pages: 1\n",
2699               gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
2700               GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
2701               gl2ps->producer, ctime(&now));
2702 
2703   if(gl2ps->format == GL2PS_PS){
2704     gl2psPrintf("%%%%Orientation: %s\n"
2705                 "%%%%DocumentMedia: Default %d %d 0 () ()\n",
2706                 (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait",
2707                 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] :
2708                 (int)gl2ps->viewport[2],
2709                 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] :
2710                 (int)gl2ps->viewport[3]);
2711   }
2712 
2713   // PATCH BURRTOOLS add a content box to the EPS
2714   gl2psPrintf("%%%%ContentBox: %d %d %d %d\n",
2715               gl2ps->boundMinX,
2716               gl2ps->boundMinY,
2717               gl2ps->boundMaxX,
2718               gl2ps->boundMaxY);
2719 
2720   gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n"
2721               "%%%%EndComments\n",
2722               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] :
2723               (int)gl2ps->viewport[0],
2724               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] :
2725               (int)gl2ps->viewport[1],
2726               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] :
2727               (int)gl2ps->viewport[2],
2728               (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] :
2729               (int)gl2ps->viewport[3]);
2730 
2731   /* RGB color: r g b C (replace C by G in output to change from rgb to gray)
2732      Grayscale: r g b G
2733      Font choose: size fontname FC
2734      Text string: (string) x y size fontname S??
2735      Rotated text string: (string) angle x y size fontname S??R
2736      Point primitive: x y size P
2737      Line width: width W
2738      Line start: x y LS
2739      Line joining last point: x y L
2740      Line end: x y LE
2741      Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T
2742      Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */
2743 
2744   gl2psPrintf("%%%%BeginProlog\n"
2745               "/gl2psdict 64 dict def gl2psdict begin\n"
2746               "0 setlinecap 0 setlinejoin\n"
2747               "/tryPS3shading %s def %% set to false to force subdivision\n"
2748               "/rThreshold %g def %% red component subdivision threshold\n"
2749               "/gThreshold %g def %% green component subdivision threshold\n"
2750               "/bThreshold %g def %% blue component subdivision threshold\n",
2751               (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true",
2752               gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]);
2753 
2754   gl2psPrintf("/BD { bind def } bind def\n"
2755               "/C  { setrgbcolor } BD\n"
2756               "/G  { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n"
2757               "/W  { setlinewidth } BD\n");
2758 
2759   gl2psPrintf("/FC { findfont exch /SH exch def SH scalefont setfont } BD\n"
2760               "/SW { dup stringwidth pop } BD\n"
2761               "/S  { FC moveto show } BD\n"
2762               "/SBC{ FC moveto SW -2 div 0 rmoveto show } BD\n"
2763               "/SBR{ FC moveto SW neg 0 rmoveto show } BD\n"
2764               "/SCL{ FC moveto 0 SH -2 div rmoveto show } BD\n"
2765               "/SCC{ FC moveto SW -2 div SH -2 div rmoveto show } BD\n"
2766               "/SCR{ FC moveto SW neg SH -2 div rmoveto show } BD\n"
2767               "/STL{ FC moveto 0 SH neg rmoveto show } BD\n"
2768               "/STC{ FC moveto SW -2 div SH neg rmoveto show } BD\n"
2769               "/STR{ FC moveto SW neg SH neg rmoveto show } BD\n");
2770 
2771   /* rotated text routines: same nameanem with R appended */
2772 
2773   gl2psPrintf("/FCT { FC translate 0 0 } BD\n"
2774               "/SR  { gsave FCT moveto rotate show grestore } BD\n"
2775               "/SBCR{ gsave FCT moveto rotate SW -2 div 0 rmoveto show grestore } BD\n"
2776               "/SBRR{ gsave FCT moveto rotate SW neg 0 rmoveto show grestore } BD\n"
2777               "/SCLR{ gsave FCT moveto rotate 0 SH -2 div rmoveto show grestore} BD\n");
2778   gl2psPrintf("/SCCR{ gsave FCT moveto rotate SW -2 div SH -2 div rmoveto show grestore} BD\n"
2779               "/SCRR{ gsave FCT moveto rotate SW neg SH -2 div rmoveto show grestore} BD\n"
2780               "/STLR{ gsave FCT moveto rotate 0 SH neg rmoveto show grestore } BD\n"
2781               "/STCR{ gsave FCT moveto rotate SW -2 div SH neg rmoveto show grestore } BD\n"
2782               "/STRR{ gsave FCT moveto rotate SW neg SH neg rmoveto show grestore } BD\n");
2783 
2784   gl2psPrintf("/P  { newpath 0.0 360.0 arc closepath fill } BD\n"
2785               "/LS { newpath moveto } BD\n"
2786               "/L  { lineto } BD\n"
2787               "/LE { lineto stroke } BD\n"
2788               "/T  { newpath moveto lineto lineto closepath fill } BD\n");
2789 
2790   /* Smooth-shaded triangle with PostScript level 3 shfill operator:
2791         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */
2792 
2793   gl2psPrintf("/STshfill {\n"
2794               "      /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n"
2795               "      /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n"
2796               "      /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n"
2797               "      gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n"
2798               "      /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n"
2799               "      shfill grestore } BD\n");
2800 
2801   /* Flat-shaded triangle with middle color:
2802         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */
2803 
2804   gl2psPrintf(/* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */
2805               "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */
2806               /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */
2807               "      3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */
2808               /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */
2809               "      3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */
2810               /* stack : x3 y3 x2 y2 x1 y1 r g b */
2811               " C T } BD\n");
2812 
2813   /* Split triangle in four sub-triangles (at sides middle points) and call the
2814      STnoshfill procedure on each, interpolating the colors in RGB space:
2815         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit
2816      (in procedure comments key: (Vi) = xi yi ri gi bi) */
2817 
2818   gl2psPrintf("/STsplit {\n"
2819               "      4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */
2820               "      4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */
2821               "      4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */
2822               "      4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */
2823               "      4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */
2824               "      5 copy 5 copy 25 15 roll\n");
2825 
2826   /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */
2827 
2828   gl2psPrintf("      9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */
2829               "      9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */
2830               "      9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */
2831               "      9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */
2832               "      9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */
2833               "      5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n");
2834 
2835   /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */
2836 
2837   gl2psPrintf("      4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */
2838               "      4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */
2839               "      4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */
2840               "      4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */
2841               "      4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */
2842               "      5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n");
2843 
2844   /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */
2845 
2846   gl2psPrintf("      STnoshfill STnoshfill STnoshfill STnoshfill } BD\n");
2847 
2848   /* Gouraud shaded triangle using recursive subdivision until the difference
2849      between corner colors does not exceed the thresholds:
2850         x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill  */
2851 
2852   gl2psPrintf("/STnoshfill {\n"
2853               "      2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */
2854               "      { STsplit }\n"
2855               "      { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */
2856               "        { STsplit }\n"
2857               "        { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */
2858               "          { STsplit }\n"
2859               "          { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */
2860               "            { STsplit }\n"
2861               "            { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */
2862               "              { STsplit }\n"
2863               "              { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */
2864               "                { STsplit }\n"
2865               "                { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */
2866   gl2psPrintf("                  { STsplit }\n"
2867               "                  { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */
2868               "                    { STsplit }\n"
2869               "                    { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */
2870               "                      { STsplit }\n"
2871               "                      { Tm }\n" /* all colors sufficiently similar */
2872               "                      ifelse }\n"
2873               "                    ifelse }\n"
2874               "                  ifelse }\n"
2875               "                ifelse }\n"
2876               "              ifelse }\n"
2877               "            ifelse }\n"
2878               "          ifelse }\n"
2879               "        ifelse }\n"
2880               "      ifelse } BD\n");
2881 
2882   gl2psPrintf("tryPS3shading\n"
2883               "{ /shfill where\n"
2884               "  { /ST { STshfill } BD }\n"
2885               "  { /ST { STnoshfill } BD }\n"
2886               "  ifelse }\n"
2887               "{ /ST { STnoshfill } BD }\n"
2888               "ifelse\n");
2889 
2890   gl2psPrintf("end\n"
2891               "%%%%EndProlog\n"
2892               "%%%%BeginSetup\n"
2893               "/DeviceRGB setcolorspace\n"
2894               "gl2psdict begin\n"
2895               "%%%%EndSetup\n"
2896               "%%%%Page: 1 1\n"
2897               "%%%%BeginPageSetup\n");
2898 
2899   if(gl2ps->options & GL2PS_LANDSCAPE){
2900     gl2psPrintf("%d 0 translate 90 rotate\n",
2901                 (int)gl2ps->viewport[3]);
2902   }
2903 
2904   gl2psPrintf("%%%%EndPageSetup\n"
2905               "mark\n"
2906               "gsave\n"
2907               "1.0 1.0 scale\n");
2908 
2909   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
2910     gl2psPrintf("%g %g %g C\n"
2911                 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
2912                 "closepath fill\n",
2913                 gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2],
2914                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2],
2915                 (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3],
2916                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
2917   }
2918 }
2919 
gl2psPrintPostScriptColor(GL2PSrgba rgba)2920 static void gl2psPrintPostScriptColor(GL2PSrgba rgba)
2921 {
2922   if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
2923     gl2psSetLastColor(rgba);
2924     gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]);
2925   }
2926 }
2927 
gl2psResetPostScriptColor(void)2928 static void gl2psResetPostScriptColor(void)
2929 {
2930   gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.;
2931 }
2932 
gl2psEndPostScriptLine(void)2933 static void gl2psEndPostScriptLine(void)
2934 {
2935   int i;
2936   if(gl2ps->lastvertex.rgba[0] >= 0.){
2937     gl2psPrintf("%g %g LE\n", gl2ps->lastvertex.xyz[0], gl2ps->lastvertex.xyz[1]);
2938     for(i = 0; i < 3; i++)
2939       gl2ps->lastvertex.xyz[i] = -1.;
2940     for(i = 0; i < 4; i++)
2941       gl2ps->lastvertex.rgba[i] = -1.;
2942   }
2943 }
2944 
gl2psParseStipplePattern(GLushort pattern,GLint factor,int * nb,int array[10])2945 static void gl2psParseStipplePattern(GLushort pattern, GLint factor,
2946                                      int *nb, int array[10])
2947 {
2948   int i, n;
2949   int on[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2950   int off[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2951   char tmp[16];
2952 
2953   /* extract the 16 bits from the OpenGL stipple pattern */
2954   for(n = 15; n >= 0; n--){
2955     tmp[n] = (char)(pattern & 0x01);
2956     pattern >>= 1;
2957   }
2958   /* compute the on/off pixel sequence */
2959   n = 0;
2960   for(i = 0; i < 8; i++){
2961     while(n < 16 && !tmp[n]){ off[i]++; n++; }
2962     while(n < 16 && tmp[n]){ on[i]++; n++; }
2963     if(n >= 15){ i++; break; }
2964   }
2965 
2966   /* store the on/off array from right to left, starting with off
2967      pixels. The PostScript specification allows for at most 11
2968      elements in the on/off array, so we limit ourselves to 5 on/off
2969      couples (our longest possible array is thus [on4 off4 on3 off3
2970      on2 off2 on1 off1 on0 off0]) */
2971   *nb = 0;
2972   for(n = i - 1; n >= 0; n--){
2973     array[(*nb)++] = factor * on[n];
2974     array[(*nb)++] = factor * off[n];
2975     if(*nb == 10) break;
2976   }
2977 }
2978 
gl2psPrintPostScriptDash(GLushort pattern,GLint factor,const char * str)2979 static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, const char *str)
2980 {
2981   int len = 0, i, n, array[10];
2982 
2983   if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
2984     return 0;
2985 
2986   gl2ps->lastpattern = pattern;
2987   gl2ps->lastfactor = factor;
2988 
2989   if(!pattern || !factor){
2990     /* solid line */
2991     len += gl2psPrintf("[] 0 %s\n", str);
2992   }
2993   else{
2994     gl2psParseStipplePattern(pattern, factor, &n, array);
2995     len += gl2psPrintf("[");
2996     for(i = 0; i < n; i++){
2997       if(i) len += gl2psPrintf(" ");
2998       len += gl2psPrintf("%d", array[i]);
2999     }
3000     len += gl2psPrintf("] 0 %s\n", str);
3001   }
3002 
3003   return len;
3004 }
3005 
gl2psPrintPostScriptPrimitive(void * data)3006 static void gl2psPrintPostScriptPrimitive(void *data)
3007 {
3008   int newline;
3009   GL2PSprimitive *prim;
3010 
3011   prim = *(GL2PSprimitive**)data;
3012 
3013   if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
3014 
3015   /* Every effort is made to draw lines as connected segments (i.e.,
3016      using a single PostScript path): this is the only way to get nice
3017      line joins and to not restart the stippling for every line
3018      segment. So if the primitive to print is not a line we must first
3019      finish the current line (if any): */
3020   if(prim->type != GL2PS_LINE) gl2psEndPostScriptLine();
3021 
3022   switch(prim->type){
3023   case GL2PS_POINT :
3024     gl2psPrintPostScriptColor(prim->verts[0].rgba);
3025     gl2psPrintf("%g %g %g P\n",
3026                 prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width);
3027     break;
3028   case GL2PS_LINE :
3029     if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
3030        !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
3031        gl2ps->lastlinewidth != prim->width ||
3032        gl2ps->lastpattern != prim->pattern ||
3033        gl2ps->lastfactor != prim->factor){
3034       /* End the current line if the new segment does not start where
3035          the last one ended, or if the color, the width or the
3036          stippling have changed (multi-stroking lines with changing
3037          colors is necessary until we use /shfill for lines;
3038          unfortunately this means that at the moment we can screw up
3039          line stippling for smooth-shaded lines) */
3040       gl2psEndPostScriptLine();
3041       newline = 1;
3042     }
3043     else{
3044       newline = 0;
3045     }
3046     if(gl2ps->lastlinewidth != prim->width){
3047       gl2ps->lastlinewidth = prim->width;
3048       gl2psPrintf("%g W\n", gl2ps->lastlinewidth);
3049     }
3050     gl2psPrintPostScriptDash(prim->pattern, prim->factor, "setdash");
3051     gl2psPrintPostScriptColor(prim->verts[0].rgba);
3052     gl2psPrintf("%g %g %s\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3053                 newline ? "LS" : "L");
3054     gl2ps->lastvertex = prim->verts[1];
3055     break;
3056   case GL2PS_TRIANGLE :
3057     if(!gl2psVertsSameColor(prim)){
3058       gl2psResetPostScriptColor();
3059       gl2psPrintf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n",
3060                   prim->verts[2].xyz[0], prim->verts[2].xyz[1],
3061                   prim->verts[2].rgba[0], prim->verts[2].rgba[1],
3062                   prim->verts[2].rgba[2], prim->verts[1].xyz[0],
3063                   prim->verts[1].xyz[1], prim->verts[1].rgba[0],
3064                   prim->verts[1].rgba[1], prim->verts[1].rgba[2],
3065                   prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3066                   prim->verts[0].rgba[0], prim->verts[0].rgba[1],
3067                   prim->verts[0].rgba[2]);
3068     }
3069     else{
3070       gl2psPrintPostScriptColor(prim->verts[0].rgba);
3071       gl2psPrintf("%g %g %g %g %g %g T\n",
3072                   prim->verts[2].xyz[0], prim->verts[2].xyz[1],
3073                   prim->verts[1].xyz[0], prim->verts[1].xyz[1],
3074                   prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3075     }
3076     break;
3077   case GL2PS_QUADRANGLE :
3078     gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
3079     break;
3080   case GL2PS_PIXMAP :
3081     gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3082                                prim->data.image);
3083     break;
3084   case GL2PS_IMAGEMAP :
3085     if(prim->data.image->type != GL2PS_IMAGEMAP_WRITTEN){
3086       gl2psPrintPostScriptColor(prim->verts[0].rgba);
3087       gl2psPrintPostScriptImagemap(prim->data.image->pixels[0],
3088                                    prim->data.image->pixels[1],
3089                                    prim->data.image->width, prim->data.image->height,
3090                                    (const unsigned char*)(&(prim->data.image->pixels[2])));
3091       prim->data.image->type = GL2PS_IMAGEMAP_WRITTEN;
3092     }
3093     break;
3094   case GL2PS_TEXT :
3095     gl2psPrintPostScriptColor(prim->verts[0].rgba);
3096     gl2psPrintf("(%s) ", prim->data.text->str);
3097     if(prim->data.text->angle)
3098       gl2psPrintf("%g ", prim->data.text->angle);
3099     gl2psPrintf("%g %g %d /%s ",
3100                 prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3101                 prim->data.text->fontsize, prim->data.text->fontname);
3102     switch(prim->data.text->alignment){
3103     case GL2PS_TEXT_C:
3104       gl2psPrintf(prim->data.text->angle ? "SCCR\n" : "SCC\n");
3105       break;
3106     case GL2PS_TEXT_CL:
3107       gl2psPrintf(prim->data.text->angle ? "SCLR\n" : "SCL\n");
3108       break;
3109     case GL2PS_TEXT_CR:
3110       gl2psPrintf(prim->data.text->angle ? "SCRR\n" : "SCR\n");
3111       break;
3112     case GL2PS_TEXT_B:
3113       gl2psPrintf(prim->data.text->angle ? "SBCR\n" : "SBC\n");
3114       break;
3115     case GL2PS_TEXT_BR:
3116       gl2psPrintf(prim->data.text->angle ? "SBRR\n" : "SBR\n");
3117       break;
3118     case GL2PS_TEXT_T:
3119       gl2psPrintf(prim->data.text->angle ? "STCR\n" : "STC\n");
3120       break;
3121     case GL2PS_TEXT_TL:
3122       gl2psPrintf(prim->data.text->angle ? "STLR\n" : "STL\n");
3123       break;
3124     case GL2PS_TEXT_TR:
3125       gl2psPrintf(prim->data.text->angle ? "STRR\n" : "STR\n");
3126       break;
3127     case GL2PS_TEXT_BL:
3128     default:
3129       gl2psPrintf(prim->data.text->angle ? "SR\n" : "S\n");
3130       break;
3131     }
3132     break;
3133   case GL2PS_SPECIAL :
3134     /* alignment contains the format for which the special output text
3135        is intended */
3136     if(prim->data.text->alignment == GL2PS_PS ||
3137        prim->data.text->alignment == GL2PS_EPS)
3138       gl2psPrintf("%s\n", prim->data.text->str);
3139     break;
3140   default :
3141     break;
3142   }
3143 }
3144 
gl2psPrintPostScriptFooter(void)3145 static void gl2psPrintPostScriptFooter(void)
3146 {
3147   gl2psPrintf("grestore\n"
3148               "showpage\n"
3149               "cleartomark\n"
3150               "%%%%PageTrailer\n"
3151               "%%%%Trailer\n"
3152               "end\n"
3153               "%%%%EOF\n");
3154 
3155   gl2psPrintGzipFooter();
3156 }
3157 
gl2psPrintPostScriptBeginViewport(GLint viewport[4])3158 static void gl2psPrintPostScriptBeginViewport(GLint viewport[4])
3159 {
3160   GLint index;
3161   GLfloat rgba[4];
3162   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
3163 
3164   glRenderMode(GL_FEEDBACK);
3165 
3166   if(gl2ps->header){
3167     gl2psPrintPostScriptHeader();
3168     gl2ps->header = GL_FALSE;
3169   }
3170 
3171   gl2psPrintf("gsave\n"
3172               "1.0 1.0 scale\n");
3173 
3174   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
3175     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
3176       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
3177     }
3178     else{
3179       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
3180       rgba[0] = gl2ps->colormap[index][0];
3181       rgba[1] = gl2ps->colormap[index][1];
3182       rgba[2] = gl2ps->colormap[index][2];
3183       rgba[3] = 1.0F;
3184     }
3185     gl2psPrintf("%g %g %g C\n"
3186                 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
3187                 "closepath fill\n",
3188                 rgba[0], rgba[1], rgba[2],
3189                 x, y, x+w, y, x+w, y+h, x, y+h);
3190   }
3191 
3192   gl2psPrintf("newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
3193               "closepath clip\n",
3194               x, y, x+w, y, x+w, y+h, x, y+h);
3195 
3196 }
3197 
gl2psPrintPostScriptEndViewport(void)3198 static GLint gl2psPrintPostScriptEndViewport(void)
3199 {
3200   GLint res;
3201 
3202   res = gl2psPrintPrimitives();
3203   gl2psPrintf("grestore\n");
3204   return res;
3205 }
3206 
gl2psPrintPostScriptFinalPrimitive(void)3207 static void gl2psPrintPostScriptFinalPrimitive(void)
3208 {
3209   /* End any remaining line, if any */
3210   gl2psEndPostScriptLine();
3211 }
3212 
3213 /* definition of the PostScript and Encapsulated PostScript backends */
3214 
3215 static GL2PSbackend gl2psPS = {
3216   gl2psPrintPostScriptHeader,
3217   gl2psPrintPostScriptFooter,
3218   gl2psPrintPostScriptBeginViewport,
3219   gl2psPrintPostScriptEndViewport,
3220   gl2psPrintPostScriptPrimitive,
3221   gl2psPrintPostScriptFinalPrimitive,
3222   "ps",
3223   "Postscript"
3224 };
3225 
3226 static GL2PSbackend gl2psEPS = {
3227   gl2psPrintPostScriptHeader,
3228   gl2psPrintPostScriptFooter,
3229   gl2psPrintPostScriptBeginViewport,
3230   gl2psPrintPostScriptEndViewport,
3231   gl2psPrintPostScriptPrimitive,
3232   gl2psPrintPostScriptFinalPrimitive,
3233   "eps",
3234   "Encapsulated Postscript"
3235 };
3236 
3237 /*********************************************************************
3238  *
3239  * LaTeX routines
3240  *
3241  *********************************************************************/
3242 
gl2psPrintTeXHeader(void)3243 static void gl2psPrintTeXHeader(void)
3244 {
3245   char name[256];
3246   time_t now;
3247   int i;
3248 
3249   if(gl2ps->filename && strlen(gl2ps->filename) < 256){
3250     for(i = strlen(gl2ps->filename)-1; i >= 0; i--){
3251       if(gl2ps->filename[i] == '.'){
3252         strncpy(name, gl2ps->filename, i);
3253         name[i] = '\0';
3254         break;
3255       }
3256     }
3257     if(i <= 0) strcpy(name, gl2ps->filename);
3258   }
3259   else{
3260     strcpy(name, "untitled");
3261   }
3262 
3263   time(&now);
3264 
3265   fprintf(gl2ps->stream,
3266           "%% Title: %s\n"
3267           "%% Creator: GL2PS %d.%d.%d%s, %s\n"
3268           "%% For: %s\n"
3269           "%% CreationDate: %s",
3270           gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
3271           GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
3272           gl2ps->producer, ctime(&now));
3273 
3274   fprintf(gl2ps->stream,
3275           "\\setlength{\\unitlength}{1pt}\n"
3276           "\\begin{picture}(0,0)\n"
3277           "\\includegraphics{%s}\n"
3278           "\\end{picture}%%\n"
3279           "%s\\begin{picture}(%d,%d)(0,0)\n",
3280           name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "",
3281           (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
3282 }
3283 
gl2psPrintTeXPrimitive(void * data)3284 static void gl2psPrintTeXPrimitive(void *data)
3285 {
3286   GL2PSprimitive *prim;
3287 
3288   prim = *(GL2PSprimitive**)data;
3289 
3290   switch(prim->type){
3291   case GL2PS_TEXT :
3292     fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont",
3293             prim->data.text->fontsize);
3294     fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)",
3295             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3296     switch(prim->data.text->alignment){
3297     case GL2PS_TEXT_C:
3298       fprintf(gl2ps->stream, "{");
3299       break;
3300     case GL2PS_TEXT_CL:
3301       fprintf(gl2ps->stream, "[l]{");
3302       break;
3303     case GL2PS_TEXT_CR:
3304       fprintf(gl2ps->stream, "[r]{");
3305       break;
3306     case GL2PS_TEXT_B:
3307       fprintf(gl2ps->stream, "[b]{");
3308       break;
3309     case GL2PS_TEXT_BR:
3310       fprintf(gl2ps->stream, "[br]{");
3311       break;
3312     case GL2PS_TEXT_T:
3313       fprintf(gl2ps->stream, "[t]{");
3314       break;
3315     case GL2PS_TEXT_TL:
3316       fprintf(gl2ps->stream, "[tl]{");
3317       break;
3318     case GL2PS_TEXT_TR:
3319       fprintf(gl2ps->stream, "[tr]{");
3320       break;
3321     case GL2PS_TEXT_BL:
3322     default:
3323       fprintf(gl2ps->stream, "[bl]{");
3324       break;
3325     }
3326     if(prim->data.text->angle)
3327       fprintf(gl2ps->stream, "\\rotatebox{%g}{", prim->data.text->angle);
3328     fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}",
3329             prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2],
3330             prim->data.text->str);
3331     if(prim->data.text->angle)
3332       fprintf(gl2ps->stream, "}");
3333     fprintf(gl2ps->stream, "}}\n");
3334     break;
3335   case GL2PS_SPECIAL :
3336     /* alignment contains the format for which the special output text
3337        is intended */
3338     if (prim->data.text->alignment == GL2PS_TEX)
3339       fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
3340     break;
3341   default :
3342     break;
3343   }
3344 }
3345 
gl2psPrintTeXFooter(void)3346 static void gl2psPrintTeXFooter(void)
3347 {
3348   fprintf(gl2ps->stream, "\\end{picture}%s\n",
3349           (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : "");
3350 }
3351 
gl2psPrintTeXBeginViewport(GLint viewport[4])3352 static void gl2psPrintTeXBeginViewport(GLint viewport[4])
3353 {
3354   glRenderMode(GL_FEEDBACK);
3355 
3356   if(gl2ps->header){
3357     gl2psPrintTeXHeader();
3358     gl2ps->header = GL_FALSE;
3359   }
3360 }
3361 
gl2psPrintTeXEndViewport(void)3362 static GLint gl2psPrintTeXEndViewport(void)
3363 {
3364   return gl2psPrintPrimitives();
3365 }
3366 
gl2psPrintTeXFinalPrimitive(void)3367 static void gl2psPrintTeXFinalPrimitive(void)
3368 {
3369 }
3370 
3371 /* definition of the LaTeX backend */
3372 
3373 static GL2PSbackend gl2psTEX = {
3374   gl2psPrintTeXHeader,
3375   gl2psPrintTeXFooter,
3376   gl2psPrintTeXBeginViewport,
3377   gl2psPrintTeXEndViewport,
3378   gl2psPrintTeXPrimitive,
3379   gl2psPrintTeXFinalPrimitive,
3380   "tex",
3381   "LaTeX text"
3382 };
3383 
3384 /*********************************************************************
3385  *
3386  * PDF routines
3387  *
3388  *********************************************************************/
3389 
gl2psPrintPDFCompressorType(void)3390 static int gl2psPrintPDFCompressorType(void)
3391 {
3392 #if defined(GL2PS_HAVE_ZLIB)
3393   if(gl2ps->options & GL2PS_COMPRESS){
3394     return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n");
3395   }
3396 #endif
3397   return 0;
3398 }
3399 
gl2psPrintPDFStrokeColor(GL2PSrgba rgba)3400 static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba)
3401 {
3402   int i, offs = 0;
3403 
3404   gl2psSetLastColor(rgba);
3405   for(i = 0; i < 3; ++i){
3406     if(GL2PS_ZERO(rgba[i]))
3407       offs += gl2psPrintf("%.0f ", 0.);
3408     else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */
3409       offs += gl2psPrintf("%f ", rgba[i]);
3410     else
3411       offs += gl2psPrintf("%g ", rgba[i]);
3412   }
3413   offs += gl2psPrintf("RG\n");
3414   return offs;
3415 }
3416 
gl2psPrintPDFFillColor(GL2PSrgba rgba)3417 static int gl2psPrintPDFFillColor(GL2PSrgba rgba)
3418 {
3419   int i, offs = 0;
3420 
3421   for(i = 0; i < 3; ++i){
3422     if(GL2PS_ZERO(rgba[i]))
3423       offs += gl2psPrintf("%.0f ", 0.);
3424     else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */
3425       offs += gl2psPrintf("%f ", rgba[i]);
3426     else
3427       offs += gl2psPrintf("%g ", rgba[i]);
3428   }
3429   offs += gl2psPrintf("rg\n");
3430   return offs;
3431 }
3432 
gl2psPrintPDFLineWidth(GLfloat lw)3433 static int gl2psPrintPDFLineWidth(GLfloat lw)
3434 {
3435   if(GL2PS_ZERO(lw))
3436     return gl2psPrintf("%.0f w\n", 0.);
3437   else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */
3438     return gl2psPrintf("%f w\n", lw);
3439   else
3440     return gl2psPrintf("%g w\n", lw);
3441 }
3442 
gl2psPutPDFText(GL2PSstring * text,int cnt,GLfloat x,GLfloat y)3443 static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y)
3444 {
3445   gl2ps->streamlength +=
3446     gl2psPrintf("BT\n"
3447                 "/F%d %d Tf\n"
3448                 "%f %f Td\n"
3449                 "(%s) Tj\n"
3450                 "ET\n",
3451                 cnt, text->fontsize, x, y, text->str);
3452 }
3453 
gl2psPutPDFImage(GL2PSimage * image,int cnt,GLfloat x,GLfloat y)3454 static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y)
3455 {
3456   gl2ps->streamlength +=
3457     gl2psPrintf("q\n"
3458                 "%d 0 0 %d %f %f cm\n"
3459                 "/Im%d Do\n"
3460                 "Q\n",
3461                 (int)image->width, (int)image->height, x, y, cnt);
3462 }
3463 
gl2psPDFstacksInit(void)3464 static void gl2psPDFstacksInit(void)
3465 {
3466   gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1;
3467   gl2ps->extgs_stack = 0;
3468   gl2ps->font_stack = 0;
3469   gl2ps->im_stack = 0;
3470   gl2ps->trgroupobjects_stack = 0;
3471   gl2ps->shader_stack = 0;
3472   gl2ps->mshader_stack = 0;
3473 }
3474 
gl2psPDFgroupObjectInit(GL2PSpdfgroup * gro)3475 static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro)
3476 {
3477   if(!gro)
3478     return;
3479 
3480   gro->ptrlist = NULL;
3481   gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno
3482     = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno
3483     = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1;
3484 }
3485 
3486 /* Build up group objects and assign name and object numbers */
3487 
gl2psPDFgroupListInit(void)3488 static void gl2psPDFgroupListInit(void)
3489 {
3490   int i;
3491   GL2PSprimitive *p = NULL;
3492   GL2PSpdfgroup gro;
3493   int lasttype = GL2PS_NO_TYPE;
3494   GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F};
3495   GLushort lastpattern = 0;
3496   GLint lastfactor = 0;
3497   GLfloat lastwidth = 1;
3498   GL2PStriangle lastt, tmpt;
3499   int lastTriangleWasNotSimpleWithSameColor = 0;
3500 
3501   if(!gl2ps->pdfprimlist)
3502     return;
3503 
3504   gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup));
3505   gl2psInitTriangle(&lastt);
3506 
3507   for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){
3508     p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i);
3509     switch(p->type){
3510     case GL2PS_PIXMAP:
3511       gl2psPDFgroupObjectInit(&gro);
3512       gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3513       gro.imno = gl2ps->im_stack++;
3514       gl2psListAdd(gro.ptrlist, &p);
3515       gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3516       break;
3517     case GL2PS_TEXT:
3518       gl2psPDFgroupObjectInit(&gro);
3519       gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3520       gro.fontno = gl2ps->font_stack++;
3521       gl2psListAdd(gro.ptrlist, &p);
3522       gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3523       break;
3524     case GL2PS_LINE:
3525       if(lasttype != p->type || lastwidth != p->width ||
3526          lastpattern != p->pattern || lastfactor != p->factor ||
3527          !gl2psSameColor(p->verts[0].rgba, lastrgba)){
3528         gl2psPDFgroupObjectInit(&gro);
3529         gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3530         gl2psListAdd(gro.ptrlist, &p);
3531         gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3532       }
3533       else{
3534         gl2psListAdd(gro.ptrlist, &p);
3535       }
3536       lastpattern = p->pattern;
3537       lastfactor = p->factor;
3538       lastwidth = p->width;
3539       lastrgba[0] = p->verts[0].rgba[0];
3540       lastrgba[1] = p->verts[0].rgba[1];
3541       lastrgba[2] = p->verts[0].rgba[2];
3542       break;
3543     case GL2PS_POINT:
3544       if(lasttype != p->type || lastwidth != p->width ||
3545          !gl2psSameColor(p->verts[0].rgba, lastrgba)){
3546         gl2psPDFgroupObjectInit(&gro);
3547         gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*));
3548         gl2psListAdd(gro.ptrlist, &p);
3549         gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3550       }
3551       else{
3552         gl2psListAdd(gro.ptrlist, &p);
3553       }
3554       lastwidth = p->width;
3555       lastrgba[0] = p->verts[0].rgba[0];
3556       lastrgba[1] = p->verts[0].rgba[1];
3557       lastrgba[2] = p->verts[0].rgba[2];
3558       break;
3559     case GL2PS_TRIANGLE:
3560       gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE);
3561       lastTriangleWasNotSimpleWithSameColor =
3562         !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) ||
3563         !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba);
3564       if(lasttype == p->type && tmpt.prop == lastt.prop &&
3565          lastTriangleWasNotSimpleWithSameColor){
3566         /* TODO Check here for last alpha */
3567         gl2psListAdd(gro.ptrlist, &p);
3568       }
3569       else{
3570         gl2psPDFgroupObjectInit(&gro);
3571         gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3572         gl2psListAdd(gro.ptrlist, &p);
3573         gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3574       }
3575       lastt = tmpt;
3576       break;
3577     default:
3578       break;
3579     }
3580     lasttype = p->type;
3581   }
3582 }
3583 
gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup * gro)3584 static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro)
3585 {
3586   GL2PStriangle t;
3587   GL2PSprimitive *prim = NULL;
3588 
3589   if(!gro)
3590     return;
3591 
3592   if(!gl2psListNbr(gro->ptrlist))
3593     return;
3594 
3595   prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3596 
3597   if(prim->type != GL2PS_TRIANGLE)
3598     return;
3599 
3600   gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
3601 
3602   if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){
3603     gro->gsno = gl2ps->extgs_stack++;
3604     gro->gsobjno = gl2ps->objects_stack ++;
3605   }
3606   else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){
3607     gro->gsno = gl2ps->extgs_stack++;
3608     gro->gsobjno = gl2ps->objects_stack++;
3609     gro->trgroupno = gl2ps->trgroupobjects_stack++;
3610     gro->trgroupobjno = gl2ps->objects_stack++;
3611     gro->maskshno = gl2ps->mshader_stack++;
3612     gro->maskshobjno = gl2ps->objects_stack++;
3613   }
3614   else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){
3615     gro->shno = gl2ps->shader_stack++;
3616     gro->shobjno = gl2ps->objects_stack++;
3617   }
3618   else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){
3619     gro->gsno = gl2ps->extgs_stack++;
3620     gro->gsobjno = gl2ps->objects_stack++;
3621     gro->shno = gl2ps->shader_stack++;
3622     gro->shobjno = gl2ps->objects_stack++;
3623   }
3624   else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){
3625     gro->gsno = gl2ps->extgs_stack++;
3626     gro->gsobjno = gl2ps->objects_stack++;
3627     gro->shno = gl2ps->shader_stack++;
3628     gro->shobjno = gl2ps->objects_stack++;
3629     gro->trgroupno = gl2ps->trgroupobjects_stack++;
3630     gro->trgroupobjno = gl2ps->objects_stack++;
3631     gro->maskshno = gl2ps->mshader_stack++;
3632     gro->maskshobjno = gl2ps->objects_stack++;
3633   }
3634 }
3635 
3636 /* Main stream data */
3637 
gl2psPDFgroupListWriteMainStream(void)3638 static void gl2psPDFgroupListWriteMainStream(void)
3639 {
3640   int i, j, lastel;
3641   GL2PSprimitive *prim = NULL, *prev = NULL;
3642   GL2PSpdfgroup *gro;
3643   GL2PStriangle t;
3644 
3645   if(!gl2ps->pdfgrouplist)
3646     return;
3647 
3648   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3649     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3650 
3651     lastel = gl2psListNbr(gro->ptrlist) - 1;
3652     if(lastel < 0)
3653       continue;
3654 
3655     prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3656 
3657     switch(prim->type){
3658     case GL2PS_POINT:
3659       gl2ps->streamlength += gl2psPrintf("1 J\n");
3660       gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
3661       gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
3662       for(j = 0; j <= lastel; ++j){
3663         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3664         gl2ps->streamlength +=
3665           gl2psPrintf("%f %f m %f %f l\n",
3666                       prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3667                       prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3668       }
3669       gl2ps->streamlength += gl2psPrintf("S\n");
3670       gl2ps->streamlength += gl2psPrintf("0 J\n");
3671       break;
3672     case GL2PS_LINE:
3673       /* We try to use as few paths as possible to draw lines, in
3674          order to get nice stippling even when the individual segments
3675          are smaller than the stipple */
3676       gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
3677       gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
3678       gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d");
3679       /* start new path */
3680       gl2ps->streamlength +=
3681         gl2psPrintf("%f %f m\n",
3682                     prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3683 
3684       for(j = 1; j <= lastel; ++j){
3685         prev = prim;
3686         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3687         if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){
3688           /* the starting point of the new segment does not match the
3689              end point of the previous line, so we end the current
3690              path and start a new one */
3691           gl2ps->streamlength +=
3692             gl2psPrintf("%f %f l\n",
3693                         prev->verts[1].xyz[0], prev->verts[1].xyz[1]);
3694           gl2ps->streamlength +=
3695             gl2psPrintf("%f %f m\n",
3696                         prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3697         }
3698         else{
3699           /* the two segements are connected, so we just append to the
3700              current path */
3701           gl2ps->streamlength +=
3702             gl2psPrintf("%f %f l\n",
3703                         prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3704         }
3705       }
3706       /* end last path */
3707       gl2ps->streamlength +=
3708         gl2psPrintf("%f %f l\n",
3709                     prim->verts[1].xyz[0], prim->verts[1].xyz[1]);
3710       gl2ps->streamlength += gl2psPrintf("S\n");
3711       break;
3712     case GL2PS_TRIANGLE:
3713       gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
3714       gl2psSortOutTrianglePDFgroup(gro);
3715 
3716       /* No alpha and const color: Simple PDF draw orders  */
3717       if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){
3718         gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba);
3719         for(j = 0; j <= lastel; ++j){
3720           prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3721           gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3722           gl2ps->streamlength
3723             += gl2psPrintf("%f %f m\n"
3724                            "%f %f l\n"
3725                            "%f %f l\n"
3726                            "h f\n",
3727                            t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3728                            t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3729                            t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3730         }
3731       }
3732       /* Const alpha < 1 and const color: Simple PDF draw orders
3733          and an extra extended Graphics State for the alpha const */
3734       else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){
3735         gl2ps->streamlength += gl2psPrintf("q\n"
3736                                            "/GS%d gs\n",
3737                                            gro->gsno);
3738         gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3739         for(j = 0; j <= lastel; ++j){
3740           prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3741           gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3742           gl2ps->streamlength
3743             += gl2psPrintf("%f %f m\n"
3744                            "%f %f l\n"
3745                            "%f %f l\n"
3746                            "h f\n",
3747                            t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3748                            t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3749                            t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3750         }
3751         gl2ps->streamlength += gl2psPrintf("Q\n");
3752       }
3753       /* Variable alpha and const color: Simple PDF draw orders
3754          and an extra extended Graphics State + Xobject + Shader
3755          object for the alpha mask */
3756       else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){
3757         gl2ps->streamlength += gl2psPrintf("q\n"
3758                                            "/GS%d gs\n"
3759                                            "/TrG%d Do\n",
3760                                            gro->gsno, gro->trgroupno);
3761         gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3762         for(j = 0; j <= lastel; ++j){
3763           prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3764           gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3765           gl2ps->streamlength
3766             += gl2psPrintf("%f %f m\n"
3767                            "%f %f l\n"
3768                            "%f %f l\n"
3769                            "h f\n",
3770                            t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3771                            t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3772                            t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3773         }
3774         gl2ps->streamlength += gl2psPrintf("Q\n");
3775       }
3776       /* Variable color and no alpha: Shader Object for the colored
3777          triangle(s) */
3778       else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){
3779         gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno);
3780       }
3781       /* Variable color and const alpha < 1: Shader Object for the
3782          colored triangle(s) and an extra extended Graphics State
3783          for the alpha const */
3784       else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){
3785         gl2ps->streamlength += gl2psPrintf("q\n"
3786                                            "/GS%d gs\n"
3787                                            "/Sh%d sh\n"
3788                                            "Q\n",
3789                                            gro->gsno, gro->shno);
3790       }
3791       /* Variable alpha and color: Shader Object for the colored
3792          triangle(s) and an extra extended Graphics State
3793          + Xobject + Shader object for the alpha mask */
3794       else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){
3795         gl2ps->streamlength += gl2psPrintf("q\n"
3796                                            "/GS%d gs\n"
3797                                            "/TrG%d Do\n"
3798                                            "/Sh%d sh\n"
3799                                            "Q\n",
3800                                            gro->gsno, gro->trgroupno, gro->shno);
3801       }
3802       break;
3803     case GL2PS_PIXMAP:
3804       for(j = 0; j <= lastel; ++j){
3805         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3806         gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0],
3807                          prim->verts[0].xyz[1]);
3808       }
3809       break;
3810     case GL2PS_TEXT:
3811       for(j = 0; j <= lastel; ++j){
3812         prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3813         gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3814         gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0],
3815                         prim->verts[0].xyz[1]);
3816       }
3817       break;
3818     default:
3819       break;
3820     }
3821   }
3822 }
3823 
3824 /* Graphics State names */
3825 
gl2psPDFgroupListWriteGStateResources(void)3826 static int gl2psPDFgroupListWriteGStateResources(void)
3827 {
3828   GL2PSpdfgroup *gro;
3829   int offs = 0;
3830   int i;
3831 
3832   offs += fprintf(gl2ps->stream,
3833                   "/ExtGState\n"
3834                   "<<\n"
3835                   "/GSa 7 0 R\n");
3836   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3837     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3838     if(gro->gsno >= 0)
3839       offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno);
3840   }
3841   offs += fprintf(gl2ps->stream, ">>\n");
3842   return offs;
3843 }
3844 
3845 /* Main Shader names */
3846 
gl2psPDFgroupListWriteShaderResources(void)3847 static int gl2psPDFgroupListWriteShaderResources(void)
3848 {
3849   GL2PSpdfgroup *gro;
3850   int offs = 0;
3851   int i;
3852 
3853   offs += fprintf(gl2ps->stream,
3854                   "/Shading\n"
3855                   "<<\n");
3856   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3857     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3858     if(gro->shno >= 0)
3859       offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno);
3860     if(gro->maskshno >= 0)
3861       offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno);
3862   }
3863   offs += fprintf(gl2ps->stream,">>\n");
3864   return offs;
3865 }
3866 
3867 /* Images & Mask Shader XObject names */
3868 
gl2psPDFgroupListWriteXObjectResources(void)3869 static int gl2psPDFgroupListWriteXObjectResources(void)
3870 {
3871   int i;
3872   GL2PSprimitive *p = NULL;
3873   GL2PSpdfgroup *gro;
3874   int offs = 0;
3875 
3876   offs += fprintf(gl2ps->stream,
3877                   "/XObject\n"
3878                   "<<\n");
3879 
3880   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3881     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3882     if(!gl2psListNbr(gro->ptrlist))
3883       continue;
3884     p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3885     switch(p->type){
3886     case GL2PS_PIXMAP:
3887       gro->imobjno = gl2ps->objects_stack++;
3888       if(GL_RGBA == p->data.image->format)  /* reserve one object for image mask */
3889         gl2ps->objects_stack++;
3890       offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno);
3891     case GL2PS_TRIANGLE:
3892       if(gro->trgroupno >=0)
3893         offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno);
3894       break;
3895     default:
3896       break;
3897     }
3898   }
3899   offs += fprintf(gl2ps->stream,">>\n");
3900   return offs;
3901 }
3902 
3903 /* Font names */
3904 
gl2psPDFgroupListWriteFontResources(void)3905 static int gl2psPDFgroupListWriteFontResources(void)
3906 {
3907   int i;
3908   GL2PSpdfgroup *gro;
3909   int offs = 0;
3910 
3911   offs += fprintf(gl2ps->stream, "/Font\n<<\n");
3912 
3913   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3914     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3915     if(gro->fontno < 0)
3916       continue;
3917     gro->fontobjno = gl2ps->objects_stack++;
3918     offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno);
3919   }
3920   offs += fprintf(gl2ps->stream, ">>\n");
3921 
3922   return offs;
3923 }
3924 
gl2psPDFgroupListDelete(void)3925 static void gl2psPDFgroupListDelete(void)
3926 {
3927   int i;
3928   GL2PSpdfgroup *gro = NULL;
3929 
3930   if(!gl2ps->pdfgrouplist)
3931     return;
3932 
3933   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3934     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i);
3935     gl2psListDelete(gro->ptrlist);
3936   }
3937 
3938   gl2psListDelete(gl2ps->pdfgrouplist);
3939   gl2ps->pdfgrouplist = NULL;
3940 }
3941 
3942 /* Print 1st PDF object - file info */
3943 
gl2psPrintPDFInfo(void)3944 static int gl2psPrintPDFInfo(void)
3945 {
3946   int offs;
3947   time_t now;
3948   struct tm *newtime;
3949 
3950   time(&now);
3951   newtime = gmtime(&now);
3952 
3953   offs = fprintf(gl2ps->stream,
3954                  "1 0 obj\n"
3955                  "<<\n"
3956                  "/Title (%s)\n"
3957                  "/Creator (GL2PS %d.%d.%d%s, %s)\n"
3958                  "/Producer (%s)\n",
3959                  gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
3960                  GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
3961                  gl2ps->producer);
3962 
3963   if(!newtime){
3964     offs += fprintf(gl2ps->stream,
3965                     ">>\n"
3966                     "endobj\n");
3967     return offs;
3968   }
3969 
3970   offs += fprintf(gl2ps->stream,
3971                   "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n"
3972                   ">>\n"
3973                   "endobj\n",
3974                   newtime->tm_year+1900,
3975                   newtime->tm_mon+1,
3976                   newtime->tm_mday,
3977                   newtime->tm_hour,
3978                   newtime->tm_min,
3979                   newtime->tm_sec);
3980   return offs;
3981 }
3982 
3983 /* Create catalog and page structure - 2nd and 3th PDF object */
3984 
gl2psPrintPDFCatalog(void)3985 static int gl2psPrintPDFCatalog(void)
3986 {
3987   return fprintf(gl2ps->stream,
3988                  "2 0 obj\n"
3989                  "<<\n"
3990                  "/Type /Catalog\n"
3991                  "/Pages 3 0 R\n"
3992                  ">>\n"
3993                  "endobj\n");
3994 }
3995 
gl2psPrintPDFPages(void)3996 static int gl2psPrintPDFPages(void)
3997 {
3998   return fprintf(gl2ps->stream,
3999                  "3 0 obj\n"
4000                  "<<\n"
4001                  "/Type /Pages\n"
4002                  "/Kids [6 0 R]\n"
4003                  "/Count 1\n"
4004                  ">>\n"
4005                  "endobj\n");
4006 }
4007 
4008 /* Open stream for data - graphical objects, fonts etc. PDF object 4 */
4009 
gl2psOpenPDFDataStream(void)4010 static int gl2psOpenPDFDataStream(void)
4011 {
4012   int offs = 0;
4013 
4014   offs += fprintf(gl2ps->stream,
4015                   "4 0 obj\n"
4016                   "<<\n"
4017                   "/Length 5 0 R\n" );
4018   offs += gl2psPrintPDFCompressorType();
4019   offs += fprintf(gl2ps->stream,
4020                   ">>\n"
4021                   "stream\n");
4022   return offs;
4023 }
4024 
4025 /* Stream setup - Graphics state, fill background if allowed */
4026 
gl2psOpenPDFDataStreamWritePreface(void)4027 static int gl2psOpenPDFDataStreamWritePreface(void)
4028 {
4029   int offs;
4030 
4031   offs = gl2psPrintf("/GSa gs\n");
4032 
4033   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4034     offs += gl2psPrintPDFFillColor(gl2ps->bgcolor);
4035     offs += gl2psPrintf("%d %d %d %d re\n",
4036                         (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4037                         (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4038     offs += gl2psPrintf("f\n");
4039   }
4040   return offs;
4041 }
4042 
4043 /* Use the functions above to create the first part of the PDF*/
4044 
gl2psPrintPDFHeader(void)4045 static void gl2psPrintPDFHeader(void)
4046 {
4047   int offs = 0;
4048   gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
4049   gl2psPDFstacksInit();
4050 
4051   gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack);
4052 
4053 #if defined(GL2PS_HAVE_ZLIB)
4054   if(gl2ps->options & GL2PS_COMPRESS){
4055     gl2psSetupCompress();
4056   }
4057 #endif
4058   gl2ps->xreflist[0] = 0;
4059   offs += fprintf(gl2ps->stream, "%%PDF-1.4\n");
4060   gl2ps->xreflist[1] = offs;
4061 
4062   offs += gl2psPrintPDFInfo();
4063   gl2ps->xreflist[2] = offs;
4064 
4065   offs += gl2psPrintPDFCatalog();
4066   gl2ps->xreflist[3] = offs;
4067 
4068   offs += gl2psPrintPDFPages();
4069   gl2ps->xreflist[4] = offs;
4070 
4071   offs += gl2psOpenPDFDataStream();
4072   gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */
4073   gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface();
4074 }
4075 
4076 /* The central primitive drawing */
4077 
gl2psPrintPDFPrimitive(void * data)4078 static void gl2psPrintPDFPrimitive(void *data)
4079 {
4080   GL2PSprimitive *prim = *(GL2PSprimitive**)data;
4081 
4082   if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled)
4083     return;
4084 
4085   prim = gl2psCopyPrimitive(prim); /* deep copy */
4086   gl2psListAdd(gl2ps->pdfprimlist, &prim);
4087 }
4088 
4089 /* close stream and ... */
4090 
gl2psClosePDFDataStream(void)4091 static int gl2psClosePDFDataStream(void)
4092 {
4093   int offs = 0;
4094 
4095 #if defined(GL2PS_HAVE_ZLIB)
4096   if(gl2ps->options & GL2PS_COMPRESS){
4097     if(Z_OK != gl2psDeflate())
4098       gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
4099     else
4100       fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream);
4101     gl2ps->streamlength += gl2ps->compress->destLen;
4102 
4103     offs += gl2ps->streamlength;
4104     gl2psFreeCompress();
4105   }
4106 #endif
4107 
4108   offs += fprintf(gl2ps->stream,
4109                   "endstream\n"
4110                   "endobj\n");
4111   return offs;
4112 }
4113 
4114 /* ... write the now known length object */
4115 
gl2psPrintPDFDataStreamLength(int val)4116 static int gl2psPrintPDFDataStreamLength(int val)
4117 {
4118   return fprintf(gl2ps->stream,
4119                  "5 0 obj\n"
4120                  "%d\n"
4121                  "endobj\n", val);
4122 }
4123 
4124 /* Put the info created before in PDF objects */
4125 
gl2psPrintPDFOpenPage(void)4126 static int gl2psPrintPDFOpenPage(void)
4127 {
4128   int offs;
4129 
4130   /* Write fixed part */
4131 
4132   offs = fprintf(gl2ps->stream,
4133                  "6 0 obj\n"
4134                  "<<\n"
4135                  "/Type /Page\n"
4136                  "/Parent 3 0 R\n"
4137                  "/MediaBox [%d %d %d %d]\n",
4138                  (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4139                  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4140 
4141   if(gl2ps->options & GL2PS_LANDSCAPE)
4142     offs += fprintf(gl2ps->stream, "/Rotate -90\n");
4143 
4144   offs += fprintf(gl2ps->stream,
4145                   "/Contents 4 0 R\n"
4146                   "/Resources\n"
4147                   "<<\n"
4148                   "/ProcSet [/PDF /Text /ImageB /ImageC]  %%/ImageI\n");
4149 
4150   return offs;
4151 
4152   /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */
4153 }
4154 
gl2psPDFgroupListWriteVariableResources(void)4155 static int gl2psPDFgroupListWriteVariableResources(void)
4156 {
4157   int offs = 0;
4158 
4159   /* a) Graphics States for shader alpha masks*/
4160   offs += gl2psPDFgroupListWriteGStateResources();
4161 
4162   /* b) Shader and shader masks */
4163   offs += gl2psPDFgroupListWriteShaderResources();
4164 
4165   /* c) XObjects (Images & Shader Masks) */
4166   offs += gl2psPDFgroupListWriteXObjectResources();
4167 
4168   /* d) Fonts */
4169   offs += gl2psPDFgroupListWriteFontResources();
4170 
4171   /* End resources and page */
4172   offs += fprintf(gl2ps->stream,
4173                   ">>\n"
4174                   ">>\n"
4175                   "endobj\n");
4176   return offs;
4177 }
4178 
4179 /* Standard Graphics State */
4180 
gl2psPrintPDFGSObject(void)4181 static int gl2psPrintPDFGSObject(void)
4182 {
4183   return fprintf(gl2ps->stream,
4184                  "7 0 obj\n"
4185                  "<<\n"
4186                  "/Type /ExtGState\n"
4187                  "/SA false\n"
4188                  "/SM 0.02\n"
4189                  "/OP false\n"
4190                  "/op false\n"
4191                  "/OPM 0\n"
4192                  "/BG2 /Default\n"
4193                  "/UCR2 /Default\n"
4194                  "/TR2 /Default\n"
4195                  ">>\n"
4196                  "endobj\n");
4197 }
4198 
4199 /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */
4200 
gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex * vertex,size_t (* action)(unsigned long data,size_t size),GLfloat dx,GLfloat dy,GLfloat xmin,GLfloat ymin)4201 static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex,
4202                                               size_t (*action)(unsigned long data,
4203                                                                size_t size),
4204                                               GLfloat dx, GLfloat dy,
4205                                               GLfloat xmin, GLfloat ymin)
4206 {
4207   int offs = 0;
4208   unsigned long imap;
4209   GLfloat diff;
4210   double dmax = ~1UL;
4211   char edgeflag = 0;
4212 
4213   /* FIXME: temp bux fix for 64 bit archs: */
4214   if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4215 
4216   offs += (*action)(edgeflag, 1);
4217 
4218   /* The Shader stream in PDF requires to be in a 'big-endian'
4219      order */
4220 
4221   if(GL2PS_ZERO(dx*dy)){
4222     offs += (*action)(0, 4);
4223     offs += (*action)(0, 4);
4224   }
4225   else{
4226     diff = (vertex->xyz[0] - xmin) / dx;
4227     if(diff > 1)
4228       diff = 1.0F;
4229     else if(diff < 0)
4230       diff = 0.0F;
4231     imap = (unsigned long)(diff * dmax);
4232     offs += (*action)(imap, 4);
4233 
4234     diff = (vertex->xyz[1] - ymin) / dy;
4235     if(diff > 1)
4236       diff = 1.0F;
4237     else if(diff < 0)
4238       diff = 0.0F;
4239     imap = (unsigned long)(diff * dmax);
4240     offs += (*action)(imap, 4);
4241   }
4242 
4243   return offs;
4244 }
4245 
4246 /* Put vertex' rgb value (8bit for every component) in shader stream */
4247 
gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex * vertex,size_t (* action)(unsigned long data,size_t size))4248 static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex,
4249                                             size_t (*action)(unsigned long data,
4250                                                              size_t size))
4251 {
4252   int offs = 0;
4253   unsigned long imap;
4254   double dmax = ~1UL;
4255 
4256   /* FIXME: temp bux fix for 64 bit archs: */
4257   if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4258 
4259   imap = (unsigned long)((vertex->rgba[0]) * dmax);
4260   offs += (*action)(imap, 1);
4261 
4262   imap = (unsigned long)((vertex->rgba[1]) * dmax);
4263   offs += (*action)(imap, 1);
4264 
4265   imap = (unsigned long)((vertex->rgba[2]) * dmax);
4266   offs += (*action)(imap, 1);
4267 
4268   return offs;
4269 }
4270 
4271 /* Put vertex' alpha (8/16bit) in shader stream */
4272 
gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex * vertex,size_t (* action)(unsigned long data,size_t size),int sigbyte)4273 static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex,
4274                                               size_t (*action)(unsigned long data,
4275                                                                size_t size),
4276                                               int sigbyte)
4277 {
4278   int offs = 0;
4279   unsigned long imap;
4280   double dmax = ~1UL;
4281 
4282   /* FIXME: temp bux fix for 64 bit archs: */
4283   if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4284 
4285   if(sigbyte != 8 && sigbyte != 16)
4286     sigbyte = 8;
4287 
4288   sigbyte /= 8;
4289 
4290   imap = (unsigned long)((vertex->rgba[3]) * dmax);
4291 
4292   offs += (*action)(imap, sigbyte);
4293 
4294   return offs;
4295 }
4296 
4297 /* Put a triangles raw data in shader stream */
4298 
gl2psPrintPDFShaderStreamData(GL2PStriangle * triangle,GLfloat dx,GLfloat dy,GLfloat xmin,GLfloat ymin,size_t (* action)(unsigned long data,size_t size),int gray)4299 static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle,
4300                                          GLfloat dx, GLfloat dy,
4301                                          GLfloat xmin, GLfloat ymin,
4302                                          size_t (*action)(unsigned long data,
4303                                                           size_t size),
4304                                          int gray)
4305 {
4306   int i, offs = 0;
4307   GL2PSvertex v;
4308 
4309   if(gray && gray != 8 && gray != 16)
4310     gray = 8;
4311 
4312   for(i = 0; i < 3; ++i){
4313     offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action,
4314                                                dx, dy, xmin, ymin);
4315     if(gray){
4316       v = triangle->vertex[i];
4317       offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray);
4318     }
4319     else{
4320       offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action);
4321     }
4322   }
4323 
4324   return offs;
4325 }
4326 
gl2psPDFRectHull(GLfloat * xmin,GLfloat * xmax,GLfloat * ymin,GLfloat * ymax,GL2PStriangle * triangles,int cnt)4327 static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax,
4328                              GLfloat *ymin, GLfloat *ymax,
4329                              GL2PStriangle *triangles, int cnt)
4330 {
4331   int i, j;
4332 
4333   *xmin = triangles[0].vertex[0].xyz[0];
4334   *xmax = triangles[0].vertex[0].xyz[0];
4335   *ymin = triangles[0].vertex[0].xyz[1];
4336   *ymax = triangles[0].vertex[0].xyz[1];
4337 
4338   for(i = 0; i < cnt; ++i){
4339     for(j = 0; j < 3; ++j){
4340       if(*xmin > triangles[i].vertex[j].xyz[0])
4341         *xmin = triangles[i].vertex[j].xyz[0];
4342       if(*xmax < triangles[i].vertex[j].xyz[0])
4343         *xmax = triangles[i].vertex[j].xyz[0];
4344       if(*ymin > triangles[i].vertex[j].xyz[1])
4345         *ymin = triangles[i].vertex[j].xyz[1];
4346       if(*ymax < triangles[i].vertex[j].xyz[1])
4347         *ymax = triangles[i].vertex[j].xyz[1];
4348     }
4349   }
4350 }
4351 
4352 /* Writes shaded triangle
4353    gray == 0 means write RGB triangles
4354    gray == 8             8bit-grayscale (for alpha masks)
4355    gray == 16            16bit-grayscale (for alpha masks) */
4356 
gl2psPrintPDFShader(int obj,GL2PStriangle * triangles,int size,int gray)4357 static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles,
4358                                int size, int gray)
4359 {
4360   int i, offs = 0, vertexbytes, done = 0;
4361   GLfloat xmin, xmax, ymin, ymax;
4362 
4363   switch(gray){
4364   case 0:
4365     vertexbytes = 1+4+4+1+1+1;
4366     break;
4367   case 8:
4368     vertexbytes = 1+4+4+1;
4369     break;
4370   case 16:
4371     vertexbytes = 1+4+4+2;
4372     break;
4373   default:
4374     gray = 8;
4375     vertexbytes = 1+4+4+1;
4376     break;
4377   }
4378 
4379   gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size);
4380 
4381   offs += fprintf(gl2ps->stream,
4382                   "%d 0 obj\n"
4383                   "<< "
4384                   "/ShadingType 4 "
4385                   "/ColorSpace %s "
4386                   "/BitsPerCoordinate 32 "
4387                   "/BitsPerComponent %d "
4388                   "/BitsPerFlag 8 "
4389                   "/Decode [%f %f %f %f 0 1 %s] ",
4390                   obj,
4391                   (gray) ? "/DeviceGray" : "/DeviceRGB",
4392                   (gray) ? gray : 8,
4393                   xmin, xmax, ymin, ymax,
4394                   (gray) ? "" : "0 1 0 1");
4395 
4396 #if defined(GL2PS_HAVE_ZLIB)
4397   if(gl2ps->options & GL2PS_COMPRESS){
4398     gl2psAllocCompress(vertexbytes * size * 3);
4399 
4400     for(i = 0; i < size; ++i)
4401       gl2psPrintPDFShaderStreamData(&triangles[i],
4402                                     xmax-xmin, ymax-ymin, xmin, ymin,
4403                                     gl2psWriteBigEndianCompress, gray);
4404 
4405     if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4406       offs += gl2psPrintPDFCompressorType();
4407       offs += fprintf(gl2ps->stream,
4408                       "/Length %d "
4409                       ">>\n"
4410                       "stream\n",
4411                       (int)gl2ps->compress->destLen);
4412       offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest,
4413                                                 gl2ps->compress->destLen,
4414                                                 1, gl2ps->stream);
4415       done = 1;
4416     }
4417     gl2psFreeCompress();
4418   }
4419 #endif
4420 
4421   if(!done){
4422     /* no compression, or too long after compression, or compress error
4423        -> write non-compressed entry */
4424     offs += fprintf(gl2ps->stream,
4425                     "/Length %d "
4426                     ">>\n"
4427                     "stream\n",
4428                     vertexbytes * 3 * size);
4429     for(i = 0; i < size; ++i)
4430       offs += gl2psPrintPDFShaderStreamData(&triangles[i],
4431                                             xmax-xmin, ymax-ymin, xmin, ymin,
4432                                             gl2psWriteBigEndian, gray);
4433   }
4434 
4435   offs += fprintf(gl2ps->stream,
4436                   "\nendstream\n"
4437                   "endobj\n");
4438 
4439   return offs;
4440 }
4441 
4442 /* Writes a XObject for a shaded triangle mask */
4443 
gl2psPrintPDFShaderMask(int obj,int childobj)4444 static int gl2psPrintPDFShaderMask(int obj, int childobj)
4445 {
4446   int offs = 0, len;
4447 
4448   offs += fprintf(gl2ps->stream,
4449                   "%d 0 obj\n"
4450                   "<<\n"
4451                   "/Type /XObject\n"
4452                   "/Subtype /Form\n"
4453                   "/BBox [ %d %d %d %d ]\n"
4454                   "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n"
4455                   ">>\n",
4456                   obj,
4457                   (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4458                   (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4459 
4460   len = (childobj>0)
4461     ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1
4462     : strlen("/TrSh0 sh\n");
4463 
4464   offs += fprintf(gl2ps->stream,
4465                   "/Length %d\n"
4466                   ">>\n"
4467                   "stream\n",
4468                   len);
4469   offs += fprintf(gl2ps->stream,
4470                   "/TrSh%d sh\n",
4471                   childobj);
4472   offs += fprintf(gl2ps->stream,
4473                   "endstream\n"
4474                   "endobj\n");
4475 
4476   return offs;
4477 }
4478 
4479 /* Writes a Extended graphics state for a shaded triangle mask if
4480    simplealpha ist true the childobj argument is ignored and a /ca
4481    statement will be written instead */
4482 
gl2psPrintPDFShaderExtGS(int obj,int childobj)4483 static int gl2psPrintPDFShaderExtGS(int obj, int childobj)
4484 {
4485   int offs = 0;
4486 
4487   offs += fprintf(gl2ps->stream,
4488                   "%d 0 obj\n"
4489                   "<<\n",
4490                   obj);
4491 
4492   offs += fprintf(gl2ps->stream,
4493                   "/SMask << /S /Alpha /G %d 0 R >> ",
4494                   childobj);
4495 
4496   offs += fprintf(gl2ps->stream,
4497                   ">>\n"
4498                   "endobj\n");
4499   return offs;
4500 }
4501 
4502 /* a simple graphics state */
4503 
gl2psPrintPDFShaderSimpleExtGS(int obj,GLfloat alpha)4504 static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha)
4505 {
4506   int offs = 0;
4507 
4508   offs += fprintf(gl2ps->stream,
4509                   "%d 0 obj\n"
4510                   "<<\n"
4511                   "/ca %g"
4512                   ">>\n"
4513                   "endobj\n",
4514                   obj, alpha);
4515   return offs;
4516 }
4517 
4518 /* Similar groups of functions for pixmaps and text */
4519 
gl2psPrintPDFPixmapStreamData(GL2PSimage * im,size_t (* action)(unsigned long data,size_t size),int gray)4520 static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im,
4521                                          size_t (*action)(unsigned long data,
4522                                                           size_t size),
4523                                          int gray)
4524 {
4525   int x, y;
4526   GLfloat r, g, b, a;
4527 
4528   if(im->format != GL_RGBA && gray)
4529     return 0;
4530 
4531   if(gray && gray !=8 && gray != 16)
4532     gray = 8;
4533 
4534   gray /= 8;
4535 
4536   for(y = 0; y < im->height; ++y){
4537     for(x = 0; x < im->width; ++x){
4538       a = gl2psGetRGB(im, x, y, &r, &g, &b);
4539       if(im->format == GL_RGBA && gray){
4540         (*action)((unsigned long)(a*255) << 24, gray);
4541       }
4542       else{
4543         (*action)((unsigned long)(r*255) << 24, 1);
4544         (*action)((unsigned long)(g*255) << 24, 1);
4545         (*action)((unsigned long)(b*255) << 24, 1);
4546       }
4547     }
4548   }
4549 
4550   switch(gray){
4551   case 0: return 3 * im->width * im->height;
4552   case 1: return im->width * im->height;
4553   case 2: return 2 * im->width * im->height;
4554   default: return 3 * im->width * im->height;
4555   }
4556 }
4557 
gl2psPrintPDFPixmap(int obj,int childobj,GL2PSimage * im,int gray)4558 static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray)
4559 {
4560   int offs = 0, done = 0, sigbytes = 3;
4561 
4562   if(gray && gray !=8 && gray != 16)
4563     gray = 8;
4564 
4565   if(gray)
4566     sigbytes = gray / 8;
4567 
4568   offs += fprintf(gl2ps->stream,
4569                   "%d 0 obj\n"
4570                   "<<\n"
4571                   "/Type /XObject\n"
4572                   "/Subtype /Image\n"
4573                   "/Width %d\n"
4574                   "/Height %d\n"
4575                   "/ColorSpace %s \n"
4576                   "/BitsPerComponent 8\n",
4577                   obj,
4578                   (int)im->width, (int)im->height,
4579                   (gray) ? "/DeviceGray" : "/DeviceRGB" );
4580   if(GL_RGBA == im->format && gray == 0){
4581     offs += fprintf(gl2ps->stream,
4582                     "/SMask %d 0 R\n",
4583                     childobj);
4584   }
4585 
4586 #if defined(GL2PS_HAVE_ZLIB)
4587   if(gl2ps->options & GL2PS_COMPRESS){
4588     gl2psAllocCompress((int)(im->width * im->height * sigbytes));
4589 
4590     gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray);
4591 
4592     if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4593       offs += gl2psPrintPDFCompressorType();
4594       offs += fprintf(gl2ps->stream,
4595                       "/Length %d "
4596                       ">>\n"
4597                       "stream\n",
4598                       (int)gl2ps->compress->destLen);
4599       offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen,
4600                                                 1, gl2ps->stream);
4601       done = 1;
4602     }
4603     gl2psFreeCompress();
4604   }
4605 #endif
4606 
4607   if(!done){
4608     /* no compression, or too long after compression, or compress error
4609        -> write non-compressed entry */
4610     offs += fprintf(gl2ps->stream,
4611                     "/Length %d "
4612                     ">>\n"
4613                     "stream\n",
4614                     (int)(im->width * im->height * sigbytes));
4615     offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray);
4616   }
4617 
4618   offs += fprintf(gl2ps->stream,
4619                   "\nendstream\n"
4620                   "endobj\n");
4621 
4622   return offs;
4623 }
4624 
gl2psPrintPDFText(int obj,GL2PSstring * s,int fontnumber)4625 static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber)
4626 {
4627   int offs = 0;
4628 
4629   offs += fprintf(gl2ps->stream,
4630                   "%d 0 obj\n"
4631                   "<<\n"
4632                   "/Type /Font\n"
4633                   "/Subtype /Type1\n"
4634                   "/Name /F%d\n"
4635                   "/BaseFont /%s\n"
4636                   "/Encoding /MacRomanEncoding\n"
4637                   ">>\n"
4638                   "endobj\n",
4639                   obj, fontnumber, s->fontname);
4640   return offs;
4641 }
4642 
4643 /* Write the physical objects */
4644 
gl2psPDFgroupListWriteObjects(int entryoffs)4645 static int gl2psPDFgroupListWriteObjects(int entryoffs)
4646 {
4647   int i,j;
4648   GL2PSprimitive *p = NULL;
4649   GL2PSpdfgroup *gro;
4650   int offs = entryoffs;
4651   GL2PStriangle *triangles;
4652   int size = 0;
4653 
4654   if(!gl2ps->pdfgrouplist)
4655     return offs;
4656 
4657   for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
4658     gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
4659     if(!gl2psListNbr(gro->ptrlist))
4660       continue;
4661     p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
4662     switch(p->type){
4663     case GL2PS_POINT:
4664       break;
4665     case GL2PS_LINE:
4666       break;
4667     case GL2PS_TRIANGLE:
4668       size = gl2psListNbr(gro->ptrlist);
4669       triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size);
4670       for(j = 0; j < size; ++j){
4671         p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
4672         gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE);
4673       }
4674       if(triangles[0].prop & T_VAR_COLOR){
4675         gl2ps->xreflist[gro->shobjno] = offs;
4676         offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0);
4677       }
4678       if(triangles[0].prop & T_ALPHA_LESS_1){
4679         gl2ps->xreflist[gro->gsobjno] = offs;
4680         offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]);
4681       }
4682       if(triangles[0].prop & T_VAR_ALPHA){
4683         gl2ps->xreflist[gro->gsobjno] = offs;
4684         offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno);
4685         gl2ps->xreflist[gro->trgroupobjno] = offs;
4686         offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno);
4687         gl2ps->xreflist[gro->maskshobjno] = offs;
4688         offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8);
4689       }
4690       gl2psFree(triangles);
4691       break;
4692     case GL2PS_PIXMAP:
4693       gl2ps->xreflist[gro->imobjno] = offs;
4694       offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0);
4695       if(p->data.image->format == GL_RGBA){
4696         gl2ps->xreflist[gro->imobjno+1] = offs;
4697         offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8);
4698       }
4699       break;
4700     case GL2PS_TEXT:
4701       gl2ps->xreflist[gro->fontobjno] = offs;
4702       offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno);
4703       break;
4704     case GL2PS_SPECIAL :
4705       /* alignment contains the format for which the special output text
4706          is intended */
4707       if(p->data.text->alignment == GL2PS_PDF)
4708         offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str);
4709       break;
4710     default:
4711       break;
4712     }
4713   }
4714   return offs;
4715 }
4716 
4717 /* All variable data has been written at this point and all required
4718    functioninality has been gathered, so we can write now file footer
4719    with cross reference table and trailer */
4720 
gl2psPrintPDFFooter(void)4721 static void gl2psPrintPDFFooter(void)
4722 {
4723   int i, offs;
4724 
4725   gl2psPDFgroupListInit();
4726   gl2psPDFgroupListWriteMainStream();
4727 
4728   offs = gl2ps->xreflist[5] + gl2ps->streamlength;
4729   offs += gl2psClosePDFDataStream();
4730   gl2ps->xreflist[5] = offs;
4731 
4732   offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength);
4733   gl2ps->xreflist[6] = offs;
4734   gl2ps->streamlength = 0;
4735 
4736   offs += gl2psPrintPDFOpenPage();
4737   offs += gl2psPDFgroupListWriteVariableResources();
4738   gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist,
4739                                        sizeof(int) * (gl2ps->objects_stack + 1));
4740   gl2ps->xreflist[7] = offs;
4741 
4742   offs += gl2psPrintPDFGSObject();
4743   gl2ps->xreflist[8] = offs;
4744 
4745   gl2ps->xreflist[gl2ps->objects_stack] =
4746     gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]);
4747 
4748   /* Start cross reference table. The file has to been opened in
4749      binary mode to preserve the 20 digit string length! */
4750   fprintf(gl2ps->stream,
4751           "xref\n"
4752           "0 %d\n"
4753           "%010d 65535 f \n", gl2ps->objects_stack, 0);
4754 
4755   for(i = 1; i < gl2ps->objects_stack; ++i)
4756     fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]);
4757 
4758   fprintf(gl2ps->stream,
4759           "trailer\n"
4760           "<<\n"
4761           "/Size %d\n"
4762           "/Info 1 0 R\n"
4763           "/Root 2 0 R\n"
4764           ">>\n"
4765           "startxref\n%d\n"
4766           "%%%%EOF\n",
4767           gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]);
4768 
4769   /* Free auxiliary lists and arrays */
4770   gl2psFree(gl2ps->xreflist);
4771   gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive);
4772   gl2psListDelete(gl2ps->pdfprimlist);
4773   gl2psPDFgroupListDelete();
4774 
4775 #if defined(GL2PS_HAVE_ZLIB)
4776   if(gl2ps->options & GL2PS_COMPRESS){
4777     gl2psFreeCompress();
4778     gl2psFree(gl2ps->compress);
4779     gl2ps->compress = NULL;
4780   }
4781 #endif
4782 }
4783 
4784 /* PDF begin viewport */
4785 
gl2psPrintPDFBeginViewport(GLint viewport[4])4786 static void gl2psPrintPDFBeginViewport(GLint viewport[4])
4787 {
4788   int offs = 0;
4789   GLint index;
4790   GLfloat rgba[4];
4791   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
4792 
4793   glRenderMode(GL_FEEDBACK);
4794 
4795   if(gl2ps->header){
4796     gl2psPrintPDFHeader();
4797     gl2ps->header = GL_FALSE;
4798   }
4799 
4800   offs += gl2psPrintf("q\n");
4801 
4802   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4803     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
4804       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
4805     }
4806     else{
4807       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
4808       rgba[0] = gl2ps->colormap[index][0];
4809       rgba[1] = gl2ps->colormap[index][1];
4810       rgba[2] = gl2ps->colormap[index][2];
4811       rgba[3] = 1.0F;
4812     }
4813     offs += gl2psPrintPDFFillColor(rgba);
4814     offs += gl2psPrintf("%d %d %d %d re\n"
4815                         "W\n"
4816                         "f\n",
4817                         x, y, w, h);
4818   }
4819   else{
4820     offs += gl2psPrintf("%d %d %d %d re\n"
4821                         "W\n"
4822                         "n\n",
4823                         x, y, w, h);
4824   }
4825 
4826   gl2ps->streamlength += offs;
4827 }
4828 
gl2psPrintPDFEndViewport(void)4829 static GLint gl2psPrintPDFEndViewport(void)
4830 {
4831   GLint res;
4832 
4833   res = gl2psPrintPrimitives();
4834   gl2ps->streamlength += gl2psPrintf("Q\n");
4835   return res;
4836 }
4837 
gl2psPrintPDFFinalPrimitive(void)4838 static void gl2psPrintPDFFinalPrimitive(void)
4839 {
4840 }
4841 
4842 /* definition of the PDF backend */
4843 
4844 static GL2PSbackend gl2psPDF = {
4845   gl2psPrintPDFHeader,
4846   gl2psPrintPDFFooter,
4847   gl2psPrintPDFBeginViewport,
4848   gl2psPrintPDFEndViewport,
4849   gl2psPrintPDFPrimitive,
4850   gl2psPrintPDFFinalPrimitive,
4851   "pdf",
4852   "Portable Document Format"
4853 };
4854 
4855 /*********************************************************************
4856  *
4857  * SVG routines
4858  *
4859  *********************************************************************/
4860 
gl2psSVGGetCoordsAndColors(int n,GL2PSvertex * verts,GL2PSxyz * xyz,GL2PSrgba * rgba)4861 static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts,
4862                                        GL2PSxyz *xyz, GL2PSrgba *rgba)
4863 {
4864   int i, j;
4865 
4866   for(i = 0; i < n; i++){
4867     xyz[i][0] = verts[i].xyz[0];
4868     xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1];
4869     xyz[i][2] = 0.0F;
4870     for(j = 0; j < 4; j++)
4871       rgba[i][j] = verts[i].rgba[j];
4872   }
4873 }
4874 
gl2psSVGGetColorString(GL2PSrgba rgba,char str[32])4875 static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32])
4876 {
4877   int r = (int)(255. * rgba[0]);
4878   int g = (int)(255. * rgba[1]);
4879   int b = (int)(255. * rgba[2]);
4880   int rc = (r < 0) ? 0 : (r > 255) ? 255 : r;
4881   int gc = (g < 0) ? 0 : (g > 255) ? 255 : g;
4882   int bc = (b < 0) ? 0 : (b > 255) ? 255 : b;
4883   sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc);
4884 }
4885 
gl2psPrintSVGHeader(void)4886 static void gl2psPrintSVGHeader(void)
4887 {
4888   int x, y, width, height;
4889   char col[32];
4890   time_t now;
4891 
4892   time(&now);
4893 
4894   if (gl2ps->options & GL2PS_LANDSCAPE){
4895     x = (int)gl2ps->viewport[1];
4896     y = (int)gl2ps->viewport[0];
4897     width = (int)gl2ps->viewport[3];
4898     height = (int)gl2ps->viewport[2];
4899   }
4900   else{
4901     x = (int)gl2ps->viewport[0];
4902     y = (int)gl2ps->viewport[1];
4903     width = (int)gl2ps->viewport[2];
4904     height = (int)gl2ps->viewport[3];
4905   }
4906 
4907   /* Compressed SVG files (.svgz) are simply gzipped SVG files */
4908   gl2psPrintGzipHeader();
4909 
4910   gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
4911   gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
4912   gl2psPrintf("     xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
4913               "     width=\"%dpx\" height=\"%dpx\" viewBox=\"%d %d %d %d\">\n",
4914               width, height, x, y, width, height);
4915   gl2psPrintf("<title>%s</title>\n", gl2ps->title);
4916   gl2psPrintf("<desc>\n");
4917   gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n"
4918               "For: %s\n"
4919               "CreationDate: %s",
4920               GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION,
4921               GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now));
4922   gl2psPrintf("</desc>\n");
4923   gl2psPrintf("<defs>\n");
4924   gl2psPrintf("</defs>\n");
4925 
4926   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4927     gl2psSVGGetColorString(gl2ps->bgcolor, col);
4928     gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
4929                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4930                 (int)gl2ps->viewport[2], (int)gl2ps->viewport[1],
4931                 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3],
4932                 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
4933   }
4934 
4935   /* group all the primitives and disable antialiasing */
4936   gl2psPrintf("<g shape-rendering=\"crispEdges\">\n");
4937 }
4938 
gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3],GL2PSrgba rgba[3])4939 static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3])
4940 {
4941   int i;
4942   GL2PSxyz xyz2[3];
4943   GL2PSrgba rgba2[3];
4944   char col[32];
4945 
4946   /* Apparently there is no easy way to do Gouraud shading in SVG
4947      without explicitly pre-defining gradients, so for now we just do
4948      recursive subdivision */
4949 
4950   if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){
4951     gl2psSVGGetColorString(rgba[0], col);
4952     gl2psPrintf("<polygon fill=\"%s\" ", col);
4953     if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
4954     gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1],
4955                 xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]);
4956   }
4957   else{
4958     /* subdivide into 4 subtriangles */
4959     for(i = 0; i < 3; i++){
4960       xyz2[0][i] = xyz[0][i];
4961       xyz2[1][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
4962       xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
4963     }
4964     for(i = 0; i < 4; i++){
4965       rgba2[0][i] = rgba[0][i];
4966       rgba2[1][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
4967       rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
4968     }
4969     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4970     for(i = 0; i < 3; i++){
4971       xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
4972       xyz2[1][i] = xyz[1][i];
4973       xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]);
4974     }
4975     for(i = 0; i < 4; i++){
4976       rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
4977       rgba2[1][i] = rgba[1][i];
4978       rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]);
4979     }
4980     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4981     for(i = 0; i < 3; i++){
4982       xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
4983       xyz2[1][i] = xyz[2][i];
4984       xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]);
4985     }
4986     for(i = 0; i < 4; i++){
4987       rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
4988       rgba2[1][i] = rgba[2][i];
4989       rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]);
4990     }
4991     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4992     for(i = 0; i < 3; i++){
4993       xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]);
4994       xyz2[1][i] = 0.5 * (xyz[1][i] + xyz[2][i]);
4995       xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]);
4996     }
4997     for(i = 0; i < 4; i++){
4998       rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]);
4999       rgba2[1][i] = 0.5 * (rgba[1][i] + rgba[2][i]);
5000       rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]);
5001     }
5002     gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
5003   }
5004 }
5005 
gl2psPrintSVGDash(GLushort pattern,GLint factor)5006 static void gl2psPrintSVGDash(GLushort pattern, GLint factor)
5007 {
5008   int i, n, array[10];
5009 
5010   if(!pattern || !factor) return; /* solid line */
5011 
5012   gl2psParseStipplePattern(pattern, factor, &n, array);
5013   gl2psPrintf("stroke-dasharray=\"");
5014   for(i = 0; i < n; i++){
5015     if(i) gl2psPrintf(",");
5016     gl2psPrintf("%d", array[i]);
5017   }
5018   gl2psPrintf("\" ");
5019 }
5020 
gl2psEndSVGLine(void)5021 static void gl2psEndSVGLine(void)
5022 {
5023   int i;
5024   if(gl2ps->lastvertex.rgba[0] >= 0.){
5025     gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0],
5026                 gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]);
5027     for(i = 0; i < 3; i++)
5028       gl2ps->lastvertex.xyz[i] = -1.;
5029     for(i = 0; i < 4; i++)
5030       gl2ps->lastvertex.rgba[i] = -1.;
5031   }
5032 }
5033 
gl2psPrintSVGPixmap(GLfloat x,GLfloat y,GL2PSimage * pixmap)5034 static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap)
5035 {
5036 #if defined(GL2PS_HAVE_LIBPNG)
5037   GL2PSlist *png;
5038   unsigned char c;
5039   int i;
5040 
5041   /* The only image types supported by the SVG standard are JPEG, PNG
5042      and SVG. Here we choose PNG, and since we want to embed the image
5043      directly in the SVG stream (and not link to an external image
5044      file), we need to encode the pixmap into PNG in memory, then
5045      encode it into base64. */
5046 
5047   png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000,
5048                         sizeof(unsigned char));
5049   gl2psConvertPixmapToPNG(pixmap, png);
5050   gl2psListEncodeBase64(png);
5051   gl2psPrintf("<image x=\"%g\" y=\"%g\" width=\"%d\" height=\"%d\"\n",
5052               x, y - pixmap->height, pixmap->width, pixmap->height);
5053   gl2psPrintf("xlink:href=\"data:image/png;base64,");
5054   for(i = 0; i < gl2psListNbr(png); i++){
5055     gl2psListRead(png, i, &c);
5056     gl2psPrintf("%c", c);
5057   }
5058   gl2psPrintf("\"/>\n");
5059   gl2psListDelete(png);
5060 #else
5061   gl2psMsg(GL2PS_WARNING, "GL2PS has to be compiled with PNG support in "
5062            "order to embed images in SVG streams");
5063 #endif
5064 }
5065 
gl2psPrintSVGPrimitive(void * data)5066 static void gl2psPrintSVGPrimitive(void *data)
5067 {
5068   GL2PSprimitive *prim;
5069   GL2PSxyz xyz[4];
5070   GL2PSrgba rgba[4];
5071   char col[32];
5072   int newline;
5073 
5074   prim = *(GL2PSprimitive**)data;
5075 
5076   if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
5077 
5078   /* We try to draw connected lines as a single path to get nice line
5079      joins and correct stippling. So if the primitive to print is not
5080      a line we must first finish the current line (if any): */
5081   if(prim->type != GL2PS_LINE) gl2psEndSVGLine();
5082 
5083   gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba);
5084 
5085   switch(prim->type){
5086   case GL2PS_POINT :
5087     gl2psSVGGetColorString(rgba[0], col);
5088     gl2psPrintf("<circle fill=\"%s\" ", col);
5089     if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
5090     gl2psPrintf("cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
5091                 xyz[0][0], xyz[0][1], 0.5 * prim->width);
5092     break;
5093   case GL2PS_LINE :
5094     if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
5095        !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
5096        gl2ps->lastlinewidth != prim->width ||
5097        gl2ps->lastpattern != prim->pattern ||
5098        gl2ps->lastfactor != prim->factor){
5099       /* End the current line if the new segment does not start where
5100          the last one ended, or if the color, the width or the
5101          stippling have changed (we will need to use multi-point
5102          gradients for smooth-shaded lines) */
5103       gl2psEndSVGLine();
5104       newline = 1;
5105     }
5106     else{
5107       newline = 0;
5108     }
5109     gl2ps->lastvertex = prim->verts[1];
5110     gl2psSetLastColor(prim->verts[0].rgba);
5111     gl2ps->lastlinewidth = prim->width;
5112     gl2ps->lastpattern = prim->pattern;
5113     gl2ps->lastfactor = prim->factor;
5114     if(newline){
5115       gl2psSVGGetColorString(rgba[0], col);
5116       gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ",
5117                   col, prim->width);
5118       if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]);
5119       gl2psPrintSVGDash(prim->pattern, prim->factor);
5120       gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]);
5121     }
5122     else{
5123       gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]);
5124     }
5125     break;
5126   case GL2PS_TRIANGLE :
5127     gl2psPrintSVGSmoothTriangle(xyz, rgba);
5128     break;
5129   case GL2PS_QUADRANGLE :
5130     gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
5131     break;
5132   case GL2PS_PIXMAP :
5133     gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image);
5134     break;
5135   case GL2PS_TEXT :
5136     gl2psSVGGetColorString(prim->verts[0].rgba, col);
5137     gl2psPrintf("<text fill=\"%s\" x=\"%g\" y=\"%g\" font-size=\"%d\" ",
5138                 col, xyz[0][0], xyz[0][1], prim->data.text->fontsize);
5139     if(!strcmp(prim->data.text->fontname, "Times-Roman"))
5140       gl2psPrintf("font-family=\"Times\">");
5141     else if(!strcmp(prim->data.text->fontname, "Times-Bold"))
5142       gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">");
5143     else if(!strcmp(prim->data.text->fontname, "Times-Italic"))
5144       gl2psPrintf("font-family=\"Times\" font-style=\"italic\">");
5145     else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic"))
5146       gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">");
5147     else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold"))
5148       gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">");
5149     else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique"))
5150       gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">");
5151     else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique"))
5152       gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">");
5153     else if(!strcmp(prim->data.text->fontname, "Courier-Bold"))
5154       gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">");
5155     else if(!strcmp(prim->data.text->fontname, "Courier-Oblique"))
5156       gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">");
5157     else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique"))
5158       gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">");
5159     else
5160       gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname);
5161     gl2psPrintf("%s</text>\n", prim->data.text->str);
5162     break;
5163   case GL2PS_SPECIAL :
5164     /* alignment contains the format for which the special output text
5165        is intended */
5166     if(prim->data.text->alignment == GL2PS_SVG)
5167       gl2psPrintf("%s\n", prim->data.text->str);
5168     break;
5169   default :
5170     break;
5171   }
5172 }
5173 
gl2psPrintSVGFooter(void)5174 static void gl2psPrintSVGFooter(void)
5175 {
5176   gl2psPrintf("</g>\n");
5177   gl2psPrintf("</svg>\n");
5178 
5179   gl2psPrintGzipFooter();
5180 }
5181 
gl2psPrintSVGBeginViewport(GLint viewport[4])5182 static void gl2psPrintSVGBeginViewport(GLint viewport[4])
5183 {
5184   GLint index;
5185   char col[32];
5186   GLfloat rgba[4];
5187   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
5188 
5189   glRenderMode(GL_FEEDBACK);
5190 
5191   if(gl2ps->header){
5192     gl2psPrintSVGHeader();
5193     gl2ps->header = GL_FALSE;
5194   }
5195 
5196   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5197     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
5198       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
5199     }
5200     else{
5201       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5202       rgba[0] = gl2ps->colormap[index][0];
5203       rgba[1] = gl2ps->colormap[index][1];
5204       rgba[2] = gl2ps->colormap[index][2];
5205       rgba[3] = 1.0F;
5206     }
5207     gl2psSVGGetColorString(rgba, col);
5208     gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
5209                 x, gl2ps->viewport[3] - y,
5210                 x + w, gl2ps->viewport[3] - y,
5211                 x + w, gl2ps->viewport[3] - (y + h),
5212                 x, gl2ps->viewport[3] - (y + h));
5213   }
5214 
5215   gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h);
5216   gl2psPrintf("  <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n",
5217               x, gl2ps->viewport[3] - y,
5218               x + w, gl2ps->viewport[3] - y,
5219               x + w, gl2ps->viewport[3] - (y + h),
5220               x, gl2ps->viewport[3] - (y + h));
5221   gl2psPrintf("</clipPath>\n");
5222   gl2psPrintf("<g clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h);
5223 }
5224 
gl2psPrintSVGEndViewport(void)5225 static GLint gl2psPrintSVGEndViewport(void)
5226 {
5227   GLint res;
5228 
5229   res = gl2psPrintPrimitives();
5230   gl2psPrintf("</g>\n");
5231   return res;
5232 }
5233 
gl2psPrintSVGFinalPrimitive(void)5234 static void gl2psPrintSVGFinalPrimitive(void)
5235 {
5236   /* End any remaining line, if any */
5237   gl2psEndSVGLine();
5238 }
5239 
5240 /* definition of the SVG backend */
5241 
5242 static GL2PSbackend gl2psSVG = {
5243   gl2psPrintSVGHeader,
5244   gl2psPrintSVGFooter,
5245   gl2psPrintSVGBeginViewport,
5246   gl2psPrintSVGEndViewport,
5247   gl2psPrintSVGPrimitive,
5248   gl2psPrintSVGFinalPrimitive,
5249   "svg",
5250   "Scalable Vector Graphics"
5251 };
5252 
5253 /*********************************************************************
5254  *
5255  * PGF routines
5256  *
5257  *********************************************************************/
5258 
gl2psPrintPGFColor(GL2PSrgba rgba)5259 static void gl2psPrintPGFColor(GL2PSrgba rgba)
5260 {
5261   if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
5262     gl2psSetLastColor(rgba);
5263     fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]);
5264   }
5265 }
5266 
gl2psPrintPGFHeader(void)5267 static void gl2psPrintPGFHeader(void)
5268 {
5269   time_t now;
5270 
5271   time(&now);
5272 
5273   fprintf(gl2ps->stream,
5274           "%% Title: %s\n"
5275           "%% Creator: GL2PS %d.%d.%d%s, %s\n"
5276           "%% For: %s\n"
5277           "%% CreationDate: %s",
5278           gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
5279           GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
5280           gl2ps->producer, ctime(&now));
5281 
5282   fprintf(gl2ps->stream, "\\begin{pgfpicture}\n");
5283   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5284     gl2psPrintPGFColor(gl2ps->bgcolor);
5285     fprintf(gl2ps->stream,
5286             "\\pgfpathrectanglecorners{"
5287             "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n"
5288             "\\pgfusepath{fill}\n",
5289             (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
5290             (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
5291   }
5292 }
5293 
gl2psPrintPGFDash(GLushort pattern,GLint factor)5294 static void gl2psPrintPGFDash(GLushort pattern, GLint factor)
5295 {
5296   int i, n, array[10];
5297 
5298   if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
5299     return;
5300 
5301   gl2ps->lastpattern = pattern;
5302   gl2ps->lastfactor = factor;
5303 
5304   if(!pattern || !factor){
5305     /* solid line */
5306     fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n");
5307   }
5308   else{
5309     gl2psParseStipplePattern(pattern, factor, &n, array);
5310     fprintf(gl2ps->stream, "\\pgfsetdash{");
5311     for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]);
5312     fprintf(gl2ps->stream, "}{0pt}\n");
5313   }
5314 }
5315 
gl2psPGFTextAlignment(int align)5316 static const char *gl2psPGFTextAlignment(int align)
5317 {
5318   switch(align){
5319   case GL2PS_TEXT_C  : return "center";
5320   case GL2PS_TEXT_CL : return "west";
5321   case GL2PS_TEXT_CR : return "east";
5322   case GL2PS_TEXT_B  : return "south";
5323   case GL2PS_TEXT_BR : return "south east";
5324   case GL2PS_TEXT_T  : return "north";
5325   case GL2PS_TEXT_TL : return "north west";
5326   case GL2PS_TEXT_TR : return "north east";
5327   case GL2PS_TEXT_BL :
5328   default            : return "south west";
5329   }
5330 }
5331 
gl2psPrintPGFPrimitive(void * data)5332 static void gl2psPrintPGFPrimitive(void *data)
5333 {
5334   GL2PSprimitive *prim;
5335 
5336   prim = *(GL2PSprimitive**)data;
5337 
5338   switch(prim->type){
5339   case GL2PS_POINT :
5340     /* Points in openGL are rectangular */
5341     gl2psPrintPGFColor(prim->verts[0].rgba);
5342     fprintf(gl2ps->stream,
5343             "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}"
5344             "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n",
5345             prim->verts[0].xyz[0]-0.5*prim->width,
5346             prim->verts[0].xyz[1]-0.5*prim->width,
5347             prim->width,prim->width);
5348     break;
5349   case GL2PS_LINE :
5350     gl2psPrintPGFColor(prim->verts[0].rgba);
5351     if(gl2ps->lastlinewidth != prim->width){
5352       gl2ps->lastlinewidth = prim->width;
5353       fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth);
5354     }
5355     gl2psPrintPGFDash(prim->pattern, prim->factor);
5356     fprintf(gl2ps->stream,
5357             "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
5358             "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5359             "\\pgfusepath{stroke}\n",
5360             prim->verts[1].xyz[0], prim->verts[1].xyz[1],
5361             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5362     break;
5363   case GL2PS_TRIANGLE :
5364     if(gl2ps->lastlinewidth != 0){
5365       gl2ps->lastlinewidth = 0;
5366       fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n");
5367     }
5368     gl2psPrintPGFColor(prim->verts[0].rgba);
5369     fprintf(gl2ps->stream,
5370             "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
5371             "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5372             "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5373             "\\pgfpathclose\n"
5374             "\\pgfusepath{fill,stroke}\n",
5375             prim->verts[2].xyz[0], prim->verts[2].xyz[1],
5376             prim->verts[1].xyz[0], prim->verts[1].xyz[1],
5377             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5378     break;
5379   case GL2PS_TEXT :
5380     fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n",
5381             prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5382 
5383     if(prim->data.text->angle)
5384       fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle);
5385 
5386     fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont",
5387             gl2psPGFTextAlignment(prim->data.text->alignment),
5388             prim->data.text->fontsize);
5389 
5390     fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}",
5391             prim->verts[0].rgba[0], prim->verts[0].rgba[1],
5392             prim->verts[0].rgba[2], prim->data.text->str);
5393 
5394     fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n");
5395     break;
5396   case GL2PS_SPECIAL :
5397     /* alignment contains the format for which the special output text
5398        is intended */
5399     if (prim->data.text->alignment == GL2PS_PGF)
5400       fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
5401     break;
5402   default :
5403     break;
5404   }
5405 }
5406 
gl2psPrintPGFFooter(void)5407 static void gl2psPrintPGFFooter(void)
5408 {
5409   fprintf(gl2ps->stream, "\\end{pgfpicture}\n");
5410 }
5411 
gl2psPrintPGFBeginViewport(GLint viewport[4])5412 static void gl2psPrintPGFBeginViewport(GLint viewport[4])
5413 {
5414   GLint index;
5415   GLfloat rgba[4];
5416   int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
5417 
5418   glRenderMode(GL_FEEDBACK);
5419 
5420   if(gl2ps->header){
5421     gl2psPrintPGFHeader();
5422     gl2ps->header = GL_FALSE;
5423   }
5424 
5425   fprintf(gl2ps->stream, "\\begin{pgfscope}\n");
5426   if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5427     if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
5428       glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
5429     }
5430     else{
5431       glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5432       rgba[0] = gl2ps->colormap[index][0];
5433       rgba[1] = gl2ps->colormap[index][1];
5434       rgba[2] = gl2ps->colormap[index][2];
5435       rgba[3] = 1.0F;
5436     }
5437     gl2psPrintPGFColor(rgba);
5438     fprintf(gl2ps->stream,
5439             "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
5440             "{\\pgfpoint{%dpt}{%dpt}}\n"
5441             "\\pgfusepath{fill}\n",
5442             x, y, w, h);
5443   }
5444 
5445   fprintf(gl2ps->stream,
5446           "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
5447           "{\\pgfpoint{%dpt}{%dpt}}\n"
5448           "\\pgfusepath{clip}\n",
5449           x, y, w, h);
5450 }
5451 
gl2psPrintPGFEndViewport(void)5452 static GLint gl2psPrintPGFEndViewport(void)
5453 {
5454   GLint res;
5455   res = gl2psPrintPrimitives();
5456   fprintf(gl2ps->stream, "\\end{pgfscope}\n");
5457   return res;
5458 }
5459 
gl2psPrintPGFFinalPrimitive(void)5460 static void gl2psPrintPGFFinalPrimitive(void)
5461 {
5462 }
5463 
5464 /* definition of the PGF backend */
5465 
5466 static GL2PSbackend gl2psPGF = {
5467   gl2psPrintPGFHeader,
5468   gl2psPrintPGFFooter,
5469   gl2psPrintPGFBeginViewport,
5470   gl2psPrintPGFEndViewport,
5471   gl2psPrintPGFPrimitive,
5472   gl2psPrintPGFFinalPrimitive,
5473   "tex",
5474   "PGF Latex Graphics"
5475 };
5476 
5477 /*********************************************************************
5478  *
5479  * General primitive printing routine
5480  *
5481  *********************************************************************/
5482 
5483 /* Warning: the ordering of the backends must match the format
5484    #defines in gl2ps.h */
5485 
5486 static GL2PSbackend *gl2psbackends[] = {
5487   &gl2psPS,  /* 0 */
5488   &gl2psEPS, /* 1 */
5489   &gl2psTEX, /* 2 */
5490   &gl2psPDF, /* 3 */
5491   &gl2psSVG, /* 4 */
5492   &gl2psPGF  /* 5 */
5493 };
5494 
gl2psComputeTightBoundingBox(void * data)5495 static void gl2psComputeTightBoundingBox(void *data)
5496 {
5497   GL2PSprimitive *prim;
5498   int i;
5499 
5500   prim = *(GL2PSprimitive**)data;
5501 
5502   for(i = 0; i < prim->numverts; i++){
5503     if(prim->verts[i].xyz[0] < gl2ps->viewport[0])
5504       gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0];
5505     if(prim->verts[i].xyz[0] > gl2ps->viewport[2])
5506       gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F);
5507     if(prim->verts[i].xyz[1] < gl2ps->viewport[1])
5508       gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1];
5509     if(prim->verts[i].xyz[1] > gl2ps->viewport[3])
5510       gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F);
5511   }
5512 }
5513 
gl2psPrintPrimitives(void)5514 static GLint gl2psPrintPrimitives(void)
5515 {
5516   GL2PSbsptree *root;
5517   GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE};
5518   GLint used;
5519 
5520   used = glRenderMode(GL_RENDER);
5521 
5522   if(used < 0){
5523     gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow");
5524     return GL2PS_OVERFLOW;
5525   }
5526 
5527   if(used > 0)
5528     gl2psParseFeedbackBuffer(used);
5529 
5530   gl2psRescaleAndOffset();
5531 
5532   if(gl2ps->header){
5533     if(gl2psListNbr(gl2ps->primitives) &&
5534        (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){
5535       gl2ps->viewport[0] = gl2ps->viewport[1] = 100000;
5536       gl2ps->viewport[2] = gl2ps->viewport[3] = -100000;
5537       gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox);
5538     }
5539     (gl2psbackends[gl2ps->format]->printHeader)();
5540     gl2ps->header = GL_FALSE;
5541   }
5542 
5543   if(!gl2psListNbr(gl2ps->primitives)){
5544     /* empty feedback buffer and/or nothing else to print */
5545     return GL2PS_NO_FEEDBACK;
5546   }
5547 
5548   switch(gl2ps->sort){
5549   case GL2PS_NO_SORT :
5550     gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
5551     gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
5552     /* reset the primitive list, waiting for the next viewport */
5553     gl2psListReset(gl2ps->primitives);
5554     break;
5555   case GL2PS_SIMPLE_SORT :
5556     gl2psListSort(gl2ps->primitives, gl2psCompareDepth);
5557     if(gl2ps->options & GL2PS_OCCLUSION_CULL){
5558       gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree);
5559       gl2psFreeBspImageTree(&gl2ps->imagetree);
5560     }
5561     gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
5562     gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
5563     /* reset the primitive list, waiting for the next viewport */
5564     gl2psListReset(gl2ps->primitives);
5565     break;
5566   case GL2PS_BSP_SORT :
5567     root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
5568     gl2psBuildBspTree(root, gl2ps->primitives);
5569     if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root);
5570     if(gl2ps->options & GL2PS_OCCLUSION_CULL){
5571       gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess,
5572                            gl2psAddInImageTree, 1);
5573       gl2psFreeBspImageTree(&gl2ps->imagetree);
5574     }
5575     gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater,
5576                          gl2psbackends[gl2ps->format]->printPrimitive, 0);
5577     gl2psFreeBspTree(&root);
5578     /* reallocate the primitive list (it's been deleted by
5579        gl2psBuildBspTree) in case there is another viewport */
5580     gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
5581     break;
5582   }
5583   gl2psbackends[gl2ps->format]->printFinalPrimitive();
5584 
5585   return GL2PS_SUCCESS;
5586 }
5587 
5588 /*********************************************************************
5589  *
5590  * Public routines
5591  *
5592  *********************************************************************/
5593 
gl2psBeginPage(const char * title,const char * producer,GLint viewport[4],GLint format,GLint sort,GLint options,GLint colormode,GLint colorsize,GL2PSrgba * colormap,GLint nr,GLint ng,GLint nb,GLint buffersize,FILE * stream,const char * filename)5594 GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
5595                                   GLint viewport[4], GLint format, GLint sort,
5596                                   GLint options, GLint colormode,
5597                                   GLint colorsize, GL2PSrgba *colormap,
5598                                   GLint nr, GLint ng, GLint nb, GLint buffersize,
5599                                   FILE *stream, const char *filename)
5600 {
5601   GLint index;
5602   int i;
5603 
5604   if(gl2ps){
5605     gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state");
5606     return GL2PS_ERROR;
5607   }
5608 
5609   gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext));
5610 
5611   // PATCH BURRTOOLS
5612   gl2ps->boundMinX = gl2ps->boundMinY = 10000;
5613   gl2ps->boundMaxX = gl2ps->boundMaxY = -10000;
5614 
5615   if(format >= 0 && format < (GLint)(sizeof(gl2psbackends)/sizeof(gl2psbackends[0]))){
5616     gl2ps->format = format;
5617   }
5618   else {
5619     gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format);
5620     gl2psFree(gl2ps);
5621     gl2ps = NULL;
5622     return GL2PS_ERROR;
5623   }
5624 
5625   switch(sort){
5626   case GL2PS_NO_SORT :
5627   case GL2PS_SIMPLE_SORT :
5628   case GL2PS_BSP_SORT :
5629     gl2ps->sort = sort;
5630     break;
5631   default :
5632     gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort);
5633     gl2psFree(gl2ps);
5634     gl2ps = NULL;
5635     return GL2PS_ERROR;
5636   }
5637 
5638   if(stream){
5639     gl2ps->stream = stream;
5640   }
5641   else{
5642     gl2psMsg(GL2PS_ERROR, "Bad file pointer");
5643     gl2psFree(gl2ps);
5644     gl2ps = NULL;
5645     return GL2PS_ERROR;
5646   }
5647 
5648   gl2ps->header = GL_TRUE;
5649   gl2ps->maxbestroot = 10;
5650   gl2ps->options = options;
5651   gl2ps->compress = NULL;
5652   gl2ps->imagemap_head = NULL;
5653   gl2ps->imagemap_tail = NULL;
5654 
5655   if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){
5656     glGetIntegerv(GL_VIEWPORT, gl2ps->viewport);
5657   }
5658   else{
5659     for(i = 0; i < 4; i++){
5660       gl2ps->viewport[i] = viewport[i];
5661     }
5662   }
5663 
5664   if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){
5665     gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)",
5666              gl2ps->viewport[0], gl2ps->viewport[1],
5667              gl2ps->viewport[2], gl2ps->viewport[3]);
5668     gl2psFree(gl2ps);
5669     gl2ps = NULL;
5670     return GL2PS_ERROR;
5671   }
5672 
5673   gl2ps->threshold[0] = nr ? 1.0F/(GLfloat)nr : 0.064F;
5674   gl2ps->threshold[1] = ng ? 1.0F/(GLfloat)ng : 0.034F;
5675   gl2ps->threshold[2] = nb ? 1.0F/(GLfloat)nb : 0.100F;
5676   gl2ps->colormode = colormode;
5677   gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048;
5678   for(i = 0; i < 3; i++){
5679     gl2ps->lastvertex.xyz[i] = -1.0F;
5680   }
5681   for(i = 0; i < 4; i++){
5682     gl2ps->lastvertex.rgba[i] = -1.0F;
5683     gl2ps->lastrgba[i] = -1.0F;
5684   }
5685   gl2ps->lastlinewidth = -1.0F;
5686   gl2ps->lastpattern = 0;
5687   gl2ps->lastfactor = 0;
5688   gl2ps->imagetree = NULL;
5689   gl2ps->primitivetoadd = NULL;
5690   gl2ps->zerosurfacearea = GL_FALSE;
5691   gl2ps->pdfprimlist = NULL;
5692   gl2ps->pdfgrouplist = NULL;
5693   gl2ps->xreflist = NULL;
5694 
5695   /* get default blending mode from current OpenGL state (enabled by
5696      default for SVG) */
5697   gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND);
5698   glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]);
5699   glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]);
5700 
5701   if(gl2ps->colormode == GL_RGBA){
5702     gl2ps->colorsize = 0;
5703     gl2ps->colormap = NULL;
5704     glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor);
5705   }
5706   else if(gl2ps->colormode == GL_COLOR_INDEX){
5707     if(!colorsize || !colormap){
5708       gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering");
5709       gl2psFree(gl2ps);
5710       gl2ps = NULL;
5711       return GL2PS_ERROR;
5712     }
5713     gl2ps->colorsize = colorsize;
5714     gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba));
5715     memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba));
5716     glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5717     gl2ps->bgcolor[0] = gl2ps->colormap[index][0];
5718     gl2ps->bgcolor[1] = gl2ps->colormap[index][1];
5719     gl2ps->bgcolor[2] = gl2ps->colormap[index][2];
5720     gl2ps->bgcolor[3] = 1.0F;
5721   }
5722   else{
5723     gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage");
5724     gl2psFree(gl2ps);
5725     gl2ps = NULL;
5726     return GL2PS_ERROR;
5727   }
5728 
5729   if(!title){
5730     gl2ps->title = (char*)gl2psMalloc(sizeof(char));
5731     gl2ps->title[0] = '\0';
5732   }
5733   else{
5734     gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char));
5735     strcpy(gl2ps->title, title);
5736   }
5737 
5738   if(!producer){
5739     gl2ps->producer = (char*)gl2psMalloc(sizeof(char));
5740     gl2ps->producer[0] = '\0';
5741   }
5742   else{
5743     gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char));
5744     strcpy(gl2ps->producer, producer);
5745   }
5746 
5747   if(!filename){
5748     gl2ps->filename = (char*)gl2psMalloc(sizeof(char));
5749     gl2ps->filename[0] = '\0';
5750   }
5751   else{
5752     gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char));
5753     strcpy(gl2ps->filename, filename);
5754   }
5755 
5756   gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
5757   gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*));
5758   gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat));
5759   glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback);
5760   glRenderMode(GL_FEEDBACK);
5761 
5762   return GL2PS_SUCCESS;
5763 }
5764 
gl2psEndPage(void)5765 GL2PSDLL_API GLint gl2psEndPage(void)
5766 {
5767   GLint res;
5768 
5769   if(!gl2ps) return GL2PS_UNINITIALIZED;
5770 
5771   res = gl2psPrintPrimitives();
5772 
5773   if(res != GL2PS_OVERFLOW)
5774     (gl2psbackends[gl2ps->format]->printFooter)();
5775 
5776   // PATCH BURRTOOLS
5777   printf("bound %i %i %i %i\n", gl2ps->boundMinX, gl2ps->boundMinY, gl2ps->boundMaxX, gl2ps->boundMaxY);
5778 
5779   fflush(gl2ps->stream);
5780 
5781   gl2psListDelete(gl2ps->primitives);
5782   gl2psListDelete(gl2ps->auxprimitives);
5783   gl2psFreeImagemap(gl2ps->imagemap_head);
5784   gl2psFree(gl2ps->colormap);
5785   gl2psFree(gl2ps->title);
5786   gl2psFree(gl2ps->producer);
5787   gl2psFree(gl2ps->filename);
5788   gl2psFree(gl2ps->feedback);
5789   gl2psFree(gl2ps);
5790   gl2ps = NULL;
5791 
5792   return res;
5793 }
5794 
gl2psBeginViewport(GLint viewport[4])5795 GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4])
5796 {
5797   if(!gl2ps) return GL2PS_UNINITIALIZED;
5798 
5799   (gl2psbackends[gl2ps->format]->beginViewport)(viewport);
5800 
5801   return GL2PS_SUCCESS;
5802 }
5803 
gl2psEndViewport(void)5804 GL2PSDLL_API GLint gl2psEndViewport(void)
5805 {
5806   GLint res;
5807 
5808   if(!gl2ps) return GL2PS_UNINITIALIZED;
5809 
5810   res = (gl2psbackends[gl2ps->format]->endViewport)();
5811 
5812   /* reset last used colors, line widths */
5813   gl2ps->lastlinewidth = -1.0F;
5814 
5815   return res;
5816 }
5817 
gl2psTextOpt(const char * str,const char * fontname,GLshort fontsize,GLint alignment,GLfloat angle)5818 GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname,
5819                                 GLshort fontsize, GLint alignment, GLfloat angle)
5820 {
5821   return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle);
5822 }
5823 
gl2psText(const char * str,const char * fontname,GLshort fontsize)5824 GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize)
5825 {
5826   return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F);
5827 }
5828 
gl2psSpecial(GLint format,const char * str)5829 GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str)
5830 {
5831   return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F);
5832 }
5833 
gl2psDrawPixels(GLsizei width,GLsizei height,GLint xorig,GLint yorig,GLenum format,GLenum type,const void * pixels)5834 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
5835                                    GLint xorig, GLint yorig,
5836                                    GLenum format, GLenum type,
5837                                    const void *pixels)
5838 {
5839   int size, i;
5840   GLfloat pos[4], *piv;
5841   GL2PSprimitive *prim;
5842   GLboolean valid;
5843 
5844   if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED;
5845 
5846   if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
5847 
5848   if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS;
5849 
5850   if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){
5851     gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for "
5852              "GL_RGB/GL_RGBA, GL_FLOAT pixels");
5853     return GL2PS_ERROR;
5854   }
5855 
5856   glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
5857   if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
5858 
5859   glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
5860 
5861   prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
5862   prim->type = GL2PS_PIXMAP;
5863   prim->boundary = 0;
5864   prim->numverts = 1;
5865   prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
5866   prim->verts[0].xyz[0] = pos[0] + xorig;
5867   prim->verts[0].xyz[1] = pos[1] + yorig;
5868   prim->verts[0].xyz[2] = pos[2];
5869   prim->culled = 0;
5870   prim->offset = 0;
5871   prim->pattern = 0;
5872   prim->factor = 0;
5873   prim->width = 1;
5874   glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
5875   prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
5876   prim->data.image->width = width;
5877   prim->data.image->height = height;
5878   prim->data.image->format = format;
5879   prim->data.image->type = type;
5880 
5881   switch(format){
5882   case GL_RGBA:
5883     if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
5884       /* special case: blending turned off */
5885       prim->data.image->format = GL_RGB;
5886       size = height * width * 3;
5887       prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5888       piv = (GLfloat*)pixels;
5889       for(i = 0; i < size; ++i, ++piv){
5890         prim->data.image->pixels[i] = *piv;
5891         if(!((i+1)%3))
5892           ++piv;
5893       }
5894     }
5895     else{
5896       size = height * width * 4;
5897       prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5898       memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
5899     }
5900     break;
5901   case GL_RGB:
5902   default:
5903     size = height * width * 3;
5904     prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5905     memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
5906     break;
5907   }
5908 
5909   gl2psListAdd(gl2ps->auxprimitives, &prim);
5910   glPassThrough(GL2PS_DRAW_PIXELS_TOKEN);
5911 
5912   return GL2PS_SUCCESS;
5913 }
5914 
gl2psDrawImageMap(GLsizei width,GLsizei height,const GLfloat position[3],const unsigned char * imagemap)5915 GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height,
5916                                      const GLfloat position[3],
5917                                      const unsigned char *imagemap){
5918   int size, i;
5919   int sizeoffloat = sizeof(GLfloat);
5920 
5921   if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED;
5922 
5923   if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
5924 
5925   size = height + height * ((width-1)/8);
5926   glPassThrough(GL2PS_IMAGEMAP_TOKEN);
5927   glBegin(GL_POINTS);
5928   glVertex3f(position[0], position[1],position[2]);
5929   glEnd();
5930   glPassThrough((GLfloat)width);
5931   glPassThrough((GLfloat)height);
5932   for(i = 0; i < size; i += sizeoffloat){
5933     float *value = (float*)imagemap;
5934     glPassThrough(*value);
5935     imagemap += sizeoffloat;
5936   }
5937   return GL2PS_SUCCESS;
5938 }
5939 
gl2psEnable(GLint mode)5940 GL2PSDLL_API GLint gl2psEnable(GLint mode)
5941 {
5942   GLint tmp;
5943 
5944   if(!gl2ps) return GL2PS_UNINITIALIZED;
5945 
5946   switch(mode){
5947   case GL2PS_POLYGON_OFFSET_FILL :
5948     glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN);
5949     glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]);
5950     glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]);
5951     break;
5952   case GL2PS_POLYGON_BOUNDARY :
5953     glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN);
5954     break;
5955   case GL2PS_LINE_STIPPLE :
5956     glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN);
5957     glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp);
5958     glPassThrough((GLfloat)tmp);
5959     glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp);
5960     glPassThrough((GLfloat)tmp);
5961     break;
5962   case GL2PS_BLEND :
5963     glPassThrough(GL2PS_BEGIN_BLEND_TOKEN);
5964     break;
5965   default :
5966     gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode);
5967     return GL2PS_WARNING;
5968   }
5969 
5970   return GL2PS_SUCCESS;
5971 }
5972 
gl2psDisable(GLint mode)5973 GL2PSDLL_API GLint gl2psDisable(GLint mode)
5974 {
5975   if(!gl2ps) return GL2PS_UNINITIALIZED;
5976 
5977   switch(mode){
5978   case GL2PS_POLYGON_OFFSET_FILL :
5979     glPassThrough(GL2PS_END_OFFSET_TOKEN);
5980     break;
5981   case GL2PS_POLYGON_BOUNDARY :
5982     glPassThrough(GL2PS_END_BOUNDARY_TOKEN);
5983     break;
5984   case GL2PS_LINE_STIPPLE :
5985     glPassThrough(GL2PS_END_STIPPLE_TOKEN);
5986     break;
5987   case GL2PS_BLEND :
5988     glPassThrough(GL2PS_END_BLEND_TOKEN);
5989     break;
5990   default :
5991     gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode);
5992     return GL2PS_WARNING;
5993   }
5994 
5995   return GL2PS_SUCCESS;
5996 }
5997 
gl2psPointSize(GLfloat value)5998 GL2PSDLL_API GLint gl2psPointSize(GLfloat value)
5999 {
6000   if(!gl2ps) return GL2PS_UNINITIALIZED;
6001 
6002   glPassThrough(GL2PS_POINT_SIZE_TOKEN);
6003   glPassThrough(value);
6004 
6005   return GL2PS_SUCCESS;
6006 }
6007 
gl2psLineWidth(GLfloat value)6008 GL2PSDLL_API GLint gl2psLineWidth(GLfloat value)
6009 {
6010   if(!gl2ps) return GL2PS_UNINITIALIZED;
6011 
6012   glPassThrough(GL2PS_LINE_WIDTH_TOKEN);
6013   glPassThrough(value);
6014 
6015   return GL2PS_SUCCESS;
6016 }
6017 
gl2psBlendFunc(GLenum sfactor,GLenum dfactor)6018 GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor)
6019 {
6020   if(!gl2ps) return GL2PS_UNINITIALIZED;
6021 
6022   if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor))
6023     return GL2PS_WARNING;
6024 
6025   glPassThrough(GL2PS_SRC_BLEND_TOKEN);
6026   glPassThrough((GLfloat)sfactor);
6027   glPassThrough(GL2PS_DST_BLEND_TOKEN);
6028   glPassThrough((GLfloat)dfactor);
6029 
6030   return GL2PS_SUCCESS;
6031 }
6032 
gl2psSetOptions(GLint options)6033 GL2PSDLL_API GLint gl2psSetOptions(GLint options)
6034 {
6035   if(!gl2ps) return GL2PS_UNINITIALIZED;
6036 
6037   gl2ps->options = options;
6038 
6039   return GL2PS_SUCCESS;
6040 }
6041 
gl2psGetOptions(GLint * options)6042 GL2PSDLL_API GLint gl2psGetOptions(GLint *options)
6043 {
6044   if(!gl2ps) {
6045     *options = 0;
6046     return GL2PS_UNINITIALIZED;
6047   }
6048 
6049   *options = gl2ps->options;
6050 
6051   return GL2PS_SUCCESS;
6052 }
6053 
gl2psGetFileExtension(GLint format)6054 GL2PSDLL_API const char *gl2psGetFileExtension(GLint format)
6055 {
6056   if(format >= 0 && format < (GLint)(sizeof(gl2psbackends)/sizeof(gl2psbackends[0])))
6057     return gl2psbackends[format]->file_extension;
6058   else
6059     return "Unknown format";
6060 }
6061 
gl2psGetFormatDescription(GLint format)6062 GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format)
6063 {
6064   if(format >= 0 && format < (GLint)(sizeof(gl2psbackends)/sizeof(gl2psbackends[0])))
6065     return gl2psbackends[format]->description;
6066   else
6067     return "Unknown format";
6068 }
6069