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