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-2024 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 
3929  offs = fprintf(gl2ps->stream,
3930  "1 0 obj\n"
3931  "<<\n"
3932  "/Title (%s)\n"
3933  "/Creator (GL2PS %d.%d.%d%s, %s)\n"
3934  "/Producer (%s)\n",
3937  gl2ps->producer);
3938 
3939  if(!gmtime_r(&now, &newtime)){
3940  offs += fprintf(gl2ps->stream,
3941  ">>\n"
3942  "endobj\n");
3943  return offs;
3944  }
3945 
3946  offs += fprintf(gl2ps->stream,
3947  "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n"
3948  ">>\n"
3949  "endobj\n",
3950  newtime.tm_year+1900,
3951  newtime.tm_mon+1,
3952  newtime.tm_mday,
3953  newtime.tm_hour,
3954  newtime.tm_min,
3955  newtime.tm_sec);
3956  return offs;
3957 }
3958 
3959 /* Create catalog and page structure - 2nd and 3th PDF object */
3960 
3961 static int gl2psPrintPDFCatalog(void)
3962 {
3963  return fprintf(gl2ps->stream,
3964  "2 0 obj\n"
3965  "<<\n"
3966  "/Type /Catalog\n"
3967  "/Pages 3 0 R\n"
3968  ">>\n"
3969  "endobj\n");
3970 }
3971 
3972 static int gl2psPrintPDFPages(void)
3973 {
3974  return fprintf(gl2ps->stream,
3975  "3 0 obj\n"
3976  "<<\n"
3977  "/Type /Pages\n"
3978  "/Kids [6 0 R]\n"
3979  "/Count 1\n"
3980  ">>\n"
3981  "endobj\n");
3982 }
3983 
3984 /* Open stream for data - graphical objects, fonts etc. PDF object 4 */
3985 
3986 static int gl2psOpenPDFDataStream(void)
3987 {
3988  int offs = 0;
3989 
3990  offs += fprintf(gl2ps->stream,
3991  "4 0 obj\n"
3992  "<<\n"
3993  "/Length 5 0 R\n" );
3994  offs += gl2psPrintPDFCompressorType();
3995  offs += fprintf(gl2ps->stream,
3996  ">>\n"
3997  "stream\n");
3998  return offs;
3999 }
4000 
4001 /* Stream setup - Graphics state, fill background if allowed */
4002 
4003 static int gl2psOpenPDFDataStreamWritePreface(void)
4004 {
4005  int offs;
4006 
4007  offs = gl2psPrintf("/GSa gs\n");
4008 
4009  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4010  offs += gl2psPrintPDFFillColor(gl2ps->bgcolor);
4011  offs += gl2psPrintf("%d %d %d %d re\n",
4012  (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4013  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4014  offs += gl2psPrintf("f\n");
4015  }
4016  return offs;
4017 }
4018 
4019 /* Use the functions above to create the first part of the PDF*/
4020 
4021 static void gl2psPrintPDFHeader(void)
4022 {
4023  int offs = 0;
4024  gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
4025  gl2psPDFstacksInit();
4026 
4027  gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack);
4028 
4029 #if defined(GL2PS_HAVE_ZLIB)
4030  if(gl2ps->options & GL2PS_COMPRESS){
4031  gl2psSetupCompress();
4032  }
4033 #endif
4034  gl2ps->xreflist[0] = 0;
4035  offs += fprintf(gl2ps->stream, "%%PDF-1.4\n");
4036  gl2ps->xreflist[1] = offs;
4037 
4038  offs += gl2psPrintPDFInfo();
4039  gl2ps->xreflist[2] = offs;
4040 
4041  offs += gl2psPrintPDFCatalog();
4042  gl2ps->xreflist[3] = offs;
4043 
4044  offs += gl2psPrintPDFPages();
4045  gl2ps->xreflist[4] = offs;
4046 
4047  offs += gl2psOpenPDFDataStream();
4048  gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */
4049  gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface();
4050 }
4051 
4052 /* The central primitive drawing */
4053 
4054 static void gl2psPrintPDFPrimitive(void *data)
4055 {
4056  GL2PSprimitive *prim = *(GL2PSprimitive**)data;
4057 
4058  if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled)
4059  return;
4060 
4061  prim = gl2psCopyPrimitive(prim); /* deep copy */
4062  gl2psListAdd(gl2ps->pdfprimlist, &prim);
4063 }
4064 
4065 /* close stream and ... */
4066 
4067 static int gl2psClosePDFDataStream(void)
4068 {
4069  int offs = 0;
4070 
4071 #if defined(GL2PS_HAVE_ZLIB)
4072  if(gl2ps->options & GL2PS_COMPRESS){
4073  if(Z_OK != gl2psDeflate())
4074  gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
4075  else
4076  fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream);
4077  gl2ps->streamlength += gl2ps->compress->destLen;
4078 
4079  offs += gl2ps->streamlength;
4080  gl2psFreeCompress();
4081  }
4082 #endif
4083 
4084  offs += fprintf(gl2ps->stream,
4085  "endstream\n"
4086  "endobj\n");
4087  return offs;
4088 }
4089 
4090 /* ... write the now known length object */
4091 
4092 static int gl2psPrintPDFDataStreamLength(int val)
4093 {
4094  return fprintf(gl2ps->stream,
4095  "5 0 obj\n"
4096  "%d\n"
4097  "endobj\n", val);
4098 }
4099 
4100 /* Put the info created before in PDF objects */
4101 
4102 static int gl2psPrintPDFOpenPage(void)
4103 {
4104  int offs;
4105 
4106  /* Write fixed part */
4107 
4108  offs = fprintf(gl2ps->stream,
4109  "6 0 obj\n"
4110  "<<\n"
4111  "/Type /Page\n"
4112  "/Parent 3 0 R\n"
4113  "/MediaBox [%d %d %d %d]\n",
4114  (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4115  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4116 
4117  if(gl2ps->options & GL2PS_LANDSCAPE)
4118  offs += fprintf(gl2ps->stream, "/Rotate -90\n");
4119 
4120  offs += fprintf(gl2ps->stream,
4121  "/Contents 4 0 R\n"
4122  "/Resources\n"
4123  "<<\n"
4124  "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n");
4125 
4126  return offs;
4127 
4128  /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */
4129 }
4130 
4131 static int gl2psPDFgroupListWriteVariableResources(void)
4132 {
4133  int offs = 0;
4134 
4135  /* a) Graphics States for shader alpha masks*/
4136  offs += gl2psPDFgroupListWriteGStateResources();
4137 
4138  /* b) Shader and shader masks */
4139  offs += gl2psPDFgroupListWriteShaderResources();
4140 
4141  /* c) XObjects (Images & Shader Masks) */
4142  offs += gl2psPDFgroupListWriteXObjectResources();
4143 
4144  /* d) Fonts */
4145  offs += gl2psPDFgroupListWriteFontResources();
4146 
4147  /* End resources and page */
4148  offs += fprintf(gl2ps->stream,
4149  ">>\n"
4150  ">>\n"
4151  "endobj\n");
4152  return offs;
4153 }
4154 
4155 /* Standard Graphics State */
4156 
4157 static int gl2psPrintPDFGSObject(void)
4158 {
4159  return fprintf(gl2ps->stream,
4160  "7 0 obj\n"
4161  "<<\n"
4162  "/Type /ExtGState\n"
4163  "/SA false\n"
4164  "/SM 0.02\n"
4165  "/OP false\n"
4166  "/op false\n"
4167  "/OPM 0\n"
4168  "/BG2 /Default\n"
4169  "/UCR2 /Default\n"
4170  "/TR2 /Default\n"
4171  ">>\n"
4172  "endobj\n");
4173 }
4174 
4175 /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */
4176 
4177 static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex,
4178  size_t (*action)(unsigned long data,
4179  size_t size),
4180  GLfloat dx, GLfloat dy,
4181  GLfloat xmin, GLfloat ymin)
4182 {
4183  int offs = 0;
4184  unsigned long imap;
4185  GLfloat diff;
4186  double dmax = static_cast<double>(~1UL);
4187  char edgeflag = 0;
4188 
4189  /* FIXME: temp bux fix for 64 bit archs: */
4190  if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4191 
4192  offs += (*action)(edgeflag, 1);
4193 
4194  /* The Shader stream in PDF requires to be in a 'big-endian'
4195  order */
4196 
4197  if(GL2PS_ZERO(dx * dy)){
4198  offs += (*action)(0, 4);
4199  offs += (*action)(0, 4);
4200  }
4201  else{
4202  diff = (vertex->xyz[0] - xmin) / dx;
4203  if(diff > 1)
4204  diff = 1.0F;
4205  else if(diff < 0)
4206  diff = 0.0F;
4207  imap = (unsigned long)(diff * dmax);
4208  offs += (*action)(imap, 4);
4209 
4210  diff = (vertex->xyz[1] - ymin) / dy;
4211  if(diff > 1)
4212  diff = 1.0F;
4213  else if(diff < 0)
4214  diff = 0.0F;
4215  imap = (unsigned long)(diff * dmax);
4216  offs += (*action)(imap, 4);
4217  }
4218 
4219  return offs;
4220 }
4221 
4222 /* Put vertex' rgb value (8bit for every component) in shader stream */
4223 
4224 static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex,
4225  size_t (*action)(unsigned long data,
4226  size_t size))
4227 {
4228  int offs = 0;
4229  unsigned long imap;
4230  double dmax = static_cast<double>(~1UL);
4231 
4232  /* FIXME: temp bux fix for 64 bit archs: */
4233  if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4234 
4235  imap = (unsigned long)((vertex->rgba[0]) * dmax);
4236  offs += (*action)(imap, 1);
4237 
4238  imap = (unsigned long)((vertex->rgba[1]) * dmax);
4239  offs += (*action)(imap, 1);
4240 
4241  imap = (unsigned long)((vertex->rgba[2]) * dmax);
4242  offs += (*action)(imap, 1);
4243 
4244  return offs;
4245 }
4246 
4247 /* Put vertex' alpha (8/16bit) in shader stream */
4248 
4249 static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex,
4250  size_t (*action)(unsigned long data,
4251  size_t size),
4252  int sigbyte)
4253 {
4254  int offs = 0;
4255  unsigned long imap;
4256  double dmax = static_cast<double>(~1UL);
4257 
4258  /* FIXME: temp bux fix for 64 bit archs: */
4259  if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4260 
4261  if(sigbyte != 8 && sigbyte != 16)
4262  sigbyte = 8;
4263 
4264  sigbyte /= 8;
4265 
4266  imap = (unsigned long)((vertex->rgba[3]) * dmax);
4267 
4268  offs += (*action)(imap, sigbyte);
4269 
4270  return offs;
4271 }
4272 
4273 /* Put a triangles raw data in shader stream */
4274 
4275 static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle,
4276  GLfloat dx, GLfloat dy,
4277  GLfloat xmin, GLfloat ymin,
4278  size_t (*action)(unsigned long data,
4279  size_t size),
4280  int gray)
4281 {
4282  int i, offs = 0;
4283  GL2PSvertex v;
4284 
4285  if(gray && gray != 8 && gray != 16)
4286  gray = 8;
4287 
4288  for(i = 0; i < 3; ++i){
4289  offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action,
4290  dx, dy, xmin, ymin);
4291  if(gray){
4292  v = triangle->vertex[i];
4293  offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray);
4294  }
4295  else{
4296  offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action);
4297  }
4298  }
4299 
4300  return offs;
4301 }
4302 
4303 static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax,
4304  GLfloat *ymin, GLfloat *ymax,
4305  GL2PStriangle *triangles, int cnt)
4306 {
4307  int i, j;
4308 
4309  *xmin = triangles[0].vertex[0].xyz[0];
4310  *xmax = triangles[0].vertex[0].xyz[0];
4311  *ymin = triangles[0].vertex[0].xyz[1];
4312  *ymax = triangles[0].vertex[0].xyz[1];
4313 
4314  for(i = 0; i < cnt; ++i){
4315  for(j = 0; j < 3; ++j){
4316  if(*xmin > triangles[i].vertex[j].xyz[0])
4317  *xmin = triangles[i].vertex[j].xyz[0];
4318  if(*xmax < triangles[i].vertex[j].xyz[0])
4319  *xmax = triangles[i].vertex[j].xyz[0];
4320  if(*ymin > triangles[i].vertex[j].xyz[1])
4321  *ymin = triangles[i].vertex[j].xyz[1];
4322  if(*ymax < triangles[i].vertex[j].xyz[1])
4323  *ymax = triangles[i].vertex[j].xyz[1];
4324  }
4325  }
4326 }
4327 
4328 /* Writes shaded triangle
4329  gray == 0 means write RGB triangles
4330  gray == 8 8bit-grayscale (for alpha masks)
4331  gray == 16 16bit-grayscale (for alpha masks) */
4332 
4333 static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles,
4334  int size, int gray)
4335 {
4336  int i, offs = 0, vertexbytes, done = 0;
4337  GLfloat xmin, xmax, ymin, ymax;
4338 
4339  switch(gray){
4340  case 0:
4341  vertexbytes = 1+4+4+1+1+1;
4342  break;
4343  case 8:
4344  vertexbytes = 1+4+4+1;
4345  break;
4346  case 16:
4347  vertexbytes = 1+4+4+2;
4348  break;
4349  default:
4350  gray = 8;
4351  vertexbytes = 1+4+4+1;
4352  break;
4353  }
4354 
4355  gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size);
4356 
4357  offs += fprintf(gl2ps->stream,
4358  "%d 0 obj\n"
4359  "<< "
4360  "/ShadingType 4 "
4361  "/ColorSpace %s "
4362  "/BitsPerCoordinate 32 "
4363  "/BitsPerComponent %d "
4364  "/BitsPerFlag 8 "
4365  "/Decode [%f %f %f %f 0 1 %s] ",
4366  obj,
4367  (gray) ? "/DeviceGray" : "/DeviceRGB",
4368  (gray) ? gray : 8,
4369  xmin, xmax, ymin, ymax,
4370  (gray) ? "" : "0 1 0 1");
4371 
4372 #if defined(GL2PS_HAVE_ZLIB)
4373  if(gl2ps->options & GL2PS_COMPRESS){
4374  gl2psAllocCompress(vertexbytes * size * 3);
4375 
4376  for(i = 0; i < size; ++i)
4377  gl2psPrintPDFShaderStreamData(&triangles[i],
4378  xmax-xmin, ymax-ymin, xmin, ymin,
4379  gl2psWriteBigEndianCompress, gray);
4380 
4381  if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4382  offs += gl2psPrintPDFCompressorType();
4383  offs += fprintf(gl2ps->stream,
4384  "/Length %d "
4385  ">>\n"
4386  "stream\n",
4387  (int)gl2ps->compress->destLen);
4388  offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest,
4389  gl2ps->compress->destLen,
4390  1, gl2ps->stream);
4391  done = 1;
4392  }
4393  gl2psFreeCompress();
4394  }
4395 #endif
4396 
4397  if(!done){
4398  /* no compression, or too long after compression, or compress error
4399  -> write non-compressed entry */
4400  offs += fprintf(gl2ps->stream,
4401  "/Length %d "
4402  ">>\n"
4403  "stream\n",
4404  vertexbytes * 3 * size);
4405  for(i = 0; i < size; ++i)
4406  offs += gl2psPrintPDFShaderStreamData(&triangles[i],
4407  xmax-xmin, ymax-ymin, xmin, ymin,
4408  gl2psWriteBigEndian, gray);
4409  }
4410 
4411  offs += fprintf(gl2ps->stream,
4412  "\nendstream\n"
4413  "endobj\n");
4414 
4415  return offs;
4416 }
4417 
4418 /* Writes a XObject for a shaded triangle mask */
4419 
4420 static int gl2psPrintPDFShaderMask(int obj, int childobj)
4421 {
4422  int offs = 0, len;
4423 
4424  offs += fprintf(gl2ps->stream,
4425  "%d 0 obj\n"
4426  "<<\n"
4427  "/Type /XObject\n"
4428  "/Subtype /Form\n"
4429  "/BBox [ %d %d %d %d ]\n"
4430  "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n"
4431  ">>\n",
4432  obj,
4433  (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4434  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4435 
4436  len = (childobj>0)
4437  ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1
4438  : strlen("/TrSh0 sh\n");
4439 
4440  offs += fprintf(gl2ps->stream,
4441  "/Length %d\n"
4442  ">>\n"
4443  "stream\n",
4444  len);
4445  offs += fprintf(gl2ps->stream,
4446  "/TrSh%d sh\n",
4447  childobj);
4448  offs += fprintf(gl2ps->stream,
4449  "endstream\n"
4450  "endobj\n");
4451 
4452  return offs;
4453 }
4454 
4455 /* Writes a Extended graphics state for a shaded triangle mask if
4456  simplealpha ist true the childobj argument is ignored and a /ca
4457  statement will be written instead */
4458 
4459 static int gl2psPrintPDFShaderExtGS(int obj, int childobj)
4460 {
4461  int offs = 0;
4462 
4463  offs += fprintf(gl2ps->stream,
4464  "%d 0 obj\n"
4465  "<<\n",
4466  obj);
4467 
4468  offs += fprintf(gl2ps->stream,
4469  "/SMask << /S /Alpha /G %d 0 R >> ",
4470  childobj);
4471 
4472  offs += fprintf(gl2ps->stream,
4473  ">>\n"
4474  "endobj\n");
4475  return offs;
4476 }
4477 
4478 /* a simple graphics state */
4479 
4480 static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha)
4481 {
4482  int offs = 0;
4483 
4484  offs += fprintf(gl2ps->stream,
4485  "%d 0 obj\n"
4486  "<<\n"
4487  "/ca %g"
4488  ">>\n"
4489  "endobj\n",
4490  obj, alpha);
4491  return offs;
4492 }
4493 
4494 /* Similar groups of functions for pixmaps and text */
4495 
4496 static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im,
4497  size_t (*action)(unsigned long data,
4498  size_t size),
4499  int gray)
4500 {
4501  int x, y, shift;
4502  GLfloat r, g, b, a;
4503 
4504  if(im->format != GL_RGBA && gray)
4505  return 0;
4506 
4507  if(gray && gray != 8 && gray != 16)
4508  gray = 8;
4509 
4510  gray /= 8;
4511 
4512  shift = (sizeof(unsigned long) - 1) * 8;
4513 
4514  for(y = 0; y < im->height; ++y){
4515  for(x = 0; x < im->width; ++x){
4516  a = gl2psGetRGB(im, x, y, &r, &g, &b);
4517  if(im->format == GL_RGBA && gray){
4518  (*action)((unsigned long)(a * 255) << shift, gray);
4519  }
4520  else{
4521  (*action)((unsigned long)(r * 255) << shift, 1);
4522  (*action)((unsigned long)(g * 255) << shift, 1);
4523  (*action)((unsigned long)(b * 255) << shift, 1);
4524  }
4525  }
4526  }
4527 
4528  switch(gray){
4529  case 0: return 3 * im->width * im->height;
4530  case 1: return im->width * im->height;
4531  case 2: return 2 * im->width * im->height;
4532  default: return 3 * im->width * im->height;
4533  }
4534 }
4535 
4536 static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray)
4537 {
4538  int offs = 0, done = 0, sigbytes = 3;
4539 
4540  if(gray && gray !=8 && gray != 16)
4541  gray = 8;
4542 
4543  if(gray)
4544  sigbytes = gray / 8;
4545 
4546  offs += fprintf(gl2ps->stream,
4547  "%d 0 obj\n"
4548  "<<\n"
4549  "/Type /XObject\n"
4550  "/Subtype /Image\n"
4551  "/Width %d\n"
4552  "/Height %d\n"
4553  "/ColorSpace %s \n"
4554  "/BitsPerComponent 8\n",
4555  obj,
4556  (int)im->width, (int)im->height,
4557  (gray) ? "/DeviceGray" : "/DeviceRGB" );
4558  if(GL_RGBA == im->format && gray == 0){
4559  offs += fprintf(gl2ps->stream,
4560  "/SMask %d 0 R\n",
4561  childobj);
4562  }
4563 
4564 #if defined(GL2PS_HAVE_ZLIB)
4565  if(gl2ps->options & GL2PS_COMPRESS){
4566  gl2psAllocCompress((int)(im->width * im->height * sigbytes));
4567 
4568  gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray);
4569 
4570  if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4571  offs += gl2psPrintPDFCompressorType();
4572  offs += fprintf(gl2ps->stream,
4573  "/Length %d "
4574  ">>\n"
4575  "stream\n",
4576  (int)gl2ps->compress->destLen);
4577  offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen,
4578  1, gl2ps->stream);
4579  done = 1;
4580  }
4581  gl2psFreeCompress();
4582  }
4583 #endif
4584 
4585  if(!done){
4586  /* no compression, or too long after compression, or compress error
4587  -> write non-compressed entry */
4588  offs += fprintf(gl2ps->stream,
4589  "/Length %d "
4590  ">>\n"
4591  "stream\n",
4592  (int)(im->width * im->height * sigbytes));
4593  offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray);
4594  }
4595 
4596  offs += fprintf(gl2ps->stream,
4597  "\nendstream\n"
4598  "endobj\n");
4599 
4600  return offs;
4601 }
4602 
4603 static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber)
4604 {
4605  int offs = 0;
4606 
4607  offs += fprintf(gl2ps->stream,
4608  "%d 0 obj\n"
4609  "<<\n"
4610  "/Type /Font\n"
4611  "/Subtype /Type1\n"
4612  "/Name /F%d\n"
4613  "/BaseFont /%s\n"
4614  "/Encoding /MacRomanEncoding\n"
4615  ">>\n"
4616  "endobj\n",
4617  obj, fontnumber, s->fontname);
4618  return offs;
4619 }
4620 
4621 /* Write the physical objects */
4622 
4623 static int gl2psPDFgroupListWriteObjects(int entryoffs)
4624 {
4625  int i,j;
4626  GL2PSprimitive *p = NULL;
4627  GL2PSpdfgroup *gro;
4628  int offs = entryoffs;
4629  GL2PStriangle *triangles;
4630  int size = 0;
4631 
4632  if(!gl2ps->pdfgrouplist)
4633  return offs;
4634 
4635  for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
4636  gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
4637  if(!gl2psListNbr(gro->ptrlist))
4638  continue;
4639  p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
4640  switch(p->type){
4641  case GL2PS_POINT:
4642  break;
4643  case GL2PS_LINE:
4644  break;
4645  case GL2PS_TRIANGLE:
4646  size = gl2psListNbr(gro->ptrlist);
4647  triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size);
4648  for(j = 0; j < size; ++j){
4649  p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
4650  gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE);
4651  }
4652  if(triangles[0].prop & T_VAR_COLOR){
4653  gl2ps->xreflist[gro->shobjno] = offs;
4654  offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0);
4655  }
4656  if(triangles[0].prop & T_ALPHA_LESS_1){
4657  gl2ps->xreflist[gro->gsobjno] = offs;
4658  offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]);
4659  }
4660  if(triangles[0].prop & T_VAR_ALPHA){
4661  gl2ps->xreflist[gro->gsobjno] = offs;
4662  offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno);
4663  gl2ps->xreflist[gro->trgroupobjno] = offs;
4664  offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno);
4665  gl2ps->xreflist[gro->maskshobjno] = offs;
4666  offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8);
4667  }
4668  gl2psFree(triangles);
4669  break;
4670  case GL2PS_PIXMAP:
4671  gl2ps->xreflist[gro->imobjno] = offs;
4672  offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0);
4673  if(p->data.image->format == GL_RGBA){
4674  gl2ps->xreflist[gro->imobjno+1] = offs;
4675  offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8);
4676  }
4677  break;
4678  case GL2PS_TEXT:
4679  gl2ps->xreflist[gro->fontobjno] = offs;
4680  offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno);
4681  break;
4682  case GL2PS_SPECIAL :
4683  /* alignment contains the format for which the special output text
4684  is intended */
4685  if(p->data.text->alignment == GL2PS_PDF)
4686  offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str);
4687  break;
4688  default:
4689  break;
4690  }
4691  }
4692  return offs;
4693 }
4694 
4695 /* All variable data has been written at this point and all required
4696  functioninality has been gathered, so we can write now file footer
4697  with cross reference table and trailer */
4698 
4699 static void gl2psPrintPDFFooter(void)
4700 {
4701  int i, offs;
4702 
4703  gl2psPDFgroupListInit();
4704  gl2psPDFgroupListWriteMainStream();
4705 
4706  offs = gl2ps->xreflist[5] + gl2ps->streamlength;
4707  offs += gl2psClosePDFDataStream();
4708  gl2ps->xreflist[5] = offs;
4709 
4710  offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength);
4711  gl2ps->xreflist[6] = offs;
4712  gl2ps->streamlength = 0;
4713 
4714  offs += gl2psPrintPDFOpenPage();
4715  offs += gl2psPDFgroupListWriteVariableResources();
4716  gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist,
4717  sizeof(int) * (gl2ps->objects_stack + 1));
4718  gl2ps->xreflist[7] = offs;
4719 
4720  offs += gl2psPrintPDFGSObject();
4721  gl2ps->xreflist[8] = offs;
4722 
4723  gl2ps->xreflist[gl2ps->objects_stack] =
4724  gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]);
4725 
4726  /* Start cross reference table. The file has to been opened in
4727  binary mode to preserve the 20 digit string length! */
4728  fprintf(gl2ps->stream,
4729  "xref\n"
4730  "0 %d\n"
4731  "%010d 65535 f \n", gl2ps->objects_stack, 0);
4732 
4733  for(i = 1; i < gl2ps->objects_stack; ++i)
4734  fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]);
4735 
4736  fprintf(gl2ps->stream,
4737  "trailer\n"
4738  "<<\n"
4739  "/Size %d\n"
4740  "/Info 1 0 R\n"
4741  "/Root 2 0 R\n"
4742  ">>\n"
4743  "startxref\n%d\n"
4744  "%%%%EOF\n",
4745  gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]);
4746 
4747  /* Free auxiliary lists and arrays */
4748  gl2psFree(gl2ps->xreflist);
4749  gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive);
4750  gl2psListDelete(gl2ps->pdfprimlist);
4751  gl2psPDFgroupListDelete();
4752 
4753 #if defined(GL2PS_HAVE_ZLIB)
4754  if(gl2ps->options & GL2PS_COMPRESS){
4755  gl2psFreeCompress();
4756  gl2psFree(gl2ps->compress);
4757  gl2ps->compress = NULL;
4758  }
4759 #endif
4760 }
4761 
4762 /* PDF begin viewport */
4763 
4764 static void gl2psPrintPDFBeginViewport(GLint viewport[4])
4765 {
4766  int offs = 0;
4767  GLint index;
4768  GLfloat rgba[4];
4769  int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
4770 
4771  glRenderMode(GL_FEEDBACK);
4772 
4773  if(gl2ps->header){
4774  gl2psPrintPDFHeader();
4775  gl2ps->header = GL_FALSE;
4776  }
4777 
4778  offs += gl2psPrintf("q\n");
4779 
4780  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4781  if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
4782  glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
4783  }
4784  else{
4785  glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
4786  rgba[0] = gl2ps->colormap[index][0];
4787  rgba[1] = gl2ps->colormap[index][1];
4788  rgba[2] = gl2ps->colormap[index][2];
4789  rgba[3] = 1.0F;
4790  }
4791  offs += gl2psPrintPDFFillColor(rgba);
4792  offs += gl2psPrintf("%d %d %d %d re\n"
4793  "W\n"
4794  "f\n",
4795  x, y, w, h);
4796  }
4797  else{
4798  offs += gl2psPrintf("%d %d %d %d re\n"
4799  "W\n"
4800  "n\n",
4801  x, y, w, h);
4802  }
4803 
4804  gl2ps->streamlength += offs;
4805 }
4806 
4807 static GLint gl2psPrintPDFEndViewport(void)
4808 {
4809  GLint res;
4810 
4811  res = gl2psPrintPrimitives();
4812  gl2ps->streamlength += gl2psPrintf("Q\n");
4813  return res;
4814 }
4815 
4816 static void gl2psPrintPDFFinalPrimitive(void)
4817 {
4818 }
4819 
4820 /* definition of the PDF backend */
4821 
4822 static GL2PSbackend gl2psPDF = {
4823  gl2psPrintPDFHeader,
4824  gl2psPrintPDFFooter,
4825  gl2psPrintPDFBeginViewport,
4826  gl2psPrintPDFEndViewport,
4827  gl2psPrintPDFPrimitive,
4828  gl2psPrintPDFFinalPrimitive,
4829  "pdf",
4830  "Portable Document Format"
4831 };
4832 
4833 /*********************************************************************
4834  *
4835  * SVG routines
4836  *
4837  *********************************************************************/
4838 
4839 static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts,
4840  GL2PSxyz *xyz, GL2PSrgba *rgba)
4841 {
4842  int i, j;
4843 
4844  for(i = 0; i < n; i++){
4845  xyz[i][0] = verts[i].xyz[0];
4846  xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1];
4847  xyz[i][2] = 0.0F;
4848  for(j = 0; j < 4; j++)
4849  rgba[i][j] = verts[i].rgba[j];
4850  }
4851 }
4852 
4853 static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32])
4854 {
4855  int r = (int)(255. * rgba[0]);
4856  int g = (int)(255. * rgba[1]);
4857  int b = (int)(255. * rgba[2]);
4858  int rc = (r < 0) ? 0 : (r > 255) ? 255 : r;
4859  int gc = (g < 0) ? 0 : (g > 255) ? 255 : g;
4860  int bc = (b < 0) ? 0 : (b > 255) ? 255 : b;
4861  sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc);
4862 }
4863 
4864 static void gl2psPrintSVGHeader(void)
4865 {
4866  int x, y, width, height;
4867  char col[32];
4868  time_t now;
4869 
4870  time(&now);
4871 
4872  if (gl2ps->options & GL2PS_LANDSCAPE){
4873  x = (int)gl2ps->viewport[1];
4874  y = (int)gl2ps->viewport[0];
4875  width = (int)gl2ps->viewport[3];
4876  height = (int)gl2ps->viewport[2];
4877  }
4878  else{
4879  x = (int)gl2ps->viewport[0];
4880  y = (int)gl2ps->viewport[1];
4881  width = (int)gl2ps->viewport[2];
4882  height = (int)gl2ps->viewport[3];
4883  }
4884 
4885  /* Compressed SVG files (.svgz) are simply gzipped SVG files */
4886  gl2psPrintGzipHeader();
4887 
4888  gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
4889  gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
4890  gl2psPrintf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
4891  " width=\"%dpx\" height=\"%dpx\" viewBox=\"%d %d %d %d\">\n",
4892  width, height, x, y, width, height);
4893  gl2psPrintf("<title>%s</title>\n", gl2ps->title);
4894  gl2psPrintf("<desc>\n");
4895  gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n"
4896  "For: %s\n"
4897  "CreationDate: %s",
4899  GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now));
4900  gl2psPrintf("</desc>\n");
4901  gl2psPrintf("<defs>\n");
4902  gl2psPrintf("</defs>\n");
4903 
4904  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4905  gl2psSVGGetColorString(gl2ps->bgcolor, col);
4906  gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
4907  (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4908  (int)gl2ps->viewport[2], (int)gl2ps->viewport[1],
4909  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3],
4910  (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
4911  }
4912 
4913  /* group all the primitives and disable antialiasing */
4914  gl2psPrintf("<g shape-rendering=\"crispEdges\">\n");
4915 }
4916 
4917 static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3])
4918 {
4919  int i;
4920  GL2PSxyz xyz2[3];
4921  GL2PSrgba rgba2[3];
4922  char col[32];
4923 
4924  /* Apparently there is no easy way to do Gouraud shading in SVG
4925  without explicitly pre-defining gradients, so for now we just do
4926  recursive subdivision */
4927 
4928  if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){
4929  gl2psSVGGetColorString(rgba[0], col);
4930  gl2psPrintf("<polygon fill=\"%s\" ", col);
4931  if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
4932  gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1],
4933  xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]);
4934  }
4935  else{
4936  /* subdivide into 4 subtriangles */
4937  for(i = 0; i < 3; i++){
4938  xyz2[0][i] = xyz[0][i];
4939  xyz2[1][i] = 0.5F * (xyz[0][i] + xyz[1][i]);
4940  xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]);
4941  }
4942  for(i = 0; i < 4; i++){
4943  rgba2[0][i] = rgba[0][i];
4944  rgba2[1][i] = 0.5F * (rgba[0][i] + rgba[1][i]);
4945  rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]);
4946  }
4947  gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4948  for(i = 0; i < 3; i++){
4949  xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]);
4950  xyz2[1][i] = xyz[1][i];
4951  xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]);
4952  }
4953  for(i = 0; i < 4; i++){
4954  rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]);
4955  rgba2[1][i] = rgba[1][i];
4956  rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]);
4957  }
4958  gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4959  for(i = 0; i < 3; i++){
4960  xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[2][i]);
4961  xyz2[1][i] = xyz[2][i];
4962  xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]);
4963  }
4964  for(i = 0; i < 4; i++){
4965  rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[2][i]);
4966  rgba2[1][i] = rgba[2][i];
4967  rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]);
4968  }
4969  gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4970  for(i = 0; i < 3; i++){
4971  xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]);
4972  xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]);
4973  xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]);
4974  }
4975  for(i = 0; i < 4; i++){
4976  rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]);
4977  rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]);
4978  rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]);
4979  }
4980  gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4981  }
4982 }
4983 
4984 static void gl2psPrintSVGDash(GLushort pattern, GLint factor)
4985 {
4986  int i, n, array[10];
4987 
4988  if(!pattern || !factor) return; /* solid line */
4989 
4990  gl2psParseStipplePattern(pattern, factor, &n, array);
4991  gl2psPrintf("stroke-dasharray=\"");
4992  for(i = 0; i < n; i++){
4993  if(i) gl2psPrintf(",");
4994  gl2psPrintf("%d", array[i]);
4995  }
4996  gl2psPrintf("\" ");
4997 }
4998 
4999 static void gl2psEndSVGLine(void)
5000 {
5001  int i;
5002  if(gl2ps->lastvertex.rgba[0] >= 0.){
5003  gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0],
5004  gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]);
5005  for(i = 0; i < 3; i++)
5006  gl2ps->lastvertex.xyz[i] = -1.;
5007  for(i = 0; i < 4; i++)
5008  gl2ps->lastvertex.rgba[i] = -1.;
5009  }
5010 }
5011 
5012 static void gl2psPrintSVGPixmap(
5013 #if defined(GL2PS_HAVE_LIBPNG)
5014 GLfloat x, GLfloat y, GL2PSimage *pixmap
5015 #else
5016 GLfloat, GLfloat, GL2PSimage *
5017 #endif
5018 )
5019 
5020 {
5021 #if defined(GL2PS_HAVE_LIBPNG)
5022  GL2PSlist *png;
5023  unsigned char c;
5024  int i;
5025 
5026  /* The only image types supported by the SVG standard are JPEG, PNG
5027  and SVG. Here we choose PNG, and since we want to embed the image
5028  directly in the SVG stream (and not link to an external image
5029  file), we need to encode the pixmap into PNG in memory, then
5030  encode it into base64. */
5031 
5032  png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000,
5033  sizeof(unsigned char));
5034  gl2psConvertPixmapToPNG(pixmap, png);
5035  gl2psListEncodeBase64(png);
5036  gl2psPrintf("<image x=\"%g\" y=\"%g\" width=\"%d\" height=\"%d\"\n",
5037  x, y - pixmap->height, pixmap->width, pixmap->height);
5038  gl2psPrintf("xlink:href=\"data:image/png;base64,");
5039  for(i = 0; i < gl2psListNbr(png); i++){
5040  gl2psListRead(png, i, &c);
5041  gl2psPrintf("%c", c);
5042  }
5043  gl2psPrintf("\"/>\n");
5044  gl2psListDelete(png);
5045 #else
5046  gl2psMsg(GL2PS_WARNING, "GL2PS must be compiled with PNG support in "
5047  "order to embed images in SVG streams");
5048 #endif
5049 }
5050 
5051 static void gl2psPrintSVGPrimitive(void *data)
5052 {
5053  GL2PSprimitive *prim;
5054  GL2PSxyz xyz[4];
5055  GL2PSrgba rgba[4];
5056  char col[32];
5057  int newline;
5058 
5059  prim = *(GL2PSprimitive**)data;
5060 
5061  if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
5062 
5063  /* We try to draw connected lines as a single path to get nice line
5064  joins and correct stippling. So if the primitive to print is not
5065  a line we must first finish the current line (if any): */
5066  if(prim->type != GL2PS_LINE) gl2psEndSVGLine();
5067 
5068  gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba);
5069 
5070  switch(prim->type){
5071  case GL2PS_POINT :
5072  gl2psSVGGetColorString(rgba[0], col);
5073  gl2psPrintf("<circle fill=\"%s\" ", col);
5074  if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
5075  gl2psPrintf("cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
5076  xyz[0][0], xyz[0][1], 0.5 * prim->width);
5077  break;
5078  case GL2PS_LINE :
5079  if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
5080  !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
5081  gl2ps->lastlinewidth != prim->width ||
5082  gl2ps->lastpattern != prim->pattern ||
5083  gl2ps->lastfactor != prim->factor){
5084  /* End the current line if the new segment does not start where
5085  the last one ended, or if the color, the width or the
5086  stippling have changed (we will need to use multi-point
5087  gradients for smooth-shaded lines) */
5088  gl2psEndSVGLine();
5089  newline = 1;
5090  }
5091  else{
5092  newline = 0;
5093  }
5094  gl2ps->lastvertex = prim->verts[1];
5095  gl2psSetLastColor(prim->verts[0].rgba);
5096  gl2ps->lastlinewidth = prim->width;
5097  gl2ps->lastpattern = prim->pattern;
5098  gl2ps->lastfactor = prim->factor;
5099  if(newline){
5100  gl2psSVGGetColorString(rgba[0], col);
5101  gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ",
5102  col, prim->width);
5103  if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]);
5104  gl2psPrintSVGDash(prim->pattern, prim->factor);
5105  gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]);
5106  }
5107  else{
5108  gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]);
5109  }
5110  break;
5111  case GL2PS_TRIANGLE :
5112  gl2psPrintSVGSmoothTriangle(xyz, rgba);
5113  break;
5114  case GL2PS_QUADRANGLE :
5115  gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
5116  break;
5117  case GL2PS_PIXMAP :
5118  gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image);
5119  break;
5120  case GL2PS_TEXT :
5121  gl2psSVGGetColorString(prim->verts[0].rgba, col);
5122  gl2psPrintf("<text fill=\"%s\" x=\"%g\" y=\"%g\" font-size=\"%d\" ",
5123  col, xyz[0][0], xyz[0][1], prim->data.text->fontsize);
5124  if(prim->data.text->angle)
5125  gl2psPrintf("transform=\"rotate(%g, %g, %g)\" ",
5126  -prim->data.text->angle, xyz[0][0], xyz[0][1]);
5127  if(!strcmp(prim->data.text->fontname, "Times-Roman"))
5128  gl2psPrintf("font-family=\"Times\">");
5129  else if(!strcmp(prim->data.text->fontname, "Times-Bold"))
5130  gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">");
5131  else if(!strcmp(prim->data.text->fontname, "Times-Italic"))
5132  gl2psPrintf("font-family=\"Times\" font-style=\"italic\">");
5133  else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic"))
5134  gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">");
5135  else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold"))
5136  gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">");
5137  else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique"))
5138  gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">");
5139  else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique"))
5140  gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">");
5141  else if(!strcmp(prim->data.text->fontname, "Courier-Bold"))
5142  gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">");
5143  else if(!strcmp(prim->data.text->fontname, "Courier-Oblique"))
5144  gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">");
5145  else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique"))
5146  gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">");
5147  else
5148  gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname);
5149  gl2psPrintf("%s</text>\n", prim->data.text->str);
5150  break;
5151  case GL2PS_SPECIAL :
5152  /* alignment contains the format for which the special output text
5153  is intended */
5154  if(prim->data.text->alignment == GL2PS_SVG)
5155  gl2psPrintf("%s\n", prim->data.text->str);
5156  break;
5157  default :
5158  break;
5159  }
5160 }
5161 
5162 static void gl2psPrintSVGFooter(void)
5163 {
5164  gl2psPrintf("</g>\n");
5165  gl2psPrintf("</svg>\n");
5166 
5167  gl2psPrintGzipFooter();
5168 }
5169 
5170 static void gl2psPrintSVGBeginViewport(GLint viewport[4])
5171 {
5172  GLint index;
5173  char col[32];
5174  GLfloat rgba[4];
5175  int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
5176 
5177  glRenderMode(GL_FEEDBACK);
5178 
5179  if(gl2ps->header){
5180  gl2psPrintSVGHeader();
5181  gl2ps->header = GL_FALSE;
5182  }
5183 
5184  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5185  if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
5186  glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
5187  }
5188  else{
5189  glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5190  rgba[0] = gl2ps->colormap[index][0];
5191  rgba[1] = gl2ps->colormap[index][1];
5192  rgba[2] = gl2ps->colormap[index][2];
5193  rgba[3] = 1.0F;
5194  }
5195  gl2psSVGGetColorString(rgba, col);
5196  gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
5197  x, gl2ps->viewport[3] - y,
5198  x + w, gl2ps->viewport[3] - y,
5199  x + w, gl2ps->viewport[3] - (y + h),
5200  x, gl2ps->viewport[3] - (y + h));
5201  }
5202 
5203  gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h);
5204  gl2psPrintf(" <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n",
5205  x, gl2ps->viewport[3] - y,
5206  x + w, gl2ps->viewport[3] - y,
5207  x + w, gl2ps->viewport[3] - (y + h),
5208  x, gl2ps->viewport[3] - (y + h));
5209  gl2psPrintf("</clipPath>\n");
5210  gl2psPrintf("<g clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h);
5211 }
5212 
5213 static GLint gl2psPrintSVGEndViewport(void)
5214 {
5215  GLint res;
5216 
5217  res = gl2psPrintPrimitives();
5218  gl2psPrintf("</g>\n");
5219  return res;
5220 }
5221 
5222 static void gl2psPrintSVGFinalPrimitive(void)
5223 {
5224  /* End any remaining line, if any */
5225  gl2psEndSVGLine();
5226 }
5227 
5228 /* definition of the SVG backend */
5229 
5230 static GL2PSbackend gl2psSVG = {
5231  gl2psPrintSVGHeader,
5232  gl2psPrintSVGFooter,
5233  gl2psPrintSVGBeginViewport,
5234  gl2psPrintSVGEndViewport,
5235  gl2psPrintSVGPrimitive,
5236  gl2psPrintSVGFinalPrimitive,
5237  "svg",
5238  "Scalable Vector Graphics"
5239 };
5240 
5241 /*********************************************************************
5242  *
5243  * PGF routines
5244  *
5245  *********************************************************************/
5246 
5247 static void gl2psPrintPGFColor(GL2PSrgba rgba)
5248 {
5249  if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
5250  gl2psSetLastColor(rgba);
5251  fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]);
5252  }
5253 }
5254 
5255 static void gl2psPrintPGFHeader(void)
5256 {
5257  time_t now;
5258 
5259  time(&now);
5260 
5261  fprintf(gl2ps->stream,
5262  "%% Title: %s\n"
5263  "%% Creator: GL2PS %d.%d.%d%s, %s\n"
5264  "%% For: %s\n"
5265  "%% CreationDate: %s",
5268  gl2ps->producer, ctime(&now));
5269 
5270  fprintf(gl2ps->stream, "\\begin{pgfpicture}\n");
5271  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5272  gl2psPrintPGFColor(gl2ps->bgcolor);
5273  fprintf(gl2ps->stream,
5274  "\\pgfpathrectanglecorners{"
5275  "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n"
5276  "\\pgfusepath{fill}\n",
5277  (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
5278  (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
5279  }
5280 }
5281 
5282 static void gl2psPrintPGFDash(GLushort pattern, GLint factor)
5283 {
5284  int i, n, array[10];
5285 
5286  if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
5287  return;
5288 
5289  gl2ps->lastpattern = pattern;
5290  gl2ps->lastfactor = factor;
5291 
5292  if(!pattern || !factor){
5293  /* solid line */
5294  fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n");
5295  }
5296  else{
5297  gl2psParseStipplePattern(pattern, factor, &n, array);
5298  fprintf(gl2ps->stream, "\\pgfsetdash{");
5299  for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]);
5300  fprintf(gl2ps->stream, "}{0pt}\n");
5301  }
5302 }
5303 
5304 static const char *gl2psPGFTextAlignment(int align)
5305 {
5306  switch(align){
5307  case GL2PS_TEXT_C : return "center";
5308  case GL2PS_TEXT_CL : return "west";
5309  case GL2PS_TEXT_CR : return "east";
5310  case GL2PS_TEXT_B : return "south";
5311  case GL2PS_TEXT_BR : return "south east";
5312  case GL2PS_TEXT_T : return "north";
5313  case GL2PS_TEXT_TL : return "north west";
5314  case GL2PS_TEXT_TR : return "north east";
5315  case GL2PS_TEXT_BL :
5316  default : return "south west";
5317  }
5318 }
5319 
5320 static void gl2psPrintPGFPrimitive(void *data)
5321 {
5322  GL2PSprimitive *prim;
5323 
5324  prim = *(GL2PSprimitive**)data;
5325 
5326  switch(prim->type){
5327  case GL2PS_POINT :
5328  /* Points in openGL are rectangular */
5329  gl2psPrintPGFColor(prim->verts[0].rgba);
5330  fprintf(gl2ps->stream,
5331  "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}"
5332  "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n",
5333  prim->verts[0].xyz[0]-0.5*prim->width,
5334  prim->verts[0].xyz[1]-0.5*prim->width,
5335  prim->width,prim->width);
5336  break;
5337  case GL2PS_LINE :
5338  gl2psPrintPGFColor(prim->verts[0].rgba);
5339  if(gl2ps->lastlinewidth != prim->width){
5340  gl2ps->lastlinewidth = prim->width;
5341  fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth);
5342  }
5343  gl2psPrintPGFDash(prim->pattern, prim->factor);
5344  fprintf(gl2ps->stream,
5345  "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
5346  "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5347  "\\pgfusepath{stroke}\n",
5348  prim->verts[1].xyz[0], prim->verts[1].xyz[1],
5349  prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5350  break;
5351  case GL2PS_TRIANGLE :
5352  if(gl2ps->lastlinewidth != 0){
5353  gl2ps->lastlinewidth = 0;
5354  fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n");
5355  }
5356  gl2psPrintPGFColor(prim->verts[0].rgba);
5357  fprintf(gl2ps->stream,
5358  "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
5359  "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5360  "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5361  "\\pgfpathclose\n"
5362  "\\pgfusepath{fill,stroke}\n",
5363  prim->verts[2].xyz[0], prim->verts[2].xyz[1],
5364  prim->verts[1].xyz[0], prim->verts[1].xyz[1],
5365  prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5366  break;
5367  case GL2PS_TEXT :
5368  fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n",
5369  prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5370 
5371  if(prim->data.text->angle)
5372  fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle);
5373 
5374  fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont",
5375  gl2psPGFTextAlignment(prim->data.text->alignment),
5376  prim->data.text->fontsize);
5377 
5378  fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}",
5379  prim->verts[0].rgba[0], prim->verts[0].rgba[1],
5380  prim->verts[0].rgba[2], prim->data.text->str);
5381 
5382  fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n");
5383  break;
5384  case GL2PS_SPECIAL :
5385  /* alignment contains the format for which the special output text
5386  is intended */
5387  if (prim->data.text->alignment == GL2PS_PGF)
5388  fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
5389  break;
5390  default :
5391  break;
5392  }
5393 }
5394 
5395 static void gl2psPrintPGFFooter(void)
5396 {
5397  fprintf(gl2ps->stream, "\\end{pgfpicture}\n");
5398 }
5399 
5400 static void gl2psPrintPGFBeginViewport(GLint viewport[4])
5401 {
5402  GLint index;
5403  GLfloat rgba[4];
5404  int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
5405 
5406  glRenderMode(GL_FEEDBACK);
5407 
5408  if(gl2ps->header){
5409  gl2psPrintPGFHeader();
5410  gl2ps->header = GL_FALSE;
5411  }
5412 
5413  fprintf(gl2ps->stream, "\\begin{pgfscope}\n");
5414  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5415  if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
5416  glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
5417  }
5418  else{
5419  glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5420  rgba[0] = gl2ps->colormap[index][0];
5421  rgba[1] = gl2ps->colormap[index][1];
5422  rgba[2] = gl2ps->colormap[index][2];
5423  rgba[3] = 1.0F;
5424  }
5425  gl2psPrintPGFColor(rgba);
5426  fprintf(gl2ps->stream,
5427  "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
5428  "{\\pgfpoint{%dpt}{%dpt}}\n"
5429  "\\pgfusepath{fill}\n",
5430  x, y, w, h);
5431  }
5432 
5433  fprintf(gl2ps->stream,
5434  "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
5435  "{\\pgfpoint{%dpt}{%dpt}}\n"
5436  "\\pgfusepath{clip}\n",
5437  x, y, w, h);
5438 }
5439 
5440 static GLint gl2psPrintPGFEndViewport(void)
5441 {
5442  GLint res;
5443  res = gl2psPrintPrimitives();
5444  fprintf(gl2ps->stream, "\\end{pgfscope}\n");
5445  return res;
5446 }
5447 
5448 static void gl2psPrintPGFFinalPrimitive(void)
5449 {
5450 }
5451 
5452 /* definition of the PGF backend */
5453 
5454 static GL2PSbackend gl2psPGF = {
5455  gl2psPrintPGFHeader,
5456  gl2psPrintPGFFooter,
5457  gl2psPrintPGFBeginViewport,
5458  gl2psPrintPGFEndViewport,
5459  gl2psPrintPGFPrimitive,
5460  gl2psPrintPGFFinalPrimitive,
5461  "tex",
5462  "PGF Latex Graphics"
5463 };
5464 
5465 /*********************************************************************
5466  *
5467  * General primitive printing routine
5468  *
5469  *********************************************************************/
5470 
5471 /* Warning: the ordering of the backends must match the format
5472  #defines in gl2ps.h */
5473 
5474 static GL2PSbackend *gl2psbackends[] = {
5475  &gl2psPS, /* 0 */
5476  &gl2psEPS, /* 1 */
5477  &gl2psTEX, /* 2 */
5478  &gl2psPDF, /* 3 */
5479  &gl2psSVG, /* 4 */
5480  &gl2psPGF /* 5 */
5481 };
5482 
5483 static void gl2psComputeTightBoundingBox(void *data)
5484 {
5485  GL2PSprimitive *prim;
5486  int i;
5487 
5488  prim = *(GL2PSprimitive**)data;
5489 
5490  for(i = 0; i < prim->numverts; i++){
5491  if(prim->verts[i].xyz[0] < gl2ps->viewport[0])
5492  gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0];
5493  if(prim->verts[i].xyz[0] > gl2ps->viewport[2])
5494  gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F);
5495  if(prim->verts[i].xyz[1] < gl2ps->viewport[1])
5496  gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1];
5497  if(prim->verts[i].xyz[1] > gl2ps->viewport[3])
5498  gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F);
5499  }
5500 }
5501 
5502 static GLint gl2psPrintPrimitives(void)
5503 {
5504  GL2PSbsptree *root;
5505  GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE};
5506  GLint used;
5507 
5508  used = glRenderMode(GL_RENDER);
5509 
5510  if(used < 0){
5511  gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow");
5512  return GL2PS_OVERFLOW;
5513  }
5514 
5515  if(used > 0)
5516  gl2psParseFeedbackBuffer(used);
5517 
5518  gl2psRescaleAndOffset();
5519 
5520  if(gl2ps->header){
5521  if(gl2psListNbr(gl2ps->primitives) &&
5522  (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){
5523  gl2ps->viewport[0] = gl2ps->viewport[1] = 100000;
5524  gl2ps->viewport[2] = gl2ps->viewport[3] = -100000;
5525  gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox);
5526  }
5527  (gl2psbackends[gl2ps->format]->printHeader)();
5528  gl2ps->header = GL_FALSE;
5529  }
5530 
5531  if(!gl2psListNbr(gl2ps->primitives)){
5532  /* empty feedback buffer and/or nothing else to print */
5533  return GL2PS_NO_FEEDBACK;
5534  }
5535 
5536  switch(gl2ps->sort){
5537  case GL2PS_NO_SORT :
5538  gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
5539  gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
5540  /* reset the primitive list, waiting for the next viewport */
5541  gl2psListReset(gl2ps->primitives);
5542  break;
5543  case GL2PS_SIMPLE_SORT :
5544  gl2psListSort(gl2ps->primitives, gl2psCompareDepth);
5545  if(gl2ps->options & GL2PS_OCCLUSION_CULL){
5546  gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree);
5547  gl2psFreeBspImageTree(&gl2ps->imagetree);
5548  }
5549  gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
5550  gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
5551  /* reset the primitive list, waiting for the next viewport */
5552  gl2psListReset(gl2ps->primitives);
5553  break;
5554  case GL2PS_BSP_SORT :
5555  root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
5556  gl2psBuildBspTree(root, gl2ps->primitives);
5557  if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root);
5558  if(gl2ps->options & GL2PS_OCCLUSION_CULL){
5559  gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess,
5560  gl2psAddInImageTree, 1);
5561  gl2psFreeBspImageTree(&gl2ps->imagetree);
5562  }
5563  gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater,
5564  gl2psbackends[gl2ps->format]->printPrimitive, 0);
5565  gl2psFreeBspTree(&root);
5566  /* reallocate the primitive list (it's been deleted by
5567  gl2psBuildBspTree) in case there is another viewport */
5568  gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
5569  break;
5570  }
5571  gl2psbackends[gl2ps->format]->printFinalPrimitive();
5572 
5573  return GL2PS_SUCCESS;
5574 }
5575 
5576 /*********************************************************************
5577  *
5578  * Public routines
5579  *
5580  *********************************************************************/
5581 
5582 GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
5583  GLint viewport[4], GLint format, GLint sort,
5584  GLint options, GLint colormode,
5585  GLint colorsize, GL2PSrgba *colormap,
5586  GLint nr, GLint ng, GLint nb, GLint buffersize,
5587  FILE *stream, const char *filename)
5588 {
5589  GLint index;
5590  int i;
5591 
5592  if(gl2ps){
5593  gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state");
5594  return GL2PS_ERROR;
5595  }
5596 
5597  gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext));
5598 
5599  if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))){
5600  gl2ps->format = format;
5601  }
5602  else {
5603  gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format);
5604  gl2psFree(gl2ps);
5605  gl2ps = NULL;
5606  return GL2PS_ERROR;
5607  }
5608 
5609  switch(sort){
5610  case GL2PS_NO_SORT :
5611  case GL2PS_SIMPLE_SORT :
5612  case GL2PS_BSP_SORT :
5613  gl2ps->sort = sort;
5614  break;
5615  default :
5616  gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort);
5617  gl2psFree(gl2ps);
5618  gl2ps = NULL;
5619  return GL2PS_ERROR;
5620  }
5621 
5622  if(stream){
5623  gl2ps->stream = stream;
5624  }
5625  else{
5626  gl2psMsg(GL2PS_ERROR, "Bad file pointer");
5627  gl2psFree(gl2ps);
5628  gl2ps = NULL;
5629  return GL2PS_ERROR;
5630  }
5631 
5632  gl2ps->header = GL_TRUE;
5633  gl2ps->maxbestroot = 10;
5634  gl2ps->options = options;
5635  gl2ps->compress = NULL;
5636  gl2ps->imagemap_head = NULL;
5637  gl2ps->imagemap_tail = NULL;
5638 
5639  if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){
5640  glGetIntegerv(GL_VIEWPORT, gl2ps->viewport);
5641  }
5642  else{
5643  for(i = 0; i < 4; i++){
5644  gl2ps->viewport[i] = viewport[i];
5645  }
5646  }
5647 
5648  if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){
5649  gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)",
5650  gl2ps->viewport[0], gl2ps->viewport[1],
5651  gl2ps->viewport[2], gl2ps->viewport[3]);
5652  gl2psFree(gl2ps);
5653  gl2ps = NULL;
5654  return GL2PS_ERROR;
5655  }
5656 
5657  gl2ps->threshold[0] = nr ? 1.0F / (GLfloat)nr : 0.064F;
5658  gl2ps->threshold[1] = ng ? 1.0F / (GLfloat)ng : 0.034F;
5659  gl2ps->threshold[2] = nb ? 1.0F / (GLfloat)nb : 0.100F;
5660  gl2ps->colormode = colormode;
5661  gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048;
5662  for(i = 0; i < 3; i++){
5663  gl2ps->lastvertex.xyz[i] = -1.0F;
5664  }
5665  for(i = 0; i < 4; i++){
5666  gl2ps->lastvertex.rgba[i] = -1.0F;
5667  gl2ps->lastrgba[i] = -1.0F;
5668  }
5669  gl2ps->lastlinewidth = -1.0F;
5670  gl2ps->lastpattern = 0;
5671  gl2ps->lastfactor = 0;
5672  gl2ps->imagetree = NULL;
5673  gl2ps->primitivetoadd = NULL;
5674  gl2ps->zerosurfacearea = GL_FALSE;
5675  gl2ps->pdfprimlist = NULL;
5676  gl2ps->pdfgrouplist = NULL;
5677  gl2ps->xreflist = NULL;
5678 
5679  /* get default blending mode from current OpenGL state (enabled by
5680  default for SVG) */
5681  gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND);
5682  glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]);
5683  glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]);
5684 
5685  if(gl2ps->colormode == GL_RGBA){
5686  gl2ps->colorsize = 0;
5687  gl2ps->colormap = NULL;
5688  glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor);
5689  }
5690  else if(gl2ps->colormode == GL_COLOR_INDEX){
5691  if(!colorsize || !colormap){
5692  gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering");
5693  gl2psFree(gl2ps);
5694  gl2ps = NULL;
5695  return GL2PS_ERROR;
5696  }
5697  gl2ps->colorsize = colorsize;
5698  gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba));
5699  memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba));
5700  glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5701  gl2ps->bgcolor[0] = gl2ps->colormap[index][0];
5702  gl2ps->bgcolor[1] = gl2ps->colormap[index][1];
5703  gl2ps->bgcolor[2] = gl2ps->colormap[index][2];
5704  gl2ps->bgcolor[3] = 1.0F;
5705  }
5706  else{
5707  gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage");
5708  gl2psFree(gl2ps);
5709  gl2ps = NULL;
5710  return GL2PS_ERROR;
5711  }
5712 
5713  if(!title){
5714  gl2ps->title = (char*)gl2psMalloc(sizeof(char));
5715  gl2ps->title[0] = '\0';
5716  }
5717  else{
5718  gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char));
5719  strcpy(gl2ps->title, title);
5720  }
5721 
5722  if(!producer){
5723  gl2ps->producer = (char*)gl2psMalloc(sizeof(char));
5724  gl2ps->producer[0] = '\0';
5725  }
5726  else{
5727  gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char));
5728  strcpy(gl2ps->producer, producer);
5729  }
5730 
5731  if(!filename){
5732  gl2ps->filename = (char*)gl2psMalloc(sizeof(char));
5733  gl2ps->filename[0] = '\0';
5734  }
5735  else{
5736  gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char));
5737  strcpy(gl2ps->filename, filename);
5738  }
5739 
5740  gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
5741  gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*));
5742  gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat));
5743  glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback);
5744  glRenderMode(GL_FEEDBACK);
5745 
5746  return GL2PS_SUCCESS;
5747 }
5748 
5750 {
5751  GLint res;
5752 
5753  if(!gl2ps) return GL2PS_UNINITIALIZED;
5754 
5755  res = gl2psPrintPrimitives();
5756 
5757  if(res != GL2PS_OVERFLOW)
5758  (gl2psbackends[gl2ps->format]->printFooter)();
5759 
5760  fflush(gl2ps->stream);
5761 
5762  gl2psListDelete(gl2ps->primitives);
5763  gl2psListDelete(gl2ps->auxprimitives);
5764  gl2psFreeImagemap(gl2ps->imagemap_head);
5765  gl2psFree(gl2ps->colormap);
5766  gl2psFree(gl2ps->title);
5767  gl2psFree(gl2ps->producer);
5768  gl2psFree(gl2ps->filename);
5769  gl2psFree(gl2ps->feedback);
5770  gl2psFree(gl2ps);
5771  gl2ps = NULL;
5772 
5773  return res;
5774 }
5775 
5776 GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4])
5777 {
5778  if(!gl2ps) return GL2PS_UNINITIALIZED;
5779 
5780  (gl2psbackends[gl2ps->format]->beginViewport)(viewport);
5781 
5782  return GL2PS_SUCCESS;
5783 }
5784 
5786 {
5787  GLint res;
5788 
5789  if(!gl2ps) return GL2PS_UNINITIALIZED;
5790 
5791  res = (gl2psbackends[gl2ps->format]->endViewport)();
5792 
5793  /* reset last used colors, line widths */
5794  gl2ps->lastlinewidth = -1.0F;
5795 
5796  return res;
5797 }
5798 
5799 GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname,
5800  GLshort fontsize, GLint alignment, GLfloat angle)
5801 {
5802  return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle);
5803 }
5804 
5805 GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize)
5806 {
5807  return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F);
5808 }
5809 
5810 GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str)
5811 {
5812  return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F);
5813 }
5814 
5815 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
5816  GLint xorig, GLint yorig,
5817  GLenum format, GLenum type,
5818  const void *pixels)
5819 {
5820  int size, i;
5821  GLfloat pos[4], *piv;
5822  GL2PSprimitive *prim;
5823  GLboolean valid;
5824 
5825  if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED;
5826 
5827  if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
5828 
5829  if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS;
5830 
5831  if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){
5832  gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for "
5833  "GL_RGB/GL_RGBA, GL_FLOAT pixels");
5834  return GL2PS_ERROR;
5835  }
5836 
5837  glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
5838  if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
5839 
5840  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
5841 
5842  prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
5843  prim->type = GL2PS_PIXMAP;
5844  prim->boundary = 0;
5845  prim->numverts = 1;
5846  prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
5847  prim->verts[0].xyz[0] = pos[0] + xorig;
5848  prim->verts[0].xyz[1] = pos[1] + yorig;
5849  prim->verts[0].xyz[2] = pos[2];
5850  prim->culled = 0;
5851  prim->offset = 0;
5852  prim->pattern = 0;
5853  prim->factor = 0;
5854  prim->width = 1;
5855  glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
5856  prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
5857  prim->data.image->width = width;
5858  prim->data.image->height = height;
5859  prim->data.image->format = format;
5860  prim->data.image->type = type;
5861 
5862  switch(format){
5863  case GL_RGBA:
5864  if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
5865  /* special case: blending turned off */
5866  prim->data.image->format = GL_RGB;
5867  size = height * width * 3;
5868  prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5869  piv = (GLfloat*)pixels;
5870  for(i = 0; i < size; ++i, ++piv){
5871  prim->data.image->pixels[i] = *piv;
5872  if(!((i+1)%3))
5873  ++piv;
5874  }
5875  }
5876  else{
5877  size = height * width * 4;
5878  prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5879  memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
5880  }
5881  break;
5882  case GL_RGB:
5883  default:
5884  size = height * width * 3;
5885  prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5886  memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
5887  break;
5888  }
5889 
5890  gl2psListAdd(gl2ps->auxprimitives, &prim);
5891  glPassThrough(GL2PS_DRAW_PIXELS_TOKEN);
5892 
5893  return GL2PS_SUCCESS;
5894 }
5895 
5896 GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height,
5897  const GLfloat position[3],
5898  const unsigned char *imagemap){
5899  int size, i;
5900  int sizeoffloat = sizeof(GLfloat);
5901 
5902  if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED;
5903 
5904  if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
5905 
5906  size = height + height * ((width - 1) / 8);
5907  glPassThrough(GL2PS_IMAGEMAP_TOKEN);
5908  glBegin(GL_POINTS);
5909  glVertex3f(position[0], position[1],position[2]);
5910  glEnd();
5911  glPassThrough((GLfloat)width);
5912  glPassThrough((GLfloat)height);
5913  for(i = 0; i < size; i += sizeoffloat){
5914  // cppcheck-suppress invalidPointerCast
5915  const float *value = reinterpret_cast<const float*>(imagemap);
5916  glPassThrough(*value);
5917  imagemap += sizeoffloat;
5918  }
5919  return GL2PS_SUCCESS;
5920 }
5921 
5923 {
5924  GLint tmp;
5925 
5926  if(!gl2ps) return GL2PS_UNINITIALIZED;
5927 
5928  switch(mode){
5930  glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN);
5931  glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]);
5932  glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]);
5933  break;
5934  case GL2PS_POLYGON_BOUNDARY :
5935  glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN);
5936  break;
5937  case GL2PS_LINE_STIPPLE :
5938  glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN);
5939  glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp);
5940  glPassThrough((GLfloat)tmp);
5941  glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp);
5942  glPassThrough((GLfloat)tmp);
5943  break;
5944  case GL2PS_BLEND :
5945  glPassThrough(GL2PS_BEGIN_BLEND_TOKEN);
5946  break;
5947  default :
5948  gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode);
5949  return GL2PS_WARNING;
5950  }
5951 
5952  return GL2PS_SUCCESS;
5953 }
5954 
5956 {
5957  if(!gl2ps) return GL2PS_UNINITIALIZED;
5958 
5959  switch(mode){
5961  glPassThrough(GL2PS_END_OFFSET_TOKEN);
5962  break;
5963  case GL2PS_POLYGON_BOUNDARY :
5964  glPassThrough(GL2PS_END_BOUNDARY_TOKEN);
5965  break;
5966  case GL2PS_LINE_STIPPLE :
5967  glPassThrough(GL2PS_END_STIPPLE_TOKEN);
5968  break;
5969  case GL2PS_BLEND :
5970  glPassThrough(GL2PS_END_BLEND_TOKEN);
5971  break;
5972  default :
5973  gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode);
5974  return GL2PS_WARNING;
5975  }
5976 
5977  return GL2PS_SUCCESS;
5978 }
5979 
5981 {
5982  if(!gl2ps) return GL2PS_UNINITIALIZED;
5983 
5984  glPassThrough(GL2PS_POINT_SIZE_TOKEN);
5985  glPassThrough(value);
5986 
5987  return GL2PS_SUCCESS;
5988 }
5989 
5991 {
5992  if(!gl2ps) return GL2PS_UNINITIALIZED;
5993 
5994  glPassThrough(GL2PS_LINE_WIDTH_TOKEN);
5995  glPassThrough(value);
5996 
5997  return GL2PS_SUCCESS;
5998 }
5999 
6000 GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor)
6001 {
6002  if(!gl2ps) return GL2PS_UNINITIALIZED;
6003 
6004  if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor))
6005  return GL2PS_WARNING;
6006 
6007  glPassThrough(GL2PS_SRC_BLEND_TOKEN);
6008  glPassThrough((GLfloat)sfactor);
6009  glPassThrough(GL2PS_DST_BLEND_TOKEN);
6010  glPassThrough((GLfloat)dfactor);
6011 
6012  return GL2PS_SUCCESS;
6013 }
6014 
6016 {
6017  if(!gl2ps) return GL2PS_UNINITIALIZED;
6018 
6019  gl2ps->options = options;
6020 
6021  return GL2PS_SUCCESS;
6022 }
6023 
6025 {
6026  if(!gl2ps) {
6027  *options = 0;
6028  return GL2PS_UNINITIALIZED;
6029  }
6030 
6031  *options = gl2ps->options;
6032 
6033  return GL2PS_SUCCESS;
6034 }
6035 
6037 {
6038  if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0])))
6039  return gl2psbackends[format]->file_extension;
6040  else
6041  return "Unknown format";
6042 }
6043 
6045 {
6046  if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0])))
6047  return gl2psbackends[format]->description;
6048  else
6049  return "Unknown format";
6050 }
GL2PS_DRAW_PIXELS_TOKEN
#define GL2PS_DRAW_PIXELS_TOKEN
Definition: gl2ps.cxx:114
node::type
void type(TYPE t)
Definition: node.h:48
GL2PScontext::shader_stack
int shader_stack
Definition: gl2ps.cxx:244
mergePhysValFiles.pattern
pattern
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:26
used
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
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:6015
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:5815
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:5990
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:5980
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:6000
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
TRTCalib_cfilter.p1
p1
Definition: TRTCalib_cfilter.py:130
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:124
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
dbg::ptr
void * ptr(T *p)
Definition: SGImplSvc.cxx:74
_GL2PSbsptree2d::front
GL2PSbsptree2d * front
Definition: gl2ps.cxx:133
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
GL2PSprimitive::data
union GL2PSprimitive::@65 data
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
TRTCalib_cfilter.p2
p2
Definition: TRTCalib_cfilter.py: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
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
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:5799
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:5785
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:85
xmin
double xmin
Definition: listroot.cxx:60
gl2psGetFormatDescription
GL2PSDLL_API const char * gl2psGetFormatDescription(GLint format)
Definition: gl2ps.cxx:6044
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
python.CaloCondTools.g
g
Definition: CaloCondTools.py:15
beamspotman.n
n
Definition: beamspotman.py:731
MuonR4::inverse
CalibratedSpacePoint::Covariance_t inverse(const CalibratedSpacePoint::Covariance_t &mat)
Inverts the parsed matrix.
Definition: MuonSpectrometer/MuonPhaseII/Event/MuonSpacePoint/src/UtilFunctions.cxx:65
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:94
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:132
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:5896
lumiFormat.array
array
Definition: lumiFormat.py:91
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:221
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:5922
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:5810
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:154
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:364
__attribute__
__attribute__((always_inline)) inline uint16_t TileCalibDrawerBase
Definition: TileCalibDrawerBase.h:190
fmt
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:6036
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:5776
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:6024
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:5582
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:132
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:5955
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:349
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:5805
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:5749