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