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