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