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