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