"Fossies" - the Fresh Open Source Software Archive 
Member "gfsview-snapshot-121130/gl2ps/gl2ps.c" (30 Nov 2012, 183658 Bytes) of package /linux/privat/gfsview-snapshot-121130.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "gl2ps.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * GL2PS, an OpenGL to PostScript Printing Library
3 * Copyright (C) 1999-2011 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 zoom_x, zoom_y;
171 GLfloat *pixels;
172 } GL2PSimage;
173
174 typedef struct _GL2PSimagemap GL2PSimagemap;
175
176 struct _GL2PSimagemap {
177 GL2PSimage *image;
178 GL2PSimagemap *next;
179 };
180
181 typedef struct {
182 GLshort type, numverts;
183 GLushort pattern;
184 char boundary, offset, culled;
185 GLint factor;
186 GLfloat width;
187 GL2PSvertex *verts;
188 union {
189 GL2PSstring *text;
190 GL2PSimage *image;
191 } data;
192 } GL2PSprimitive;
193
194 typedef struct {
195 #if defined(GL2PS_HAVE_ZLIB)
196 Bytef *dest, *src, *start;
197 uLongf destLen, srcLen;
198 #else
199 int dummy;
200 #endif
201 } GL2PScompress;
202
203 typedef struct{
204 GL2PSlist* ptrlist;
205 int gsno, fontno, imno, shno, maskshno, trgroupno;
206 int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno;
207 } GL2PSpdfgroup;
208
209 typedef struct {
210 /* General */
211 GLint format, sort, options, colorsize, colormode, buffersize;
212 char *title, *producer, *filename;
213 GLboolean boundary, blending;
214 GLfloat *feedback, offset[2], lastlinewidth;
215 GLint viewport[4], blendfunc[2], lastfactor;
216 GL2PSrgba *colormap, lastrgba, threshold, bgcolor;
217 GLushort lastpattern;
218 GL2PSvertex lastvertex;
219 GL2PSlist *primitives, *auxprimitives;
220 FILE *stream;
221 GL2PScompress *compress;
222 GLboolean header;
223
224 /* BSP-specific */
225 GLint maxbestroot;
226
227 /* Occlusion culling-specific */
228 GLboolean zerosurfacearea;
229 GL2PSbsptree2d *imagetree;
230 GL2PSprimitive *primitivetoadd;
231
232 /* PDF-specific */
233 int streamlength;
234 GL2PSlist *pdfprimlist, *pdfgrouplist;
235 int *xreflist;
236 int objects_stack; /* available objects */
237 int extgs_stack; /* graphics state object number */
238 int font_stack; /* font object number */
239 int im_stack; /* image object number */
240 int trgroupobjects_stack; /* xobject numbers */
241 int shader_stack; /* shader object numbers */
242 int mshader_stack; /* mask shader object numbers */
243
244 /* for image map list */
245 GL2PSimagemap *imagemap_head;
246 GL2PSimagemap *imagemap_tail;
247 } GL2PScontext;
248
249 typedef struct {
250 void (*printHeader)(void);
251 void (*printFooter)(void);
252 void (*beginViewport)(GLint viewport[4]);
253 GLint (*endViewport)(void);
254 void (*printPrimitive)(void *data);
255 void (*printFinalPrimitive)(void);
256 const char *file_extension;
257 const char *description;
258 } GL2PSbackend;
259
260 /* The gl2ps context. gl2ps is not thread safe (we should create a
261 local GL2PScontext during gl2psBeginPage) */
262
263 static GL2PScontext *gl2ps = NULL;
264
265 /* Need to forward-declare this one */
266
267 static GLint gl2psPrintPrimitives(void);
268
269 /*********************************************************************
270 *
271 * Utility routines
272 *
273 *********************************************************************/
274
275 static void gl2psMsg(GLint level, const char *fmt, ...)
276 {
277 va_list args;
278
279 if(!(gl2ps->options & GL2PS_SILENT)){
280 switch(level){
281 case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break;
282 case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break;
283 case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break;
284 }
285 va_start(args, fmt);
286 vfprintf(stderr, fmt, args);
287 va_end(args);
288 fprintf(stderr, "\n");
289 }
290 /* if(level == GL2PS_ERROR) exit(1); */
291 }
292
293 static void *gl2psMalloc(size_t size)
294 {
295 void *ptr;
296
297 if(!size) return NULL;
298 ptr = malloc(size);
299 if(!ptr){
300 gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory");
301 return NULL;
302 }
303 return ptr;
304 }
305
306 static void *gl2psRealloc(void *ptr, size_t size)
307 {
308 void *orig = ptr;
309 if(!size) return NULL;
310 ptr = realloc(orig, size);
311 if(!ptr){
312 gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory");
313 free(orig);
314 return NULL;
315 }
316 return ptr;
317 }
318
319 static void gl2psFree(void *ptr)
320 {
321 if(!ptr) return;
322 free(ptr);
323 }
324
325 static int gl2psWriteBigEndian(unsigned long data, int bytes)
326 {
327 int i;
328 int size = sizeof(unsigned long);
329 for(i = 1; i <= bytes; ++i){
330 fputc(0xff & (data >> (size - i) * 8), gl2ps->stream);
331 }
332 return bytes;
333 }
334
335 /* zlib compression helper routines */
336
337 #if defined(GL2PS_HAVE_ZLIB)
338
339 static void gl2psSetupCompress(void)
340 {
341 gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress));
342 gl2ps->compress->src = NULL;
343 gl2ps->compress->start = NULL;
344 gl2ps->compress->dest = NULL;
345 gl2ps->compress->srcLen = 0;
346 gl2ps->compress->destLen = 0;
347 }
348
349 static void gl2psFreeCompress(void)
350 {
351 if(!gl2ps->compress)
352 return;
353 gl2psFree(gl2ps->compress->start);
354 gl2psFree(gl2ps->compress->dest);
355 gl2ps->compress->src = NULL;
356 gl2ps->compress->start = NULL;
357 gl2ps->compress->dest = NULL;
358 gl2ps->compress->srcLen = 0;
359 gl2ps->compress->destLen = 0;
360 }
361
362 static int gl2psAllocCompress(unsigned int srcsize)
363 {
364 gl2psFreeCompress();
365
366 if(!gl2ps->compress || !srcsize)
367 return GL2PS_ERROR;
368
369 gl2ps->compress->srcLen = srcsize;
370 gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
371 gl2ps->compress->src = (Bytef*)gl2psMalloc(gl2ps->compress->srcLen);
372 gl2ps->compress->start = gl2ps->compress->src;
373 gl2ps->compress->dest = (Bytef*)gl2psMalloc(gl2ps->compress->destLen);
374
375 return GL2PS_SUCCESS;
376 }
377
378 static void *gl2psReallocCompress(unsigned int srcsize)
379 {
380 if(!gl2ps->compress || !srcsize)
381 return NULL;
382
383 if(srcsize < gl2ps->compress->srcLen)
384 return gl2ps->compress->start;
385
386 gl2ps->compress->srcLen = srcsize;
387 gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
388 gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src,
389 gl2ps->compress->srcLen);
390 gl2ps->compress->start = gl2ps->compress->src;
391 gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest,
392 gl2ps->compress->destLen);
393
394 return gl2ps->compress->start;
395 }
396
397 static int gl2psWriteBigEndianCompress(unsigned long data, int bytes)
398 {
399 int i;
400 int size = sizeof(unsigned long);
401 for(i = 1; i <= bytes; ++i){
402 *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8));
403 ++gl2ps->compress->src;
404 }
405 return bytes;
406 }
407
408 static int gl2psDeflate(void)
409 {
410 /* For compatibility with older zlib versions, we use compress(...)
411 instead of compress2(..., Z_BEST_COMPRESSION) */
412 return compress(gl2ps->compress->dest, &gl2ps->compress->destLen,
413 gl2ps->compress->start, gl2ps->compress->srcLen);
414 }
415
416 #endif
417
418 static int gl2psPrintf(const char* fmt, ...)
419 {
420 int ret;
421 va_list args;
422
423 #if defined(GL2PS_HAVE_ZLIB)
424 unsigned int oldsize = 0;
425 static char buf[1000];
426 if(gl2ps->options & GL2PS_COMPRESS){
427 va_start(args, fmt);
428 ret = vsprintf(buf, fmt, args);
429 va_end(args);
430 oldsize = gl2ps->compress->srcLen;
431 gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret);
432 memcpy(gl2ps->compress->start+oldsize, buf, ret);
433 ret = 0;
434 }
435 else{
436 #endif
437 va_start(args, fmt);
438 ret = vfprintf(gl2ps->stream, fmt, args);
439 va_end(args);
440 #if defined(GL2PS_HAVE_ZLIB)
441 }
442 #endif
443 return ret;
444 }
445
446 static void gl2psPrintGzipHeader(void)
447 {
448 #if defined(GL2PS_HAVE_ZLIB)
449 char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */
450 8, /* compression method: Z_DEFLATED */
451 0, /* flags */
452 0, 0, 0, 0, /* time */
453 2, /* extra flags: max compression */
454 '\x03'}; /* OS code: 0x03 (Unix) */
455
456 if(gl2ps->options & GL2PS_COMPRESS){
457 gl2psSetupCompress();
458 /* add the gzip file header */
459 fwrite(tmp, 10, 1, gl2ps->stream);
460 }
461 #endif
462 }
463
464 static void gl2psPrintGzipFooter(void)
465 {
466 #if defined(GL2PS_HAVE_ZLIB)
467 int n;
468 uLong crc, len;
469 char tmp[8];
470
471 if(gl2ps->options & GL2PS_COMPRESS){
472 if(Z_OK != gl2psDeflate()){
473 gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
474 }
475 else{
476 /* determine the length of the header in the zlib stream */
477 n = 2; /* CMF+FLG */
478 if(gl2ps->compress->dest[1] & (1<<5)){
479 n += 4; /* DICTID */
480 }
481 /* write the data, without the zlib header and footer */
482 fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4),
483 1, gl2ps->stream);
484 /* add the gzip file footer */
485 crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen);
486 for(n = 0; n < 4; ++n){
487 tmp[n] = (char)(crc & 0xff);
488 crc >>= 8;
489 }
490 len = gl2ps->compress->srcLen;
491 for(n = 4; n < 8; ++n){
492 tmp[n] = (char)(len & 0xff);
493 len >>= 8;
494 }
495 fwrite(tmp, 8, 1, gl2ps->stream);
496 }
497 gl2psFreeCompress();
498 gl2psFree(gl2ps->compress);
499 gl2ps->compress = NULL;
500 }
501 #endif
502 }
503
504 /* The list handling routines */
505
506 static void gl2psListRealloc(GL2PSlist *list, GLint n)
507 {
508 if(!list){
509 gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list");
510 return;
511 }
512 if(n <= 0) return;
513 if(!list->array){
514 list->nmax = n;
515 list->array = (char*)gl2psMalloc(list->nmax * list->size);
516 }
517 else{
518 if(n > list->nmax){
519 list->nmax = ((n - 1) / list->incr + 1) * list->incr;
520 list->array = (char*)gl2psRealloc(list->array,
521 list->nmax * list->size);
522 }
523 }
524 }
525
526 static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size)
527 {
528 GL2PSlist *list;
529
530 if(n < 0) n = 0;
531 if(incr <= 0) incr = 1;
532 list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist));
533 list->nmax = 0;
534 list->incr = incr;
535 list->size = size;
536 list->n = 0;
537 list->array = NULL;
538 gl2psListRealloc(list, n);
539 return list;
540 }
541
542 static void gl2psListReset(GL2PSlist *list)
543 {
544 if(!list) return;
545 list->n = 0;
546 }
547
548 static void gl2psListDelete(GL2PSlist *list)
549 {
550 if(!list) return;
551 gl2psFree(list->array);
552 gl2psFree(list);
553 }
554
555 static void gl2psListAdd(GL2PSlist *list, void *data)
556 {
557 if(!list){
558 gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list");
559 return;
560 }
561 list->n++;
562 gl2psListRealloc(list, list->n);
563 memcpy(&list->array[(list->n - 1) * list->size], data, list->size);
564 }
565
566 static int gl2psListNbr(GL2PSlist *list)
567 {
568 if(!list)
569 return 0;
570 return list->n;
571 }
572
573 static void *gl2psListPointer(GL2PSlist *list, GLint index)
574 {
575 if(!list){
576 gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list");
577 return NULL;
578 }
579 if((index < 0) || (index >= list->n)){
580 gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer");
581 return NULL;
582 }
583 return &list->array[index * list->size];
584 }
585
586 static void gl2psListSort(GL2PSlist *list,
587 int (*fcmp)(const void *a, const void *b))
588 {
589 if(!list)
590 return;
591 qsort(list->array, list->n, list->size, fcmp);
592 }
593
594 static void gl2psListAction(GL2PSlist *list, void (*action)(void *data))
595 {
596 GLint i;
597
598 for(i = 0; i < gl2psListNbr(list); i++){
599 (*action)(gl2psListPointer(list, i));
600 }
601 }
602
603 static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data))
604 {
605 GLint i;
606
607 for(i = gl2psListNbr(list); i > 0; i--){
608 (*action)(gl2psListPointer(list, i-1));
609 }
610 }
611
612 #if defined(GL2PS_HAVE_LIBPNG)
613
614 static void gl2psListRead(GL2PSlist *list, int index, void *data)
615 {
616 if((index < 0) || (index >= list->n))
617 gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead");
618 memcpy(data, &list->array[index * list->size], list->size);
619 }
620
621 static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len)
622 {
623 static const char cb64[] =
624 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
625
626 out[0] = cb64[ in[0] >> 2 ];
627 out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
628 out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=';
629 out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '=';
630 }
631
632 static void gl2psListEncodeBase64(GL2PSlist *list)
633 {
634 unsigned char *buffer, in[3], out[4];
635 int i, n, index, len;
636
637 n = list->n * list->size;
638 buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned char));
639 memcpy(buffer, list->array, n * sizeof(unsigned char));
640 gl2psListReset(list);
641
642 index = 0;
643 while(index < n) {
644 len = 0;
645 for(i = 0; i < 3; i++) {
646 if(index < n){
647 in[i] = buffer[index];
648 len++;
649 }
650 else{
651 in[i] = 0;
652 }
653 index++;
654 }
655 if(len) {
656 gl2psEncodeBase64Block(in, out, len);
657 for(i = 0; i < 4; i++)
658 gl2psListAdd(list, &out[i]);
659 }
660 }
661 gl2psFree(buffer);
662 }
663
664 #endif
665
666 /* Helpers for rgba colors */
667
668 static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2)
669 {
670 if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) ||
671 !GL2PS_ZERO(rgba1[1] - rgba2[1]) ||
672 !GL2PS_ZERO(rgba1[2] - rgba2[2]))
673 return GL_FALSE;
674 return GL_TRUE;
675 }
676
677 static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim)
678 {
679 int i;
680
681 for(i = 1; i < prim->numverts; i++){
682 if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){
683 return GL_FALSE;
684 }
685 }
686 return GL_TRUE;
687 }
688
689 static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[],
690 GL2PSrgba threshold)
691 {
692 int i;
693
694 if(n < 2) return GL_TRUE;
695
696 for(i = 1; i < n; i++){
697 if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] ||
698 fabs(rgba[0][1] - rgba[i][1]) > threshold[1] ||
699 fabs(rgba[0][2] - rgba[i][2]) > threshold[2])
700 return GL_FALSE;
701 }
702
703 return GL_TRUE;
704 }
705
706 static void gl2psSetLastColor(GL2PSrgba rgba)
707 {
708 int i;
709 for(i = 0; i < 3; ++i){
710 gl2ps->lastrgba[i] = rgba[i];
711 }
712 }
713
714 static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y,
715 GLfloat *red, GLfloat *green, GLfloat *blue)
716 {
717
718 GLsizei width = im->width;
719 GLsizei height = im->height;
720 GLfloat *pixels = im->pixels;
721 GLfloat *pimag;
722
723 /* OpenGL image is from down to up, PS image is up to down */
724 switch(im->format){
725 case GL_RGBA:
726 pimag = pixels + 4 * (width * (height - 1 - y) + x);
727 break;
728 case GL_RGB:
729 default:
730 pimag = pixels + 3 * (width * (height - 1 - y) + x);
731 break;
732 }
733 *red = *pimag; pimag++;
734 *green = *pimag; pimag++;
735 *blue = *pimag; pimag++;
736
737 return (im->format == GL_RGBA) ? *pimag : 1.0F;
738 }
739
740 /* Helper routines for pixmaps */
741
742 static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im)
743 {
744 int size;
745 GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
746
747 image->width = im->width;
748 image->height = im->height;
749 image->format = im->format;
750 image->type = im->type;
751 image->zoom_x = im->zoom_x;
752 image->zoom_y = im->zoom_y;
753
754 switch(image->format){
755 case GL_RGBA:
756 size = image->height * image->width * 4 * sizeof(GLfloat);
757 break;
758 case GL_RGB:
759 default:
760 size = image->height * image->width * 3 * sizeof(GLfloat);
761 break;
762 }
763
764 image->pixels = (GLfloat*)gl2psMalloc(size);
765 memcpy(image->pixels, im->pixels, size);
766
767 return image;
768 }
769
770 static void gl2psFreePixmap(GL2PSimage *im)
771 {
772 if(!im)
773 return;
774 gl2psFree(im->pixels);
775 gl2psFree(im);
776 }
777
778 #if defined(GL2PS_HAVE_LIBPNG)
779
780 #if !defined(png_jmpbuf)
781 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
782 #endif
783
784 static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length)
785 {
786 unsigned int i;
787 GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr);
788 for(i = 0; i < length; i++)
789 gl2psListAdd(png, &data[i]);
790 }
791
792 static void gl2psUserFlushPNG(png_structp png_ptr)
793 {
794 (void) png_ptr; /* not used */
795 }
796
797 static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png)
798 {
799 png_structp png_ptr;
800 png_infop info_ptr;
801 unsigned char *row_data;
802 GLfloat dr, dg, db;
803 int row, col;
804
805 if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
806 return;
807
808 if(!(info_ptr = png_create_info_struct(png_ptr))){
809 png_destroy_write_struct(&png_ptr, NULL);
810 return;
811 }
812
813 if(setjmp(png_jmpbuf(png_ptr))) {
814 png_destroy_write_struct(&png_ptr, &info_ptr);
815 return;
816 }
817
818 png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG);
819 png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
820 png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8,
821 PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
822 PNG_FILTER_TYPE_BASE);
823 png_write_info(png_ptr, info_ptr);
824
825 row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char));
826 for(row = 0; row < pixmap->height; row++){
827 for(col = 0; col < pixmap->width; col++){
828 gl2psGetRGB(pixmap, col, row, &dr, &dg, &db);
829 row_data[3*col] = (unsigned char)(255. * dr);
830 row_data[3*col+1] = (unsigned char)(255. * dg);
831 row_data[3*col+2] = (unsigned char)(255. * db);
832 }
833 png_write_row(png_ptr, (png_bytep)row_data);
834 }
835 gl2psFree(row_data);
836
837 png_write_end(png_ptr, info_ptr);
838 png_destroy_write_struct(&png_ptr, &info_ptr);
839 }
840
841 #endif
842
843 /* Helper routines for text strings */
844
845 static GLint gl2psAddText(GLint type, const char *str, const char *fontname,
846 GLshort fontsize, GLint alignment, GLfloat angle)
847 {
848 GLfloat pos[4];
849 GL2PSprimitive *prim;
850 GLboolean valid;
851
852 if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED;
853
854 if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS;
855
856 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
857 if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */
858
859 glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
860
861 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
862 prim->type = type;
863 prim->boundary = 0;
864 prim->numverts = 1;
865 prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex));
866 prim->verts[0].xyz[0] = pos[0];
867 prim->verts[0].xyz[1] = pos[1];
868 prim->verts[0].xyz[2] = pos[2];
869 prim->culled = 0;
870 prim->offset = 0;
871 prim->pattern = 0;
872 prim->factor = 0;
873 prim->width = 1;
874 glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
875 prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
876 prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char));
877 strcpy(prim->data.text->str, str);
878 prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char));
879 strcpy(prim->data.text->fontname, fontname);
880 prim->data.text->fontsize = fontsize;
881 prim->data.text->alignment = alignment;
882 prim->data.text->angle = angle;
883
884 gl2psListAdd(gl2ps->auxprimitives, &prim);
885 glPassThrough(GL2PS_TEXT_TOKEN);
886
887 return GL2PS_SUCCESS;
888 }
889
890 static GL2PSstring *gl2psCopyText(GL2PSstring *t)
891 {
892 GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
893 text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char));
894 strcpy(text->str, t->str);
895 text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char));
896 strcpy(text->fontname, t->fontname);
897 text->fontsize = t->fontsize;
898 text->alignment = t->alignment;
899 text->angle = t->angle;
900
901 return text;
902 }
903
904 static void gl2psFreeText(GL2PSstring *text)
905 {
906 if(!text)
907 return;
908 gl2psFree(text->str);
909 gl2psFree(text->fontname);
910 gl2psFree(text);
911 }
912
913 /* Helpers for blending modes */
914
915 static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor)
916 {
917 /* returns TRUE if gl2ps supports the argument combination: only two
918 blending modes have been implemented so far */
919
920 if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) ||
921 (sfactor == GL_ONE && dfactor == GL_ZERO) )
922 return GL_TRUE;
923 return GL_FALSE;
924 }
925
926 static void gl2psAdaptVertexForBlending(GL2PSvertex *v)
927 {
928 /* Transforms vertex depending on the actual blending function -
929 currently the vertex v is considered as source vertex and his
930 alpha value is changed to 1.0 if source blending GL_ONE is
931 active. This might be extended in the future */
932
933 if(!v || !gl2ps)
934 return;
935
936 if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){
937 v->rgba[3] = 1.0F;
938 return;
939 }
940
941 switch(gl2ps->blendfunc[0]){
942 case GL_ONE:
943 v->rgba[3] = 1.0F;
944 break;
945 default:
946 break;
947 }
948 }
949
950 static void gl2psAssignTriangleProperties(GL2PStriangle *t)
951 {
952 /* int i; */
953
954 t->prop = T_VAR_COLOR;
955
956 /* Uncommenting the following lines activates an even more fine
957 grained distinction between triangle types - please don't delete,
958 a remarkable amount of PDF handling code inside this file depends
959 on it if activated */
960 /*
961 t->prop = T_CONST_COLOR;
962 for(i = 0; i < 3; ++i){
963 if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) ||
964 !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){
965 t->prop = T_VAR_COLOR;
966 break;
967 }
968 }
969 */
970
971 if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) ||
972 !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){
973 t->prop |= T_VAR_ALPHA;
974 }
975 else{
976 if(t->vertex[0].rgba[3] < 1)
977 t->prop |= T_ALPHA_LESS_1;
978 else
979 t->prop |= T_ALPHA_1;
980 }
981 }
982
983 static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p,
984 GLboolean assignprops)
985 {
986 t->vertex[0] = p->verts[0];
987 t->vertex[1] = p->verts[1];
988 t->vertex[2] = p->verts[2];
989 if(GL_TRUE == assignprops)
990 gl2psAssignTriangleProperties(t);
991 }
992
993 static void gl2psInitTriangle(GL2PStriangle *t)
994 {
995 int i;
996 GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} };
997 for(i = 0; i < 3; i++)
998 t->vertex[i] = vertex;
999 t->prop = T_UNDEFINED;
1000 }
1001
1002 /* Miscellaneous helper routines */
1003
1004 static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p)
1005 {
1006 GL2PSprimitive *prim;
1007
1008 if(!p){
1009 gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive");
1010 return NULL;
1011 }
1012
1013 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1014
1015 prim->type = p->type;
1016 prim->numverts = p->numverts;
1017 prim->boundary = p->boundary;
1018 prim->offset = p->offset;
1019 prim->pattern = p->pattern;
1020 prim->factor = p->factor;
1021 prim->culled = p->culled;
1022 prim->width = p->width;
1023 prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex));
1024 memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex));
1025
1026 switch(prim->type){
1027 case GL2PS_PIXMAP :
1028 prim->data.image = gl2psCopyPixmap(p->data.image);
1029 break;
1030 case GL2PS_TEXT :
1031 case GL2PS_SPECIAL :
1032 prim->data.text = gl2psCopyText(p->data.text);
1033 break;
1034 default:
1035 break;
1036 }
1037
1038 return prim;
1039 }
1040
1041 static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2)
1042 {
1043 if(!GL2PS_ZERO(p1[0] - p2[0]) ||
1044 !GL2PS_ZERO(p1[1] - p2[1]) ||
1045 !GL2PS_ZERO(p1[2] - p2[2]))
1046 return GL_FALSE;
1047 return GL_TRUE;
1048 }
1049
1050 /*********************************************************************
1051 *
1052 * 3D sorting routines
1053 *
1054 *********************************************************************/
1055
1056 static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane)
1057 {
1058 return (plane[0] * point[0] +
1059 plane[1] * point[1] +
1060 plane[2] * point[2] +
1061 plane[3]);
1062 }
1063
1064 static GLfloat gl2psPsca(GLfloat *a, GLfloat *b)
1065 {
1066 return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
1067 }
1068
1069 static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c)
1070 {
1071 c[0] = a[1]*b[2] - a[2]*b[1];
1072 c[1] = a[2]*b[0] - a[0]*b[2];
1073 c[2] = a[0]*b[1] - a[1]*b[0];
1074 }
1075
1076 static GLfloat gl2psNorm(GLfloat *a)
1077 {
1078 return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
1079 }
1080
1081 static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c)
1082 {
1083 GLfloat norm;
1084
1085 gl2psPvec(a, b, c);
1086 if(!GL2PS_ZERO(norm = gl2psNorm(c))){
1087 c[0] = c[0] / norm;
1088 c[1] = c[1] / norm;
1089 c[2] = c[2] / norm;
1090 }
1091 else{
1092 /* The plane is still wrong despite our tests in gl2psGetPlane.
1093 Let's return a dummy value for now (this is a hack: we should
1094 do more intelligent tests in GetPlane) */
1095 c[0] = c[1] = 0.0F;
1096 c[2] = 1.0F;
1097 }
1098 }
1099
1100 static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane)
1101 {
1102 GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F};
1103
1104 switch(prim->type){
1105 case GL2PS_TRIANGLE :
1106 case GL2PS_QUADRANGLE :
1107 v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0];
1108 v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1];
1109 v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2];
1110 w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0];
1111 w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1];
1112 w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2];
1113 if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) ||
1114 (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){
1115 plane[0] = plane[1] = 0.0F;
1116 plane[2] = 1.0F;
1117 plane[3] = -prim->verts[0].xyz[2];
1118 }
1119 else{
1120 gl2psGetNormal(v, w, plane);
1121 plane[3] =
1122 - plane[0] * prim->verts[0].xyz[0]
1123 - plane[1] * prim->verts[0].xyz[1]
1124 - plane[2] * prim->verts[0].xyz[2];
1125 }
1126 break;
1127 case GL2PS_LINE :
1128 v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0];
1129 v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1];
1130 v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2];
1131 if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){
1132 plane[0] = plane[1] = 0.0F;
1133 plane[2] = 1.0F;
1134 plane[3] = -prim->verts[0].xyz[2];
1135 }
1136 else{
1137 if(GL2PS_ZERO(v[0])) w[0] = 1.0F;
1138 else if(GL2PS_ZERO(v[1])) w[1] = 1.0F;
1139 else w[2] = 1.0F;
1140 gl2psGetNormal(v, w, plane);
1141 plane[3] =
1142 - plane[0] * prim->verts[0].xyz[0]
1143 - plane[1] * prim->verts[0].xyz[1]
1144 - plane[2] * prim->verts[0].xyz[2];
1145 }
1146 break;
1147 case GL2PS_POINT :
1148 case GL2PS_PIXMAP :
1149 case GL2PS_TEXT :
1150 case GL2PS_SPECIAL :
1151 case GL2PS_IMAGEMAP:
1152 plane[0] = plane[1] = 0.0F;
1153 plane[2] = 1.0F;
1154 plane[3] = -prim->verts[0].xyz[2];
1155 break;
1156 default :
1157 gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree");
1158 plane[0] = plane[1] = plane[3] = 0.0F;
1159 plane[2] = 1.0F;
1160 break;
1161 }
1162 }
1163
1164 static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane,
1165 GL2PSvertex *c)
1166 {
1167 GL2PSxyz v;
1168 GLfloat sect, psca;
1169
1170 v[0] = b->xyz[0] - a->xyz[0];
1171 v[1] = b->xyz[1] - a->xyz[1];
1172 v[2] = b->xyz[2] - a->xyz[2];
1173
1174 if(!GL2PS_ZERO(psca = gl2psPsca(plane, v)))
1175 sect = -gl2psComparePointPlane(a->xyz, plane) / psca;
1176 else
1177 sect = 0.0F;
1178
1179 c->xyz[0] = a->xyz[0] + v[0] * sect;
1180 c->xyz[1] = a->xyz[1] + v[1] * sect;
1181 c->xyz[2] = a->xyz[2] + v[2] * sect;
1182
1183 c->rgba[0] = (1 - sect) * a->rgba[0] + sect * b->rgba[0];
1184 c->rgba[1] = (1 - sect) * a->rgba[1] + sect * b->rgba[1];
1185 c->rgba[2] = (1 - sect) * a->rgba[2] + sect * b->rgba[2];
1186 c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3];
1187 }
1188
1189 static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane,
1190 GL2PSprimitive *child, GLshort numverts,
1191 GLshort *index0, GLshort *index1)
1192 {
1193 GLshort i;
1194
1195 if(parent->type == GL2PS_IMAGEMAP){
1196 child->type = GL2PS_IMAGEMAP;
1197 child->data.image = parent->data.image;
1198 }
1199 else{
1200 if(numverts > 4){
1201 gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts);
1202 numverts = 4;
1203 }
1204 switch(numverts){
1205 case 1 : child->type = GL2PS_POINT; break;
1206 case 2 : child->type = GL2PS_LINE; break;
1207 case 3 : child->type = GL2PS_TRIANGLE; break;
1208 case 4 : child->type = GL2PS_QUADRANGLE; break;
1209 default: child->type = GL2PS_NO_TYPE; break;
1210 }
1211 }
1212
1213 child->boundary = 0; /* FIXME: not done! */
1214 child->culled = parent->culled;
1215 child->offset = parent->offset;
1216 child->pattern = parent->pattern;
1217 child->factor = parent->factor;
1218 child->width = parent->width;
1219 child->numverts = numverts;
1220 child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
1221
1222 for(i = 0; i < numverts; i++){
1223 if(index1[i] < 0){
1224 child->verts[i] = parent->verts[index0[i]];
1225 }
1226 else{
1227 gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]],
1228 plane, &child->verts[i]);
1229 }
1230 }
1231 }
1232
1233 static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb,
1234 GLshort i, GLshort j)
1235 {
1236 GLint k;
1237
1238 for(k = 0; k < *nb; k++){
1239 if((index0[k] == i && index1[k] == j) ||
1240 (index1[k] == i && index0[k] == j)) return;
1241 }
1242 index0[*nb] = i;
1243 index1[*nb] = j;
1244 (*nb)++;
1245 }
1246
1247 static GLshort gl2psGetIndex(GLshort i, GLshort num)
1248 {
1249 return (i < num - 1) ? i + 1 : 0;
1250 }
1251
1252 static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane)
1253 {
1254 GLint type = GL2PS_COINCIDENT;
1255 GLshort i, j;
1256 GLfloat d[5];
1257
1258 for(i = 0; i < prim->numverts; i++){
1259 d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
1260 }
1261
1262 if(prim->numverts < 2){
1263 return 0;
1264 }
1265 else{
1266 for(i = 0; i < prim->numverts; i++){
1267 j = gl2psGetIndex(i, prim->numverts);
1268 if(d[j] > GL2PS_EPSILON){
1269 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF;
1270 else if(type != GL2PS_IN_BACK_OF) return 1;
1271 if(d[i] < -GL2PS_EPSILON) return 1;
1272 }
1273 else if(d[j] < -GL2PS_EPSILON){
1274 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF;
1275 else if(type != GL2PS_IN_FRONT_OF) return 1;
1276 if(d[i] > GL2PS_EPSILON) return 1;
1277 }
1278 }
1279 }
1280 return 0;
1281 }
1282
1283 static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane,
1284 GL2PSprimitive **front, GL2PSprimitive **back)
1285 {
1286 GLshort i, j, in = 0, out = 0, in0[5], in1[5], out0[5], out1[5];
1287 GLint type;
1288 GLfloat d[5];
1289
1290 type = GL2PS_COINCIDENT;
1291
1292 for(i = 0; i < prim->numverts; i++){
1293 d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
1294 }
1295
1296 switch(prim->type){
1297 case GL2PS_POINT :
1298 if(d[0] > GL2PS_EPSILON) type = GL2PS_IN_BACK_OF;
1299 else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF;
1300 else type = GL2PS_COINCIDENT;
1301 break;
1302 default :
1303 for(i = 0; i < prim->numverts; i++){
1304 j = gl2psGetIndex(i, prim->numverts);
1305 if(d[j] > GL2PS_EPSILON){
1306 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF;
1307 else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING;
1308 if(d[i] < -GL2PS_EPSILON){
1309 gl2psAddIndex(in0, in1, &in, i, j);
1310 gl2psAddIndex(out0, out1, &out, i, j);
1311 type = GL2PS_SPANNING;
1312 }
1313 gl2psAddIndex(out0, out1, &out, j, -1);
1314 }
1315 else if(d[j] < -GL2PS_EPSILON){
1316 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF;
1317 else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING;
1318 if(d[i] > GL2PS_EPSILON){
1319 gl2psAddIndex(in0, in1, &in, i, j);
1320 gl2psAddIndex(out0, out1, &out, i, j);
1321 type = GL2PS_SPANNING;
1322 }
1323 gl2psAddIndex(in0, in1, &in, j, -1);
1324 }
1325 else{
1326 gl2psAddIndex(in0, in1, &in, j, -1);
1327 gl2psAddIndex(out0, out1, &out, j, -1);
1328 }
1329 }
1330 break;
1331 }
1332
1333 if(type == GL2PS_SPANNING){
1334 *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1335 *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1336 gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1);
1337 gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1);
1338 }
1339
1340 return type;
1341 }
1342
1343 static void gl2psDivideQuad(GL2PSprimitive *quad,
1344 GL2PSprimitive **t1, GL2PSprimitive **t2)
1345 {
1346 *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1347 *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1348 (*t1)->type = (*t2)->type = GL2PS_TRIANGLE;
1349 (*t1)->numverts = (*t2)->numverts = 3;
1350 (*t1)->culled = (*t2)->culled = quad->culled;
1351 (*t1)->offset = (*t2)->offset = quad->offset;
1352 (*t1)->pattern = (*t2)->pattern = quad->pattern;
1353 (*t1)->factor = (*t2)->factor = quad->factor;
1354 (*t1)->width = (*t2)->width = quad->width;
1355 (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex));
1356 (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex));
1357 (*t1)->verts[0] = quad->verts[0];
1358 (*t1)->verts[1] = quad->verts[1];
1359 (*t1)->verts[2] = quad->verts[2];
1360 (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0);
1361 (*t2)->verts[0] = quad->verts[0];
1362 (*t2)->verts[1] = quad->verts[2];
1363 (*t2)->verts[2] = quad->verts[3];
1364 (*t2)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 8) ? 4 : 0);
1365 }
1366
1367 static int gl2psCompareDepth(const void *a, const void *b)
1368 {
1369 const GL2PSprimitive *q, *w;
1370 GLfloat dq = 0.0F, dw = 0.0F, diff;
1371 int i;
1372
1373 q = *(const GL2PSprimitive* const*)a;
1374 w = *(const GL2PSprimitive* const*)b;
1375
1376 for(i = 0; i < q->numverts; i++){
1377 dq += q->verts[i].xyz[2];
1378 }
1379 dq /= (GLfloat)q->numverts;
1380
1381 for(i = 0; i < w->numverts; i++){
1382 dw += w->verts[i].xyz[2];
1383 }
1384 dw /= (GLfloat)w->numverts;
1385
1386 diff = dq - dw;
1387 if(diff > 0.){
1388 return -1;
1389 }
1390 else if(diff < 0.){
1391 return 1;
1392 }
1393 else{
1394 return 0;
1395 }
1396 }
1397
1398 static int gl2psTrianglesFirst(const void *a, const void *b)
1399 {
1400 const GL2PSprimitive *q, *w;
1401
1402 q = *(const GL2PSprimitive* const*)a;
1403 w = *(const GL2PSprimitive* const*)b;
1404 return (q->type < w->type ? 1 : -1);
1405 }
1406
1407 static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root)
1408 {
1409 GLint i, j, count, best = 1000000, index = 0;
1410 GL2PSprimitive *prim1, *prim2;
1411 GL2PSplane plane;
1412 GLint maxp;
1413
1414 if(!gl2psListNbr(primitives)){
1415 gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list");
1416 return 0;
1417 }
1418
1419 *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0);
1420
1421 if(gl2ps->options & GL2PS_BEST_ROOT){
1422 maxp = gl2psListNbr(primitives);
1423 if(maxp > gl2ps->maxbestroot){
1424 maxp = gl2ps->maxbestroot;
1425 }
1426 for(i = 0; i < maxp; i++){
1427 prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i);
1428 gl2psGetPlane(prim1, plane);
1429 count = 0;
1430 for(j = 0; j < gl2psListNbr(primitives); j++){
1431 if(j != i){
1432 prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j);
1433 count += gl2psTestSplitPrimitive(prim2, plane);
1434 }
1435 if(count > best) break;
1436 }
1437 if(count < best){
1438 best = count;
1439 index = i;
1440 *root = prim1;
1441 if(!count) return index;
1442 }
1443 }
1444 /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */
1445 return index;
1446 }
1447 else{
1448 return 0;
1449 }
1450 }
1451
1452 static void gl2psFreeImagemap(GL2PSimagemap *list)
1453 {
1454 GL2PSimagemap *next;
1455 while(list != NULL){
1456 next = list->next;
1457 gl2psFree(list->image->pixels);
1458 gl2psFree(list->image);
1459 gl2psFree(list);
1460 list = next;
1461 }
1462 }
1463
1464 static void gl2psFreePrimitive(void *data)
1465 {
1466 GL2PSprimitive *q;
1467
1468 q = *(GL2PSprimitive**)data;
1469 gl2psFree(q->verts);
1470 if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){
1471 gl2psFreeText(q->data.text);
1472 }
1473 else if(q->type == GL2PS_PIXMAP){
1474 gl2psFreePixmap(q->data.image);
1475 }
1476 gl2psFree(q);
1477 }
1478
1479 static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list)
1480 {
1481 GL2PSprimitive *t1, *t2;
1482
1483 if(prim->type != GL2PS_QUADRANGLE){
1484 gl2psListAdd(list, &prim);
1485 }
1486 else{
1487 gl2psDivideQuad(prim, &t1, &t2);
1488 gl2psListAdd(list, &t1);
1489 gl2psListAdd(list, &t2);
1490 gl2psFreePrimitive(&prim);
1491 }
1492
1493 }
1494
1495 static void gl2psFreeBspTree(GL2PSbsptree **tree)
1496 {
1497 if(*tree){
1498 if((*tree)->back) gl2psFreeBspTree(&(*tree)->back);
1499 if((*tree)->primitives){
1500 gl2psListAction((*tree)->primitives, gl2psFreePrimitive);
1501 gl2psListDelete((*tree)->primitives);
1502 }
1503 if((*tree)->front) gl2psFreeBspTree(&(*tree)->front);
1504 gl2psFree(*tree);
1505 *tree = NULL;
1506 }
1507 }
1508
1509 static GLboolean gl2psGreater(GLfloat f1, GLfloat f2)
1510 {
1511 if(f1 > f2) return GL_TRUE;
1512 else return GL_FALSE;
1513 }
1514
1515 static GLboolean gl2psLess(GLfloat f1, GLfloat f2)
1516 {
1517 if(f1 < f2) return GL_TRUE;
1518 else return GL_FALSE;
1519 }
1520
1521 static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives)
1522 {
1523 GL2PSprimitive *prim, *frontprim = NULL, *backprim = NULL;
1524 GL2PSlist *frontlist, *backlist;
1525 GLint i, index;
1526
1527 tree->front = NULL;
1528 tree->back = NULL;
1529 tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
1530 index = gl2psFindRoot(primitives, &prim);
1531 gl2psGetPlane(prim, tree->plane);
1532 gl2psAddPrimitiveInList(prim, tree->primitives);
1533
1534 frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
1535 backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
1536
1537 for(i = 0; i < gl2psListNbr(primitives); i++){
1538 if(i != index){
1539 prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i);
1540 switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){
1541 case GL2PS_COINCIDENT:
1542 gl2psAddPrimitiveInList(prim, tree->primitives);
1543 break;
1544 case GL2PS_IN_BACK_OF:
1545 gl2psAddPrimitiveInList(prim, backlist);
1546 break;
1547 case GL2PS_IN_FRONT_OF:
1548 gl2psAddPrimitiveInList(prim, frontlist);
1549 break;
1550 case GL2PS_SPANNING:
1551 gl2psAddPrimitiveInList(backprim, backlist);
1552 gl2psAddPrimitiveInList(frontprim, frontlist);
1553 gl2psFreePrimitive(&prim);
1554 break;
1555 }
1556 }
1557 }
1558
1559 if(gl2psListNbr(tree->primitives)){
1560 gl2psListSort(tree->primitives, gl2psTrianglesFirst);
1561 }
1562
1563 if(gl2psListNbr(frontlist)){
1564 gl2psListSort(frontlist, gl2psTrianglesFirst);
1565 tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
1566 gl2psBuildBspTree(tree->front, frontlist);
1567 }
1568 else{
1569 gl2psListDelete(frontlist);
1570 }
1571
1572 if(gl2psListNbr(backlist)){
1573 gl2psListSort(backlist, gl2psTrianglesFirst);
1574 tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
1575 gl2psBuildBspTree(tree->back, backlist);
1576 }
1577 else{
1578 gl2psListDelete(backlist);
1579 }
1580
1581 gl2psListDelete(primitives);
1582 }
1583
1584 static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon,
1585 GLboolean (*compare)(GLfloat f1, GLfloat f2),
1586 void (*action)(void *data), int inverse)
1587 {
1588 GLfloat result;
1589
1590 if(!tree) return;
1591
1592 result = gl2psComparePointPlane(eye, tree->plane);
1593
1594 if(GL_TRUE == compare(result, epsilon)){
1595 gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
1596 if(inverse){
1597 gl2psListActionInverse(tree->primitives, action);
1598 }
1599 else{
1600 gl2psListAction(tree->primitives, action);
1601 }
1602 gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
1603 }
1604 else if(GL_TRUE == compare(-epsilon, result)){
1605 gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
1606 if(inverse){
1607 gl2psListActionInverse(tree->primitives, action);
1608 }
1609 else{
1610 gl2psListAction(tree->primitives, action);
1611 }
1612 gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
1613 }
1614 else{
1615 gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse);
1616 gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse);
1617 }
1618 }
1619
1620 static void gl2psRescaleAndOffset(void)
1621 {
1622 GL2PSprimitive *prim;
1623 GLfloat minZ, maxZ, rangeZ, scaleZ;
1624 GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ;
1625 int i, j;
1626
1627 if(!gl2psListNbr(gl2ps->primitives))
1628 return;
1629
1630 /* get z-buffer range */
1631 prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, 0);
1632 minZ = maxZ = prim->verts[0].xyz[2];
1633 for(i = 1; i < prim->numverts; i++){
1634 if(prim->verts[i].xyz[2] < minZ) minZ = prim->verts[i].xyz[2];
1635 if(prim->verts[i].xyz[2] > maxZ) maxZ = prim->verts[i].xyz[2];
1636 }
1637 for(i = 1; i < gl2psListNbr(gl2ps->primitives); i++){
1638 prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i);
1639 for(j = 0; j < prim->numverts; j++){
1640 if(prim->verts[j].xyz[2] < minZ) minZ = prim->verts[j].xyz[2];
1641 if(prim->verts[j].xyz[2] > maxZ) maxZ = prim->verts[j].xyz[2];
1642 }
1643 }
1644 rangeZ = (maxZ - minZ);
1645
1646 /* rescale z-buffer coordinate in [0,GL2PS_ZSCALE], to make it of
1647 the same order of magnitude as the x and y coordinates */
1648 scaleZ = GL2PS_ZERO(rangeZ) ? GL2PS_ZSCALE : (GL2PS_ZSCALE / rangeZ);
1649 /* avoid precision loss (we use floats!) */
1650 if(scaleZ > 100000.F) scaleZ = 100000.F;
1651
1652 /* apply offsets */
1653 for(i = 0; i < gl2psListNbr(gl2ps->primitives); i++){
1654 prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i);
1655 for(j = 0; j < prim->numverts; j++){
1656 prim->verts[j].xyz[2] = (prim->verts[j].xyz[2] - minZ) * scaleZ;
1657 }
1658 if((gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET) &&
1659 (prim->type == GL2PS_LINE)){
1660 if(gl2ps->sort == GL2PS_SIMPLE_SORT){
1661 prim->verts[0].xyz[2] -= GL2PS_ZOFFSET_LARGE;
1662 prim->verts[1].xyz[2] -= GL2PS_ZOFFSET_LARGE;
1663 }
1664 else{
1665 prim->verts[0].xyz[2] -= GL2PS_ZOFFSET;
1666 prim->verts[1].xyz[2] -= GL2PS_ZOFFSET;
1667 }
1668 }
1669 else if(prim->offset && (prim->type == GL2PS_TRIANGLE)){
1670 factor = gl2ps->offset[0];
1671 units = gl2ps->offset[1];
1672 area =
1673 (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) *
1674 (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) -
1675 (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) *
1676 (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]);
1677 if(!GL2PS_ZERO(area)){
1678 dZdX =
1679 ((prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) *
1680 (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) -
1681 (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) *
1682 (prim->verts[2].xyz[2] - prim->verts[1].xyz[2])) / area;
1683 dZdY =
1684 ((prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) *
1685 (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) -
1686 (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) *
1687 (prim->verts[1].xyz[2] - prim->verts[0].xyz[2])) / area;
1688 maxdZ = (GLfloat)sqrt(dZdX * dZdX + dZdY * dZdY);
1689 }
1690 else{
1691 maxdZ = 0.0F;
1692 }
1693 dZ = factor * maxdZ + units;
1694 prim->verts[0].xyz[2] += dZ;
1695 prim->verts[1].xyz[2] += dZ;
1696 prim->verts[2].xyz[2] += dZ;
1697 }
1698 }
1699 }
1700
1701 /*********************************************************************
1702 *
1703 * 2D sorting routines (for occlusion culling)
1704 *
1705 *********************************************************************/
1706
1707 static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane)
1708 {
1709 GLfloat n;
1710
1711 plane[0] = b[1] - a[1];
1712 plane[1] = a[0] - b[0];
1713 n = (GLfloat)sqrt(plane[0]*plane[0] + plane[1]*plane[1]);
1714 plane[2] = 0.0F;
1715 if(!GL2PS_ZERO(n)){
1716 plane[0] /= n;
1717 plane[1] /= n;
1718 plane[3] = -plane[0]*a[0]-plane[1]*a[1];
1719 return 1;
1720 }
1721 else{
1722 plane[0] = -1.0F;
1723 plane[1] = 0.0F;
1724 plane[3] = a[0];
1725 return 0;
1726 }
1727 }
1728
1729 static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree)
1730 {
1731 if(*tree){
1732 if((*tree)->back) gl2psFreeBspImageTree(&(*tree)->back);
1733 if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front);
1734 gl2psFree(*tree);
1735 *tree = NULL;
1736 }
1737 }
1738
1739 static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane)
1740 {
1741 GLfloat pt_dis;
1742
1743 pt_dis = gl2psComparePointPlane(point, plane);
1744 if(pt_dis > GL2PS_EPSILON) return GL2PS_POINT_INFRONT;
1745 else if(pt_dis < -GL2PS_EPSILON) return GL2PS_POINT_BACK;
1746 else return GL2PS_POINT_COINCIDENT;
1747 }
1748
1749 static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim,
1750 GL2PSbsptree2d **tree)
1751 {
1752 GLint ret = 0;
1753 GLint i;
1754 GLint offset = 0;
1755 GL2PSbsptree2d *head = NULL, *cur = NULL;
1756
1757 if((*tree == NULL) && (prim->numverts > 2)){
1758 /* don't cull if transparent
1759 for(i = 0; i < prim->numverts - 1; i++)
1760 if(prim->verts[i].rgba[3] < 1.0F) return;
1761 */
1762 head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1763 for(i = 0; i < prim->numverts-1; i++){
1764 if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz,
1765 prim->verts[i+1].xyz,
1766 head->plane)){
1767 if(prim->numverts-i > 3){
1768 offset++;
1769 }
1770 else{
1771 gl2psFree(head);
1772 return;
1773 }
1774 }
1775 else{
1776 break;
1777 }
1778 }
1779 head->back = NULL;
1780 head->front = NULL;
1781 for(i = 2+offset; i < prim->numverts; i++){
1782 ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane);
1783 if(ret != GL2PS_POINT_COINCIDENT) break;
1784 }
1785 switch(ret){
1786 case GL2PS_POINT_INFRONT :
1787 cur = head;
1788 for(i = 1+offset; i < prim->numverts-1; i++){
1789 if(cur->front == NULL){
1790 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1791 }
1792 if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
1793 prim->verts[i+1].xyz,
1794 cur->front->plane)){
1795 cur = cur->front;
1796 cur->front = NULL;
1797 cur->back = NULL;
1798 }
1799 }
1800 if(cur->front == NULL){
1801 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1802 }
1803 if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
1804 prim->verts[offset].xyz,
1805 cur->front->plane)){
1806 cur->front->front = NULL;
1807 cur->front->back = NULL;
1808 }
1809 else{
1810 gl2psFree(cur->front);
1811 cur->front = NULL;
1812 }
1813 break;
1814 case GL2PS_POINT_BACK :
1815 for(i = 0; i < 4; i++){
1816 head->plane[i] = -head->plane[i];
1817 }
1818 cur = head;
1819 for(i = 1+offset; i < prim->numverts-1; i++){
1820 if(cur->front == NULL){
1821 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1822 }
1823 if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz,
1824 prim->verts[i].xyz,
1825 cur->front->plane)){
1826 cur = cur->front;
1827 cur->front = NULL;
1828 cur->back = NULL;
1829 }
1830 }
1831 if(cur->front == NULL){
1832 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
1833 }
1834 if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz,
1835 prim->verts[i].xyz,
1836 cur->front->plane)){
1837 cur->front->front = NULL;
1838 cur->front->back = NULL;
1839 }
1840 else{
1841 gl2psFree(cur->front);
1842 cur->front = NULL;
1843 }
1844 break;
1845 default:
1846 gl2psFree(head);
1847 return;
1848 }
1849 (*tree) = head;
1850 }
1851 }
1852
1853 static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane)
1854 {
1855 GLint i;
1856 GLint pos;
1857
1858 pos = gl2psCheckPoint(prim->verts[0].xyz, plane);
1859 for(i = 1; i < prim->numverts; i++){
1860 pos |= gl2psCheckPoint(prim->verts[i].xyz, plane);
1861 if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING;
1862 }
1863 if(pos & GL2PS_POINT_INFRONT) return GL2PS_IN_FRONT_OF;
1864 else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF;
1865 else return GL2PS_COINCIDENT;
1866 }
1867
1868 static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent,
1869 GLshort numverts,
1870 GL2PSvertex *vertx)
1871 {
1872 GLint i;
1873 GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1874
1875 if(parent->type == GL2PS_IMAGEMAP){
1876 child->type = GL2PS_IMAGEMAP;
1877 child->data.image = parent->data.image;
1878 }
1879 else {
1880 switch(numverts){
1881 case 1 : child->type = GL2PS_POINT; break;
1882 case 2 : child->type = GL2PS_LINE; break;
1883 case 3 : child->type = GL2PS_TRIANGLE; break;
1884 case 4 : child->type = GL2PS_QUADRANGLE; break;
1885 default: child->type = GL2PS_NO_TYPE; break; /* FIXME */
1886 }
1887 }
1888 child->boundary = 0; /* FIXME: not done! */
1889 child->culled = parent->culled;
1890 child->offset = parent->offset;
1891 child->pattern = parent->pattern;
1892 child->factor = parent->factor;
1893 child->width = parent->width;
1894 child->numverts = numverts;
1895 child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
1896 for(i = 0; i < numverts; i++){
1897 child->verts[i] = vertx[i];
1898 }
1899 return child;
1900 }
1901
1902 static void gl2psSplitPrimitive2D(GL2PSprimitive *prim,
1903 GL2PSplane plane,
1904 GL2PSprimitive **front,
1905 GL2PSprimitive **back)
1906 {
1907 /* cur will hold the position of the current vertex
1908 prev will hold the position of the previous vertex
1909 prev0 will hold the position of the vertex number 0
1910 v1 and v2 represent the current and previous vertices, respectively
1911 flag is set if the current vertex should be checked against the plane */
1912 GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1;
1913
1914 /* list of vertices that will go in front and back primitive */
1915 GL2PSvertex *front_list = NULL, *back_list = NULL;
1916
1917 /* number of vertices in front and back list */
1918 GLshort front_count = 0, back_count = 0;
1919
1920 for(i = 0; i <= prim->numverts; i++){
1921 v1 = i;
1922 if(v1 == prim->numverts){
1923 if(prim->numverts < 3) break;
1924 v1 = 0;
1925 v2 = prim->numverts - 1;
1926 cur = prev0;
1927 }
1928 else if(flag){
1929 cur = gl2psCheckPoint(prim->verts[v1].xyz, plane);
1930 if(i == 0){
1931 prev0 = cur;
1932 }
1933 }
1934 if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) &&
1935 (i < prim->numverts)){
1936 if(cur == GL2PS_POINT_INFRONT){
1937 front_count++;
1938 front_list = (GL2PSvertex*)gl2psRealloc(front_list,
1939 sizeof(GL2PSvertex)*front_count);
1940 front_list[front_count-1] = prim->verts[v1];
1941 }
1942 else if(cur == GL2PS_POINT_BACK){
1943 back_count++;
1944 back_list = (GL2PSvertex*)gl2psRealloc(back_list,
1945 sizeof(GL2PSvertex)*back_count);
1946 back_list[back_count-1] = prim->verts[v1];
1947 }
1948 else{
1949 front_count++;
1950 front_list = (GL2PSvertex*)gl2psRealloc(front_list,
1951 sizeof(GL2PSvertex)*front_count);
1952 front_list[front_count-1] = prim->verts[v1];
1953 back_count++;
1954 back_list = (GL2PSvertex*)gl2psRealloc(back_list,
1955 sizeof(GL2PSvertex)*back_count);
1956 back_list[back_count-1] = prim->verts[v1];
1957 }
1958 flag = 1;
1959 }
1960 else if((prev != cur) && (cur != 0) && (prev != 0)){
1961 if(v1 != 0){
1962 v2 = v1-1;
1963 i--;
1964 }
1965 front_count++;
1966 front_list = (GL2PSvertex*)gl2psRealloc(front_list,
1967 sizeof(GL2PSvertex)*front_count);
1968 gl2psCutEdge(&prim->verts[v2], &prim->verts[v1],
1969 plane, &front_list[front_count-1]);
1970 back_count++;
1971 back_list = (GL2PSvertex*)gl2psRealloc(back_list,
1972 sizeof(GL2PSvertex)*back_count);
1973 back_list[back_count-1] = front_list[front_count-1];
1974 flag = 0;
1975 }
1976 prev = cur;
1977 }
1978 *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list);
1979 *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list);
1980 gl2psFree(front_list);
1981 gl2psFree(back_list);
1982 }
1983
1984 static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree)
1985 {
1986 GLint ret = 0;
1987 GL2PSprimitive *frontprim = NULL, *backprim = NULL;
1988
1989 /* FIXME: until we consider the actual extent of text strings and
1990 pixmaps, never cull them. Otherwise the whole string/pixmap gets
1991 culled as soon as the reference point is hidden */
1992 if(prim->type == GL2PS_PIXMAP ||
1993 prim->type == GL2PS_TEXT ||
1994 prim->type == GL2PS_SPECIAL){
1995 return 1;
1996 }
1997
1998 if(*tree == NULL){
1999 if((prim->type != GL2PS_IMAGEMAP) && (GL_FALSE == gl2ps->zerosurfacearea)){
2000 gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree);
2001 }
2002 return 1;
2003 }
2004 else{
2005 switch(gl2psCheckPrimitive(prim, (*tree)->plane)){
2006 case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back);
2007 case GL2PS_IN_FRONT_OF:
2008 if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front);
2009 else return 0;
2010 case GL2PS_SPANNING:
2011 gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim);
2012 ret = gl2psAddInBspImageTree(backprim, &(*tree)->back);
2013 if((*tree)->front != NULL){
2014 if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){
2015 ret = 1;
2016 }
2017 }
2018 gl2psFree(frontprim->verts);
2019 gl2psFree(frontprim);
2020 gl2psFree(backprim->verts);
2021 gl2psFree(backprim);
2022 return ret;
2023 case GL2PS_COINCIDENT:
2024 if((*tree)->back != NULL){
2025 gl2ps->zerosurfacearea = GL_TRUE;
2026 ret = gl2psAddInBspImageTree(prim, &(*tree)->back);
2027 gl2ps->zerosurfacearea = GL_FALSE;
2028 if(ret) return ret;
2029 }
2030 if((*tree)->front != NULL){
2031 gl2ps->zerosurfacearea = GL_TRUE;
2032 ret = gl2psAddInBspImageTree(prim, &(*tree)->front);
2033 gl2ps->zerosurfacearea = GL_FALSE;
2034 if(ret) return ret;
2035 }
2036 if(prim->type == GL2PS_LINE) return 1;
2037 else return 0;
2038 }
2039 }
2040 return 0;
2041 }
2042
2043 static void gl2psAddInImageTree(void *data)
2044 {
2045 GL2PSprimitive *prim = *(GL2PSprimitive **)data;
2046 gl2ps->primitivetoadd = prim;
2047 if(prim->type == GL2PS_IMAGEMAP && prim->data.image->format == GL2PS_IMAGEMAP_VISIBLE){
2048 prim->culled = 1;
2049 }
2050 else if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){
2051 prim->culled = 1;
2052 }
2053 else if(prim->type == GL2PS_IMAGEMAP){
2054 prim->data.image->format = GL2PS_IMAGEMAP_VISIBLE;
2055 }
2056 }
2057
2058 /* Boundary construction */
2059
2060 static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list)
2061 {
2062 GL2PSprimitive *b;
2063 GLshort i;
2064 GL2PSxyz c;
2065
2066 c[0] = c[1] = c[2] = 0.0F;
2067 for(i = 0; i < prim->numverts; i++){
2068 c[0] += prim->verts[i].xyz[0];
2069 c[1] += prim->verts[i].xyz[1];
2070 }
2071 c[0] /= prim->numverts;
2072 c[1] /= prim->numverts;
2073
2074 for(i = 0; i < prim->numverts; i++){
2075 if(prim->boundary & (GLint)pow(2., i)){
2076 b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
2077 b->type = GL2PS_LINE;
2078 b->offset = prim->offset;
2079 b->pattern = prim->pattern;
2080 b->factor = prim->factor;
2081 b->culled = prim->culled;
2082 b->width = prim->width;
2083 b->boundary = 0;
2084 b->numverts = 2;
2085 b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex));
2086
2087 #if 0 /* FIXME: need to work on boundary offset... */
2088 v[0] = c[0] - prim->verts[i].xyz[0];
2089 v[1] = c[1] - prim->verts[i].xyz[1];
2090 v[2] = 0.0F;
2091 norm = gl2psNorm(v);
2092 v[0] /= norm;
2093 v[1] /= norm;
2094 b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0];
2095 b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1];
2096 b->verts[0].xyz[2] = prim->verts[i].xyz[2];
2097 v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
2098 v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
2099 norm = gl2psNorm(v);
2100 v[0] /= norm;
2101 v[1] /= norm;
2102 b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0];
2103 b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1];
2104 b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
2105 #else
2106 b->verts[0].xyz[0] = prim->verts[i].xyz[0];
2107 b->verts[0].xyz[1] = prim->verts[i].xyz[1];
2108 b->verts[0].xyz[2] = prim->verts[i].xyz[2];
2109 b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
2110 b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
2111 b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
2112 #endif
2113
2114 b->verts[0].rgba[0] = 0.0F;
2115 b->verts[0].rgba[1] = 0.0F;
2116 b->verts[0].rgba[2] = 0.0F;
2117 b->verts[0].rgba[3] = 0.0F;
2118 b->verts[1].rgba[0] = 0.0F;
2119 b->verts[1].rgba[1] = 0.0F;
2120 b->verts[1].rgba[2] = 0.0F;
2121 b->verts[1].rgba[3] = 0.0F;
2122 gl2psListAdd(list, &b);
2123 }
2124 }
2125
2126 }
2127
2128 static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree)
2129 {
2130 GLint i;
2131 GL2PSprimitive *prim;
2132
2133 if(!tree) return;
2134 gl2psBuildPolygonBoundary(tree->back);
2135 for(i = 0; i < gl2psListNbr(tree->primitives); i++){
2136 prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i);
2137 if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives);
2138 }
2139 gl2psBuildPolygonBoundary(tree->front);
2140 }
2141
2142 /*********************************************************************
2143 *
2144 * Feedback buffer parser
2145 *
2146 *********************************************************************/
2147
2148 static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts,
2149 GL2PSvertex *verts, GLint offset,
2150 GLushort pattern, GLint factor,
2151 GLfloat width, char boundary)
2152 {
2153 GL2PSprimitive *prim;
2154
2155 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
2156 prim->type = type;
2157 prim->numverts = numverts;
2158 prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex));
2159 memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex));
2160 prim->boundary = boundary;
2161 prim->offset = offset;
2162 prim->pattern = pattern;
2163 prim->factor = factor;
2164 prim->width = width;
2165 prim->culled = 0;
2166
2167 /* FIXME: here we should have an option to split stretched
2168 tris/quads to enhance SIMPLE_SORT */
2169
2170 gl2psListAdd(gl2ps->primitives, &prim);
2171 }
2172
2173 static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p)
2174 {
2175 GLint i;
2176
2177 v->xyz[0] = p[0];
2178 v->xyz[1] = p[1];
2179 v->xyz[2] = p[2];
2180
2181 if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){
2182 i = (GLint)(p[3] + 0.5);
2183 v->rgba[0] = gl2ps->colormap[i][0];
2184 v->rgba[1] = gl2ps->colormap[i][1];
2185 v->rgba[2] = gl2ps->colormap[i][2];
2186 v->rgba[3] = gl2ps->colormap[i][3];
2187 return 4;
2188 }
2189 else{
2190 v->rgba[0] = p[3];
2191 v->rgba[1] = p[4];
2192 v->rgba[2] = p[5];
2193 v->rgba[3] = p[6];
2194 return 7;
2195 }
2196 }
2197
2198 static void gl2psParseFeedbackBuffer(GLint used)
2199 {
2200 char flag;
2201 GLushort pattern = 0;
2202 GLboolean boundary;
2203 GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0;
2204 GLfloat lwidth = 1.0F, psize = 1.0F;
2205 GLfloat *current;
2206 GL2PSvertex vertices[3];
2207 GL2PSprimitive *prim;
2208 GL2PSimagemap *node;
2209
2210 current = gl2ps->feedback;
2211 boundary = gl2ps->boundary = GL_FALSE;
2212
2213 while(used > 0){
2214
2215 if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE;
2216
2217 switch((GLint)*current){
2218 case GL_POINT_TOKEN :
2219 current ++;
2220 used --;
2221 i = gl2psGetVertex(&vertices[0], current);
2222 current += i;
2223 used -= i;
2224 gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0,
2225 pattern, factor, psize, 0);
2226 break;
2227 case GL_LINE_TOKEN :
2228 case GL_LINE_RESET_TOKEN :
2229 current ++;
2230 used --;
2231 i = gl2psGetVertex(&vertices[0], current);
2232 current += i;
2233 used -= i;
2234 i = gl2psGetVertex(&vertices[1], current);
2235 current += i;
2236 used -= i;
2237 gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0,
2238 pattern, factor, lwidth, 0);
2239 break;
2240 case GL_POLYGON_TOKEN :
2241 count = (GLint)current[1];
2242 current += 2;
2243 used -= 2;
2244 v = vtot = 0;
2245 while(count > 0 && used > 0){
2246 i = gl2psGetVertex(&vertices[v], current);
2247 gl2psAdaptVertexForBlending(&vertices[v]);
2248 current += i;
2249 used -= i;
2250 count --;
2251 vtot++;
2252 if(v == 2){
2253 if(GL_TRUE == boundary){
2254 if(!count && vtot == 2) flag = 1|2|4;
2255 else if(!count) flag = 2|4;
2256 else if(vtot == 2) flag = 1|2;
2257 else flag = 2;
2258 }
2259 else
2260 flag = 0;
2261 gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices, offset,
2262 pattern, factor, 1, flag);
2263 vertices[1] = vertices[2];
2264 }
2265 else
2266 v ++;
2267 }
2268 break;
2269 case GL_BITMAP_TOKEN :
2270 case GL_DRAW_PIXEL_TOKEN :
2271 case GL_COPY_PIXEL_TOKEN :
2272 current ++;
2273 used --;
2274 i = gl2psGetVertex(&vertices[0], current);
2275 current += i;
2276 used -= i;
2277 break;
2278 case GL_PASS_THROUGH_TOKEN :
2279 switch((GLint)current[1]){
2280 case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break;
2281 case GL2PS_END_OFFSET_TOKEN : offset = 0; break;
2282 case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break;
2283 case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break;
2284 case GL2PS_END_STIPPLE_TOKEN : pattern = factor = 0; break;
2285 case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break;
2286 case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break;
2287 case GL2PS_BEGIN_STIPPLE_TOKEN :
2288 current += 2;
2289 used -= 2;
2290 pattern = (GLushort)current[1];
2291 current += 2;
2292 used -= 2;
2293 factor = (GLint)current[1];
2294 break;
2295 case GL2PS_SRC_BLEND_TOKEN :
2296 current += 2;
2297 used -= 2;
2298 gl2ps->blendfunc[0] = (GLint)current[1];
2299 break;
2300 case GL2PS_DST_BLEND_TOKEN :
2301 current += 2;
2302 used -= 2;
2303 gl2ps->blendfunc[1] = (GLint)current[1];
2304 break;
2305 case GL2PS_POINT_SIZE_TOKEN :
2306 current += 2;
2307 used -= 2;
2308 psize = current[1];
2309 break;
2310 case GL2PS_LINE_WIDTH_TOKEN :
2311 current += 2;
2312 used -= 2;
2313 lwidth = current[1];
2314 break;
2315 case GL2PS_IMAGEMAP_TOKEN :
2316 prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive));
2317 prim->type = GL2PS_IMAGEMAP;
2318 prim->boundary = 0;
2319 prim->numverts = 4;
2320 prim->verts = (GL2PSvertex *)gl2psMalloc(4 * sizeof(GL2PSvertex));
2321 prim->culled = 0;
2322 prim->offset = 0;
2323 prim->pattern = 0;
2324 prim->factor = 0;
2325 prim->width = 1;
2326
2327 node = (GL2PSimagemap*)gl2psMalloc(sizeof(GL2PSimagemap));
2328 node->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
2329 node->image->type = 0;
2330 node->image->format = 0;
2331 node->image->zoom_x = 1.0F;
2332 node->image->zoom_y = 1.0F;
2333 node->next = NULL;
2334
2335 if(gl2ps->imagemap_head == NULL)
2336 gl2ps->imagemap_head = node;
2337 else
2338 gl2ps->imagemap_tail->next = node;
2339 gl2ps->imagemap_tail = node;
2340 prim->data.image = node->image;
2341
2342 current += 2; used -= 2;
2343 i = gl2psGetVertex(&prim->verts[0], ¤t[1]);
2344 current += i; used -= i;
2345
2346 node->image->width = (GLint)current[2];
2347 current += 2; used -= 2;
2348 node->image->height = (GLint)current[2];
2349 prim->verts[0].xyz[0] = prim->verts[0].xyz[0] - (int)(node->image->width / 2) + 0.5F;
2350 prim->verts[0].xyz[1] = prim->verts[0].xyz[1] - (int)(node->image->height / 2) + 0.5F;
2351 for(i = 1; i < 4; i++){
2352 for(v = 0; v < 3; v++){
2353 prim->verts[i].xyz[v] = prim->verts[0].xyz[v];
2354 prim->verts[i].rgba[v] = prim->verts[0].rgba[v];
2355 }
2356 prim->verts[i].rgba[v] = prim->verts[0].rgba[v];
2357 }
2358 prim->verts[1].xyz[0] = prim->verts[1].xyz[0] + node->image->width;
2359 prim->verts[2].xyz[0] = prim->verts[1].xyz[0];
2360 prim->verts[2].xyz[1] = prim->verts[2].xyz[1] + node->image->height;
2361 prim->verts[3].xyz[1] = prim->verts[2].xyz[1];
2362
2363 sizeoffloat = sizeof(GLfloat);
2364 v = 2 * sizeoffloat;
2365 vtot = node->image->height + node->image->height *
2366 ((node->image->width - 1) / 8);
2367 node->image->pixels = (GLfloat*)gl2psMalloc(v + vtot);
2368 node->image->pixels[0] = prim->verts[0].xyz[0];
2369 node->image->pixels[1] = prim->verts[0].xyz[1];
2370
2371 for(i = 0; i < vtot; i += sizeoffloat){
2372 current += 2; used -= 2;
2373 if((vtot - i) >= 4)
2374 memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), sizeoffloat);
2375 else
2376 memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), vtot - i);
2377 }
2378 current++; used--;
2379 gl2psListAdd(gl2ps->primitives, &prim);
2380 break;
2381 case GL2PS_DRAW_PIXELS_TOKEN :
2382 case GL2PS_TEXT_TOKEN :
2383 if(auxindex < gl2psListNbr(gl2ps->auxprimitives))
2384 gl2psListAdd(gl2ps->primitives,
2385 gl2psListPointer(gl2ps->auxprimitives, auxindex++));
2386 else
2387 gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer");
2388 break;
2389 }
2390 current += 2;
2391 used -= 2;
2392 break;
2393 default :
2394 gl2psMsg(GL2PS_WARNING, "Unknown token in buffer");
2395 current ++;
2396 used --;
2397 break;
2398 }
2399 }
2400
2401 gl2psListReset(gl2ps->auxprimitives);
2402 }
2403
2404 /*********************************************************************
2405 *
2406 * PostScript routines
2407 *
2408 *********************************************************************/
2409
2410 static void gl2psWriteByte(unsigned char byte)
2411 {
2412 unsigned char h = byte / 16;
2413 unsigned char l = byte % 16;
2414 gl2psPrintf("%x%x", h, l);
2415 }
2416
2417 static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im)
2418 {
2419 GLuint nbhex, nbyte, nrgb, nbits;
2420 GLuint row, col, ibyte, icase;
2421 GLfloat dr, dg, db, fgrey;
2422 unsigned char red = 0, green = 0, blue = 0, b, grey;
2423 GLuint width = (GLuint)im->width;
2424 GLuint height = (GLuint)im->height;
2425
2426 /* FIXME: should we define an option for these? Or just keep the
2427 8-bit per component case? */
2428 int greyscale = 0; /* set to 1 to output greyscale image */
2429 int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */
2430
2431 if((width <= 0) || (height <= 0)) return;
2432
2433 gl2psPrintf("gsave\n");
2434 gl2psPrintf("%.2f %.2f translate\n", x, y);
2435 gl2psPrintf("%.2f %.2f scale\n", width * im->zoom_x, height * im->zoom_y);
2436
2437 if(greyscale){ /* greyscale */
2438 gl2psPrintf("/picstr %d string def\n", width);
2439 gl2psPrintf("%d %d %d\n", width, height, 8);
2440 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2441 gl2psPrintf("{ currentfile picstr readhexstring pop }\n");
2442 gl2psPrintf("image\n");
2443 for(row = 0; row < height; row++){
2444 for(col = 0; col < width; col++){
2445 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2446 fgrey = (0.30F * dr + 0.59F * dg + 0.11F * db);
2447 grey = (unsigned char)(255. * fgrey);
2448 gl2psWriteByte(grey);
2449 }
2450 gl2psPrintf("\n");
2451 }
2452 nbhex = width * height * 2;
2453 gl2psPrintf("%%%% nbhex digit :%d\n", nbhex);
2454 }
2455 else if(nbit == 2){ /* color, 2 bits for r and g and b; rgbs following each other */
2456 nrgb = width * 3;
2457 nbits = nrgb * nbit;
2458 nbyte = nbits / 8;
2459 if((nbyte * 8) != nbits) nbyte++;
2460 gl2psPrintf("/rgbstr %d string def\n", nbyte);
2461 gl2psPrintf("%d %d %d\n", width, height, nbit);
2462 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2463 gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
2464 gl2psPrintf("false 3\n");
2465 gl2psPrintf("colorimage\n");
2466 for(row = 0; row < height; row++){
2467 icase = 1;
2468 col = 0;
2469 b = 0;
2470 for(ibyte = 0; ibyte < nbyte; ibyte++){
2471 if(icase == 1) {
2472 if(col < width) {
2473 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2474 }
2475 else {
2476 dr = dg = db = 0;
2477 }
2478 col++;
2479 red = (unsigned char)(3. * dr);
2480 green = (unsigned char)(3. * dg);
2481 blue = (unsigned char)(3. * db);
2482 b = red;
2483 b = (b<<2) + green;
2484 b = (b<<2) + blue;
2485 if(col < width) {
2486 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2487 }
2488 else {
2489 dr = dg = db = 0;
2490 }
2491 col++;
2492 red = (unsigned char)(3. * dr);
2493 green = (unsigned char)(3. * dg);
2494 blue = (unsigned char)(3. * db);
2495 b = (b<<2) + red;
2496 gl2psWriteByte(b);
2497 b = 0;
2498 icase++;
2499 }
2500 else if(icase == 2) {
2501 b = green;
2502 b = (b<<2) + blue;
2503 if(col < width) {
2504 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2505 }
2506 else {
2507 dr = dg = db = 0;
2508 }
2509 col++;
2510 red = (unsigned char)(3. * dr);
2511 green = (unsigned char)(3. * dg);
2512 blue = (unsigned char)(3. * db);
2513 b = (b<<2) + red;
2514 b = (b<<2) + green;
2515 gl2psWriteByte(b);
2516 b = 0;
2517 icase++;
2518 }
2519 else if(icase == 3) {
2520 b = blue;
2521 if(col < width) {
2522 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2523 }
2524 else {
2525 dr = dg = db = 0;
2526 }
2527 col++;
2528 red = (unsigned char)(3. * dr);
2529 green = (unsigned char)(3. * dg);
2530 blue = (unsigned char)(3. * db);
2531 b = (b<<2) + red;
2532 b = (b<<2) + green;
2533 b = (b<<2) + blue;
2534 gl2psWriteByte(b);
2535 b = 0;
2536 icase = 1;
2537 }
2538 }
2539 gl2psPrintf("\n");
2540 }
2541 }
2542 else if(nbit == 4){ /* color, 4 bits for r and g and b; rgbs following each other */
2543 nrgb = width * 3;
2544 nbits = nrgb * nbit;
2545 nbyte = nbits / 8;
2546 if((nbyte * 8) != nbits) nbyte++;
2547 gl2psPrintf("/rgbstr %d string def\n", nbyte);
2548 gl2psPrintf("%d %d %d\n", width, height, nbit);
2549 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2550 gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
2551 gl2psPrintf("false 3\n");
2552 gl2psPrintf("colorimage\n");
2553 for(row = 0; row < height; row++){
2554 col = 0;
2555 icase = 1;
2556 for(ibyte = 0; ibyte < nbyte; ibyte++){
2557 if(icase == 1) {
2558 if(col < width) {
2559 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2560 }
2561 else {
2562 dr = dg = db = 0;
2563 }
2564 col++;
2565 red = (unsigned char)(15. * dr);
2566 green = (unsigned char)(15. * dg);
2567 gl2psPrintf("%x%x", red, green);
2568 icase++;
2569 }
2570 else if(icase == 2) {
2571 blue = (unsigned char)(15. * db);
2572 if(col < width) {
2573 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2574 }
2575 else {
2576 dr = dg = db = 0;
2577 }
2578 col++;
2579 red = (unsigned char)(15. * dr);
2580 gl2psPrintf("%x%x", blue, red);
2581 icase++;
2582 }
2583 else if(icase == 3) {
2584 green = (unsigned char)(15. * dg);
2585 blue = (unsigned char)(15. * db);
2586 gl2psPrintf("%x%x", green, blue);
2587 icase = 1;
2588 }
2589 }
2590 gl2psPrintf("\n");
2591 }
2592 }
2593 else{ /* 8 bit for r and g and b */
2594 nbyte = width * 3;
2595 gl2psPrintf("/rgbstr %d string def\n", nbyte);
2596 gl2psPrintf("%d %d %d\n", width, height, 8);
2597 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height);
2598 gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n");
2599 gl2psPrintf("false 3\n");
2600 gl2psPrintf("colorimage\n");
2601 for(row = 0; row < height; row++){
2602 for(col = 0; col < width; col++){
2603 gl2psGetRGB(im, col, row, &dr, &dg, &db);
2604 red = (unsigned char)(255. * dr);
2605 gl2psWriteByte(red);
2606 green = (unsigned char)(255. * dg);
2607 gl2psWriteByte(green);
2608 blue = (unsigned char)(255. * db);
2609 gl2psWriteByte(blue);
2610 }
2611 gl2psPrintf("\n");
2612 }
2613 }
2614
2615 gl2psPrintf("grestore\n");
2616 }
2617
2618 static void gl2psPrintPostScriptImagemap(GLfloat x, GLfloat y,
2619 GLsizei width, GLsizei height,
2620 const unsigned char *imagemap){
2621 int i, size;
2622
2623 if((width <= 0) || (height <= 0)) return;
2624
2625 size = height + height * (width - 1) / 8;
2626
2627 gl2psPrintf("gsave\n");
2628 gl2psPrintf("%.2f %.2f translate\n", x, y);
2629 gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height);
2630 gl2psPrintf("[ %d 0 0 -%d 0 %d ] {<", width, height);
2631 for(i = 0; i < size; i++){
2632 gl2psWriteByte(*imagemap);
2633 imagemap++;
2634 }
2635 gl2psPrintf(">} imagemask\ngrestore\n");
2636 }
2637
2638 static void gl2psPrintPostScriptHeader(void)
2639 {
2640 time_t now;
2641
2642 /* Since compression is not part of the PostScript standard,
2643 compressed PostScript files are just gzipped PostScript files
2644 ("ps.gz" or "eps.gz") */
2645 gl2psPrintGzipHeader();
2646
2647 time(&now);
2648
2649 if(gl2ps->format == GL2PS_PS){
2650 gl2psPrintf("%%!PS-Adobe-3.0\n");
2651 }
2652 else{
2653 gl2psPrintf("%%!PS-Adobe-3.0 EPSF-3.0\n");
2654 }
2655
2656 gl2psPrintf("%%%%Title: %s\n"
2657 "%%%%Creator: GL2PS %d.%d.%d%s, %s\n"
2658 "%%%%For: %s\n"
2659 "%%%%CreationDate: %s"
2660 "%%%%LanguageLevel: 3\n"
2661 "%%%%DocumentData: Clean7Bit\n"
2662 "%%%%Pages: 1\n",
2663 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
2664 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
2665 gl2ps->producer, ctime(&now));
2666
2667 if(gl2ps->format == GL2PS_PS){
2668 gl2psPrintf("%%%%Orientation: %s\n"
2669 "%%%%DocumentMedia: Default %d %d 0 () ()\n",
2670 (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait",
2671 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] :
2672 (int)gl2ps->viewport[2],
2673 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] :
2674 (int)gl2ps->viewport[3]);
2675 }
2676
2677 gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n"
2678 "%%%%EndComments\n",
2679 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] :
2680 (int)gl2ps->viewport[0],
2681 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] :
2682 (int)gl2ps->viewport[1],
2683 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] :
2684 (int)gl2ps->viewport[2],
2685 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] :
2686 (int)gl2ps->viewport[3]);
2687
2688 /* RGB color: r g b C (replace C by G in output to change from rgb to gray)
2689 Grayscale: r g b G
2690 Font choose: size fontname FC
2691 Text string: (string) x y size fontname S??
2692 Rotated text string: (string) angle x y size fontname S??R
2693 Point primitive: x y size P
2694 Line width: width W
2695 Line start: x y LS
2696 Line joining last point: x y L
2697 Line end: x y LE
2698 Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T
2699 Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */
2700
2701 gl2psPrintf("%%%%BeginProlog\n"
2702 "/gl2psdict 64 dict def gl2psdict begin\n"
2703 "0 setlinecap 0 setlinejoin\n"
2704 "/tryPS3shading %s def %% set to false to force subdivision\n"
2705 "/rThreshold %g def %% red component subdivision threshold\n"
2706 "/gThreshold %g def %% green component subdivision threshold\n"
2707 "/bThreshold %g def %% blue component subdivision threshold\n",
2708 (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true",
2709 gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]);
2710
2711 gl2psPrintf("/BD { bind def } bind def\n"
2712 "/C { setrgbcolor } BD\n"
2713 "/G { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n"
2714 "/W { setlinewidth } BD\n");
2715
2716 gl2psPrintf("/FC { findfont exch /SH exch def SH scalefont setfont } BD\n"
2717 "/SW { dup stringwidth pop } BD\n"
2718 "/S { FC moveto show } BD\n"
2719 "/SBC{ FC moveto SW -2 div 0 rmoveto show } BD\n"
2720 "/SBR{ FC moveto SW neg 0 rmoveto show } BD\n"
2721 "/SCL{ FC moveto 0 SH -2 div rmoveto show } BD\n"
2722 "/SCC{ FC moveto SW -2 div SH -2 div rmoveto show } BD\n"
2723 "/SCR{ FC moveto SW neg SH -2 div rmoveto show } BD\n"
2724 "/STL{ FC moveto 0 SH neg rmoveto show } BD\n"
2725 "/STC{ FC moveto SW -2 div SH neg rmoveto show } BD\n"
2726 "/STR{ FC moveto SW neg SH neg rmoveto show } BD\n");
2727
2728 /* rotated text routines: same nameanem with R appended */
2729
2730 gl2psPrintf("/FCT { FC translate 0 0 } BD\n"
2731 "/SR { gsave FCT moveto rotate show grestore } BD\n"
2732 "/SBCR{ gsave FCT moveto rotate SW -2 div 0 rmoveto show grestore } BD\n"
2733 "/SBRR{ gsave FCT moveto rotate SW neg 0 rmoveto show grestore } BD\n"
2734 "/SCLR{ gsave FCT moveto rotate 0 SH -2 div rmoveto show grestore} BD\n");
2735 gl2psPrintf("/SCCR{ gsave FCT moveto rotate SW -2 div SH -2 div rmoveto show grestore} BD\n"
2736 "/SCRR{ gsave FCT moveto rotate SW neg SH -2 div rmoveto show grestore} BD\n"
2737 "/STLR{ gsave FCT moveto rotate 0 SH neg rmoveto show grestore } BD\n"
2738 "/STCR{ gsave FCT moveto rotate SW -2 div SH neg rmoveto show grestore } BD\n"
2739 "/STRR{ gsave FCT moveto rotate SW neg SH neg rmoveto show grestore } BD\n");
2740
2741 gl2psPrintf("/P { newpath 0.0 360.0 arc closepath fill } BD\n"
2742 "/LS { newpath moveto } BD\n"
2743 "/L { lineto } BD\n"
2744 "/LE { lineto stroke } BD\n"
2745 "/T { newpath moveto lineto lineto closepath fill } BD\n");
2746
2747 /* Smooth-shaded triangle with PostScript level 3 shfill operator:
2748 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */
2749
2750 gl2psPrintf("/STshfill {\n"
2751 " /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n"
2752 " /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n"
2753 " /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n"
2754 " gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n"
2755 " /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n"
2756 " shfill grestore } BD\n");
2757
2758 /* Flat-shaded triangle with middle color:
2759 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */
2760
2761 gl2psPrintf(/* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */
2762 "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */
2763 /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */
2764 " 3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */
2765 /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */
2766 " 3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */
2767 /* stack : x3 y3 x2 y2 x1 y1 r g b */
2768 " C T } BD\n");
2769
2770 /* Split triangle in four sub-triangles (at sides middle points) and call the
2771 STnoshfill procedure on each, interpolating the colors in RGB space:
2772 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit
2773 (in procedure comments key: (Vi) = xi yi ri gi bi) */
2774
2775 gl2psPrintf("/STsplit {\n"
2776 " 4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */
2777 " 4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */
2778 " 4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */
2779 " 4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */
2780 " 4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */
2781 " 5 copy 5 copy 25 15 roll\n");
2782
2783 /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */
2784
2785 gl2psPrintf(" 9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */
2786 " 9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */
2787 " 9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */
2788 " 9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */
2789 " 9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */
2790 " 5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n");
2791
2792 /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */
2793
2794 gl2psPrintf(" 4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */
2795 " 4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */
2796 " 4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */
2797 " 4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */
2798 " 4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */
2799 " 5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n");
2800
2801 /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */
2802
2803 gl2psPrintf(" STnoshfill STnoshfill STnoshfill STnoshfill } BD\n");
2804
2805 /* Gouraud shaded triangle using recursive subdivision until the difference
2806 between corner colors does not exceed the thresholds:
2807 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill */
2808
2809 gl2psPrintf("/STnoshfill {\n"
2810 " 2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */
2811 " { STsplit }\n"
2812 " { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */
2813 " { STsplit }\n"
2814 " { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */
2815 " { STsplit }\n"
2816 " { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */
2817 " { STsplit }\n"
2818 " { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */
2819 " { STsplit }\n"
2820 " { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */
2821 " { STsplit }\n"
2822 " { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */
2823 gl2psPrintf(" { STsplit }\n"
2824 " { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */
2825 " { STsplit }\n"
2826 " { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */
2827 " { STsplit }\n"
2828 " { Tm }\n" /* all colors sufficiently similar */
2829 " ifelse }\n"
2830 " ifelse }\n"
2831 " ifelse }\n"
2832 " ifelse }\n"
2833 " ifelse }\n"
2834 " ifelse }\n"
2835 " ifelse }\n"
2836 " ifelse }\n"
2837 " ifelse } BD\n");
2838
2839 gl2psPrintf("tryPS3shading\n"
2840 "{ /shfill where\n"
2841 " { /ST { STshfill } BD }\n"
2842 " { /ST { STnoshfill } BD }\n"
2843 " ifelse }\n"
2844 "{ /ST { STnoshfill } BD }\n"
2845 "ifelse\n");
2846
2847 gl2psPrintf("end\n"
2848 "%%%%EndProlog\n"
2849 "%%%%BeginSetup\n"
2850 "/DeviceRGB setcolorspace\n"
2851 "gl2psdict begin\n"
2852 "%%%%EndSetup\n"
2853 "%%%%Page: 1 1\n"
2854 "%%%%BeginPageSetup\n");
2855
2856 if(gl2ps->options & GL2PS_LANDSCAPE){
2857 gl2psPrintf("%d 0 translate 90 rotate\n",
2858 (int)gl2ps->viewport[3]);
2859 }
2860
2861 gl2psPrintf("%%%%EndPageSetup\n"
2862 "mark\n"
2863 "gsave\n"
2864 "1.0 1.0 scale\n");
2865
2866 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
2867 gl2psPrintf("%g %g %g C\n"
2868 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
2869 "closepath fill\n",
2870 gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2],
2871 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2],
2872 (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3],
2873 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]);
2874 }
2875 }
2876
2877 static void gl2psPrintPostScriptColor(GL2PSrgba rgba)
2878 {
2879 if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
2880 gl2psSetLastColor(rgba);
2881 gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]);
2882 }
2883 }
2884
2885 static void gl2psResetPostScriptColor(void)
2886 {
2887 gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.;
2888 }
2889
2890 static void gl2psEndPostScriptLine(void)
2891 {
2892 int i;
2893 if(gl2ps->lastvertex.rgba[0] >= 0.){
2894 gl2psPrintf("%g %g LE\n", gl2ps->lastvertex.xyz[0], gl2ps->lastvertex.xyz[1]);
2895 for(i = 0; i < 3; i++)
2896 gl2ps->lastvertex.xyz[i] = -1.;
2897 for(i = 0; i < 4; i++)
2898 gl2ps->lastvertex.rgba[i] = -1.;
2899 }
2900 }
2901
2902 static void gl2psParseStipplePattern(GLushort pattern, GLint factor,
2903 int *nb, int array[10])
2904 {
2905 int i, n;
2906 int on[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2907 int off[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2908 char tmp[16];
2909
2910 /* extract the 16 bits from the OpenGL stipple pattern */
2911 for(n = 15; n >= 0; n--){
2912 tmp[n] = (char)(pattern & 0x01);
2913 pattern >>= 1;
2914 }
2915 /* compute the on/off pixel sequence */
2916 n = 0;
2917 for(i = 0; i < 8; i++){
2918 while(n < 16 && !tmp[n]){ off[i]++; n++; }
2919 while(n < 16 && tmp[n]){ on[i]++; n++; }
2920 if(n >= 15){ i++; break; }
2921 }
2922
2923 /* store the on/off array from right to left, starting with off
2924 pixels. The PostScript specification allows for at most 11
2925 elements in the on/off array, so we limit ourselves to 5 on/off
2926 couples (our longest possible array is thus [on4 off4 on3 off3
2927 on2 off2 on1 off1 on0 off0]) */
2928 *nb = 0;
2929 for(n = i - 1; n >= 0; n--){
2930 array[(*nb)++] = factor * on[n];
2931 array[(*nb)++] = factor * off[n];
2932 if(*nb == 10) break;
2933 }
2934 }
2935
2936 static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, const char *str)
2937 {
2938 int len = 0, i, n, array[10];
2939
2940 if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor)
2941 return 0;
2942
2943 gl2ps->lastpattern = pattern;
2944 gl2ps->lastfactor = factor;
2945
2946 if(!pattern || !factor){
2947 /* solid line */
2948 len += gl2psPrintf("[] 0 %s\n", str);
2949 }
2950 else{
2951 gl2psParseStipplePattern(pattern, factor, &n, array);
2952 len += gl2psPrintf("[");
2953 for(i = 0; i < n; i++){
2954 if(i) len += gl2psPrintf(" ");
2955 len += gl2psPrintf("%d", array[i]);
2956 }
2957 len += gl2psPrintf("] 0 %s\n", str);
2958 }
2959
2960 return len;
2961 }
2962
2963 static void gl2psPrintPostScriptPrimitive(void *data)
2964 {
2965 int newline;
2966 GL2PSprimitive *prim;
2967
2968 prim = *(GL2PSprimitive**)data;
2969
2970 if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return;
2971
2972 /* Every effort is made to draw lines as connected segments (i.e.,
2973 using a single PostScript path): this is the only way to get nice
2974 line joins and to not restart the stippling for every line
2975 segment. So if the primitive to print is not a line we must first
2976 finish the current line (if any): */
2977 if(prim->type != GL2PS_LINE) gl2psEndPostScriptLine();
2978
2979 switch(prim->type){
2980 case GL2PS_POINT :
2981 gl2psPrintPostScriptColor(prim->verts[0].rgba);
2982 gl2psPrintf("%g %g %g P\n",
2983 prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width);
2984 break;
2985 case GL2PS_LINE :
2986 if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) ||
2987 !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) ||
2988 gl2ps->lastlinewidth != prim->width ||
2989 gl2ps->lastpattern != prim->pattern ||
2990 gl2ps->lastfactor != prim->factor){
2991 /* End the current line if the new segment does not start where
2992 the last one ended, or if the color, the width or the
2993 stippling have changed (multi-stroking lines with changing
2994 colors is necessary until we use /shfill for lines;
2995 unfortunately this means that at the moment we can screw up
2996 line stippling for smooth-shaded lines) */
2997 gl2psEndPostScriptLine();
2998 newline = 1;
2999 }
3000 else{
3001 newline = 0;
3002 }
3003 if(gl2ps->lastlinewidth != prim->width){
3004 gl2ps->lastlinewidth = prim->width;
3005 gl2psPrintf("%g W\n", gl2ps->lastlinewidth);
3006 }
3007 gl2psPrintPostScriptDash(prim->pattern, prim->factor, "setdash");
3008 gl2psPrintPostScriptColor(prim->verts[0].rgba);
3009 gl2psPrintf("%g %g %s\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3010 newline ? "LS" : "L");
3011 gl2ps->lastvertex = prim->verts[1];
3012 break;
3013 case GL2PS_TRIANGLE :
3014 if(!gl2psVertsSameColor(prim)){
3015 gl2psResetPostScriptColor();
3016 gl2psPrintf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n",
3017 prim->verts[2].xyz[0], prim->verts[2].xyz[1],
3018 prim->verts[2].rgba[0], prim->verts[2].rgba[1],
3019 prim->verts[2].rgba[2], prim->verts[1].xyz[0],
3020 prim->verts[1].xyz[1], prim->verts[1].rgba[0],
3021 prim->verts[1].rgba[1], prim->verts[1].rgba[2],
3022 prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3023 prim->verts[0].rgba[0], prim->verts[0].rgba[1],
3024 prim->verts[0].rgba[2]);
3025 }
3026 else{
3027 gl2psPrintPostScriptColor(prim->verts[0].rgba);
3028 gl2psPrintf("%g %g %g %g %g %g T\n",
3029 prim->verts[2].xyz[0], prim->verts[2].xyz[1],
3030 prim->verts[1].xyz[0], prim->verts[1].xyz[1],
3031 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3032 }
3033 break;
3034 case GL2PS_QUADRANGLE :
3035 gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
3036 break;
3037 case GL2PS_PIXMAP :
3038 gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3039 prim->data.image);
3040 break;
3041 case GL2PS_IMAGEMAP :
3042 if(prim->data.image->type != GL2PS_IMAGEMAP_WRITTEN){
3043 gl2psPrintPostScriptColor(prim->verts[0].rgba);
3044 gl2psPrintPostScriptImagemap(prim->data.image->pixels[0],
3045 prim->data.image->pixels[1],
3046 prim->data.image->width, prim->data.image->height,
3047 (const unsigned char*)(&(prim->data.image->pixels[2])));
3048 prim->data.image->type = GL2PS_IMAGEMAP_WRITTEN;
3049 }
3050 break;
3051 case GL2PS_TEXT :
3052 gl2psPrintPostScriptColor(prim->verts[0].rgba);
3053 gl2psPrintf("(%s) ", prim->data.text->str);
3054 if(prim->data.text->angle)
3055 gl2psPrintf("%g ", prim->data.text->angle);
3056 gl2psPrintf("%g %g %d /%s ",
3057 prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3058 prim->data.text->fontsize, prim->data.text->fontname);
3059 switch(prim->data.text->alignment){
3060 case GL2PS_TEXT_C:
3061 gl2psPrintf(prim->data.text->angle ? "SCCR\n" : "SCC\n");
3062 break;
3063 case GL2PS_TEXT_CL:
3064 gl2psPrintf(prim->data.text->angle ? "SCLR\n" : "SCL\n");
3065 break;
3066 case GL2PS_TEXT_CR:
3067 gl2psPrintf(prim->data.text->angle ? "SCRR\n" : "SCR\n");
3068 break;
3069 case GL2PS_TEXT_B:
3070 gl2psPrintf(prim->data.text->angle ? "SBCR\n" : "SBC\n");
3071 break;
3072 case GL2PS_TEXT_BR:
3073 gl2psPrintf(prim->data.text->angle ? "SBRR\n" : "SBR\n");
3074 break;
3075 case GL2PS_TEXT_T:
3076 gl2psPrintf(prim->data.text->angle ? "STCR\n" : "STC\n");
3077 break;
3078 case GL2PS_TEXT_TL:
3079 gl2psPrintf(prim->data.text->angle ? "STLR\n" : "STL\n");
3080 break;
3081 case GL2PS_TEXT_TR:
3082 gl2psPrintf(prim->data.text->angle ? "STRR\n" : "STR\n");
3083 break;
3084 case GL2PS_TEXT_BL:
3085 default:
3086 gl2psPrintf(prim->data.text->angle ? "SR\n" : "S\n");
3087 break;
3088 }
3089 break;
3090 case GL2PS_SPECIAL :
3091 /* alignment contains the format for which the special output text
3092 is intended */
3093 if(prim->data.text->alignment == GL2PS_PS ||
3094 prim->data.text->alignment == GL2PS_EPS)
3095 gl2psPrintf("%s\n", prim->data.text->str);
3096 break;
3097 default :
3098 break;
3099 }
3100 }
3101
3102 static void gl2psPrintPostScriptFooter(void)
3103 {
3104 gl2psPrintf("grestore\n"
3105 "showpage\n"
3106 "cleartomark\n"
3107 "%%%%PageTrailer\n"
3108 "%%%%Trailer\n"
3109 "end\n"
3110 "%%%%EOF\n");
3111
3112 gl2psPrintGzipFooter();
3113 }
3114
3115 static void gl2psPrintPostScriptBeginViewport(GLint viewport[4])
3116 {
3117 GLint index;
3118 GLfloat rgba[4];
3119 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
3120
3121 glRenderMode(GL_FEEDBACK);
3122
3123 if(gl2ps->header){
3124 gl2psPrintPostScriptHeader();
3125 gl2ps->header = GL_FALSE;
3126 }
3127
3128 gl2psPrintf("gsave\n"
3129 "1.0 1.0 scale\n");
3130
3131 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
3132 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
3133 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
3134 }
3135 else{
3136 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
3137 rgba[0] = gl2ps->colormap[index][0];
3138 rgba[1] = gl2ps->colormap[index][1];
3139 rgba[2] = gl2ps->colormap[index][2];
3140 rgba[3] = 1.0F;
3141 }
3142 gl2psPrintf("%g %g %g C\n"
3143 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
3144 "closepath fill\n",
3145 rgba[0], rgba[1], rgba[2],
3146 x, y, x+w, y, x+w, y+h, x, y+h);
3147 }
3148
3149 gl2psPrintf("newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
3150 "closepath clip\n",
3151 x, y, x+w, y, x+w, y+h, x, y+h);
3152
3153 }
3154
3155 static GLint gl2psPrintPostScriptEndViewport(void)
3156 {
3157 GLint res;
3158
3159 res = gl2psPrintPrimitives();
3160 gl2psPrintf("grestore\n");
3161 return res;
3162 }
3163
3164 static void gl2psPrintPostScriptFinalPrimitive(void)
3165 {
3166 /* End any remaining line, if any */
3167 gl2psEndPostScriptLine();
3168 }
3169
3170 /* definition of the PostScript and Encapsulated PostScript backends */
3171
3172 static GL2PSbackend gl2psPS = {
3173 gl2psPrintPostScriptHeader,
3174 gl2psPrintPostScriptFooter,
3175 gl2psPrintPostScriptBeginViewport,
3176 gl2psPrintPostScriptEndViewport,
3177 gl2psPrintPostScriptPrimitive,
3178 gl2psPrintPostScriptFinalPrimitive,
3179 "ps",
3180 "Postscript"
3181 };
3182
3183 static GL2PSbackend gl2psEPS = {
3184 gl2psPrintPostScriptHeader,
3185 gl2psPrintPostScriptFooter,
3186 gl2psPrintPostScriptBeginViewport,
3187 gl2psPrintPostScriptEndViewport,
3188 gl2psPrintPostScriptPrimitive,
3189 gl2psPrintPostScriptFinalPrimitive,
3190 "eps",
3191 "Encapsulated Postscript"
3192 };
3193
3194 /*********************************************************************
3195 *
3196 * LaTeX routines
3197 *
3198 *********************************************************************/
3199
3200 static void gl2psPrintTeXHeader(void)
3201 {
3202 char name[256];
3203 time_t now;
3204 int i;
3205
3206 if(gl2ps->filename && strlen(gl2ps->filename) < 256){
3207 for(i = (int)strlen(gl2ps->filename) - 1; i >= 0; i--){
3208 if(gl2ps->filename[i] == '.'){
3209 strncpy(name, gl2ps->filename, i);
3210 name[i] = '\0';
3211 break;
3212 }
3213 }
3214 if(i <= 0) strcpy(name, gl2ps->filename);
3215 }
3216 else{
3217 strcpy(name, "untitled");
3218 }
3219
3220 time(&now);
3221
3222 fprintf(gl2ps->stream,
3223 "%% Title: %s\n"
3224 "%% Creator: GL2PS %d.%d.%d%s, %s\n"
3225 "%% For: %s\n"
3226 "%% CreationDate: %s",
3227 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
3228 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
3229 gl2ps->producer, ctime(&now));
3230
3231 fprintf(gl2ps->stream,
3232 "\\setlength{\\unitlength}{1pt}\n"
3233 "\\begin{picture}(0,0)\n"
3234 "\\includegraphics{%s}\n"
3235 "\\end{picture}%%\n"
3236 "%s\\begin{picture}(%d,%d)(0,0)\n",
3237 name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "",
3238 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
3239 }
3240
3241 static void gl2psPrintTeXPrimitive(void *data)
3242 {
3243 GL2PSprimitive *prim;
3244
3245 prim = *(GL2PSprimitive**)data;
3246
3247 switch(prim->type){
3248 case GL2PS_TEXT :
3249 fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont",
3250 prim->data.text->fontsize);
3251 fprintf(gl2ps->stream, "\\put(%g,%g)",
3252 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3253 if(prim->data.text->angle)
3254 fprintf(gl2ps->stream, "{\\rotatebox{%g}", prim->data.text->angle);
3255 fprintf(gl2ps->stream, "{\\makebox(0,0)");
3256 switch(prim->data.text->alignment){
3257 case GL2PS_TEXT_C:
3258 fprintf(gl2ps->stream, "{");
3259 break;
3260 case GL2PS_TEXT_CL:
3261 fprintf(gl2ps->stream, "[l]{");
3262 break;
3263 case GL2PS_TEXT_CR:
3264 fprintf(gl2ps->stream, "[r]{");
3265 break;
3266 case GL2PS_TEXT_B:
3267 fprintf(gl2ps->stream, "[b]{");
3268 break;
3269 case GL2PS_TEXT_BR:
3270 fprintf(gl2ps->stream, "[br]{");
3271 break;
3272 case GL2PS_TEXT_T:
3273 fprintf(gl2ps->stream, "[t]{");
3274 break;
3275 case GL2PS_TEXT_TL:
3276 fprintf(gl2ps->stream, "[tl]{");
3277 break;
3278 case GL2PS_TEXT_TR:
3279 fprintf(gl2ps->stream, "[tr]{");
3280 break;
3281 case GL2PS_TEXT_BL:
3282 default:
3283 fprintf(gl2ps->stream, "[bl]{");
3284 break;
3285 }
3286 fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}",
3287 prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2],
3288 prim->data.text->str);
3289 if(prim->data.text->angle)
3290 fprintf(gl2ps->stream, "}");
3291 fprintf(gl2ps->stream, "}}\n");
3292 break;
3293 case GL2PS_SPECIAL :
3294 /* alignment contains the format for which the special output text
3295 is intended */
3296 if (prim->data.text->alignment == GL2PS_TEX)
3297 fprintf(gl2ps->stream, "%s\n", prim->data.text->str);
3298 break;
3299 default :
3300 break;
3301 }
3302 }
3303
3304 static void gl2psPrintTeXFooter(void)
3305 {
3306 fprintf(gl2ps->stream, "\\end{picture}%s\n",
3307 (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : "");
3308 }
3309
3310 static void gl2psPrintTeXBeginViewport(GLint viewport[4])
3311 {
3312 (void) viewport; /* not used */
3313 glRenderMode(GL_FEEDBACK);
3314
3315 if(gl2ps->header){
3316 gl2psPrintTeXHeader();
3317 gl2ps->header = GL_FALSE;
3318 }
3319 }
3320
3321 static GLint gl2psPrintTeXEndViewport(void)
3322 {
3323 return gl2psPrintPrimitives();
3324 }
3325
3326 static void gl2psPrintTeXFinalPrimitive(void)
3327 {
3328 }
3329
3330 /* definition of the LaTeX backend */
3331
3332 static GL2PSbackend gl2psTEX = {
3333 gl2psPrintTeXHeader,
3334 gl2psPrintTeXFooter,
3335 gl2psPrintTeXBeginViewport,
3336 gl2psPrintTeXEndViewport,
3337 gl2psPrintTeXPrimitive,
3338 gl2psPrintTeXFinalPrimitive,
3339 "tex",
3340 "LaTeX text"
3341 };
3342
3343 /*********************************************************************
3344 *
3345 * PDF routines
3346 *
3347 *********************************************************************/
3348
3349 static int gl2psPrintPDFCompressorType(void)
3350 {
3351 #if defined(GL2PS_HAVE_ZLIB)
3352 if(gl2ps->options & GL2PS_COMPRESS){
3353 return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n");
3354 }
3355 #endif
3356 return 0;
3357 }
3358
3359 static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba)
3360 {
3361 int i, offs = 0;
3362
3363 gl2psSetLastColor(rgba);
3364 for(i = 0; i < 3; ++i){
3365 if(GL2PS_ZERO(rgba[i]))
3366 offs += gl2psPrintf("%.0f ", 0.);
3367 else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */
3368 offs += gl2psPrintf("%f ", rgba[i]);
3369 else
3370 offs += gl2psPrintf("%g ", rgba[i]);
3371 }
3372 offs += gl2psPrintf("RG\n");
3373 return offs;
3374 }
3375
3376 static int gl2psPrintPDFFillColor(GL2PSrgba rgba)
3377 {
3378 int i, offs = 0;
3379
3380 for(i = 0; i < 3; ++i){
3381 if(GL2PS_ZERO(rgba[i]))
3382 offs += gl2psPrintf("%.0f ", 0.);
3383 else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */
3384 offs += gl2psPrintf("%f ", rgba[i]);
3385 else
3386 offs += gl2psPrintf("%g ", rgba[i]);
3387 }
3388 offs += gl2psPrintf("rg\n");
3389 return offs;
3390 }
3391
3392 static int gl2psPrintPDFLineWidth(GLfloat lw)
3393 {
3394 if(GL2PS_ZERO(lw))
3395 return gl2psPrintf("%.0f w\n", 0.);
3396 else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */
3397 return gl2psPrintf("%f w\n", lw);
3398 else
3399 return gl2psPrintf("%g w\n", lw);
3400 }
3401
3402 static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y)
3403 {
3404 GLfloat rad, crad, srad;
3405
3406 if(text->angle == 0.0F){
3407 gl2ps->streamlength += gl2psPrintf
3408 ("BT\n"
3409 "/F%d %d Tf\n"
3410 "%f %f Td\n"
3411 "(%s) Tj\n"
3412 "ET\n",
3413 cnt, text->fontsize, x, y, text->str);
3414 }
3415 else{
3416 rad = (GLfloat)(M_PI * text->angle / 180.0F);
3417 srad = (GLfloat)sin(rad);
3418 crad = (GLfloat)cos(rad);
3419 gl2ps->streamlength += gl2psPrintf
3420 ("BT\n"
3421 "/F%d %d Tf\n"
3422 "%f %f %f %f %f %f Tm\n"
3423 "(%s) Tj\n"
3424 "ET\n",
3425 cnt, text->fontsize, crad, srad, -srad, crad, x, y, text->str);
3426 }
3427 }
3428
3429 static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y)
3430 {
3431 gl2ps->streamlength += gl2psPrintf
3432 ("q\n"
3433 "%d 0 0 %d %f %f cm\n"
3434 "/Im%d Do\n"
3435 "Q\n",
3436 (int)image->width, (int)image->height, x, y, cnt);
3437 }
3438
3439 static void gl2psPDFstacksInit(void)
3440 {
3441 gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1;
3442 gl2ps->extgs_stack = 0;
3443 gl2ps->font_stack = 0;
3444 gl2ps->im_stack = 0;
3445 gl2ps->trgroupobjects_stack = 0;
3446 gl2ps->shader_stack = 0;
3447 gl2ps->mshader_stack = 0;
3448 }
3449
3450 static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro)
3451 {
3452 if(!gro)
3453 return;
3454
3455 gro->ptrlist = NULL;
3456 gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno
3457 = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno
3458 = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1;
3459 }
3460
3461 /* Build up group objects and assign name and object numbers */
3462
3463 static void gl2psPDFgroupListInit(void)
3464 {
3465 int i;
3466 GL2PSprimitive *p = NULL;
3467 GL2PSpdfgroup gro;
3468 int lasttype = GL2PS_NO_TYPE;
3469 GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F};
3470 GLushort lastpattern = 0;
3471 GLint lastfactor = 0;
3472 GLfloat lastwidth = 1;
3473 GL2PStriangle lastt, tmpt;
3474 int lastTriangleWasNotSimpleWithSameColor = 0;
3475
3476 if(!gl2ps->pdfprimlist)
3477 return;
3478
3479 gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup));
3480 gl2psInitTriangle(&lastt);
3481
3482 for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){
3483 p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i);
3484 switch(p->type){
3485 case GL2PS_PIXMAP:
3486 gl2psPDFgroupObjectInit(&gro);
3487 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3488 gro.imno = gl2ps->im_stack++;
3489 gl2psListAdd(gro.ptrlist, &p);
3490 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3491 break;
3492 case GL2PS_TEXT:
3493 gl2psPDFgroupObjectInit(&gro);
3494 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3495 gro.fontno = gl2ps->font_stack++;
3496 gl2psListAdd(gro.ptrlist, &p);
3497 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3498 break;
3499 case GL2PS_LINE:
3500 if(lasttype != p->type || lastwidth != p->width ||
3501 lastpattern != p->pattern || lastfactor != p->factor ||
3502 !gl2psSameColor(p->verts[0].rgba, lastrgba)){
3503 gl2psPDFgroupObjectInit(&gro);
3504 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3505 gl2psListAdd(gro.ptrlist, &p);
3506 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3507 }
3508 else{
3509 gl2psListAdd(gro.ptrlist, &p);
3510 }
3511 lastpattern = p->pattern;
3512 lastfactor = p->factor;
3513 lastwidth = p->width;
3514 lastrgba[0] = p->verts[0].rgba[0];
3515 lastrgba[1] = p->verts[0].rgba[1];
3516 lastrgba[2] = p->verts[0].rgba[2];
3517 break;
3518 case GL2PS_POINT:
3519 if(lasttype != p->type || lastwidth != p->width ||
3520 !gl2psSameColor(p->verts[0].rgba, lastrgba)){
3521 gl2psPDFgroupObjectInit(&gro);
3522 gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*));
3523 gl2psListAdd(gro.ptrlist, &p);
3524 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3525 }
3526 else{
3527 gl2psListAdd(gro.ptrlist, &p);
3528 }
3529 lastwidth = p->width;
3530 lastrgba[0] = p->verts[0].rgba[0];
3531 lastrgba[1] = p->verts[0].rgba[1];
3532 lastrgba[2] = p->verts[0].rgba[2];
3533 break;
3534 case GL2PS_TRIANGLE:
3535 gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE);
3536 lastTriangleWasNotSimpleWithSameColor =
3537 !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) ||
3538 !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba);
3539 if(lasttype == p->type && tmpt.prop == lastt.prop &&
3540 lastTriangleWasNotSimpleWithSameColor){
3541 /* TODO Check here for last alpha */
3542 gl2psListAdd(gro.ptrlist, &p);
3543 }
3544 else{
3545 gl2psPDFgroupObjectInit(&gro);
3546 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
3547 gl2psListAdd(gro.ptrlist, &p);
3548 gl2psListAdd(gl2ps->pdfgrouplist, &gro);
3549 }
3550 lastt = tmpt;
3551 break;
3552 default:
3553 break;
3554 }
3555 lasttype = p->type;
3556 }
3557 }
3558
3559 static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro)
3560 {
3561 GL2PStriangle t;
3562 GL2PSprimitive *prim = NULL;
3563
3564 if(!gro)
3565 return;
3566
3567 if(!gl2psListNbr(gro->ptrlist))
3568 return;
3569
3570 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3571
3572 if(prim->type != GL2PS_TRIANGLE)
3573 return;
3574
3575 gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
3576
3577 if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){
3578 gro->gsno = gl2ps->extgs_stack++;
3579 gro->gsobjno = gl2ps->objects_stack ++;
3580 }
3581 else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){
3582 gro->gsno = gl2ps->extgs_stack++;
3583 gro->gsobjno = gl2ps->objects_stack++;
3584 gro->trgroupno = gl2ps->trgroupobjects_stack++;
3585 gro->trgroupobjno = gl2ps->objects_stack++;
3586 gro->maskshno = gl2ps->mshader_stack++;
3587 gro->maskshobjno = gl2ps->objects_stack++;
3588 }
3589 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){
3590 gro->shno = gl2ps->shader_stack++;
3591 gro->shobjno = gl2ps->objects_stack++;
3592 }
3593 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){
3594 gro->gsno = gl2ps->extgs_stack++;
3595 gro->gsobjno = gl2ps->objects_stack++;
3596 gro->shno = gl2ps->shader_stack++;
3597 gro->shobjno = gl2ps->objects_stack++;
3598 }
3599 else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){
3600 gro->gsno = gl2ps->extgs_stack++;
3601 gro->gsobjno = gl2ps->objects_stack++;
3602 gro->shno = gl2ps->shader_stack++;
3603 gro->shobjno = gl2ps->objects_stack++;
3604 gro->trgroupno = gl2ps->trgroupobjects_stack++;
3605 gro->trgroupobjno = gl2ps->objects_stack++;
3606 gro->maskshno = gl2ps->mshader_stack++;
3607 gro->maskshobjno = gl2ps->objects_stack++;
3608 }
3609 }
3610
3611 /* Main stream data */
3612
3613 static void gl2psPDFgroupListWriteMainStream(void)
3614 {
3615 int i, j, lastel;
3616 GL2PSprimitive *prim = NULL, *prev = NULL;
3617 GL2PSpdfgroup *gro;
3618 GL2PStriangle t;
3619
3620 if(!gl2ps->pdfgrouplist)
3621 return;
3622
3623 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3624 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3625
3626 lastel = gl2psListNbr(gro->ptrlist) - 1;
3627 if(lastel < 0)
3628 continue;
3629
3630 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3631
3632 switch(prim->type){
3633 case GL2PS_POINT:
3634 gl2ps->streamlength += gl2psPrintf("1 J\n");
3635 gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
3636 gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
3637 for(j = 0; j <= lastel; ++j){
3638 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3639 gl2ps->streamlength +=
3640 gl2psPrintf("%f %f m %f %f l\n",
3641 prim->verts[0].xyz[0], prim->verts[0].xyz[1],
3642 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3643 }
3644 gl2ps->streamlength += gl2psPrintf("S\n");
3645 gl2ps->streamlength += gl2psPrintf("0 J\n");
3646 break;
3647 case GL2PS_LINE:
3648 /* We try to use as few paths as possible to draw lines, in
3649 order to get nice stippling even when the individual segments
3650 are smaller than the stipple */
3651 gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width);
3652 gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba);
3653 gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d");
3654 /* start new path */
3655 gl2ps->streamlength +=
3656 gl2psPrintf("%f %f m\n",
3657 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3658
3659 for(j = 1; j <= lastel; ++j){
3660 prev = prim;
3661 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3662 if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){
3663 /* the starting point of the new segment does not match the
3664 end point of the previous line, so we end the current
3665 path and start a new one */
3666 gl2ps->streamlength +=
3667 gl2psPrintf("%f %f l\n",
3668 prev->verts[1].xyz[0], prev->verts[1].xyz[1]);
3669 gl2ps->streamlength +=
3670 gl2psPrintf("%f %f m\n",
3671 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3672 }
3673 else{
3674 /* the two segements are connected, so we just append to the
3675 current path */
3676 gl2ps->streamlength +=
3677 gl2psPrintf("%f %f l\n",
3678 prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
3679 }
3680 }
3681 /* end last path */
3682 gl2ps->streamlength +=
3683 gl2psPrintf("%f %f l\n",
3684 prim->verts[1].xyz[0], prim->verts[1].xyz[1]);
3685 gl2ps->streamlength += gl2psPrintf("S\n");
3686 break;
3687 case GL2PS_TRIANGLE:
3688 gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE);
3689 gl2psSortOutTrianglePDFgroup(gro);
3690
3691 /* No alpha and const color: Simple PDF draw orders */
3692 if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){
3693 gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba);
3694 for(j = 0; j <= lastel; ++j){
3695 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3696 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3697 gl2ps->streamlength
3698 += gl2psPrintf("%f %f m\n"
3699 "%f %f l\n"
3700 "%f %f l\n"
3701 "h f\n",
3702 t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3703 t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3704 t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3705 }
3706 }
3707 /* Const alpha < 1 and const color: Simple PDF draw orders
3708 and an extra extended Graphics State for the alpha const */
3709 else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){
3710 gl2ps->streamlength += gl2psPrintf("q\n"
3711 "/GS%d gs\n",
3712 gro->gsno);
3713 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3714 for(j = 0; j <= lastel; ++j){
3715 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3716 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3717 gl2ps->streamlength
3718 += gl2psPrintf("%f %f m\n"
3719 "%f %f l\n"
3720 "%f %f l\n"
3721 "h f\n",
3722 t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3723 t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3724 t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3725 }
3726 gl2ps->streamlength += gl2psPrintf("Q\n");
3727 }
3728 /* Variable alpha and const color: Simple PDF draw orders
3729 and an extra extended Graphics State + Xobject + Shader
3730 object for the alpha mask */
3731 else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){
3732 gl2ps->streamlength += gl2psPrintf("q\n"
3733 "/GS%d gs\n"
3734 "/TrG%d Do\n",
3735 gro->gsno, gro->trgroupno);
3736 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3737 for(j = 0; j <= lastel; ++j){
3738 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3739 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE);
3740 gl2ps->streamlength
3741 += gl2psPrintf("%f %f m\n"
3742 "%f %f l\n"
3743 "%f %f l\n"
3744 "h f\n",
3745 t.vertex[0].xyz[0], t.vertex[0].xyz[1],
3746 t.vertex[1].xyz[0], t.vertex[1].xyz[1],
3747 t.vertex[2].xyz[0], t.vertex[2].xyz[1]);
3748 }
3749 gl2ps->streamlength += gl2psPrintf("Q\n");
3750 }
3751 /* Variable color and no alpha: Shader Object for the colored
3752 triangle(s) */
3753 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){
3754 gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno);
3755 }
3756 /* Variable color and const alpha < 1: Shader Object for the
3757 colored triangle(s) and an extra extended Graphics State
3758 for the alpha const */
3759 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){
3760 gl2ps->streamlength += gl2psPrintf("q\n"
3761 "/GS%d gs\n"
3762 "/Sh%d sh\n"
3763 "Q\n",
3764 gro->gsno, gro->shno);
3765 }
3766 /* Variable alpha and color: Shader Object for the colored
3767 triangle(s) and an extra extended Graphics State
3768 + Xobject + Shader object for the alpha mask */
3769 else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){
3770 gl2ps->streamlength += gl2psPrintf("q\n"
3771 "/GS%d gs\n"
3772 "/TrG%d Do\n"
3773 "/Sh%d sh\n"
3774 "Q\n",
3775 gro->gsno, gro->trgroupno, gro->shno);
3776 }
3777 break;
3778 case GL2PS_PIXMAP:
3779 for(j = 0; j <= lastel; ++j){
3780 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3781 gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0],
3782 prim->verts[0].xyz[1]);
3783 }
3784 break;
3785 case GL2PS_TEXT:
3786 for(j = 0; j <= lastel; ++j){
3787 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
3788 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba);
3789 gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0],
3790 prim->verts[0].xyz[1]);
3791 }
3792 break;
3793 default:
3794 break;
3795 }
3796 }
3797 }
3798
3799 /* Graphics State names */
3800
3801 static int gl2psPDFgroupListWriteGStateResources(void)
3802 {
3803 GL2PSpdfgroup *gro;
3804 int offs = 0;
3805 int i;
3806
3807 offs += fprintf(gl2ps->stream,
3808 "/ExtGState\n"
3809 "<<\n"
3810 "/GSa 7 0 R\n");
3811 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3812 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3813 if(gro->gsno >= 0)
3814 offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno);
3815 }
3816 offs += fprintf(gl2ps->stream, ">>\n");
3817 return offs;
3818 }
3819
3820 /* Main Shader names */
3821
3822 static int gl2psPDFgroupListWriteShaderResources(void)
3823 {
3824 GL2PSpdfgroup *gro;
3825 int offs = 0;
3826 int i;
3827
3828 offs += fprintf(gl2ps->stream,
3829 "/Shading\n"
3830 "<<\n");
3831 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3832 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3833 if(gro->shno >= 0)
3834 offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno);
3835 if(gro->maskshno >= 0)
3836 offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno);
3837 }
3838 offs += fprintf(gl2ps->stream,">>\n");
3839 return offs;
3840 }
3841
3842 /* Images & Mask Shader XObject names */
3843
3844 static int gl2psPDFgroupListWriteXObjectResources(void)
3845 {
3846 int i;
3847 GL2PSprimitive *p = NULL;
3848 GL2PSpdfgroup *gro;
3849 int offs = 0;
3850
3851 offs += fprintf(gl2ps->stream,
3852 "/XObject\n"
3853 "<<\n");
3854
3855 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3856 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3857 if(!gl2psListNbr(gro->ptrlist))
3858 continue;
3859 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
3860 switch(p->type){
3861 case GL2PS_PIXMAP:
3862 gro->imobjno = gl2ps->objects_stack++;
3863 if(GL_RGBA == p->data.image->format) /* reserve one object for image mask */
3864 gl2ps->objects_stack++;
3865 offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno);
3866 case GL2PS_TRIANGLE:
3867 if(gro->trgroupno >=0)
3868 offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno);
3869 break;
3870 default:
3871 break;
3872 }
3873 }
3874 offs += fprintf(gl2ps->stream,">>\n");
3875 return offs;
3876 }
3877
3878 /* Font names */
3879
3880 static int gl2psPDFgroupListWriteFontResources(void)
3881 {
3882 int i;
3883 GL2PSpdfgroup *gro;
3884 int offs = 0;
3885
3886 offs += fprintf(gl2ps->stream, "/Font\n<<\n");
3887
3888 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3889 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
3890 if(gro->fontno < 0)
3891 continue;
3892 gro->fontobjno = gl2ps->objects_stack++;
3893 offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno);
3894 }
3895 offs += fprintf(gl2ps->stream, ">>\n");
3896
3897 return offs;
3898 }
3899
3900 static void gl2psPDFgroupListDelete(void)
3901 {
3902 int i;
3903 GL2PSpdfgroup *gro = NULL;
3904
3905 if(!gl2ps->pdfgrouplist)
3906 return;
3907
3908 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
3909 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i);
3910 gl2psListDelete(gro->ptrlist);
3911 }
3912
3913 gl2psListDelete(gl2ps->pdfgrouplist);
3914 gl2ps->pdfgrouplist = NULL;
3915 }
3916
3917 /* Print 1st PDF object - file info */
3918
3919 static int gl2psPrintPDFInfo(void)
3920 {
3921 int offs;
3922 time_t now;
3923 struct tm *newtime;
3924
3925 time(&now);
3926 newtime = gmtime(&now);
3927
3928 offs = fprintf(gl2ps->stream,
3929 "1 0 obj\n"
3930 "<<\n"
3931 "/Title (%s)\n"
3932 "/Creator (GL2PS %d.%d.%d%s, %s)\n"
3933 "/Producer (%s)\n",
3934 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION,
3935 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT,
3936 gl2ps->producer);
3937
3938 if(!newtime){
3939 offs += fprintf(gl2ps->stream,
3940 ">>\n"
3941 "endobj\n");
3942 return offs;
3943 }
3944
3945 offs += fprintf(gl2ps->stream,
3946 "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n"
3947 ">>\n"
3948 "endobj\n",
3949 newtime->tm_year+1900,
3950 newtime->tm_mon+1,
3951 newtime->tm_mday,
3952 newtime->tm_hour,
3953 newtime->tm_min,
3954 newtime->tm_sec);
3955 return offs;
3956 }
3957
3958 /* Create catalog and page structure - 2nd and 3th PDF object */
3959
3960 static int gl2psPrintPDFCatalog(void)
3961 {
3962 return fprintf(gl2ps->stream,
3963 "2 0 obj\n"
3964 "<<\n"
3965 "/Type /Catalog\n"
3966 "/Pages 3 0 R\n"
3967 ">>\n"
3968 "endobj\n");
3969 }
3970
3971 static int gl2psPrintPDFPages(void)
3972 {
3973 return fprintf(gl2ps->stream,
3974 "3 0 obj\n"
3975 "<<\n"
3976 "/Type /Pages\n"
3977 "/Kids [6 0 R]\n"
3978 "/Count 1\n"
3979 ">>\n"
3980 "endobj\n");
3981 }
3982
3983 /* Open stream for data - graphical objects, fonts etc. PDF object 4 */
3984
3985 static int gl2psOpenPDFDataStream(void)
3986 {
3987 int offs = 0;
3988
3989 offs += fprintf(gl2ps->stream,
3990 "4 0 obj\n"
3991 "<<\n"
3992 "/Length 5 0 R\n" );
3993 offs += gl2psPrintPDFCompressorType();
3994 offs += fprintf(gl2ps->stream,
3995 ">>\n"
3996 "stream\n");
3997 return offs;
3998 }
3999
4000 /* Stream setup - Graphics state, fill background if allowed */
4001
4002 static int gl2psOpenPDFDataStreamWritePreface(void)
4003 {
4004 int offs;
4005
4006 offs = gl2psPrintf("/GSa gs\n");
4007
4008 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
4009 offs += gl2psPrintPDFFillColor(gl2ps->bgcolor);
4010 offs += gl2psPrintf("%d %d %d %d re\n",
4011 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4012 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4013 offs += gl2psPrintf("f\n");
4014 }
4015 return offs;
4016 }
4017
4018 /* Use the functions above to create the first part of the PDF*/
4019
4020 static void gl2psPrintPDFHeader(void)
4021 {
4022 int offs = 0;
4023 gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
4024 gl2psPDFstacksInit();
4025
4026 gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack);
4027
4028 #if defined(GL2PS_HAVE_ZLIB)
4029 if(gl2ps->options & GL2PS_COMPRESS){
4030 gl2psSetupCompress();
4031 }
4032 #endif
4033 gl2ps->xreflist[0] = 0;
4034 offs += fprintf(gl2ps->stream, "%%PDF-1.4\n");
4035 gl2ps->xreflist[1] = offs;
4036
4037 offs += gl2psPrintPDFInfo();
4038 gl2ps->xreflist[2] = offs;
4039
4040 offs += gl2psPrintPDFCatalog();
4041 gl2ps->xreflist[3] = offs;
4042
4043 offs += gl2psPrintPDFPages();
4044 gl2ps->xreflist[4] = offs;
4045
4046 offs += gl2psOpenPDFDataStream();
4047 gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */
4048 gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface();
4049 }
4050
4051 /* The central primitive drawing */
4052
4053 static void gl2psPrintPDFPrimitive(void *data)
4054 {
4055 GL2PSprimitive *prim = *(GL2PSprimitive**)data;
4056
4057 if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled)
4058 return;
4059
4060 prim = gl2psCopyPrimitive(prim); /* deep copy */
4061 gl2psListAdd(gl2ps->pdfprimlist, &prim);
4062 }
4063
4064 /* close stream and ... */
4065
4066 static int gl2psClosePDFDataStream(void)
4067 {
4068 int offs = 0;
4069
4070 #if defined(GL2PS_HAVE_ZLIB)
4071 if(gl2ps->options & GL2PS_COMPRESS){
4072 if(Z_OK != gl2psDeflate())
4073 gl2psMsg(GL2PS_ERROR, "Zlib deflate error");
4074 else
4075 fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream);
4076 gl2ps->streamlength += gl2ps->compress->destLen;
4077
4078 offs += gl2ps->streamlength;
4079 gl2psFreeCompress();
4080 }
4081 #endif
4082
4083 offs += fprintf(gl2ps->stream,
4084 "endstream\n"
4085 "endobj\n");
4086 return offs;
4087 }
4088
4089 /* ... write the now known length object */
4090
4091 static int gl2psPrintPDFDataStreamLength(int val)
4092 {
4093 return fprintf(gl2ps->stream,
4094 "5 0 obj\n"
4095 "%d\n"
4096 "endobj\n", val);
4097 }
4098
4099 /* Put the info created before in PDF objects */
4100
4101 static int gl2psPrintPDFOpenPage(void)
4102 {
4103 int offs;
4104
4105 /* Write fixed part */
4106
4107 offs = fprintf(gl2ps->stream,
4108 "6 0 obj\n"
4109 "<<\n"
4110 "/Type /Page\n"
4111 "/Parent 3 0 R\n"
4112 "/MediaBox [%d %d %d %d]\n",
4113 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4114 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4115
4116 if(gl2ps->options & GL2PS_LANDSCAPE)
4117 offs += fprintf(gl2ps->stream, "/Rotate -90\n");
4118
4119 offs += fprintf(gl2ps->stream,
4120 "/Contents 4 0 R\n"
4121 "/Resources\n"
4122 "<<\n"
4123 "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n");
4124
4125 return offs;
4126
4127 /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */
4128 }
4129
4130 static int gl2psPDFgroupListWriteVariableResources(void)
4131 {
4132 int offs = 0;
4133
4134 /* a) Graphics States for shader alpha masks*/
4135 offs += gl2psPDFgroupListWriteGStateResources();
4136
4137 /* b) Shader and shader masks */
4138 offs += gl2psPDFgroupListWriteShaderResources();
4139
4140 /* c) XObjects (Images & Shader Masks) */
4141 offs += gl2psPDFgroupListWriteXObjectResources();
4142
4143 /* d) Fonts */
4144 offs += gl2psPDFgroupListWriteFontResources();
4145
4146 /* End resources and page */
4147 offs += fprintf(gl2ps->stream,
4148 ">>\n"
4149 ">>\n"
4150 "endobj\n");
4151 return offs;
4152 }
4153
4154 /* Standard Graphics State */
4155
4156 static int gl2psPrintPDFGSObject(void)
4157 {
4158 return fprintf(gl2ps->stream,
4159 "7 0 obj\n"
4160 "<<\n"
4161 "/Type /ExtGState\n"
4162 "/SA false\n"
4163 "/SM 0.02\n"
4164 "/OP false\n"
4165 "/op false\n"
4166 "/OPM 0\n"
4167 "/BG2 /Default\n"
4168 "/UCR2 /Default\n"
4169 "/TR2 /Default\n"
4170 ">>\n"
4171 "endobj\n");
4172 }
4173
4174 /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */
4175
4176 static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex,
4177 int (*action)(unsigned long data, int size),
4178 GLfloat dx, GLfloat dy,
4179 GLfloat xmin, GLfloat ymin)
4180 {
4181 int offs = 0;
4182 unsigned long imap;
4183 GLfloat diff;
4184 double dmax = ~1UL;
4185 char edgeflag = 0;
4186
4187 /* FIXME: temp bux fix for 64 bit archs: */
4188 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4189
4190 offs += (*action)(edgeflag, 1);
4191
4192 /* The Shader stream in PDF requires to be in a 'big-endian'
4193 order */
4194
4195 if(GL2PS_ZERO(dx * dy)){
4196 offs += (*action)(0, 4);
4197 offs += (*action)(0, 4);
4198 }
4199 else{
4200 diff = (vertex->xyz[0] - xmin) / dx;
4201 if(diff > 1)
4202 diff = 1.0F;
4203 else if(diff < 0)
4204 diff = 0.0F;
4205 imap = (unsigned long)(diff * dmax);
4206 offs += (*action)(imap, 4);
4207
4208 diff = (vertex->xyz[1] - ymin) / dy;
4209 if(diff > 1)
4210 diff = 1.0F;
4211 else if(diff < 0)
4212 diff = 0.0F;
4213 imap = (unsigned long)(diff * dmax);
4214 offs += (*action)(imap, 4);
4215 }
4216
4217 return offs;
4218 }
4219
4220 /* Put vertex' rgb value (8bit for every component) in shader stream */
4221
4222 static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex,
4223 int (*action)(unsigned long data, int size))
4224 {
4225 int offs = 0;
4226 unsigned long imap;
4227 double dmax = ~1UL;
4228
4229 /* FIXME: temp bux fix for 64 bit archs: */
4230 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4231
4232 imap = (unsigned long)((vertex->rgba[0]) * dmax);
4233 offs += (*action)(imap, 1);
4234
4235 imap = (unsigned long)((vertex->rgba[1]) * dmax);
4236 offs += (*action)(imap, 1);
4237
4238 imap = (unsigned long)((vertex->rgba[2]) * dmax);
4239 offs += (*action)(imap, 1);
4240
4241 return offs;
4242 }
4243
4244 /* Put vertex' alpha (8/16bit) in shader stream */
4245
4246 static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex,
4247 int (*action)(unsigned long data, int size),
4248 int sigbyte)
4249 {
4250 int offs = 0;
4251 unsigned long imap;
4252 double dmax = ~1UL;
4253
4254 /* FIXME: temp bux fix for 64 bit archs: */
4255 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.;
4256
4257 if(sigbyte != 8 && sigbyte != 16)
4258 sigbyte = 8;
4259
4260 sigbyte /= 8;
4261
4262 imap = (unsigned long)((vertex->rgba[3]) * dmax);
4263
4264 offs += (*action)(imap, sigbyte);
4265
4266 return offs;
4267 }
4268
4269 /* Put a triangles raw data in shader stream */
4270
4271 static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle,
4272 GLfloat dx, GLfloat dy,
4273 GLfloat xmin, GLfloat ymin,
4274 int (*action)(unsigned long data, int size),
4275 int gray)
4276 {
4277 int i, offs = 0;
4278 GL2PSvertex v;
4279
4280 if(gray && gray != 8 && gray != 16)
4281 gray = 8;
4282
4283 for(i = 0; i < 3; ++i){
4284 offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action,
4285 dx, dy, xmin, ymin);
4286 if(gray){
4287 v = triangle->vertex[i];
4288 offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray);
4289 }
4290 else{
4291 offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action);
4292 }
4293 }
4294
4295 return offs;
4296 }
4297
4298 static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax,
4299 GLfloat *ymin, GLfloat *ymax,
4300 GL2PStriangle *triangles, int cnt)
4301 {
4302 int i, j;
4303
4304 *xmin = triangles[0].vertex[0].xyz[0];
4305 *xmax = triangles[0].vertex[0].xyz[0];
4306 *ymin = triangles[0].vertex[0].xyz[1];
4307 *ymax = triangles[0].vertex[0].xyz[1];
4308
4309 for(i = 0; i < cnt; ++i){
4310 for(j = 0; j < 3; ++j){
4311 if(*xmin > triangles[i].vertex[j].xyz[0])
4312 *xmin = triangles[i].vertex[j].xyz[0];
4313 if(*xmax < triangles[i].vertex[j].xyz[0])
4314 *xmax = triangles[i].vertex[j].xyz[0];
4315 if(*ymin > triangles[i].vertex[j].xyz[1])
4316 *ymin = triangles[i].vertex[j].xyz[1];
4317 if(*ymax < triangles[i].vertex[j].xyz[1])
4318 *ymax = triangles[i].vertex[j].xyz[1];
4319 }
4320 }
4321 }
4322
4323 /* Writes shaded triangle
4324 gray == 0 means write RGB triangles
4325 gray == 8 8bit-grayscale (for alpha masks)
4326 gray == 16 16bit-grayscale (for alpha masks) */
4327
4328 static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles,
4329 int size, int gray)
4330 {
4331 int i, offs = 0, vertexbytes, done = 0;
4332 GLfloat xmin, xmax, ymin, ymax;
4333
4334 switch(gray){
4335 case 0:
4336 vertexbytes = 1+4+4+1+1+1;
4337 break;
4338 case 8:
4339 vertexbytes = 1+4+4+1;
4340 break;
4341 case 16:
4342 vertexbytes = 1+4+4+2;
4343 break;
4344 default:
4345 gray = 8;
4346 vertexbytes = 1+4+4+1;
4347 break;
4348 }
4349
4350 gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size);
4351
4352 offs += fprintf(gl2ps->stream,
4353 "%d 0 obj\n"
4354 "<< "
4355 "/ShadingType 4 "
4356 "/ColorSpace %s "
4357 "/BitsPerCoordinate 32 "
4358 "/BitsPerComponent %d "
4359 "/BitsPerFlag 8 "
4360 "/Decode [%f %f %f %f 0 1 %s] ",
4361 obj,
4362 (gray) ? "/DeviceGray" : "/DeviceRGB",
4363 (gray) ? gray : 8,
4364 xmin, xmax, ymin, ymax,
4365 (gray) ? "" : "0 1 0 1");
4366
4367 #if defined(GL2PS_HAVE_ZLIB)
4368 if(gl2ps->options & GL2PS_COMPRESS){
4369 gl2psAllocCompress(vertexbytes * size * 3);
4370
4371 for(i = 0; i < size; ++i)
4372 gl2psPrintPDFShaderStreamData(&triangles[i],
4373 xmax-xmin, ymax-ymin, xmin, ymin,
4374 gl2psWriteBigEndianCompress, gray);
4375
4376 if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4377 offs += gl2psPrintPDFCompressorType();
4378 offs += fprintf(gl2ps->stream,
4379 "/Length %d "
4380 ">>\n"
4381 "stream\n",
4382 (int)gl2ps->compress->destLen);
4383 offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest,
4384 gl2ps->compress->destLen,
4385 1, gl2ps->stream);
4386 done = 1;
4387 }
4388 gl2psFreeCompress();
4389 }
4390 #endif
4391
4392 if(!done){
4393 /* no compression, or too long after compression, or compress error
4394 -> write non-compressed entry */
4395 offs += fprintf(gl2ps->stream,
4396 "/Length %d "
4397 ">>\n"
4398 "stream\n",
4399 vertexbytes * 3 * size);
4400 for(i = 0; i < size; ++i)
4401 offs += gl2psPrintPDFShaderStreamData(&triangles[i],
4402 xmax-xmin, ymax-ymin, xmin, ymin,
4403 gl2psWriteBigEndian, gray);
4404 }
4405
4406 offs += fprintf(gl2ps->stream,
4407 "\nendstream\n"
4408 "endobj\n");
4409
4410 return offs;
4411 }
4412
4413 /* Writes a XObject for a shaded triangle mask */
4414
4415 static int gl2psPrintPDFShaderMask(int obj, int childobj)
4416 {
4417 int offs = 0, len;
4418
4419 offs += fprintf(gl2ps->stream,
4420 "%d 0 obj\n"
4421 "<<\n"
4422 "/Type /XObject\n"
4423 "/Subtype /Form\n"
4424 "/BBox [ %d %d %d %d ]\n"
4425 "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n"
4426 ">>\n",
4427 obj,
4428 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1],
4429 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]);
4430
4431 len = (childobj>0)
4432 ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1
4433 : strlen("/TrSh0 sh\n");
4434
4435 offs += fprintf(gl2ps->stream,
4436 "/Length %d\n"
4437 ">>\n"
4438 "stream\n",
4439 len);
4440 offs += fprintf(gl2ps->stream,
4441 "/TrSh%d sh\n",
4442 childobj);
4443 offs += fprintf(gl2ps->stream,
4444 "endstream\n"
4445 "endobj\n");
4446
4447 return offs;
4448 }
4449
4450 /* Writes a Extended graphics state for a shaded triangle mask if
4451 simplealpha ist true the childobj argument is ignored and a /ca
4452 statement will be written instead */
4453
4454 static int gl2psPrintPDFShaderExtGS(int obj, int childobj)
4455 {
4456 int offs = 0;
4457
4458 offs += fprintf(gl2ps->stream,
4459 "%d 0 obj\n"
4460 "<<\n",
4461 obj);
4462
4463 offs += fprintf(gl2ps->stream,
4464 "/SMask << /S /Alpha /G %d 0 R >> ",
4465 childobj);
4466
4467 offs += fprintf(gl2ps->stream,
4468 ">>\n"
4469 "endobj\n");
4470 return offs;
4471 }
4472
4473 /* a simple graphics state */
4474
4475 static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha)
4476 {
4477 int offs = 0;
4478
4479 offs += fprintf(gl2ps->stream,
4480 "%d 0 obj\n"
4481 "<<\n"
4482 "/ca %g"
4483 ">>\n"
4484 "endobj\n",
4485 obj, alpha);
4486 return offs;
4487 }
4488
4489 /* Similar groups of functions for pixmaps and text */
4490
4491 static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im,
4492 int (*action)(unsigned long data, int size),
4493 int gray)
4494 {
4495 int x, y, shift;
4496 GLfloat r, g, b, a;
4497
4498 if(im->format != GL_RGBA && gray)
4499 return 0;
4500
4501 if(gray && gray != 8 && gray != 16)
4502 gray = 8;
4503
4504 gray /= 8;
4505
4506 shift = (sizeof(unsigned long) - 1) * 8;
4507
4508 for(y = 0; y < im->height; ++y){
4509 for(x = 0; x < im->width; ++x){
4510 a = gl2psGetRGB(im, x, y, &r, &g, &b);
4511 if(im->format == GL_RGBA && gray){
4512 (*action)((unsigned long)(a * 255) << shift, gray);
4513 }
4514 else{
4515 (*action)((unsigned long)(r * 255) << shift, 1);
4516 (*action)((unsigned long)(g * 255) << shift, 1);
4517 (*action)((unsigned long)(b * 255) << shift, 1);
4518 }
4519 }
4520 }
4521
4522 switch(gray){
4523 case 0: return 3 * im->width * im->height;
4524 case 1: return im->width * im->height;
4525 case 2: return 2 * im->width * im->height;
4526 default: return 3 * im->width * im->height;
4527 }
4528 }
4529
4530 static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray)
4531 {
4532 int offs = 0, done = 0, sigbytes = 3;
4533
4534 if(gray && gray !=8 && gray != 16)
4535 gray = 8;
4536
4537 if(gray)
4538 sigbytes = gray / 8;
4539
4540 offs += fprintf(gl2ps->stream,
4541 "%d 0 obj\n"
4542 "<<\n"
4543 "/Type /XObject\n"
4544 "/Subtype /Image\n"
4545 "/Width %d\n"
4546 "/Height %d\n"
4547 "/ColorSpace %s \n"
4548 "/BitsPerComponent 8\n",
4549 obj,
4550 (int)im->width, (int)im->height,
4551 (gray) ? "/DeviceGray" : "/DeviceRGB" );
4552 if(GL_RGBA == im->format && gray == 0){
4553 offs += fprintf(gl2ps->stream,
4554 "/SMask %d 0 R\n",
4555 childobj);
4556 }
4557
4558 #if defined(GL2PS_HAVE_ZLIB)
4559 if(gl2ps->options & GL2PS_COMPRESS){
4560 gl2psAllocCompress((int)(im->width * im->height * sigbytes));
4561
4562 gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray);
4563
4564 if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){
4565 offs += gl2psPrintPDFCompressorType();
4566 offs += fprintf(gl2ps->stream,
4567 "/Length %d "
4568 ">>\n"
4569 "stream\n",
4570 (int)gl2ps->compress->destLen);
4571 offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen,
4572 1, gl2ps->stream);
4573 done = 1;
4574 }
4575 gl2psFreeCompress();
4576 }
4577 #endif
4578
4579 if(!done){
4580 /* no compression, or too long after compression, or compress error
4581 -> write non-compressed entry */
4582 offs += fprintf(gl2ps->stream,
4583 "/Length %d "
4584 ">>\n"
4585 "stream\n",
4586 (int)(im->width * im->height * sigbytes));
4587 offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray);
4588 }
4589
4590 offs += fprintf(gl2ps->stream,
4591 "\nendstream\n"
4592 "endobj\n");
4593
4594 return offs;
4595 }
4596
4597 static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber)
4598 {
4599 int offs = 0;
4600
4601 offs += fprintf(gl2ps->stream,
4602 "%d 0 obj\n"
4603 "<<\n"
4604 "/Type /Font\n"
4605 "/Subtype /Type1\n"
4606 "/Name /F%d\n"
4607 "/BaseFont /%s\n"
4608 "/Encoding /MacRomanEncoding\n"
4609 ">>\n"
4610 "endobj\n",
4611 obj, fontnumber, s->fontname);
4612 return offs;
4613 }
4614
4615 /* Write the physical objects */
4616
4617 static int gl2psPDFgroupListWriteObjects(int entryoffs)
4618 {
4619 int i,j;
4620 GL2PSprimitive *p = NULL;
4621 GL2PSpdfgroup *gro;
4622 int offs = entryoffs;
4623 GL2PStriangle *triangles;
4624 int size = 0;
4625
4626 if(!gl2ps->pdfgrouplist)
4627 return offs;
4628
4629 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){
4630 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i);
4631 if(!gl2psListNbr(gro->ptrlist))
4632 continue;
4633 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0);
4634 switch(p->type){
4635 case GL2PS_POINT:
4636 break;
4637 case GL2PS_LINE:
4638 break;
4639 case GL2PS_TRIANGLE:
4640 size = gl2psListNbr(gro->ptrlist);
4641 triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size);
4642 for(j = 0; j < size; ++j){
4643 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j);
4644 gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE);
4645 }
4646 if(triangles[0].prop & T_VAR_COLOR){
4647 gl2ps->xreflist[gro->shobjno] = offs;
4648 offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0);
4649 }
4650 if(triangles[0].prop & T_ALPHA_LESS_1){
4651 gl2ps->xreflist[gro->gsobjno] = offs;
4652 offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]);
4653 }
4654 if(triangles[0].prop & T_VAR_ALPHA){
4655 gl2ps->xreflist[gro->gsobjno] = offs;
4656 offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno);
4657 gl2ps->xreflist[gro->trgroupobjno] = offs;
4658 offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno);
4659 gl2ps->xreflist[gro->maskshobjno] = offs;
4660 offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8);
4661 }
4662 gl2psFree(triangles);
4663 break;
4664 case GL2PS_PIXMAP:
4665 gl2ps->xreflist[gro->imobjno] = offs;
4666 offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0);
4667 if(p->data.image->format == GL_RGBA){
4668 gl2ps->xreflist[gro->imobjno+1] = offs;
4669 offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8);
4670 }
4671 break;
4672 case GL2PS_TEXT:
4673 gl2ps->xreflist[gro->fontobjno] = offs;
4674 offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno);
4675 break;
4676 case GL2PS_SPECIAL :
4677 /* alignment contains the format for which the special output text
4678 is intended */
4679 if(p->data.text->alignment == GL2PS_PDF)
4680 offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str);
4681 break;
4682 default:
4683 break;
4684 }
4685 }
4686 return offs;
4687 }
4688
4689 /* All variable data has been written at this point and all required
4690 functioninality has been gathered, so we can write now file footer
4691 with cross reference table and trailer */
4692
4693 static void gl2psPrintPDFFooter(void)
4694 {
4695 int i, offs;
4696
4697 gl2psPDFgroupListInit();
4698 gl2psPDFgroupListWriteMainStream();
4699
4700 offs = gl2ps->xreflist[5] + gl2ps->streamlength;
4701 offs += gl2psClosePDFDataStream();
4702 gl2ps->xreflist[5] = offs;
4703
4704 offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength);
4705 gl2ps->xreflist[6] = offs;
4706 gl2ps->streamlength = 0;
4707
4708 offs += gl2psPrintPDFOpenPage();
4709 offs += gl2psPDFgroupListWriteVariableResources();
4710 gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist,
4711 sizeof(int) * (gl2ps->objects_stack + 1));
4712 gl2ps->xreflist[7] = offs;
4713
4714 offs += gl2psPrintPDFGSObject();
4715 gl2ps->xreflist[8] = offs;
4716
4717 gl2ps->xreflist[gl2ps->objects_stack] =
4718 gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]);
4719
4720 /* Start cross reference table. The file has to been opened in
4721 binary mode to preserve the 20 digit string length! */
4722 fprintf(gl2ps->stream,
4723 "xref\n"
4724 "0 %d\n