Fork me on GitHub

source: svn/trunk/Utilities/FROG/Includes/GL2PS/gl2ps.c@ 522

Last change on this file since 522 was 95, checked in by severine ovyn, 16 years ago

first commit frog

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