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