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