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