Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/g4tools/include/tools/gl2ps

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

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