source: trunk/source/visualization/externals/gl2ps/src/gl2ps.cc@ 1269

Last change on this file since 1269 was 1228, checked in by garnier, 16 years ago

update geant4.9.3 tag

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