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