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