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