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