comparison src/gl2ps.c @ 9798:2d6a5af744b6

printing for fltk backend using gl2ps
author Shai Ayal <shaiay@users.sourceforge.net>
date Tue, 10 Nov 2009 19:48:02 -0500
parents
children 7dedfd70dd9f
comparison
equal deleted inserted replaced
9797:f569f46a1c34 9798:2d6a5af744b6
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
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
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 exit(1);
301 }
302 return(ptr);
303 }
304
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 exit(1);
312 }
313 return(ptr);
314 }
315
316 static void gl2psFree(void *ptr)
317 {
318 if(!ptr) return;
319 free(ptr);
320 }
321
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
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
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
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
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
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
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
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
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
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
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
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
539 static void gl2psListReset(GL2PSlist *list)
540 {
541 if(!list) return;
542 list->n = 0;
543 }
544
545 static void gl2psListDelete(GL2PSlist *list)
546 {
547 if(!list) return;
548 gl2psFree(list->array);
549 gl2psFree(list);
550 }
551
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
563 static int gl2psListNbr(GL2PSlist *list)
564 {
565 if(!list)
566 return 0;
567 return(list->n);
568 }
569
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
787 static void gl2psUserFlushPNG(png_structp png_ptr)
788 {
789 }
790
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1241 static GLshort gl2psGetIndex(GLshort i, GLshort num)
1242 {
1243 return (i < num - 1) ? i + 1 : 0;
1244 }
1245
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
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
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
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
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
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
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
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
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
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
1503 static GLboolean gl2psGreater(GLfloat f1, GLfloat f2)
1504 {
1505 if(f1 > f2) return GL_TRUE;
1506 else return GL_FALSE;
1507 }
1508
1509 static GLboolean gl2psLess(GLfloat f1, GLfloat f2)
1510 {
1511 if(f1 < f2) return GL_TRUE;
1512 else return GL_FALSE;
1513 }
1514
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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], &current[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
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
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
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
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
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
2877 static void gl2psResetPostScriptColor(void)
2878 {
2879 gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.;
2880 }
2881
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
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
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
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
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
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
3147 static GLint gl2psPrintPostScriptEndViewport(void)
3148 {
3149 GLint res;
3150
3151 res = gl2psPrintPrimitives();
3152 gl2psPrintf("grestore\n");
3153 return res;
3154 }
3155
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
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 = 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
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
3295 static void gl2psPrintTeXFooter(void)
3296 {
3297 fprintf(gl2ps->stream, "\\end{picture}%s\n",
3298 (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : "");
3299 }
3300
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
3311 static GLint gl2psPrintTeXEndViewport(void)
3312 {
3313 return gl2psPrintPrimitives();
3314 }
3315
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
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
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
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
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
3392 static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y)
3393 {
3394 gl2ps->streamlength +=
3395 gl2psPrintf("BT\n"
3396 "/F%d %d Tf\n"
3397 "%f %f Td\n"
3398 "(%s) Tj\n"
3399 "ET\n",
3400 cnt, text->fontsize, x, y, text->str);
3401 }
3402
3403 static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y)
3404 {
3405 gl2ps->streamlength +=
3406 gl2psPrintf("q\n"
3407 "%d 0 0 %d %f %f cm\n"
3408 "/Im%d Do\n"
3409 "Q\n",
3410 (int)image->width, (int)image->height, x, y, cnt);
3411 }
3412
3413 static void gl2psPDFstacksInit(void)
3414 {
3415 gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1;
3416 gl2ps->extgs_stack = 0;
3417 gl2ps->font_stack = 0;
3418 gl2ps->im_stack = 0;
3419 gl2ps->trgroupobjects_stack = 0;
3420 gl2ps->shader_stack = 0;
3421 gl2ps->mshader_stack = 0;
3422 }
3423
3424 static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro)
3425 {
3426 if(!gro)
3427 return;
3428
3429 gro->ptrlist = NULL;
3430 gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno
3431 = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno
3432 = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1;
3433 }
3434
3435 /* Build up group objects and assign name and object numbers */
3436
3437 static void gl2psPDFgroupListInit(void)
3438 {
3439 int i;
3440 GL2PSprimitive *p = NULL;
3441 GL2PSpdfgroup gro;
3442 int lasttype = GL2PS_NO_TYPE;
3443 GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F};
3444 GLushort lastpattern = 0;
3445 GLint lastfactor = 0;
3446 GLfloat lastwidth = 1;
3447 GL2PStriangle lastt, tmpt;
3448 int lastTriangleWasNotSimpleWithSameColor = 0;
3449
3450 if(!gl2ps->pdfprimlist)
3451 return;
3452
3453 gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup));
3454 gl2psInitTriangle(&lastt);
3455
3456 for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){
3457 p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i);
3458 switch(p->type){
3459 case GL2PS_PIXMAP:
3460 gl2psPDFgroupObjectInit(&gro);
3461 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3462 gro.imno = gl2ps->im_stack++;
3463 gl2psListAdd(gro.ptrlist, &p);
3464 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3465 break;
3466 case GL2PS_TEXT:
3467 gl2psPDFgroupObjectInit(&gro);
3468 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3469 gro.fontno = gl2ps->font_stack++;
3470 gl2psListAdd(gro.ptrlist, &p);
3471 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3472 break;
3473 case GL2PS_LINE:
3474 if(lasttype != p->type || lastwidth != p->width ||
3475 lastpattern != p->pattern || lastfactor != p->factor ||
3476 !gl2psSameColor(p->verts[0].rgba, lastrgba)){
3477 gl2psPDFgroupObjectInit(&gro);
3478 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3479 gl2psListAdd(gro.ptrlist, &p);
3480 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3481 }
3482 else{
3483 gl2psListAdd(gro.ptrlist, &p);
3484 }
3485 lastpattern = p->pattern;
3486 lastfactor = p->factor;
3487 lastwidth = p->width;
3488 lastrgba[0] = p->verts[0].rgba[0];
3489 lastrgba[1] = p->verts[0].rgba[1];
3490 lastrgba[2] = p->verts[0].rgba[2];
3491 break;
3492 case GL2PS_POINT:
3493 if(lasttype != p->type || lastwidth != p->width ||
3494 !gl2psSameColor(p->verts[0].rgba, lastrgba)){
3495 gl2psPDFgroupObjectInit(&gro);
3496 gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*));
3497 gl2psListAdd(gro.ptrlist, &p);
3498 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3499 }
3500 else{
3501 gl2psListAdd(gro.ptrlist, &p);
3502 }
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_TRIANGLE:
3509 gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE);
3510 lastTriangleWasNotSimpleWithSameColor =
3511 !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) ||
3512 !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba);
3513 if(lasttype == p->type && tmpt.prop == lastt.prop &&
3514 lastTriangleWasNotSimpleWithSameColor){
3515 /* TODO Check here for last alpha */
3516 gl2psListAdd(gro.ptrlist, &p);
3517 }
3518 else{
3519 gl2psPDFgroupObjectInit(&gro);
3520 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3521 gl2psListAdd(gro.ptrlist, &p);
3522 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3523 }
3524 lastt = tmpt;
3525 break;
3526 default:
3527 break;
3528 }
3529 lasttype = p->type;
3530 }
3531 }
3532
3533 static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro)
3534 {
3535 GL2PStriangle t;
3536 GL2PSprimitive *prim = NULL;
3537
3538 if(!gro)
3539 return;
3540
3541 if(!gl2psListNbr(gro->ptrlist))
3542 return;
3543
3544 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3545
3546 if(prim->type != GL2PS_TRIANGLE)
3547 return;
3548
3549 gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
3550
3551 if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){
3552 gro->gsno = gl2ps->extgs_stack++;
3553 gro->gsobjno = gl2ps->objects_stack ++;
3554 }
3555 else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){
3556 gro->gsno = gl2ps->extgs_stack++;
3557 gro->gsobjno = gl2ps->objects_stack++;
3558 gro->trgroupno = gl2ps->trgroupobjects_stack++;
3559 gro->trgroupobjno = gl2ps->objects_stack++;
3560 gro->maskshno = gl2ps->mshader_stack++;
3561 gro->maskshobjno = gl2ps->objects_stack++;
3562 }
3563 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){
3564 gro->shno = gl2ps->shader_stack++;
3565 gro->shobjno = gl2ps->objects_stack++;
3566 }
3567 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){
3568 gro->gsno = gl2ps->extgs_stack++;
3569 gro->gsobjno = gl2ps->objects_stack++;
3570 gro->shno = gl2ps->shader_stack++;
3571 gro->shobjno = gl2ps->objects_stack++;
3572 }
3573 else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){
3574 gro->gsno = gl2ps->extgs_stack++;
3575 gro->gsobjno = gl2ps->objects_stack++;
3576 gro->shno = gl2ps->shader_stack++;
3577 gro->shobjno = gl2ps->objects_stack++;
3578 gro->trgroupno = gl2ps->trgroupobjects_stack++;
3579 gro->trgroupobjno = gl2ps->objects_stack++;
3580 gro->maskshno = gl2ps->mshader_stack++;
3581 gro->maskshobjno = gl2ps->objects_stack++;
3582 }
3583 }
3584
3585 /* Main stream data */
3586
3587 static void gl2psPDFgroupListWriteMainStream(void)
3588 {
3589 int i, j, lastel;
3590 GL2PSprimitive *prim = NULL, *prev = NULL;
3591 GL2PSpdfgroup *gro;
3592 GL2PStriangle t;
3593
3594 if(!gl2ps->pdfgrouplist)
3595 return;
3596
3597 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3598 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3599
3600 lastel = gl2psListNbr(gro->ptrlist) - 1;
3601 if(lastel < 0)
3602 continue;
3603
3604 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3605
3606 switch(prim->type){
3607 case GL2PS_POINT:
3608 gl2ps->streamlength += gl2psPrintf("1 J\n");
3609 gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
3610 gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
3611 for(j = 0; j <= lastel; ++j){
3612 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3613 gl2ps->streamlength +=
3614 gl2psPrintf("%f %f m %f %f l\n",
3615 prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3616 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3617 }
3618 gl2ps->streamlength += gl2psPrintf("S\n");
3619 gl2ps->streamlength += gl2psPrintf("0 J\n");
3620 break;
3621 case GL2PS_LINE:
3622 /* We try to use as few paths as possible to draw lines, in
3623 order to get nice stippling even when the individual segments
3624 are smaller than the stipple */
3625 gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
3626 gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
3627 gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d");
3628 /* start new path */
3629 gl2ps->streamlength +=
3630 gl2psPrintf("%f %f m\n",
3631 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3632
3633 for(j = 1; j <= lastel; ++j){
3634 prev = prim;
3635 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3636 if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){
3637 /* the starting point of the new segment does not match the
3638 end point of the previous line, so we end the current
3639 path and start a new one */
3640 gl2ps->streamlength +=
3641 gl2psPrintf("%f %f l\n",
3642 prev->verts[1].xyz[0], prev->verts[1].xyz[1]);
3643 gl2ps->streamlength +=
3644 gl2psPrintf("%f %f m\n",
3645 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3646 }
3647 else{
3648 /* the two segements are connected, so we just append to the
3649 current path */
3650 gl2ps->streamlength +=
3651 gl2psPrintf("%f %f l\n",
3652 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3653 }
3654 }
3655 /* end last path */
3656 gl2ps->streamlength +=
3657 gl2psPrintf("%f %f l\n",
3658 prim->verts[1].xyz[0], prim->verts[1].xyz[1]);
3659 gl2ps->streamlength += gl2psPrintf("S\n");
3660 break;
3661 case GL2PS_TRIANGLE:
3662 gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
3663 gl2psSortOutTrianglePDFgroup(gro);
3664
3665 /* No alpha and const color: Simple PDF draw orders */
3666 if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){
3667 gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba);
3668 for(j = 0; j <= lastel; ++j){
3669 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3670 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3671 gl2ps->streamlength
3672 += gl2psPrintf("%f %f m\n"
3673 "%f %f l\n"
3674 "%f %f l\n"
3675 "h f\n",
3676 t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3677 t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3678 t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3679 }
3680 }
3681 /* Const alpha < 1 and const color: Simple PDF draw orders
3682 and an extra extended Graphics State for the alpha const */
3683 else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){
3684 gl2ps->streamlength += gl2psPrintf("q\n"
3685 "/GS%d gs\n",
3686 gro->gsno);
3687 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3688 for(j = 0; j <= lastel; ++j){
3689 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3690 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3691 gl2ps->streamlength
3692 += gl2psPrintf("%f %f m\n"
3693 "%f %f l\n"
3694 "%f %f l\n"
3695 "h f\n",
3696 t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3697 t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3698 t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3699 }
3700 gl2ps->streamlength += gl2psPrintf("Q\n");
3701 }
3702 /* Variable alpha and const color: Simple PDF draw orders
3703 and an extra extended Graphics State + Xobject + Shader
3704 object for the alpha mask */
3705 else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){
3706 gl2ps->streamlength += gl2psPrintf("q\n"
3707 "/GS%d gs\n"
3708 "/TrG%d Do\n",
3709 gro->gsno, gro->trgroupno);
3710 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3711 for(j = 0; j <= lastel; ++j){
3712 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3713 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3714 gl2ps->streamlength
3715 += gl2psPrintf("%f %f m\n"
3716 "%f %f l\n"
3717 "%f %f l\n"
3718 "h f\n",
3719 t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3720 t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3721 t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3722 }
3723 gl2ps->streamlength += gl2psPrintf("Q\n");
3724 }
3725 /* Variable color and no alpha: Shader Object for the colored
3726 triangle(s) */
3727 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){
3728 gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno);
3729 }
3730 /* Variable color and const alpha < 1: Shader Object for the
3731 colored triangle(s) and an extra extended Graphics State
3732 for the alpha const */
3733 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){
3734 gl2ps->streamlength += gl2psPrintf("q\n"
3735 "/GS%d gs\n"
3736 "/Sh%d sh\n"
3737 "Q\n",
3738 gro->gsno, gro->shno);
3739 }
3740 /* Variable alpha and color: Shader Object for the colored
3741 triangle(s) and an extra extended Graphics State
3742 + Xobject + Shader object for the alpha mask */
3743 else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){
3744 gl2ps->streamlength += gl2psPrintf("q\n"
3745 "/GS%d gs\n"
3746 "/TrG%d Do\n"
3747 "/Sh%d sh\n"
3748 "Q\n",
3749 gro->gsno, gro->trgroupno, gro->shno);
3750 }
3751 break;
3752 case GL2PS_PIXMAP:
3753 for(j = 0; j <= lastel; ++j){
3754 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3755 gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0],
3756 prim->verts[0].xyz[1]);
3757 }
3758 break;
3759 case GL2PS_TEXT:
3760 for(j = 0; j <= lastel; ++j){
3761 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3762 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3763 gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0],
3764 prim->verts[0].xyz[1]);
3765 }
3766 break;
3767 default:
3768 break;
3769 }
3770 }
3771 }
3772
3773 /* Graphics State names */
3774
3775 static int gl2psPDFgroupListWriteGStateResources(void)
3776 {
3777 GL2PSpdfgroup *gro;
3778 int offs = 0;
3779 int i;
3780
3781 offs += fprintf(gl2ps->stream,
3782 "/ExtGState\n"
3783 "<<\n"
3784 "/GSa 7 0 R\n");
3785 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3786 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3787 if(gro->gsno >= 0)
3788 offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno);
3789 }
3790 offs += fprintf(gl2ps->stream, ">>\n");
3791 return offs;
3792 }
3793
3794 /* Main Shader names */
3795
3796 static int gl2psPDFgroupListWriteShaderResources(void)
3797 {
3798 GL2PSpdfgroup *gro;
3799 int offs = 0;
3800 int i;
3801
3802 offs += fprintf(gl2ps->stream,
3803 "/Shading\n"
3804 "<<\n");
3805 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3806 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3807 if(gro->shno >= 0)
3808 offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno);
3809 if(gro->maskshno >= 0)
3810 offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno);
3811 }
3812 offs += fprintf(gl2ps->stream,">>\n");
3813 return offs;
3814 }
3815
3816 /* Images & Mask Shader XObject names */
3817
3818 static int gl2psPDFgroupListWriteXObjectResources(void)
3819 {
3820 int i;
3821 GL2PSprimitive *p = NULL;
3822 GL2PSpdfgroup *gro;
3823 int offs = 0;
3824
3825 offs += fprintf(gl2ps->stream,
3826 "/XObject\n"
3827 "<<\n");
3828
3829 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3830 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3831 if(!gl2psListNbr(gro->ptrlist))
3832 continue;
3833 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3834 switch(p->type){
3835 case GL2PS_PIXMAP:
3836 gro->imobjno = gl2ps->objects_stack++;
3837 if(GL_RGBA == p->data.image->format) /* reserve one object for image mask */
3838 gl2ps->objects_stack++;
3839 offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno);
3840 case GL2PS_TRIANGLE:
3841 if(gro->trgroupno >=0)
3842 offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno);
3843 break;
3844 default:
3845 break;
3846 }
3847 }
3848 offs += fprintf(gl2ps->stream,">>\n");
3849 return offs;
3850 }
3851
3852 /* Font names */
3853
3854 static int gl2psPDFgroupListWriteFontResources(void)
3855 {
3856 int i;
3857 GL2PSpdfgroup *gro;
3858 int offs = 0;
3859
3860 offs += fprintf(gl2ps->stream, "/Font\n<<\n");
3861
3862 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3863 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3864 if(gro->fontno < 0)
3865 continue;
3866 gro->fontobjno = gl2ps->objects_stack++;
3867 offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno);
3868 }
3869 offs += fprintf(gl2ps->stream, ">>\n");
3870
3871 return offs;
3872 }
3873
3874 static void gl2psPDFgroupListDelete(void)
3875 {
3876 int i;
3877 GL2PSpdfgroup *gro = NULL;
3878
3879 if(!gl2ps->pdfgrouplist)
3880 return;
3881
3882 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3883 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i);
3884 gl2psListDelete(gro->ptrlist);
3885 }
3886
3887 gl2psListDelete(gl2ps->pdfgrouplist);
3888 gl2ps->pdfgrouplist = NULL;
3889 }
3890
3891 /* Print 1st PDF object - file info */
3892
3893 static int gl2psPrintPDFInfo(void)
3894 {
3895 int offs;
3896 time_t now;
3897 struct tm *newtime;
3898
3899 time(&now);
3900 newtime = gmtime(&now);
3901
3902 offs = fprintf(gl2ps->stream,
3903 "1 0 obj\n"
3904 "<<\n"
3905 "/Title (%s)\n"
3906 "/Creator (GL2PS %d.%d.%d%s, %s)\n"
3907 "/Producer (%s)\n",
3908 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
3909 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
3910 gl2ps->producer);
3911
3912 if(!newtime){
3913 offs += fprintf(gl2ps->stream,
3914 ">>\n"
3915 "endobj\n");
3916 return offs;
3917 }
3918
3919 offs += fprintf(gl2ps->stream,
3920 "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n"
3921 ">>\n"
3922 "endobj\n",
3923 newtime->tm_year+1900,
3924 newtime->tm_mon+1,
3925 newtime->tm_mday,
3926 newtime->tm_hour,
3927 newtime->tm_min,
3928 newtime->tm_sec);
3929 return offs;
3930 }
3931
3932 /* Create catalog and page structure - 2nd and 3th PDF object */
3933
3934 static int gl2psPrintPDFCatalog(void)
3935 {
3936 return fprintf(gl2ps->stream,
3937 "2 0 obj\n"
3938 "<<\n"
3939 "/Type /Catalog\n"
3940 "/Pages 3 0 R\n"
3941 ">>\n"
3942 "endobj\n");
3943 }
3944
3945 static int gl2psPrintPDFPages(void)
3946 {
3947 return fprintf(gl2ps->stream,
3948 "3 0 obj\n"
3949 "<<\n"
3950 "/Type /Pages\n"
3951 "/Kids [6 0 R]\n"
3952 "/Count 1\n"
3953 ">>\n"
3954 "endobj\n");
3955 }
3956
3957 /* Open stream for data - graphical objects, fonts etc. PDF object 4 */
3958
3959 static int gl2psOpenPDFDataStream(void)
3960 {
3961 int offs = 0;
3962
3963 offs += fprintf(gl2ps->stream,
3964 "4 0 obj\n"
3965 "<<\n"
3966 "/Length 5 0 R\n" );
3967 offs += gl2psPrintPDFCompressorType();
3968 offs += fprintf(gl2ps->stream,
3969 ">>\n"
3970 "stream\n");
3971 return offs;
3972 }
3973
3974 /* Stream setup - Graphics state, fill background if allowed */
3975
3976 static int gl2psOpenPDFDataStreamWritePreface(void)
3977 {
3978 int offs;
3979
3980 offs = gl2psPrintf("/GSa gs\n");
3981
3982 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
3983 offs += gl2psPrintPDFFillColor(gl2ps->bgcolor);
3984 offs += gl2psPrintf("%d %d %d %d re\n",
3985 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
3986 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
3987 offs += gl2psPrintf("f\n");
3988 }
3989 return offs;
3990 }
3991
3992 /* Use the functions above to create the first part of the PDF*/
3993
3994 static void gl2psPrintPDFHeader(void)
3995 {
3996 int offs = 0;
3997 gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
3998 gl2psPDFstacksInit();
3999
4000 gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack);
4001
4002 #if defined(GL2PS_HAVE_ZLIB)
4003 if(gl2ps->options & GL2PS_COMPRESS){
4004 gl2psSetupCompress();
4005 }
4006 #endif
4007 gl2ps->xreflist[0] = 0;
4008 offs += fprintf(gl2ps->stream, "%%PDF-1.4\n");
4009 gl2ps->xreflist[1] = offs;
4010
4011 offs += gl2psPrintPDFInfo();
4012 gl2ps->xreflist[2] = offs;
4013
4014 offs += gl2psPrintPDFCatalog();
4015 gl2ps->xreflist[3] = offs;
4016
4017 offs += gl2psPrintPDFPages();
4018 gl2ps->xreflist[4] = offs;
4019
4020 offs += gl2psOpenPDFDataStream();
4021 gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */
4022 gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface();
4023 }
4024
4025 /* The central primitive drawing */
4026
4027 static void gl2psPrintPDFPrimitive(void *data)
4028 {
4029 GL2PSprimitive *prim = *(GL2PSprimitive**)data;
4030
4031 if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled)
4032 return;
4033
4034 prim = gl2psCopyPrimitive(prim); /* deep copy */
4035 gl2psListAdd(gl2ps->pdfprimlist, &prim);
4036 }
4037
4038 /* close stream and ... */
4039
4040 static int gl2psClosePDFDataStream(void)
4041 {
4042 int offs = 0;
4043
4044 #if defined(GL2PS_HAVE_ZLIB)
4045 if(gl2ps->options & GL2PS_COMPRESS){
4046 if(Z_OK != gl2psDeflate())
4047 gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
4048 else
4049 fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream);
4050 gl2ps->streamlength += gl2ps->compress->destLen;
4051
4052 offs += gl2ps->streamlength;
4053 gl2psFreeCompress();
4054 }
4055 #endif
4056
4057 offs += fprintf(gl2ps->stream,
4058 "endstream\n"
4059 "endobj\n");
4060 return offs;
4061 }
4062
4063 /* ... write the now known length object */
4064
4065 static int gl2psPrintPDFDataStreamLength(int val)
4066 {
4067 return fprintf(gl2ps->stream,
4068 "5 0 obj\n"
4069 "%d\n"
4070 "endobj\n", val);
4071 }
4072
4073 /* Put the info created before in PDF objects */
4074
4075 static int gl2psPrintPDFOpenPage(void)
4076 {
4077 int offs;
4078
4079 /* Write fixed part */
4080
4081 offs = fprintf(gl2ps->stream,
4082 "6 0 obj\n"
4083 "<<\n"
4084 "/Type /Page\n"
4085 "/Parent 3 0 R\n"
4086 "/MediaBox [%d %d %d %d]\n",
4087 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4088 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4089
4090 if(gl2ps->options & GL2PS_LANDSCAPE)
4091 offs += fprintf(gl2ps->stream, "/Rotate -90\n");
4092
4093 offs += fprintf(gl2ps->stream,
4094 "/Contents 4 0 R\n"
4095 "/Resources\n"
4096 "<<\n"
4097 "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n");
4098
4099 return offs;
4100
4101 /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */
4102 }
4103
4104 static int gl2psPDFgroupListWriteVariableResources(void)
4105 {
4106 int offs = 0;
4107
4108 /* a) Graphics States for shader alpha masks*/
4109 offs += gl2psPDFgroupListWriteGStateResources();
4110
4111 /* b) Shader and shader masks */
4112 offs += gl2psPDFgroupListWriteShaderResources();
4113
4114 /* c) XObjects (Images & Shader Masks) */
4115 offs += gl2psPDFgroupListWriteXObjectResources();
4116
4117 /* d) Fonts */
4118 offs += gl2psPDFgroupListWriteFontResources();
4119
4120 /* End resources and page */
4121 offs += fprintf(gl2ps->stream,
4122 ">>\n"
4123 ">>\n"
4124 "endobj\n");
4125 return offs;
4126 }
4127
4128 /* Standard Graphics State */
4129
4130 static int gl2psPrintPDFGSObject(void)
4131 {
4132 return fprintf(gl2ps->stream,
4133 "7 0 obj\n"
4134 "<<\n"
4135 "/Type /ExtGState\n"
4136 "/SA false\n"
4137 "/SM 0.02\n"
4138 "/OP false\n"
4139 "/op false\n"
4140 "/OPM 0\n"
4141 "/BG2 /Default\n"
4142 "/UCR2 /Default\n"
4143 "/TR2 /Default\n"
4144 ">>\n"
4145 "endobj\n");
4146 }
4147
4148 /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */
4149
4150 static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex,
4151 size_t (*action)(unsigned long data,
4152 size_t size),
4153 GLfloat dx, GLfloat dy,
4154 GLfloat xmin, GLfloat ymin)
4155 {
4156 int offs = 0;
4157 unsigned long imap;
4158 GLfloat diff;
4159 double dmax = ~1UL;
4160 char edgeflag = 0;
4161
4162 /* FIXME: temp bux fix for 64 bit archs: */
4163 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4164
4165 offs += (*action)(edgeflag, 1);
4166
4167 /* The Shader stream in PDF requires to be in a 'big-endian'
4168 order */
4169
4170 if(GL2PS_ZERO(dx * dy)){
4171 offs += (*action)(0, 4);
4172 offs += (*action)(0, 4);
4173 }
4174 else{
4175 diff = (vertex->xyz[0] - xmin) / dx;
4176 if(diff > 1)
4177 diff = 1.0F;
4178 else if(diff < 0)
4179 diff = 0.0F;
4180 imap = (unsigned long)(diff * dmax);
4181 offs += (*action)(imap, 4);
4182
4183 diff = (vertex->xyz[1] - ymin) / dy;
4184 if(diff > 1)
4185 diff = 1.0F;
4186 else if(diff < 0)
4187 diff = 0.0F;
4188 imap = (unsigned long)(diff * dmax);
4189 offs += (*action)(imap, 4);
4190 }
4191
4192 return offs;
4193 }
4194
4195 /* Put vertex' rgb value (8bit for every component) in shader stream */
4196
4197 static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex,
4198 size_t (*action)(unsigned long data,
4199 size_t size))
4200 {
4201 int offs = 0;
4202 unsigned long imap;
4203 double dmax = ~1UL;
4204
4205 /* FIXME: temp bux fix for 64 bit archs: */
4206 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4207
4208 imap = (unsigned long)((vertex->rgba[0]) * dmax);
4209 offs += (*action)(imap, 1);
4210
4211 imap = (unsigned long)((vertex->rgba[1]) * dmax);
4212 offs += (*action)(imap, 1);
4213
4214 imap = (unsigned long)((vertex->rgba[2]) * dmax);
4215 offs += (*action)(imap, 1);
4216
4217 return offs;
4218 }
4219
4220 /* Put vertex' alpha (8/16bit) in shader stream */
4221
4222 static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex,
4223 size_t (*action)(unsigned long data,
4224 size_t size),
4225 int sigbyte)
4226 {
4227 int offs = 0;
4228 unsigned long imap;
4229 double dmax = ~1UL;
4230
4231 /* FIXME: temp bux fix for 64 bit archs: */
4232 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4233
4234 if(sigbyte != 8 && sigbyte != 16)
4235 sigbyte = 8;
4236
4237 sigbyte /= 8;
4238
4239 imap = (unsigned long)((vertex->rgba[3]) * dmax);
4240
4241 offs += (*action)(imap, sigbyte);
4242
4243 return offs;
4244 }
4245
4246 /* Put a triangles raw data in shader stream */
4247
4248 static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle,
4249 GLfloat dx, GLfloat dy,
4250 GLfloat xmin, GLfloat ymin,
4251 size_t (*action)(unsigned long data,
4252 size_t size),
4253 int gray)
4254 {
4255 int i, offs = 0;
4256 GL2PSvertex v;
4257
4258 if(gray && gray != 8 && gray != 16)
4259 gray = 8;
4260
4261 for(i = 0; i < 3; ++i){
4262 offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action,
4263 dx, dy, xmin, ymin);
4264 if(gray){
4265 v = triangle->vertex[i];
4266 offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray);
4267 }
4268 else{
4269 offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action);
4270 }
4271 }
4272
4273 return offs;
4274 }
4275
4276 static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax,
4277 GLfloat *ymin, GLfloat *ymax,
4278 GL2PStriangle *triangles, int cnt)
4279 {
4280 int i, j;
4281
4282 *xmin = triangles[0].vertex[0].xyz[0];
4283 *xmax = triangles[0].vertex[0].xyz[0];
4284 *ymin = triangles[0].vertex[0].xyz[1];
4285 *ymax = triangles[0].vertex[0].xyz[1];
4286
4287 for(i = 0; i < cnt; ++i){
4288 for(j = 0; j < 3; ++j){
4289 if(*xmin > triangles[i].vertex[j].xyz[0])
4290 *xmin = triangles[i].vertex[j].xyz[0];
4291 if(*xmax < triangles[i].vertex[j].xyz[0])
4292 *xmax = triangles[i].vertex[j].xyz[0];
4293 if(*ymin > triangles[i].vertex[j].xyz[1])
4294 *ymin = triangles[i].vertex[j].xyz[1];
4295 if(*ymax < triangles[i].vertex[j].xyz[1])
4296 *ymax = triangles[i].vertex[j].xyz[1];
4297 }
4298 }
4299 }
4300
4301 /* Writes shaded triangle
4302 gray == 0 means write RGB triangles
4303 gray == 8 8bit-grayscale (for alpha masks)
4304 gray == 16 16bit-grayscale (for alpha masks) */
4305
4306 static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles,
4307 int size, int gray)
4308 {
4309 int i, offs = 0, vertexbytes, done = 0;
4310 GLfloat xmin, xmax, ymin, ymax;
4311
4312 switch(gray){
4313 case 0:
4314 vertexbytes = 1+4+4+1+1+1;
4315 break;
4316 case 8:
4317 vertexbytes = 1+4+4+1;
4318 break;
4319 case 16:
4320 vertexbytes = 1+4+4+2;
4321 break;
4322 default:
4323 gray = 8;
4324 vertexbytes = 1+4+4+1;
4325 break;
4326 }
4327
4328 gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size);
4329
4330 offs += fprintf(gl2ps->stream,
4331 "%d 0 obj\n"
4332 "<< "
4333 "/ShadingType 4 "
4334 "/ColorSpace %s "
4335 "/BitsPerCoordinate 32 "
4336 "/BitsPerComponent %d "
4337 "/BitsPerFlag 8 "
4338 "/Decode [%f %f %f %f 0 1 %s] ",
4339 obj,
4340 (gray) ? "/DeviceGray" : "/DeviceRGB",
4341 (gray) ? gray : 8,
4342 xmin, xmax, ymin, ymax,
4343 (gray) ? "" : "0 1 0 1");
4344
4345 #if defined(GL2PS_HAVE_ZLIB)
4346 if(gl2ps->options & GL2PS_COMPRESS){
4347 gl2psAllocCompress(vertexbytes * size * 3);
4348
4349 for(i = 0; i < size; ++i)
4350 gl2psPrintPDFShaderStreamData(&triangles[i],
4351 xmax-xmin, ymax-ymin, xmin, ymin,
4352 gl2psWriteBigEndianCompress, gray);
4353
4354 if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4355 offs += gl2psPrintPDFCompressorType();
4356 offs += fprintf(gl2ps->stream,
4357 "/Length %d "
4358 ">>\n"
4359 "stream\n",
4360 (int)gl2ps->compress->destLen);
4361 offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest,
4362 gl2ps->compress->destLen,
4363 1, gl2ps->stream);
4364 done = 1;
4365 }
4366 gl2psFreeCompress();
4367 }
4368 #endif
4369
4370 if(!done){
4371 /* no compression, or too long after compression, or compress error
4372 -> write non-compressed entry */
4373 offs += fprintf(gl2ps->stream,
4374 "/Length %d "
4375 ">>\n"
4376 "stream\n",
4377 vertexbytes * 3 * size);
4378 for(i = 0; i < size; ++i)
4379 offs += gl2psPrintPDFShaderStreamData(&triangles[i],
4380 xmax-xmin, ymax-ymin, xmin, ymin,
4381 gl2psWriteBigEndian, gray);
4382 }
4383
4384 offs += fprintf(gl2ps->stream,
4385 "\nendstream\n"
4386 "endobj\n");
4387
4388 return offs;
4389 }
4390
4391 /* Writes a XObject for a shaded triangle mask */
4392
4393 static int gl2psPrintPDFShaderMask(int obj, int childobj)
4394 {
4395 int offs = 0, len;
4396
4397 offs += fprintf(gl2ps->stream,
4398 "%d 0 obj\n"
4399 "<<\n"
4400 "/Type /XObject\n"
4401 "/Subtype /Form\n"
4402 "/BBox [ %d %d %d %d ]\n"
4403 "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n"
4404 ">>\n",
4405 obj,
4406 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4407 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4408
4409 len = (childobj>0)
4410 ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1
4411 : strlen("/TrSh0 sh\n");
4412
4413 offs += fprintf(gl2ps->stream,
4414 "/Length %d\n"
4415 ">>\n"
4416 "stream\n",
4417 len);
4418 offs += fprintf(gl2ps->stream,
4419 "/TrSh%d sh\n",
4420 childobj);
4421 offs += fprintf(gl2ps->stream,
4422 "endstream\n"
4423 "endobj\n");
4424
4425 return offs;
4426 }
4427
4428 /* Writes a Extended graphics state for a shaded triangle mask if
4429 simplealpha ist true the childobj argument is ignored and a /ca
4430 statement will be written instead */
4431
4432 static int gl2psPrintPDFShaderExtGS(int obj, int childobj)
4433 {
4434 int offs = 0;
4435
4436 offs += fprintf(gl2ps->stream,
4437 "%d 0 obj\n"
4438 "<<\n",
4439 obj);
4440
4441 offs += fprintf(gl2ps->stream,
4442 "/SMask << /S /Alpha /G %d 0 R >> ",
4443 childobj);
4444
4445 offs += fprintf(gl2ps->stream,
4446 ">>\n"
4447 "endobj\n");
4448 return offs;
4449 }
4450
4451 /* a simple graphics state */
4452
4453 static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha)
4454 {
4455 int offs = 0;
4456
4457 offs += fprintf(gl2ps->stream,
4458 "%d 0 obj\n"
4459 "<<\n"
4460 "/ca %g"
4461 ">>\n"
4462 "endobj\n",
4463 obj, alpha);
4464 return offs;
4465 }
4466
4467 /* Similar groups of functions for pixmaps and text */
4468
4469 static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im,
4470 size_t (*action)(unsigned long data,
4471 size_t size),
4472 int gray)
4473 {
4474 int x, y;
4475 GLfloat r, g, b, a;
4476
4477 if(im->format != GL_RGBA && gray)
4478 return 0;
4479
4480 if(gray && gray !=8 && gray != 16)
4481 gray = 8;
4482
4483 gray /= 8;
4484
4485 for(y = 0; y < im->height; ++y){
4486 for(x = 0; x < im->width; ++x){
4487 a = gl2psGetRGB(im, x, y, &r, &g, &b);
4488 if(im->format == GL_RGBA && gray){
4489 (*action)((unsigned long)(a*255) << 24, gray);
4490 }
4491 else{
4492 (*action)((unsigned long)(r*255) << 24, 1);
4493 (*action)((unsigned long)(g*255) << 24, 1);
4494 (*action)((unsigned long)(b*255) << 24, 1);
4495 }
4496 }
4497 }
4498
4499 switch(gray){
4500 case 0: return 3 * im->width * im->height;
4501 case 1: return im->width * im->height;
4502 case 2: return 2 * im->width * im->height;
4503 default: return 3 * im->width * im->height;
4504 }
4505 }
4506
4507 static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray)
4508 {
4509 int offs = 0, done = 0, sigbytes = 3;
4510
4511 if(gray && gray !=8 && gray != 16)
4512 gray = 8;
4513
4514 if(gray)
4515 sigbytes = gray / 8;
4516
4517 offs += fprintf(gl2ps->stream,
4518 "%d 0 obj\n"
4519 "<<\n"
4520 "/Type /XObject\n"
4521 "/Subtype /Image\n"
4522 "/Width %d\n"
4523 "/Height %d\n"
4524 "/ColorSpace %s \n"
4525 "/BitsPerComponent 8\n",
4526 obj,
4527 (int)im->width, (int)im->height,
4528 (gray) ? "/DeviceGray" : "/DeviceRGB" );
4529 if(GL_RGBA == im->format && gray == 0){
4530 offs += fprintf(gl2ps->stream,
4531 "/SMask %d 0 R\n",
4532 childobj);
4533 }
4534
4535 #if defined(GL2PS_HAVE_ZLIB)
4536 if(gl2ps->options & GL2PS_COMPRESS){
4537 gl2psAllocCompress((int)(im->width * im->height * sigbytes));
4538
4539 gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray);
4540
4541 if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4542 offs += gl2psPrintPDFCompressorType();
4543 offs += fprintf(gl2ps->stream,
4544 "/Length %d "
4545 ">>\n"
4546 "stream\n",
4547 (int)gl2ps->compress->destLen);
4548 offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen,
4549 1, gl2ps->stream);
4550 done = 1;
4551 }
4552 gl2psFreeCompress();
4553 }
4554 #endif
4555
4556 if(!done){
4557 /* no compression, or too long after compression, or compress error
4558 -> write non-compressed entry */
4559 offs += fprintf(gl2ps->stream,
4560 "/Length %d "
4561 ">>\n"
4562 "stream\n",
4563 (int)(im->width * im->height * sigbytes));
4564 offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray);
4565 }
4566
4567 offs += fprintf(gl2ps->stream,
4568 "\nendstream\n"
4569 "endobj\n");
4570
4571 return offs;
4572 }
4573
4574 static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber)
4575 {
4576 int offs = 0;
4577
4578 offs += fprintf(gl2ps->stream,
4579 "%d 0 obj\n"
4580 "<<\n"
4581 "/Type /Font\n"
4582 "/Subtype /Type1\n"
4583 "/Name /F%d\n"
4584 "/BaseFont /%s\n"
4585 "/Encoding /MacRomanEncoding\n"
4586 ">>\n"
4587 "endobj\n",
4588 obj, fontnumber, s->fontname);
4589 return offs;
4590 }
4591
4592 /* Write the physical objects */
4593
4594 static int gl2psPDFgroupListWriteObjects(int entryoffs)
4595 {
4596 int i,j;
4597 GL2PSprimitive *p = NULL;
4598 GL2PSpdfgroup *gro;
4599 int offs = entryoffs;
4600 GL2PStriangle *triangles;
4601 int size = 0;
4602
4603 if(!gl2ps->pdfgrouplist)
4604 return offs;
4605
4606 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
4607 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
4608 if(!gl2psListNbr(gro->ptrlist))
4609 continue;
4610 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
4611 switch(p->type){
4612 case GL2PS_POINT:
4613 break;
4614 case GL2PS_LINE:
4615 break;
4616 case GL2PS_TRIANGLE:
4617 size = gl2psListNbr(gro->ptrlist);
4618 triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size);
4619 for(j = 0; j < size; ++j){
4620 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
4621 gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE);
4622 }
4623 if(triangles[0].prop & T_VAR_COLOR){
4624 gl2ps->xreflist[gro->shobjno] = offs;
4625 offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0);
4626 }
4627 if(triangles[0].prop & T_ALPHA_LESS_1){
4628 gl2ps->xreflist[gro->gsobjno] = offs;
4629 offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]);
4630 }
4631 if(triangles[0].prop & T_VAR_ALPHA){
4632 gl2ps->xreflist[gro->gsobjno] = offs;
4633 offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno);
4634 gl2ps->xreflist[gro->trgroupobjno] = offs;
4635 offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno);
4636 gl2ps->xreflist[gro->maskshobjno] = offs;
4637 offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8);
4638 }
4639 gl2psFree(triangles);
4640 break;
4641 case GL2PS_PIXMAP:
4642 gl2ps->xreflist[gro->imobjno] = offs;
4643 offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0);
4644 if(p->data.image->format == GL_RGBA){
4645 gl2ps->xreflist[gro->imobjno+1] = offs;
4646 offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8);
4647 }
4648 break;
4649 case GL2PS_TEXT:
4650 gl2ps->xreflist[gro->fontobjno] = offs;
4651 offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno);
4652 break;
4653 case GL2PS_SPECIAL :
4654 /* alignment contains the format for which the special output text
4655 is intended */
4656 if(p->data.text->alignment == GL2PS_PDF)
4657 offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str);
4658 break;
4659 default:
4660 break;
4661 }
4662 }
4663 return offs;
4664 }
4665
4666 /* All variable data has been written at this point and all required
4667 functioninality has been gathered, so we can write now file footer
4668 with cross reference table and trailer */
4669
4670 static void gl2psPrintPDFFooter(void)
4671 {
4672 int i, offs;
4673
4674 gl2psPDFgroupListInit();
4675 gl2psPDFgroupListWriteMainStream();
4676
4677 offs = gl2ps->xreflist[5] + gl2ps->streamlength;
4678 offs += gl2psClosePDFDataStream();
4679 gl2ps->xreflist[5] = offs;
4680
4681 offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength);
4682 gl2ps->xreflist[6] = offs;
4683 gl2ps->streamlength = 0;
4684
4685 offs += gl2psPrintPDFOpenPage();
4686 offs += gl2psPDFgroupListWriteVariableResources();
4687 gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist,
4688 sizeof(int) * (gl2ps->objects_stack + 1));
4689 gl2ps->xreflist[7] = offs;
4690
4691 offs += gl2psPrintPDFGSObject();
4692 gl2ps->xreflist[8] = offs;
4693
4694 gl2ps->xreflist[gl2ps->objects_stack] =
4695 gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]);
4696
4697 /* Start cross reference table. The file has to been opened in
4698 binary mode to preserve the 20 digit string length! */
4699 fprintf(gl2ps->stream,
4700 "xref\n"
4701 "0 %d\n"
4702 "%010d 65535 f \n", gl2ps->objects_stack, 0);
4703
4704 for(i = 1; i < gl2ps->objects_stack; ++i)
4705 fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]);
4706
4707 fprintf(gl2ps->stream,
4708 "trailer\n"
4709 "<<\n"
4710 "/Size %d\n"
4711 "/Info 1 0 R\n"
4712 "/Root 2 0 R\n"
4713 ">>\n"
4714 "startxref\n%d\n"
4715 "%%%%EOF\n",
4716 gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]);
4717
4718 /* Free auxiliary lists and arrays */
4719 gl2psFree(gl2ps->xreflist);
4720 gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive);
4721 gl2psListDelete(gl2ps->pdfprimlist);
4722 gl2psPDFgroupListDelete();
4723
4724 #if defined(GL2PS_HAVE_ZLIB)
4725 if(gl2ps->options & GL2PS_COMPRESS){
4726 gl2psFreeCompress();
4727 gl2psFree(gl2ps->compress);
4728 gl2ps->compress = NULL;
4729 }
4730 #endif
4731 }
4732
4733 /* PDF begin viewport */
4734
4735 static void gl2psPrintPDFBeginViewport(GLint viewport[4])
4736 {
4737 int offs = 0;
4738 GLint index;
4739 GLfloat rgba[4];
4740 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
4741
4742 glRenderMode(GL_FEEDBACK);
4743
4744 if(gl2ps->header){
4745 gl2psPrintPDFHeader();
4746 gl2ps->header = GL_FALSE;
4747 }
4748
4749 offs += gl2psPrintf("q\n");
4750
4751 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4752 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
4753 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
4754 }
4755 else{
4756 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
4757 rgba[0] = gl2ps->colormap[index][0];
4758 rgba[1] = gl2ps->colormap[index][1];
4759 rgba[2] = gl2ps->colormap[index][2];
4760 rgba[3] = 1.0F;
4761 }
4762 offs += gl2psPrintPDFFillColor(rgba);
4763 offs += gl2psPrintf("%d %d %d %d re\n"
4764 "W\n"
4765 "f\n",
4766 x, y, w, h);
4767 }
4768 else{
4769 offs += gl2psPrintf("%d %d %d %d re\n"
4770 "W\n"
4771 "n\n",
4772 x, y, w, h);
4773 }
4774
4775 gl2ps->streamlength += offs;
4776 }
4777
4778 static GLint gl2psPrintPDFEndViewport(void)
4779 {
4780 GLint res;
4781
4782 res = gl2psPrintPrimitives();
4783 gl2ps->streamlength += gl2psPrintf("Q\n");
4784 return res;
4785 }
4786
4787 static void gl2psPrintPDFFinalPrimitive(void)
4788 {
4789 }
4790
4791 /* definition of the PDF backend */
4792
4793 static GL2PSbackend gl2psPDF = {
4794 gl2psPrintPDFHeader,
4795 gl2psPrintPDFFooter,
4796 gl2psPrintPDFBeginViewport,
4797 gl2psPrintPDFEndViewport,
4798 gl2psPrintPDFPrimitive,
4799 gl2psPrintPDFFinalPrimitive,
4800 "pdf",
4801 "Portable Document Format"
4802 };
4803
4804 /*********************************************************************
4805 *
4806 * SVG routines
4807 *
4808 *********************************************************************/
4809
4810 static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts,
4811 GL2PSxyz *xyz, GL2PSrgba *rgba)
4812 {
4813 int i, j;
4814
4815 for(i = 0; i < n; i++){
4816 xyz[i][0] = verts[i].xyz[0];
4817 xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1];
4818 xyz[i][2] = 0.0F;
4819 for(j = 0; j < 4; j++)
4820 rgba[i][j] = verts[i].rgba[j];
4821 }
4822 }
4823
4824 static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32])
4825 {
4826 int r = (int)(255. * rgba[0]);
4827 int g = (int)(255. * rgba[1]);
4828 int b = (int)(255. * rgba[2]);
4829 int rc = (r < 0) ? 0 : (r > 255) ? 255 : r;
4830 int gc = (g < 0) ? 0 : (g > 255) ? 255 : g;
4831 int bc = (b < 0) ? 0 : (b > 255) ? 255 : b;
4832 sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc);
4833 }
4834
4835 static void gl2psPrintSVGHeader(void)
4836 {
4837 int x, y, width, height;
4838 char col[32];
4839 time_t now;
4840
4841 time(&now);
4842
4843 if (gl2ps->options & GL2PS_LANDSCAPE){
4844 x = (int)gl2ps->viewport[1];
4845 y = (int)gl2ps->viewport[0];
4846 width = (int)gl2ps->viewport[3];
4847 height = (int)gl2ps->viewport[2];
4848 }
4849 else{
4850 x = (int)gl2ps->viewport[0];
4851 y = (int)gl2ps->viewport[1];
4852 width = (int)gl2ps->viewport[2];
4853 height = (int)gl2ps->viewport[3];
4854 }
4855
4856 /* Compressed SVG files (.svgz) are simply gzipped SVG files */
4857 gl2psPrintGzipHeader();
4858
4859 gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
4860 gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
4861 gl2psPrintf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
4862 " width=\"%dpx\" height=\"%dpx\" viewBox=\"%d %d %d %d\">\n",
4863 width, height, x, y, width, height);
4864 gl2psPrintf("<title>%s</title>\n", gl2ps->title);
4865 gl2psPrintf("<desc>\n");
4866 gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n"
4867 "For: %s\n"
4868 "CreationDate: %s",
4869 GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION,
4870 GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now));
4871 gl2psPrintf("</desc>\n");
4872 gl2psPrintf("<defs>\n");
4873 gl2psPrintf("</defs>\n");
4874
4875 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4876 gl2psSVGGetColorString(gl2ps->bgcolor, col);
4877 gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
4878 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4879 (int)gl2ps->viewport[2], (int)gl2ps->viewport[1],
4880 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3],
4881 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
4882 }
4883
4884 /* group all the primitives and disable antialiasing */
4885 gl2psPrintf("<g shape-rendering=\"crispEdges\">\n");
4886 }
4887
4888 static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3])
4889 {
4890 int i;
4891 GL2PSxyz xyz2[3];
4892 GL2PSrgba rgba2[3];
4893 char col[32];
4894
4895 /* Apparently there is no easy way to do Gouraud shading in SVG
4896 without explicitly pre-defining gradients, so for now we just do
4897 recursive subdivision */
4898
4899 if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){
4900 gl2psSVGGetColorString(rgba[0], col);
4901 gl2psPrintf("<polygon fill=\"%s\" ", col);
4902 if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
4903 gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1],
4904 xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]);
4905 }
4906 else{
4907 /* subdivide into 4 subtriangles */
4908 for(i = 0; i < 3; i++){
4909 xyz2[0][i] = xyz[0][i];
4910 xyz2[1][i] = 0.5F * (xyz[0][i] + xyz[1][i]);
4911 xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]);
4912 }
4913 for(i = 0; i < 4; i++){
4914 rgba2[0][i] = rgba[0][i];
4915 rgba2[1][i] = 0.5F * (rgba[0][i] + rgba[1][i]);
4916 rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]);
4917 }
4918 gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4919 for(i = 0; i < 3; i++){
4920 xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]);
4921 xyz2[1][i] = xyz[1][i];
4922 xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]);
4923 }
4924 for(i = 0; i < 4; i++){
4925 rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]);
4926 rgba2[1][i] = rgba[1][i];
4927 rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]);
4928 }
4929 gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4930 for(i = 0; i < 3; i++){
4931 xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[2][i]);
4932 xyz2[1][i] = xyz[2][i];
4933 xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]);
4934 }
4935 for(i = 0; i < 4; i++){
4936 rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[2][i]);
4937 rgba2[1][i] = rgba[2][i];
4938 rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]);
4939 }
4940 gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4941 for(i = 0; i < 3; i++){
4942 xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]);
4943 xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]);
4944 xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]);
4945 }
4946 for(i = 0; i < 4; i++){
4947 rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]);
4948 rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]);
4949 rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]);
4950 }
4951 gl2psPrintSVGSmoothTriangle(xyz2, rgba2);
4952 }
4953 }
4954
4955 static void gl2psPrintSVGDash(GLushort pattern, GLint factor)
4956 {
4957 int i, n, array[10];
4958
4959 if(!pattern || !factor) return; /* solid line */
4960
4961 gl2psParseStipplePattern(pattern, factor, &n, array);
4962 gl2psPrintf("stroke-dasharray=\"");
4963 for(i = 0; i < n; i++){
4964 if(i) gl2psPrintf(",");
4965 gl2psPrintf("%d", array[i]);
4966 }
4967 gl2psPrintf("\" ");
4968 }
4969
4970 static void gl2psEndSVGLine(void)
4971 {
4972 int i;
4973 if(gl2ps->lastvertex.rgba[0] >= 0.){
4974 gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0],
4975 gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]);
4976 for(i = 0; i < 3; i++)
4977 gl2ps->lastvertex.xyz[i] = -1.;
4978 for(i = 0; i < 4; i++)
4979 gl2ps->lastvertex.rgba[i] = -1.;
4980 }
4981 }
4982
4983 static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap)
4984 {
4985 #if defined(GL2PS_HAVE_LIBPNG)
4986 GL2PSlist *png;
4987 unsigned char c;
4988 int i;
4989
4990 /* The only image types supported by the SVG standard are JPEG, PNG
4991 and SVG. Here we choose PNG, and since we want to embed the image
4992 directly in the SVG stream (and not link to an external image
4993 file), we need to encode the pixmap into PNG in memory, then
4994 encode it into base64. */
4995
4996 png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000,
4997 sizeof(unsigned char));
4998 gl2psConvertPixmapToPNG(pixmap, png);
4999 gl2psListEncodeBase64(png);
5000 gl2psPrintf("<image x=\"%g\" y=\"%g\" width=\"%d\" height=\"%d\"\n",
5001 x, y - pixmap->height, pixmap->width, pixmap->height);
5002 gl2psPrintf("xlink:href=\"data:image/png;base64,");
5003 for(i = 0; i < gl2psListNbr(png); i++){
5004 gl2psListRead(png, i, &c);
5005 gl2psPrintf("%c", c);
5006 }
5007 gl2psPrintf("\"/>\n");
5008 gl2psListDelete(png);
5009 #else
5010 gl2psMsg(GL2PS_WARNING, "GL2PS must be compiled with PNG support in "
5011 "order to embed images in SVG streams");
5012 #endif
5013 }
5014
5015 static void gl2psPrintSVGPrimitive(void *data)
5016 {
5017 GL2PSprimitive *prim;
5018 GL2PSxyz xyz[4];
5019 GL2PSrgba rgba[4];
5020 char col[32];
5021 int newline;
5022
5023 prim = *(GL2PSprimitive**)data;
5024
5025 if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
5026
5027 /* We try to draw connected lines as a single path to get nice line
5028 joins and correct stippling. So if the primitive to print is not
5029 a line we must first finish the current line (if any): */
5030 if(prim->type != GL2PS_LINE) gl2psEndSVGLine();
5031
5032 gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba);
5033
5034 switch(prim->type){
5035 case GL2PS_POINT :
5036 gl2psSVGGetColorString(rgba[0], col);
5037 gl2psPrintf("<circle fill=\"%s\" ", col);
5038 if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]);
5039 gl2psPrintf("cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
5040 xyz[0][0], xyz[0][1], 0.5 * prim->width);
5041 break;
5042 case GL2PS_LINE :
5043 if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
5044 !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
5045 gl2ps->lastlinewidth != prim->width ||
5046 gl2ps->lastpattern != prim->pattern ||
5047 gl2ps->lastfactor != prim->factor){
5048 /* End the current line if the new segment does not start where
5049 the last one ended, or if the color, the width or the
5050 stippling have changed (we will need to use multi-point
5051 gradients for smooth-shaded lines) */
5052 gl2psEndSVGLine();
5053 newline = 1;
5054 }
5055 else{
5056 newline = 0;
5057 }
5058 gl2ps->lastvertex = prim->verts[1];
5059 gl2psSetLastColor(prim->verts[0].rgba);
5060 gl2ps->lastlinewidth = prim->width;
5061 gl2ps->lastpattern = prim->pattern;
5062 gl2ps->lastfactor = prim->factor;
5063 if(newline){
5064 gl2psSVGGetColorString(rgba[0], col);
5065 gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ",
5066 col, prim->width);
5067 if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]);
5068 gl2psPrintSVGDash(prim->pattern, prim->factor);
5069 gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]);
5070 }
5071 else{
5072 gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]);
5073 }
5074 break;
5075 case GL2PS_TRIANGLE :
5076 gl2psPrintSVGSmoothTriangle(xyz, rgba);
5077 break;
5078 case GL2PS_QUADRANGLE :
5079 gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
5080 break;
5081 case GL2PS_PIXMAP :
5082 gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image);
5083 break;
5084 case GL2PS_TEXT :
5085 gl2psSVGGetColorString(prim->verts[0].rgba, col);
5086 gl2psPrintf("<text fill=\"%s\" x=\"%g\" y=\"%g\" font-size=\"%d\" ",
5087 col, xyz[0][0], xyz[0][1], prim->data.text->fontsize);
5088 if(prim->data.text->angle)
5089 gl2psPrintf("transform=\"rotate(%g, %g, %g)\" ",
5090 -prim->data.text->angle, xyz[0][0], xyz[0][1]);
5091 if(!strcmp(prim->data.text->fontname, "Times-Roman"))
5092 gl2psPrintf("font-family=\"Times\">");
5093 else if(!strcmp(prim->data.text->fontname, "Times-Bold"))
5094 gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">");
5095 else if(!strcmp(prim->data.text->fontname, "Times-Italic"))
5096 gl2psPrintf("font-family=\"Times\" font-style=\"italic\">");
5097 else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic"))
5098 gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">");
5099 else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold"))
5100 gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">");
5101 else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique"))
5102 gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">");
5103 else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique"))
5104 gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">");
5105 else if(!strcmp(prim->data.text->fontname, "Courier-Bold"))
5106 gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">");
5107 else if(!strcmp(prim->data.text->fontname, "Courier-Oblique"))
5108 gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">");
5109 else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique"))
5110 gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">");
5111 else
5112 gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname);
5113 gl2psPrintf("%s</text>\n", prim->data.text->str);
5114 break;
5115 case GL2PS_SPECIAL :
5116 /* alignment contains the format for which the special output text
5117 is intended */
5118 if(prim->data.text->alignment == GL2PS_SVG)
5119 gl2psPrintf("%s\n", prim->data.text->str);
5120 break;
5121 default :
5122 break;
5123 }
5124 }
5125
5126 static void gl2psPrintSVGFooter(void)
5127 {
5128 gl2psPrintf("</g>\n");
5129 gl2psPrintf("</svg>\n");
5130
5131 gl2psPrintGzipFooter();
5132 }
5133
5134 static void gl2psPrintSVGBeginViewport(GLint viewport[4])
5135 {
5136 GLint index;
5137 char col[32];
5138 GLfloat rgba[4];
5139 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
5140
5141 glRenderMode(GL_FEEDBACK);
5142
5143 if(gl2ps->header){
5144 gl2psPrintSVGHeader();
5145 gl2ps->header = GL_FALSE;
5146 }
5147
5148 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5149 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
5150 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
5151 }
5152 else{
5153 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5154 rgba[0] = gl2ps->colormap[index][0];
5155 rgba[1] = gl2ps->colormap[index][1];
5156 rgba[2] = gl2ps->colormap[index][2];
5157 rgba[3] = 1.0F;
5158 }
5159 gl2psSVGGetColorString(rgba, col);
5160 gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col,
5161 x, gl2ps->viewport[3] - y,
5162 x + w, gl2ps->viewport[3] - y,
5163 x + w, gl2ps->viewport[3] - (y + h),
5164 x, gl2ps->viewport[3] - (y + h));
5165 }
5166
5167 gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h);
5168 gl2psPrintf(" <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n",
5169 x, gl2ps->viewport[3] - y,
5170 x + w, gl2ps->viewport[3] - y,
5171 x + w, gl2ps->viewport[3] - (y + h),
5172 x, gl2ps->viewport[3] - (y + h));
5173 gl2psPrintf("</clipPath>\n");
5174 gl2psPrintf("<g clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h);
5175 }
5176
5177 static GLint gl2psPrintSVGEndViewport(void)
5178 {
5179 GLint res;
5180
5181 res = gl2psPrintPrimitives();
5182 gl2psPrintf("</g>\n");
5183 return res;
5184 }
5185
5186 static void gl2psPrintSVGFinalPrimitive(void)
5187 {
5188 /* End any remaining line, if any */
5189 gl2psEndSVGLine();
5190 }
5191
5192 /* definition of the SVG backend */
5193
5194 static GL2PSbackend gl2psSVG = {
5195 gl2psPrintSVGHeader,
5196 gl2psPrintSVGFooter,
5197 gl2psPrintSVGBeginViewport,
5198 gl2psPrintSVGEndViewport,
5199 gl2psPrintSVGPrimitive,
5200 gl2psPrintSVGFinalPrimitive,
5201 "svg",
5202 "Scalable Vector Graphics"
5203 };
5204
5205 /*********************************************************************
5206 *
5207 * PGF routines
5208 *
5209 *********************************************************************/
5210
5211 static void gl2psPrintPGFColor(GL2PSrgba rgba)
5212 {
5213 if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
5214 gl2psSetLastColor(rgba);
5215 fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]);
5216 }
5217 }
5218
5219 static void gl2psPrintPGFHeader(void)
5220 {
5221 time_t now;
5222
5223 time(&now);
5224
5225 fprintf(gl2ps->stream,
5226 "%% Title: %s\n"
5227 "%% Creator: GL2PS %d.%d.%d%s, %s\n"
5228 "%% For: %s\n"
5229 "%% CreationDate: %s",
5230 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
5231 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
5232 gl2ps->producer, ctime(&now));
5233
5234 fprintf(gl2ps->stream, "\\begin{pgfpicture}\n");
5235 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5236 gl2psPrintPGFColor(gl2ps->bgcolor);
5237 fprintf(gl2ps->stream,
5238 "\\pgfpathrectanglecorners{"
5239 "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n"
5240 "\\pgfusepath{fill}\n",
5241 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
5242 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
5243 }
5244 }
5245
5246 static void gl2psPrintPGFDash(GLushort pattern, GLint factor)
5247 {
5248 int i, n, array[10];
5249
5250 if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
5251 return;
5252
5253 gl2ps->lastpattern = pattern;
5254 gl2ps->lastfactor = factor;
5255
5256 if(!pattern || !factor){
5257 /* solid line */
5258 fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n");
5259 }
5260 else{
5261 gl2psParseStipplePattern(pattern, factor, &n, array);
5262 fprintf(gl2ps->stream, "\\pgfsetdash{");
5263 for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]);
5264 fprintf(gl2ps->stream, "}{0pt}\n");
5265 }
5266 }
5267
5268 static const char *gl2psPGFTextAlignment(int align)
5269 {
5270 switch(align){
5271 case GL2PS_TEXT_C : return "center";
5272 case GL2PS_TEXT_CL : return "west";
5273 case GL2PS_TEXT_CR : return "east";
5274 case GL2PS_TEXT_B : return "south";
5275 case GL2PS_TEXT_BR : return "south east";
5276 case GL2PS_TEXT_T : return "north";
5277 case GL2PS_TEXT_TL : return "north west";
5278 case GL2PS_TEXT_TR : return "north east";
5279 case GL2PS_TEXT_BL :
5280 default : return "south west";
5281 }
5282 }
5283
5284 static void gl2psPrintPGFPrimitive(void *data)
5285 {
5286 GL2PSprimitive *prim;
5287
5288 prim = *(GL2PSprimitive**)data;
5289
5290 switch(prim->type){
5291 case GL2PS_POINT :
5292 /* Points in openGL are rectangular */
5293 gl2psPrintPGFColor(prim->verts[0].rgba);
5294 fprintf(gl2ps->stream,
5295 "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}"
5296 "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n",
5297 prim->verts[0].xyz[0]-0.5*prim->width,
5298 prim->verts[0].xyz[1]-0.5*prim->width,
5299 prim->width,prim->width);
5300 break;
5301 case GL2PS_LINE :
5302 gl2psPrintPGFColor(prim->verts[0].rgba);
5303 if(gl2ps->lastlinewidth != prim->width){
5304 gl2ps->lastlinewidth = prim->width;
5305 fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth);
5306 }
5307 gl2psPrintPGFDash(prim->pattern, prim->factor);
5308 fprintf(gl2ps->stream,
5309 "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
5310 "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5311 "\\pgfusepath{stroke}\n",
5312 prim->verts[1].xyz[0], prim->verts[1].xyz[1],
5313 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5314 break;
5315 case GL2PS_TRIANGLE :
5316 if(gl2ps->lastlinewidth != 0){
5317 gl2ps->lastlinewidth = 0;
5318 fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n");
5319 }
5320 gl2psPrintPGFColor(prim->verts[0].rgba);
5321 fprintf(gl2ps->stream,
5322 "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n"
5323 "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5324 "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n"
5325 "\\pgfpathclose\n"
5326 "\\pgfusepath{fill,stroke}\n",
5327 prim->verts[2].xyz[0], prim->verts[2].xyz[1],
5328 prim->verts[1].xyz[0], prim->verts[1].xyz[1],
5329 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5330 break;
5331 case GL2PS_TEXT :
5332 fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n",
5333 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
5334
5335 if(prim->data.text->angle)
5336 fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle);
5337
5338 fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont",
5339 gl2psPGFTextAlignment(prim->data.text->alignment),
5340 prim->data.text->fontsize);
5341
5342 fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}",
5343 prim->verts[0].rgba[0], prim->verts[0].rgba[1],
5344 prim->verts[0].rgba[2], prim->data.text->str);
5345
5346 fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n");
5347 break;
5348 case GL2PS_SPECIAL :
5349 /* alignment contains the format for which the special output text
5350 is intended */
5351 if (prim->data.text->alignment == GL2PS_PGF)
5352 fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
5353 break;
5354 default :
5355 break;
5356 }
5357 }
5358
5359 static void gl2psPrintPGFFooter(void)
5360 {
5361 fprintf(gl2ps->stream, "\\end{pgfpicture}\n");
5362 }
5363
5364 static void gl2psPrintPGFBeginViewport(GLint viewport[4])
5365 {
5366 GLint index;
5367 GLfloat rgba[4];
5368 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
5369
5370 glRenderMode(GL_FEEDBACK);
5371
5372 if(gl2ps->header){
5373 gl2psPrintPGFHeader();
5374 gl2ps->header = GL_FALSE;
5375 }
5376
5377 fprintf(gl2ps->stream, "\\begin{pgfscope}\n");
5378 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
5379 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
5380 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
5381 }
5382 else{
5383 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5384 rgba[0] = gl2ps->colormap[index][0];
5385 rgba[1] = gl2ps->colormap[index][1];
5386 rgba[2] = gl2ps->colormap[index][2];
5387 rgba[3] = 1.0F;
5388 }
5389 gl2psPrintPGFColor(rgba);
5390 fprintf(gl2ps->stream,
5391 "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
5392 "{\\pgfpoint{%dpt}{%dpt}}\n"
5393 "\\pgfusepath{fill}\n",
5394 x, y, w, h);
5395 }
5396
5397 fprintf(gl2ps->stream,
5398 "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}"
5399 "{\\pgfpoint{%dpt}{%dpt}}\n"
5400 "\\pgfusepath{clip}\n",
5401 x, y, w, h);
5402 }
5403
5404 static GLint gl2psPrintPGFEndViewport(void)
5405 {
5406 GLint res;
5407 res = gl2psPrintPrimitives();
5408 fprintf(gl2ps->stream, "\\end{pgfscope}\n");
5409 return res;
5410 }
5411
5412 static void gl2psPrintPGFFinalPrimitive(void)
5413 {
5414 }
5415
5416 /* definition of the PGF backend */
5417
5418 static GL2PSbackend gl2psPGF = {
5419 gl2psPrintPGFHeader,
5420 gl2psPrintPGFFooter,
5421 gl2psPrintPGFBeginViewport,
5422 gl2psPrintPGFEndViewport,
5423 gl2psPrintPGFPrimitive,
5424 gl2psPrintPGFFinalPrimitive,
5425 "tex",
5426 "PGF Latex Graphics"
5427 };
5428
5429 /*********************************************************************
5430 *
5431 * General primitive printing routine
5432 *
5433 *********************************************************************/
5434
5435 /* Warning: the ordering of the backends must match the format
5436 #defines in gl2ps.h */
5437
5438 static GL2PSbackend *gl2psbackends[] = {
5439 &gl2psPS, /* 0 */
5440 &gl2psEPS, /* 1 */
5441 &gl2psTEX, /* 2 */
5442 &gl2psPDF, /* 3 */
5443 &gl2psSVG, /* 4 */
5444 &gl2psPGF /* 5 */
5445 };
5446
5447 static void gl2psComputeTightBoundingBox(void *data)
5448 {
5449 GL2PSprimitive *prim;
5450 int i;
5451
5452 prim = *(GL2PSprimitive**)data;
5453
5454 for(i = 0; i < prim->numverts; i++){
5455 if(prim->verts[i].xyz[0] < gl2ps->viewport[0])
5456 gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0];
5457 if(prim->verts[i].xyz[0] > gl2ps->viewport[2])
5458 gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F);
5459 if(prim->verts[i].xyz[1] < gl2ps->viewport[1])
5460 gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1];
5461 if(prim->verts[i].xyz[1] > gl2ps->viewport[3])
5462 gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F);
5463 }
5464 }
5465
5466 static GLint gl2psPrintPrimitives(void)
5467 {
5468 GL2PSbsptree *root;
5469 GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE};
5470 GLint used;
5471
5472 used = glRenderMode(GL_RENDER);
5473
5474 if(used < 0){
5475 gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow");
5476 return GL2PS_OVERFLOW;
5477 }
5478
5479 if(used > 0)
5480 gl2psParseFeedbackBuffer(used);
5481
5482 gl2psRescaleAndOffset();
5483
5484 if(gl2ps->header){
5485 if(gl2psListNbr(gl2ps->primitives) &&
5486 (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){
5487 gl2ps->viewport[0] = gl2ps->viewport[1] = 100000;
5488 gl2ps->viewport[2] = gl2ps->viewport[3] = -100000;
5489 gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox);
5490 }
5491 (gl2psbackends[gl2ps->format]->printHeader)();
5492 gl2ps->header = GL_FALSE;
5493 }
5494
5495 if(!gl2psListNbr(gl2ps->primitives)){
5496 /* empty feedback buffer and/or nothing else to print */
5497 return GL2PS_NO_FEEDBACK;
5498 }
5499
5500 switch(gl2ps->sort){
5501 case GL2PS_NO_SORT :
5502 gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
5503 gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
5504 /* reset the primitive list, waiting for the next viewport */
5505 gl2psListReset(gl2ps->primitives);
5506 break;
5507 case GL2PS_SIMPLE_SORT :
5508 gl2psListSort(gl2ps->primitives, gl2psCompareDepth);
5509 if(gl2ps->options & GL2PS_OCCLUSION_CULL){
5510 gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree);
5511 gl2psFreeBspImageTree(&gl2ps->imagetree);
5512 }
5513 gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive);
5514 gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
5515 /* reset the primitive list, waiting for the next viewport */
5516 gl2psListReset(gl2ps->primitives);
5517 break;
5518 case GL2PS_BSP_SORT :
5519 root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
5520 gl2psBuildBspTree(root, gl2ps->primitives);
5521 if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root);
5522 if(gl2ps->options & GL2PS_OCCLUSION_CULL){
5523 gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess,
5524 gl2psAddInImageTree, 1);
5525 gl2psFreeBspImageTree(&gl2ps->imagetree);
5526 }
5527 gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater,
5528 gl2psbackends[gl2ps->format]->printPrimitive, 0);
5529 gl2psFreeBspTree(&root);
5530 /* reallocate the primitive list (it's been deleted by
5531 gl2psBuildBspTree) in case there is another viewport */
5532 gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
5533 break;
5534 }
5535 gl2psbackends[gl2ps->format]->printFinalPrimitive();
5536
5537 return GL2PS_SUCCESS;
5538 }
5539
5540 /*********************************************************************
5541 *
5542 * Public routines
5543 *
5544 *********************************************************************/
5545
5546 GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
5547 GLint viewport[4], GLint format, GLint sort,
5548 GLint options, GLint colormode,
5549 GLint colorsize, GL2PSrgba *colormap,
5550 GLint nr, GLint ng, GLint nb, GLint buffersize,
5551 FILE *stream, const char *filename)
5552 {
5553 GLint index;
5554 int i;
5555
5556 if(gl2ps){
5557 gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state");
5558 return GL2PS_ERROR;
5559 }
5560
5561 gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext));
5562
5563 if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))){
5564 gl2ps->format = format;
5565 }
5566 else {
5567 gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format);
5568 gl2psFree(gl2ps);
5569 gl2ps = NULL;
5570 return GL2PS_ERROR;
5571 }
5572
5573 switch(sort){
5574 case GL2PS_NO_SORT :
5575 case GL2PS_SIMPLE_SORT :
5576 case GL2PS_BSP_SORT :
5577 gl2ps->sort = sort;
5578 break;
5579 default :
5580 gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort);
5581 gl2psFree(gl2ps);
5582 gl2ps = NULL;
5583 return GL2PS_ERROR;
5584 }
5585
5586 if(stream){
5587 gl2ps->stream = stream;
5588 }
5589 else{
5590 gl2psMsg(GL2PS_ERROR, "Bad file pointer");
5591 gl2psFree(gl2ps);
5592 gl2ps = NULL;
5593 return GL2PS_ERROR;
5594 }
5595
5596 gl2ps->header = GL_TRUE;
5597 gl2ps->maxbestroot = 10;
5598 gl2ps->options = options;
5599 gl2ps->compress = NULL;
5600 gl2ps->imagemap_head = NULL;
5601 gl2ps->imagemap_tail = NULL;
5602
5603 if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){
5604 glGetIntegerv(GL_VIEWPORT, gl2ps->viewport);
5605 }
5606 else{
5607 for(i = 0; i < 4; i++){
5608 gl2ps->viewport[i] = viewport[i];
5609 }
5610 }
5611
5612 if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){
5613 gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)",
5614 gl2ps->viewport[0], gl2ps->viewport[1],
5615 gl2ps->viewport[2], gl2ps->viewport[3]);
5616 gl2psFree(gl2ps);
5617 gl2ps = NULL;
5618 return GL2PS_ERROR;
5619 }
5620
5621 gl2ps->threshold[0] = nr ? 1.0F / (GLfloat)nr : 0.064F;
5622 gl2ps->threshold[1] = ng ? 1.0F / (GLfloat)ng : 0.034F;
5623 gl2ps->threshold[2] = nb ? 1.0F / (GLfloat)nb : 0.100F;
5624 gl2ps->colormode = colormode;
5625 gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048;
5626 for(i = 0; i < 3; i++){
5627 gl2ps->lastvertex.xyz[i] = -1.0F;
5628 }
5629 for(i = 0; i < 4; i++){
5630 gl2ps->lastvertex.rgba[i] = -1.0F;
5631 gl2ps->lastrgba[i] = -1.0F;
5632 }
5633 gl2ps->lastlinewidth = -1.0F;
5634 gl2ps->lastpattern = 0;
5635 gl2ps->lastfactor = 0;
5636 gl2ps->imagetree = NULL;
5637 gl2ps->primitivetoadd = NULL;
5638 gl2ps->zerosurfacearea = GL_FALSE;
5639 gl2ps->pdfprimlist = NULL;
5640 gl2ps->pdfgrouplist = NULL;
5641 gl2ps->xreflist = NULL;
5642
5643 /* get default blending mode from current OpenGL state (enabled by
5644 default for SVG) */
5645 gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND);
5646 glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]);
5647 glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]);
5648
5649 if(gl2ps->colormode == GL_RGBA){
5650 gl2ps->colorsize = 0;
5651 gl2ps->colormap = NULL;
5652 glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor);
5653 }
5654 else if(gl2ps->colormode == GL_COLOR_INDEX){
5655 if(!colorsize || !colormap){
5656 gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering");
5657 gl2psFree(gl2ps);
5658 gl2ps = NULL;
5659 return GL2PS_ERROR;
5660 }
5661 gl2ps->colorsize = colorsize;
5662 gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba));
5663 memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba));
5664 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
5665 gl2ps->bgcolor[0] = gl2ps->colormap[index][0];
5666 gl2ps->bgcolor[1] = gl2ps->colormap[index][1];
5667 gl2ps->bgcolor[2] = gl2ps->colormap[index][2];
5668 gl2ps->bgcolor[3] = 1.0F;
5669 }
5670 else{
5671 gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage");
5672 gl2psFree(gl2ps);
5673 gl2ps = NULL;
5674 return GL2PS_ERROR;
5675 }
5676
5677 if(!title){
5678 gl2ps->title = (char*)gl2psMalloc(sizeof(char));
5679 gl2ps->title[0] = '\0';
5680 }
5681 else{
5682 gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char));
5683 strcpy(gl2ps->title, title);
5684 }
5685
5686 if(!producer){
5687 gl2ps->producer = (char*)gl2psMalloc(sizeof(char));
5688 gl2ps->producer[0] = '\0';
5689 }
5690 else{
5691 gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char));
5692 strcpy(gl2ps->producer, producer);
5693 }
5694
5695 if(!filename){
5696 gl2ps->filename = (char*)gl2psMalloc(sizeof(char));
5697 gl2ps->filename[0] = '\0';
5698 }
5699 else{
5700 gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char));
5701 strcpy(gl2ps->filename, filename);
5702 }
5703
5704 gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
5705 gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*));
5706 gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat));
5707 glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback);
5708 glRenderMode(GL_FEEDBACK);
5709
5710 return GL2PS_SUCCESS;
5711 }
5712
5713 GL2PSDLL_API GLint gl2psEndPage(void)
5714 {
5715 GLint res;
5716
5717 if(!gl2ps) return GL2PS_UNINITIALIZED;
5718
5719 res = gl2psPrintPrimitives();
5720
5721 if(res != GL2PS_OVERFLOW)
5722 (gl2psbackends[gl2ps->format]->printFooter)();
5723
5724 fflush(gl2ps->stream);
5725
5726 gl2psListDelete(gl2ps->primitives);
5727 gl2psListDelete(gl2ps->auxprimitives);
5728 gl2psFreeImagemap(gl2ps->imagemap_head);
5729 gl2psFree(gl2ps->colormap);
5730 gl2psFree(gl2ps->title);
5731 gl2psFree(gl2ps->producer);
5732 gl2psFree(gl2ps->filename);
5733 gl2psFree(gl2ps->feedback);
5734 gl2psFree(gl2ps);
5735 gl2ps = NULL;
5736
5737 return res;
5738 }
5739
5740 GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4])
5741 {
5742 if(!gl2ps) return GL2PS_UNINITIALIZED;
5743
5744 (gl2psbackends[gl2ps->format]->beginViewport)(viewport);
5745
5746 return GL2PS_SUCCESS;
5747 }
5748
5749 GL2PSDLL_API GLint gl2psEndViewport(void)
5750 {
5751 GLint res;
5752
5753 if(!gl2ps) return GL2PS_UNINITIALIZED;
5754
5755 res = (gl2psbackends[gl2ps->format]->endViewport)();
5756
5757 /* reset last used colors, line widths */
5758 gl2ps->lastlinewidth = -1.0F;
5759
5760 return res;
5761 }
5762
5763 GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname,
5764 GLshort fontsize, GLint alignment, GLfloat angle)
5765 {
5766 return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle);
5767 }
5768
5769 GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize)
5770 {
5771 return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F);
5772 }
5773
5774 GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str)
5775 {
5776 return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F);
5777 }
5778
5779 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
5780 GLint xorig, GLint yorig,
5781 GLenum format, GLenum type,
5782 const void *pixels)
5783 {
5784 int size, i;
5785 GLfloat pos[4], *piv;
5786 GL2PSprimitive *prim;
5787 GLboolean valid;
5788
5789 if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED;
5790
5791 if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
5792
5793 if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS;
5794
5795 if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){
5796 gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for "
5797 "GL_RGB/GL_RGBA, GL_FLOAT pixels");
5798 return GL2PS_ERROR;
5799 }
5800
5801 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
5802 if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
5803
5804 glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
5805
5806 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
5807 prim->type = GL2PS_PIXMAP;
5808 prim->boundary = 0;
5809 prim->numverts = 1;
5810 prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
5811 prim->verts[0].xyz[0] = pos[0] + xorig;
5812 prim->verts[0].xyz[1] = pos[1] + yorig;
5813 prim->verts[0].xyz[2] = pos[2];
5814 prim->culled = 0;
5815 prim->offset = 0;
5816 prim->pattern = 0;
5817 prim->factor = 0;
5818 prim->width = 1;
5819 glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
5820 prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
5821 prim->data.image->width = width;
5822 prim->data.image->height = height;
5823 prim->data.image->format = format;
5824 prim->data.image->type = type;
5825
5826 switch(format){
5827 case GL_RGBA:
5828 if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
5829 /* special case: blending turned off */
5830 prim->data.image->format = GL_RGB;
5831 size = height * width * 3;
5832 prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5833 piv = (GLfloat*)pixels;
5834 for(i = 0; i < size; ++i, ++piv){
5835 prim->data.image->pixels[i] = *piv;
5836 if(!((i+1)%3))
5837 ++piv;
5838 }
5839 }
5840 else{
5841 size = height * width * 4;
5842 prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5843 memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
5844 }
5845 break;
5846 case GL_RGB:
5847 default:
5848 size = height * width * 3;
5849 prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat));
5850 memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat));
5851 break;
5852 }
5853
5854 gl2psListAdd(gl2ps->auxprimitives, &prim);
5855 glPassThrough(GL2PS_DRAW_PIXELS_TOKEN);
5856
5857 return GL2PS_SUCCESS;
5858 }
5859
5860 GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height,
5861 const GLfloat position[3],
5862 const unsigned char *imagemap){
5863 int size, i;
5864 int sizeoffloat = sizeof(GLfloat);
5865
5866 if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED;
5867
5868 if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
5869
5870 size = height + height * ((width - 1) / 8);
5871 glPassThrough(GL2PS_IMAGEMAP_TOKEN);
5872 glBegin(GL_POINTS);
5873 glVertex3f(position[0], position[1],position[2]);
5874 glEnd();
5875 glPassThrough((GLfloat)width);
5876 glPassThrough((GLfloat)height);
5877 for(i = 0; i < size; i += sizeoffloat){
5878 float *value = (float*)imagemap;
5879 glPassThrough(*value);
5880 imagemap += sizeoffloat;
5881 }
5882 return GL2PS_SUCCESS;
5883 }
5884
5885 GL2PSDLL_API GLint gl2psEnable(GLint mode)
5886 {
5887 GLint tmp;
5888
5889 if(!gl2ps) return GL2PS_UNINITIALIZED;
5890
5891 switch(mode){
5892 case GL2PS_POLYGON_OFFSET_FILL :
5893 glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN);
5894 glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]);
5895 glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]);
5896 break;
5897 case GL2PS_POLYGON_BOUNDARY :
5898 glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN);
5899 break;
5900 case GL2PS_LINE_STIPPLE :
5901 glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN);
5902 glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp);
5903 glPassThrough((GLfloat)tmp);
5904 glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp);
5905 glPassThrough((GLfloat)tmp);
5906 break;
5907 case GL2PS_BLEND :
5908 glPassThrough(GL2PS_BEGIN_BLEND_TOKEN);
5909 break;
5910 default :
5911 gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode);
5912 return GL2PS_WARNING;
5913 }
5914
5915 return GL2PS_SUCCESS;
5916 }
5917
5918 GL2PSDLL_API GLint gl2psDisable(GLint mode)
5919 {
5920 if(!gl2ps) return GL2PS_UNINITIALIZED;
5921
5922 switch(mode){
5923 case GL2PS_POLYGON_OFFSET_FILL :
5924 glPassThrough(GL2PS_END_OFFSET_TOKEN);
5925 break;
5926 case GL2PS_POLYGON_BOUNDARY :
5927 glPassThrough(GL2PS_END_BOUNDARY_TOKEN);
5928 break;
5929 case GL2PS_LINE_STIPPLE :
5930 glPassThrough(GL2PS_END_STIPPLE_TOKEN);
5931 break;
5932 case GL2PS_BLEND :
5933 glPassThrough(GL2PS_END_BLEND_TOKEN);
5934 break;
5935 default :
5936 gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode);
5937 return GL2PS_WARNING;
5938 }
5939
5940 return GL2PS_SUCCESS;
5941 }
5942
5943 GL2PSDLL_API GLint gl2psPointSize(GLfloat value)
5944 {
5945 if(!gl2ps) return GL2PS_UNINITIALIZED;
5946
5947 glPassThrough(GL2PS_POINT_SIZE_TOKEN);
5948 glPassThrough(value);
5949
5950 return GL2PS_SUCCESS;
5951 }
5952
5953 GL2PSDLL_API GLint gl2psLineWidth(GLfloat value)
5954 {
5955 if(!gl2ps) return GL2PS_UNINITIALIZED;
5956
5957 glPassThrough(GL2PS_LINE_WIDTH_TOKEN);
5958 glPassThrough(value);
5959
5960 return GL2PS_SUCCESS;
5961 }
5962
5963 GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor)
5964 {
5965 if(!gl2ps) return GL2PS_UNINITIALIZED;
5966
5967 if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor))
5968 return GL2PS_WARNING;
5969
5970 glPassThrough(GL2PS_SRC_BLEND_TOKEN);
5971 glPassThrough((GLfloat)sfactor);
5972 glPassThrough(GL2PS_DST_BLEND_TOKEN);
5973 glPassThrough((GLfloat)dfactor);
5974
5975 return GL2PS_SUCCESS;
5976 }
5977
5978 GL2PSDLL_API GLint gl2psSetOptions(GLint options)
5979 {
5980 if(!gl2ps) return GL2PS_UNINITIALIZED;
5981
5982 gl2ps->options = options;
5983
5984 return GL2PS_SUCCESS;
5985 }
5986
5987 GL2PSDLL_API GLint gl2psGetOptions(GLint *options)
5988 {
5989 if(!gl2ps) {
5990 *options = 0;
5991 return GL2PS_UNINITIALIZED;
5992 }
5993
5994 *options = gl2ps->options;
5995
5996 return GL2PS_SUCCESS;
5997 }
5998
5999 GL2PSDLL_API const char *gl2psGetFileExtension(GLint format)
6000 {
6001 if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0])))
6002 return gl2psbackends[format]->file_extension;
6003 else
6004 return "Unknown format";
6005 }
6006
6007 GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format)
6008 {
6009 if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0])))
6010 return gl2psbackends[format]->description;
6011 else
6012 return "Unknown format";
6013 }