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

Last change on this file since 1350 was 1346, checked in by garnier, 15 years ago

before tag

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