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