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

Last change on this file since 961 was 937, checked in by garnier, 17 years ago

Update gl2ps to 1.3.3 version of Feb 2009

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