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