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