SUMO - Simulation of Urban MObility
|
00001 /* 00002 * GL2PS, an OpenGL to PostScript Printing Library 00003 * Copyright (C) 1999-2011 C. Geuzaine 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of either: 00007 * 00008 * a) the GNU Library General Public License as published by the Free 00009 * Software Foundation, either version 2 of the License, or (at your 00010 * option) any later version; or 00011 * 00012 * b) the GL2PS License as published by Christophe Geuzaine, either 00013 * version 2 of the License, or (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, but 00016 * WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either 00018 * the GNU Library General Public License or the GL2PS License for 00019 * more details. 00020 * 00021 * You should have received a copy of the GNU Library General Public 00022 * License along with this library in the file named "COPYING.LGPL"; 00023 * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, 00024 * Cambridge, MA 02139, USA. 00025 * 00026 * You should have received a copy of the GL2PS License with this 00027 * library in the file named "COPYING.GL2PS"; if not, I will be glad 00028 * to provide one. 00029 * 00030 * For the latest info about gl2ps and a full list of contributors, 00031 * see http://www.geuz.org/gl2ps/. 00032 * 00033 * Please report all bugs and problems to <gl2ps@geuz.org>. 00034 */ 00035 00036 #include "gl2ps.h" 00037 00038 #include <math.h> 00039 #include <string.h> 00040 #include <sys/types.h> 00041 #include <stdarg.h> 00042 #include <time.h> 00043 #include <float.h> 00044 00045 #if defined(GL2PS_HAVE_ZLIB) 00046 #include <zlib.h> 00047 #endif 00048 00049 #if defined(GL2PS_HAVE_LIBPNG) 00050 #include <png.h> 00051 #endif 00052 00053 #ifndef M_PI 00054 #define M_PI 3.1415926535897932384626433832795 00055 #endif 00056 00057 00058 /********************************************************************* 00059 * 00060 * Private definitions, data structures and prototypes 00061 * 00062 *********************************************************************/ 00063 00064 /* Magic numbers (assuming that the order of magnitude of window 00065 coordinates is 10^3) */ 00066 00067 #define GL2PS_EPSILON 5.0e-3F 00068 #define GL2PS_ZSCALE 1000.0F 00069 #define GL2PS_ZOFFSET 5.0e-2F 00070 #define GL2PS_ZOFFSET_LARGE 20.0F 00071 #define GL2PS_ZERO(arg) (fabs(arg) < 1.e-20) 00072 00073 /* Primitive types */ 00074 00075 #define GL2PS_NO_TYPE -1 00076 #define GL2PS_TEXT 1 00077 #define GL2PS_POINT 2 00078 #define GL2PS_LINE 3 00079 #define GL2PS_QUADRANGLE 4 00080 #define GL2PS_TRIANGLE 5 00081 #define GL2PS_PIXMAP 6 00082 #define GL2PS_IMAGEMAP 7 00083 #define GL2PS_IMAGEMAP_WRITTEN 8 00084 #define GL2PS_IMAGEMAP_VISIBLE 9 00085 #define GL2PS_SPECIAL 10 00086 00087 /* BSP tree primitive comparison */ 00088 00089 #define GL2PS_COINCIDENT 1 00090 #define GL2PS_IN_FRONT_OF 2 00091 #define GL2PS_IN_BACK_OF 3 00092 #define GL2PS_SPANNING 4 00093 00094 /* 2D BSP tree primitive comparison */ 00095 00096 #define GL2PS_POINT_COINCIDENT 0 00097 #define GL2PS_POINT_INFRONT 1 00098 #define GL2PS_POINT_BACK 2 00099 00100 /* Internal feedback buffer pass-through tokens */ 00101 00102 #define GL2PS_BEGIN_OFFSET_TOKEN 1 00103 #define GL2PS_END_OFFSET_TOKEN 2 00104 #define GL2PS_BEGIN_BOUNDARY_TOKEN 3 00105 #define GL2PS_END_BOUNDARY_TOKEN 4 00106 #define GL2PS_BEGIN_STIPPLE_TOKEN 5 00107 #define GL2PS_END_STIPPLE_TOKEN 6 00108 #define GL2PS_POINT_SIZE_TOKEN 7 00109 #define GL2PS_LINE_WIDTH_TOKEN 8 00110 #define GL2PS_BEGIN_BLEND_TOKEN 9 00111 #define GL2PS_END_BLEND_TOKEN 10 00112 #define GL2PS_SRC_BLEND_TOKEN 11 00113 #define GL2PS_DST_BLEND_TOKEN 12 00114 #define GL2PS_IMAGEMAP_TOKEN 13 00115 #define GL2PS_DRAW_PIXELS_TOKEN 14 00116 #define GL2PS_TEXT_TOKEN 15 00117 00118 typedef enum { 00119 T_UNDEFINED = -1, 00120 T_CONST_COLOR = 1, 00121 T_VAR_COLOR = 1<<1, 00122 T_ALPHA_1 = 1<<2, 00123 T_ALPHA_LESS_1 = 1<<3, 00124 T_VAR_ALPHA = 1<<4 00125 } GL2PS_TRIANGLE_PROPERTY; 00126 00127 typedef GLfloat GL2PSxyz[3]; 00128 typedef GLfloat GL2PSplane[4]; 00129 00130 typedef struct _GL2PSbsptree2d GL2PSbsptree2d; 00131 00132 struct _GL2PSbsptree2d { 00133 GL2PSplane plane; 00134 GL2PSbsptree2d *front, *back; 00135 }; 00136 00137 typedef struct { 00138 GLint nmax, size, incr, n; 00139 char *array; 00140 } GL2PSlist; 00141 00142 typedef struct _GL2PSbsptree GL2PSbsptree; 00143 00144 struct _GL2PSbsptree { 00145 GL2PSplane plane; 00146 GL2PSlist *primitives; 00147 GL2PSbsptree *front, *back; 00148 }; 00149 00150 typedef struct { 00151 GL2PSxyz xyz; 00152 GL2PSrgba rgba; 00153 } GL2PSvertex; 00154 00155 typedef struct { 00156 GL2PSvertex vertex[3]; 00157 int prop; 00158 } GL2PStriangle; 00159 00160 typedef struct { 00161 GLshort fontsize; 00162 char *str, *fontname; 00163 /* Note: for a 'special' string, 'alignment' holds the format 00164 (PostScript, PDF, etc.) of the special string */ 00165 GLint alignment; 00166 GLfloat angle; 00167 } GL2PSstring; 00168 00169 typedef struct { 00170 GLsizei width, height; 00171 /* Note: for an imagemap, 'type' indicates if it has already been 00172 written to the file or not, and 'format' indicates if it is 00173 visible or not */ 00174 GLenum format, type; 00175 GLfloat zoom_x, zoom_y; 00176 GLfloat *pixels; 00177 } GL2PSimage; 00178 00179 typedef struct _GL2PSimagemap GL2PSimagemap; 00180 00181 struct _GL2PSimagemap { 00182 GL2PSimage *image; 00183 GL2PSimagemap *next; 00184 }; 00185 00186 typedef struct { 00187 GLshort type, numverts; 00188 GLushort pattern; 00189 char boundary, offset, culled; 00190 GLint factor; 00191 GLfloat width; 00192 GL2PSvertex *verts; 00193 union { 00194 GL2PSstring *text; 00195 GL2PSimage *image; 00196 } data; 00197 } GL2PSprimitive; 00198 00199 typedef struct { 00200 #if defined(GL2PS_HAVE_ZLIB) 00201 Bytef *dest, *src, *start; 00202 uLongf destLen, srcLen; 00203 #else 00204 int dummy; 00205 #endif 00206 } GL2PScompress; 00207 00208 typedef struct{ 00209 GL2PSlist* ptrlist; 00210 int gsno, fontno, imno, shno, maskshno, trgroupno; 00211 int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno; 00212 } GL2PSpdfgroup; 00213 00214 typedef struct { 00215 /* General */ 00216 GLint format, sort, options, colorsize, colormode, buffersize; 00217 char *title, *producer, *filename; 00218 GLboolean boundary, blending; 00219 GLfloat *feedback, offset[2], lastlinewidth; 00220 GLint viewport[4], blendfunc[2], lastfactor; 00221 GL2PSrgba *colormap, lastrgba, threshold, bgcolor; 00222 GLushort lastpattern; 00223 GL2PSvertex lastvertex; 00224 GL2PSlist *primitives, *auxprimitives; 00225 FILE *stream; 00226 GL2PScompress *compress; 00227 GLboolean header; 00228 00229 /* BSP-specific */ 00230 GLint maxbestroot; 00231 00232 /* Occlusion culling-specific */ 00233 GLboolean zerosurfacearea; 00234 GL2PSbsptree2d *imagetree; 00235 GL2PSprimitive *primitivetoadd; 00236 00237 /* PDF-specific */ 00238 int streamlength; 00239 GL2PSlist *pdfprimlist, *pdfgrouplist; 00240 int *xreflist; 00241 int objects_stack; /* available objects */ 00242 int extgs_stack; /* graphics state object number */ 00243 int font_stack; /* font object number */ 00244 int im_stack; /* image object number */ 00245 int trgroupobjects_stack; /* xobject numbers */ 00246 int shader_stack; /* shader object numbers */ 00247 int mshader_stack; /* mask shader object numbers */ 00248 00249 /* for image map list */ 00250 GL2PSimagemap *imagemap_head; 00251 GL2PSimagemap *imagemap_tail; 00252 } GL2PScontext; 00253 00254 typedef struct { 00255 void (*printHeader)(void); 00256 void (*printFooter)(void); 00257 void (*beginViewport)(GLint viewport[4]); 00258 GLint (*endViewport)(void); 00259 void (*printPrimitive)(void *data); 00260 void (*printFinalPrimitive)(void); 00261 const char *file_extension; 00262 const char *description; 00263 } GL2PSbackend; 00264 00265 /* The gl2ps context. gl2ps is not thread safe (we should create a 00266 local GL2PScontext during gl2psBeginPage) */ 00267 00268 static GL2PScontext *gl2ps = NULL; 00269 00270 /* Need to forward-declare this one */ 00271 00272 static GLint gl2psPrintPrimitives(void); 00273 00274 /********************************************************************* 00275 * 00276 * Utility routines 00277 * 00278 *********************************************************************/ 00279 00280 static void gl2psMsg(GLint level, const char *fmt, ...) 00281 { 00282 va_list args; 00283 00284 if(!(gl2ps->options & GL2PS_SILENT)){ 00285 switch(level){ 00286 case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break; 00287 case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break; 00288 case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break; 00289 } 00290 va_start(args, fmt); 00291 vfprintf(stderr, fmt, args); 00292 va_end(args); 00293 fprintf(stderr, "\n"); 00294 } 00295 /* if(level == GL2PS_ERROR) exit(1); */ 00296 } 00297 00298 static void *gl2psMalloc(size_t size) 00299 { 00300 void *ptr; 00301 00302 if(!size) return NULL; 00303 ptr = malloc(size); 00304 if(!ptr){ 00305 gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory"); 00306 return NULL; 00307 } 00308 return ptr; 00309 } 00310 00311 static void *gl2psRealloc(void *ptr, size_t size) 00312 { 00313 void *orig = ptr; 00314 if(!size) return NULL; 00315 ptr = realloc(orig, size); 00316 if(!ptr){ 00317 gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory"); 00318 free(orig); 00319 return NULL; 00320 } 00321 return ptr; 00322 } 00323 00324 static void gl2psFree(void *ptr) 00325 { 00326 if(!ptr) return; 00327 free(ptr); 00328 } 00329 00330 static int gl2psWriteBigEndian(unsigned long data, int bytes) 00331 { 00332 int i; 00333 int size = sizeof(unsigned long); 00334 for(i = 1; i <= bytes; ++i){ 00335 fputc(0xff & (data >> (size - i) * 8), gl2ps->stream); 00336 } 00337 return bytes; 00338 } 00339 00340 /* zlib compression helper routines */ 00341 00342 #if defined(GL2PS_HAVE_ZLIB) 00343 00344 static void gl2psSetupCompress(void) 00345 { 00346 gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress)); 00347 gl2ps->compress->src = NULL; 00348 gl2ps->compress->start = NULL; 00349 gl2ps->compress->dest = NULL; 00350 gl2ps->compress->srcLen = 0; 00351 gl2ps->compress->destLen = 0; 00352 } 00353 00354 static void gl2psFreeCompress(void) 00355 { 00356 if(!gl2ps->compress) 00357 return; 00358 gl2psFree(gl2ps->compress->start); 00359 gl2psFree(gl2ps->compress->dest); 00360 gl2ps->compress->src = NULL; 00361 gl2ps->compress->start = NULL; 00362 gl2ps->compress->dest = NULL; 00363 gl2ps->compress->srcLen = 0; 00364 gl2ps->compress->destLen = 0; 00365 } 00366 00367 static int gl2psAllocCompress(unsigned int srcsize) 00368 { 00369 gl2psFreeCompress(); 00370 00371 if(!gl2ps->compress || !srcsize) 00372 return GL2PS_ERROR; 00373 00374 gl2ps->compress->srcLen = srcsize; 00375 gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); 00376 gl2ps->compress->src = (Bytef*)gl2psMalloc(gl2ps->compress->srcLen); 00377 gl2ps->compress->start = gl2ps->compress->src; 00378 gl2ps->compress->dest = (Bytef*)gl2psMalloc(gl2ps->compress->destLen); 00379 00380 return GL2PS_SUCCESS; 00381 } 00382 00383 static void *gl2psReallocCompress(unsigned int srcsize) 00384 { 00385 if(!gl2ps->compress || !srcsize) 00386 return NULL; 00387 00388 if(srcsize < gl2ps->compress->srcLen) 00389 return gl2ps->compress->start; 00390 00391 gl2ps->compress->srcLen = srcsize; 00392 gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); 00393 gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, 00394 gl2ps->compress->srcLen); 00395 gl2ps->compress->start = gl2ps->compress->src; 00396 gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, 00397 gl2ps->compress->destLen); 00398 00399 return gl2ps->compress->start; 00400 } 00401 00402 static int gl2psWriteBigEndianCompress(unsigned long data, int bytes) 00403 { 00404 int i; 00405 int size = sizeof(unsigned long); 00406 for(i = 1; i <= bytes; ++i){ 00407 *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8)); 00408 ++gl2ps->compress->src; 00409 } 00410 return bytes; 00411 } 00412 00413 static int gl2psDeflate(void) 00414 { 00415 /* For compatibility with older zlib versions, we use compress(...) 00416 instead of compress2(..., Z_BEST_COMPRESSION) */ 00417 return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, 00418 gl2ps->compress->start, gl2ps->compress->srcLen); 00419 } 00420 00421 #endif 00422 00423 static int gl2psPrintf(const char* fmt, ...) 00424 { 00425 int ret; 00426 va_list args; 00427 00428 #if defined(GL2PS_HAVE_ZLIB) 00429 unsigned int oldsize = 0; 00430 static char buf[1000]; 00431 if(gl2ps->options & GL2PS_COMPRESS){ 00432 va_start(args, fmt); 00433 ret = vsprintf(buf, fmt, args); 00434 va_end(args); 00435 oldsize = gl2ps->compress->srcLen; 00436 gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret); 00437 memcpy(gl2ps->compress->start+oldsize, buf, ret); 00438 ret = 0; 00439 } 00440 else{ 00441 #endif 00442 va_start(args, fmt); 00443 ret = vfprintf(gl2ps->stream, fmt, args); 00444 va_end(args); 00445 #if defined(GL2PS_HAVE_ZLIB) 00446 } 00447 #endif 00448 return ret; 00449 } 00450 00451 static void gl2psPrintGzipHeader(void) 00452 { 00453 #if defined(GL2PS_HAVE_ZLIB) 00454 char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */ 00455 8, /* compression method: Z_DEFLATED */ 00456 0, /* flags */ 00457 0, 0, 0, 0, /* time */ 00458 2, /* extra flags: max compression */ 00459 '\x03'}; /* OS code: 0x03 (Unix) */ 00460 00461 if(gl2ps->options & GL2PS_COMPRESS){ 00462 gl2psSetupCompress(); 00463 /* add the gzip file header */ 00464 fwrite(tmp, 10, 1, gl2ps->stream); 00465 } 00466 #endif 00467 } 00468 00469 static void gl2psPrintGzipFooter(void) 00470 { 00471 #if defined(GL2PS_HAVE_ZLIB) 00472 int n; 00473 uLong crc, len; 00474 char tmp[8]; 00475 00476 if(gl2ps->options & GL2PS_COMPRESS){ 00477 if(Z_OK != gl2psDeflate()){ 00478 gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); 00479 } 00480 else{ 00481 /* determine the length of the header in the zlib stream */ 00482 n = 2; /* CMF+FLG */ 00483 if(gl2ps->compress->dest[1] & (1<<5)){ 00484 n += 4; /* DICTID */ 00485 } 00486 /* write the data, without the zlib header and footer */ 00487 fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), 00488 1, gl2ps->stream); 00489 /* add the gzip file footer */ 00490 crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen); 00491 for(n = 0; n < 4; ++n){ 00492 tmp[n] = (char)(crc & 0xff); 00493 crc >>= 8; 00494 } 00495 len = gl2ps->compress->srcLen; 00496 for(n = 4; n < 8; ++n){ 00497 tmp[n] = (char)(len & 0xff); 00498 len >>= 8; 00499 } 00500 fwrite(tmp, 8, 1, gl2ps->stream); 00501 } 00502 gl2psFreeCompress(); 00503 gl2psFree(gl2ps->compress); 00504 gl2ps->compress = NULL; 00505 } 00506 #endif 00507 } 00508 00509 /* The list handling routines */ 00510 00511 static void gl2psListRealloc(GL2PSlist *list, GLint n) 00512 { 00513 if(!list){ 00514 gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list"); 00515 return; 00516 } 00517 if(n <= 0) return; 00518 if(!list->array){ 00519 list->nmax = n; 00520 list->array = (char*)gl2psMalloc(list->nmax * list->size); 00521 } 00522 else{ 00523 if(n > list->nmax){ 00524 list->nmax = ((n - 1) / list->incr + 1) * list->incr; 00525 list->array = (char*)gl2psRealloc(list->array, 00526 list->nmax * list->size); 00527 } 00528 } 00529 } 00530 00531 static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size) 00532 { 00533 GL2PSlist *list; 00534 00535 if(n < 0) n = 0; 00536 if(incr <= 0) incr = 1; 00537 list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist)); 00538 list->nmax = 0; 00539 list->incr = incr; 00540 list->size = size; 00541 list->n = 0; 00542 list->array = NULL; 00543 gl2psListRealloc(list, n); 00544 return list; 00545 } 00546 00547 static void gl2psListReset(GL2PSlist *list) 00548 { 00549 if(!list) return; 00550 list->n = 0; 00551 } 00552 00553 static void gl2psListDelete(GL2PSlist *list) 00554 { 00555 if(!list) return; 00556 gl2psFree(list->array); 00557 gl2psFree(list); 00558 } 00559 00560 static void gl2psListAdd(GL2PSlist *list, void *data) 00561 { 00562 if(!list){ 00563 gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list"); 00564 return; 00565 } 00566 list->n++; 00567 gl2psListRealloc(list, list->n); 00568 memcpy(&list->array[(list->n - 1) * list->size], data, list->size); 00569 } 00570 00571 static int gl2psListNbr(GL2PSlist *list) 00572 { 00573 if(!list) 00574 return 0; 00575 return list->n; 00576 } 00577 00578 static void *gl2psListPointer(GL2PSlist *list, GLint index) 00579 { 00580 if(!list){ 00581 gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list"); 00582 return NULL; 00583 } 00584 if((index < 0) || (index >= list->n)){ 00585 gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer"); 00586 return NULL; 00587 } 00588 return &list->array[index * list->size]; 00589 } 00590 00591 static void gl2psListSort(GL2PSlist *list, 00592 int (*fcmp)(const void *a, const void *b)) 00593 { 00594 if(!list) 00595 return; 00596 qsort(list->array, list->n, list->size, fcmp); 00597 } 00598 00599 static void gl2psListAction(GL2PSlist *list, void (*action)(void *data)) 00600 { 00601 GLint i; 00602 00603 for(i = 0; i < gl2psListNbr(list); i++){ 00604 (*action)(gl2psListPointer(list, i)); 00605 } 00606 } 00607 00608 static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)) 00609 { 00610 GLint i; 00611 00612 for(i = gl2psListNbr(list); i > 0; i--){ 00613 (*action)(gl2psListPointer(list, i-1)); 00614 } 00615 } 00616 00617 #if defined(GL2PS_HAVE_LIBPNG) 00618 00619 static void gl2psListRead(GL2PSlist *list, int index, void *data) 00620 { 00621 if((index < 0) || (index >= list->n)) 00622 gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead"); 00623 memcpy(data, &list->array[index * list->size], list->size); 00624 } 00625 00626 static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len) 00627 { 00628 static const char cb64[] = 00629 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 00630 00631 out[0] = cb64[ in[0] >> 2 ]; 00632 out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; 00633 out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='; 00634 out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '='; 00635 } 00636 00637 static void gl2psListEncodeBase64(GL2PSlist *list) 00638 { 00639 unsigned char *buffer, in[3], out[4]; 00640 int i, n, index, len; 00641 00642 n = list->n * list->size; 00643 buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned char)); 00644 memcpy(buffer, list->array, n * sizeof(unsigned char)); 00645 gl2psListReset(list); 00646 00647 index = 0; 00648 while(index < n) { 00649 len = 0; 00650 for(i = 0; i < 3; i++) { 00651 if(index < n){ 00652 in[i] = buffer[index]; 00653 len++; 00654 } 00655 else{ 00656 in[i] = 0; 00657 } 00658 index++; 00659 } 00660 if(len) { 00661 gl2psEncodeBase64Block(in, out, len); 00662 for(i = 0; i < 4; i++) 00663 gl2psListAdd(list, &out[i]); 00664 } 00665 } 00666 gl2psFree(buffer); 00667 } 00668 00669 #endif 00670 00671 /* Helpers for rgba colors */ 00672 00673 static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2) 00674 { 00675 if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) || 00676 !GL2PS_ZERO(rgba1[1] - rgba2[1]) || 00677 !GL2PS_ZERO(rgba1[2] - rgba2[2])) 00678 return GL_FALSE; 00679 return GL_TRUE; 00680 } 00681 00682 static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim) 00683 { 00684 int i; 00685 00686 for(i = 1; i < prim->numverts; i++){ 00687 if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){ 00688 return GL_FALSE; 00689 } 00690 } 00691 return GL_TRUE; 00692 } 00693 00694 static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[], 00695 GL2PSrgba threshold) 00696 { 00697 int i; 00698 00699 if(n < 2) return GL_TRUE; 00700 00701 for(i = 1; i < n; i++){ 00702 if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] || 00703 fabs(rgba[0][1] - rgba[i][1]) > threshold[1] || 00704 fabs(rgba[0][2] - rgba[i][2]) > threshold[2]) 00705 return GL_FALSE; 00706 } 00707 00708 return GL_TRUE; 00709 } 00710 00711 static void gl2psSetLastColor(GL2PSrgba rgba) 00712 { 00713 int i; 00714 for(i = 0; i < 3; ++i){ 00715 gl2ps->lastrgba[i] = rgba[i]; 00716 } 00717 } 00718 00719 static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y, 00720 GLfloat *red, GLfloat *green, GLfloat *blue) 00721 { 00722 00723 GLsizei width = im->width; 00724 GLsizei height = im->height; 00725 GLfloat *pixels = im->pixels; 00726 GLfloat *pimag; 00727 00728 /* OpenGL image is from down to up, PS image is up to down */ 00729 switch(im->format){ 00730 case GL_RGBA: 00731 pimag = pixels + 4 * (width * (height - 1 - y) + x); 00732 break; 00733 case GL_RGB: 00734 default: 00735 pimag = pixels + 3 * (width * (height - 1 - y) + x); 00736 break; 00737 } 00738 *red = *pimag; pimag++; 00739 *green = *pimag; pimag++; 00740 *blue = *pimag; pimag++; 00741 00742 return (im->format == GL_RGBA) ? *pimag : 1.0F; 00743 } 00744 00745 /* Helper routines for pixmaps */ 00746 00747 static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im) 00748 { 00749 int size; 00750 GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); 00751 00752 image->width = im->width; 00753 image->height = im->height; 00754 image->format = im->format; 00755 image->type = im->type; 00756 image->zoom_x = im->zoom_x; 00757 image->zoom_y = im->zoom_y; 00758 00759 switch(image->format){ 00760 case GL_RGBA: 00761 size = image->height * image->width * 4 * sizeof(GLfloat); 00762 break; 00763 case GL_RGB: 00764 default: 00765 size = image->height * image->width * 3 * sizeof(GLfloat); 00766 break; 00767 } 00768 00769 image->pixels = (GLfloat*)gl2psMalloc(size); 00770 memcpy(image->pixels, im->pixels, size); 00771 00772 return image; 00773 } 00774 00775 static void gl2psFreePixmap(GL2PSimage *im) 00776 { 00777 if(!im) 00778 return; 00779 gl2psFree(im->pixels); 00780 gl2psFree(im); 00781 } 00782 00783 #if defined(GL2PS_HAVE_LIBPNG) 00784 00785 #if !defined(png_jmpbuf) 00786 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 00787 #endif 00788 00789 static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length) 00790 { 00791 unsigned int i; 00792 GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr); 00793 for(i = 0; i < length; i++) 00794 gl2psListAdd(png, &data[i]); 00795 } 00796 00797 static void gl2psUserFlushPNG(png_structp png_ptr) 00798 { 00799 (void) png_ptr; /* not used */ 00800 } 00801 00802 static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png) 00803 { 00804 png_structp png_ptr; 00805 png_infop info_ptr; 00806 unsigned char *row_data; 00807 GLfloat dr, dg, db; 00808 int row, col; 00809 00810 if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) 00811 return; 00812 00813 if(!(info_ptr = png_create_info_struct(png_ptr))){ 00814 png_destroy_write_struct(&png_ptr, NULL); 00815 return; 00816 } 00817 00818 if(setjmp(png_jmpbuf(png_ptr))) { 00819 png_destroy_write_struct(&png_ptr, &info_ptr); 00820 return; 00821 } 00822 00823 png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG); 00824 png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); 00825 png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, 00826 PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 00827 PNG_FILTER_TYPE_BASE); 00828 png_write_info(png_ptr, info_ptr); 00829 00830 row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char)); 00831 for(row = 0; row < pixmap->height; row++){ 00832 for(col = 0; col < pixmap->width; col++){ 00833 gl2psGetRGB(pixmap, col, row, &dr, &dg, &db); 00834 row_data[3*col] = (unsigned char)(255. * dr); 00835 row_data[3*col+1] = (unsigned char)(255. * dg); 00836 row_data[3*col+2] = (unsigned char)(255. * db); 00837 } 00838 png_write_row(png_ptr, (png_bytep)row_data); 00839 } 00840 gl2psFree(row_data); 00841 00842 png_write_end(png_ptr, info_ptr); 00843 png_destroy_write_struct(&png_ptr, &info_ptr); 00844 } 00845 00846 #endif 00847 00848 /* Helper routines for text strings */ 00849 00850 static GLint gl2psAddText(GLint type, const char *str, const char *fontname, 00851 GLshort fontsize, GLint alignment, GLfloat angle) 00852 { 00853 GLfloat pos[4]; 00854 GL2PSprimitive *prim; 00855 GLboolean valid; 00856 00857 if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED; 00858 00859 if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS; 00860 00861 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); 00862 if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ 00863 00864 glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); 00865 00866 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 00867 prim->type = (GLshort)type; 00868 prim->boundary = 0; 00869 prim->numverts = 1; 00870 prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); 00871 prim->verts[0].xyz[0] = pos[0]; 00872 prim->verts[0].xyz[1] = pos[1]; 00873 prim->verts[0].xyz[2] = pos[2]; 00874 prim->culled = 0; 00875 prim->offset = 0; 00876 prim->pattern = 0; 00877 prim->factor = 0; 00878 prim->width = 1; 00879 glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); 00880 prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); 00881 prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char)); 00882 strcpy(prim->data.text->str, str); 00883 prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); 00884 strcpy(prim->data.text->fontname, fontname); 00885 prim->data.text->fontsize = fontsize; 00886 prim->data.text->alignment = alignment; 00887 prim->data.text->angle = angle; 00888 00889 gl2psListAdd(gl2ps->auxprimitives, &prim); 00890 glPassThrough(GL2PS_TEXT_TOKEN); 00891 00892 return GL2PS_SUCCESS; 00893 } 00894 00895 static GL2PSstring *gl2psCopyText(GL2PSstring *t) 00896 { 00897 GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); 00898 text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char)); 00899 strcpy(text->str, t->str); 00900 text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char)); 00901 strcpy(text->fontname, t->fontname); 00902 text->fontsize = t->fontsize; 00903 text->alignment = t->alignment; 00904 text->angle = t->angle; 00905 00906 return text; 00907 } 00908 00909 static void gl2psFreeText(GL2PSstring *text) 00910 { 00911 if(!text) 00912 return; 00913 gl2psFree(text->str); 00914 gl2psFree(text->fontname); 00915 gl2psFree(text); 00916 } 00917 00918 /* Helpers for blending modes */ 00919 00920 static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor) 00921 { 00922 /* returns TRUE if gl2ps supports the argument combination: only two 00923 blending modes have been implemented so far */ 00924 00925 if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || 00926 (sfactor == GL_ONE && dfactor == GL_ZERO) ) 00927 return GL_TRUE; 00928 return GL_FALSE; 00929 } 00930 00931 static void gl2psAdaptVertexForBlending(GL2PSvertex *v) 00932 { 00933 /* Transforms vertex depending on the actual blending function - 00934 currently the vertex v is considered as source vertex and his 00935 alpha value is changed to 1.0 if source blending GL_ONE is 00936 active. This might be extended in the future */ 00937 00938 if(!v || !gl2ps) 00939 return; 00940 00941 if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ 00942 v->rgba[3] = 1.0F; 00943 return; 00944 } 00945 00946 switch(gl2ps->blendfunc[0]){ 00947 case GL_ONE: 00948 v->rgba[3] = 1.0F; 00949 break; 00950 default: 00951 break; 00952 } 00953 } 00954 00955 static void gl2psAssignTriangleProperties(GL2PStriangle *t) 00956 { 00957 /* int i; */ 00958 00959 t->prop = T_VAR_COLOR; 00960 00961 /* Uncommenting the following lines activates an even more fine 00962 grained distinction between triangle types - please don't delete, 00963 a remarkable amount of PDF handling code inside this file depends 00964 on it if activated */ 00965 /* 00966 t->prop = T_CONST_COLOR; 00967 for(i = 0; i < 3; ++i){ 00968 if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || 00969 !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){ 00970 t->prop = T_VAR_COLOR; 00971 break; 00972 } 00973 } 00974 */ 00975 00976 if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || 00977 !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){ 00978 t->prop |= T_VAR_ALPHA; 00979 } 00980 else{ 00981 if(t->vertex[0].rgba[3] < 1) 00982 t->prop |= T_ALPHA_LESS_1; 00983 else 00984 t->prop |= T_ALPHA_1; 00985 } 00986 } 00987 00988 static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p, 00989 GLboolean assignprops) 00990 { 00991 t->vertex[0] = p->verts[0]; 00992 t->vertex[1] = p->verts[1]; 00993 t->vertex[2] = p->verts[2]; 00994 if(GL_TRUE == assignprops) 00995 gl2psAssignTriangleProperties(t); 00996 } 00997 00998 static void gl2psInitTriangle(GL2PStriangle *t) 00999 { 01000 int i; 01001 GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} }; 01002 for(i = 0; i < 3; i++) 01003 t->vertex[i] = vertex; 01004 t->prop = T_UNDEFINED; 01005 } 01006 01007 /* Miscellaneous helper routines */ 01008 01009 static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p) 01010 { 01011 GL2PSprimitive *prim; 01012 01013 if(!p){ 01014 gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive"); 01015 return NULL; 01016 } 01017 01018 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 01019 01020 prim->type = p->type; 01021 prim->numverts = p->numverts; 01022 prim->boundary = p->boundary; 01023 prim->offset = p->offset; 01024 prim->pattern = p->pattern; 01025 prim->factor = p->factor; 01026 prim->culled = p->culled; 01027 prim->width = p->width; 01028 prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex)); 01029 memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex)); 01030 01031 switch(prim->type){ 01032 case GL2PS_PIXMAP : 01033 prim->data.image = gl2psCopyPixmap(p->data.image); 01034 break; 01035 case GL2PS_TEXT : 01036 case GL2PS_SPECIAL : 01037 prim->data.text = gl2psCopyText(p->data.text); 01038 break; 01039 default: 01040 break; 01041 } 01042 01043 return prim; 01044 } 01045 01046 static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2) 01047 { 01048 if(!GL2PS_ZERO(p1[0] - p2[0]) || 01049 !GL2PS_ZERO(p1[1] - p2[1]) || 01050 !GL2PS_ZERO(p1[2] - p2[2])) 01051 return GL_FALSE; 01052 return GL_TRUE; 01053 } 01054 01055 /********************************************************************* 01056 * 01057 * 3D sorting routines 01058 * 01059 *********************************************************************/ 01060 01061 static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane) 01062 { 01063 return (plane[0] * point[0] + 01064 plane[1] * point[1] + 01065 plane[2] * point[2] + 01066 plane[3]); 01067 } 01068 01069 static GLfloat gl2psPsca(GLfloat *a, GLfloat *b) 01070 { 01071 return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]); 01072 } 01073 01074 static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c) 01075 { 01076 c[0] = a[1]*b[2] - a[2]*b[1]; 01077 c[1] = a[2]*b[0] - a[0]*b[2]; 01078 c[2] = a[0]*b[1] - a[1]*b[0]; 01079 } 01080 01081 static GLfloat gl2psNorm(GLfloat *a) 01082 { 01083 return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); 01084 } 01085 01086 static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c) 01087 { 01088 GLfloat norm; 01089 01090 gl2psPvec(a, b, c); 01091 if(!GL2PS_ZERO(norm = gl2psNorm(c))){ 01092 c[0] = c[0] / norm; 01093 c[1] = c[1] / norm; 01094 c[2] = c[2] / norm; 01095 } 01096 else{ 01097 /* The plane is still wrong despite our tests in gl2psGetPlane. 01098 Let's return a dummy value for now (this is a hack: we should 01099 do more intelligent tests in GetPlane) */ 01100 c[0] = c[1] = 0.0F; 01101 c[2] = 1.0F; 01102 } 01103 } 01104 01105 static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane) 01106 { 01107 GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F}; 01108 01109 switch(prim->type){ 01110 case GL2PS_TRIANGLE : 01111 case GL2PS_QUADRANGLE : 01112 v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; 01113 v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; 01114 v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; 01115 w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0]; 01116 w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1]; 01117 w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2]; 01118 if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) || 01119 (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){ 01120 plane[0] = plane[1] = 0.0F; 01121 plane[2] = 1.0F; 01122 plane[3] = -prim->verts[0].xyz[2]; 01123 } 01124 else{ 01125 gl2psGetNormal(v, w, plane); 01126 plane[3] = 01127 - plane[0] * prim->verts[0].xyz[0] 01128 - plane[1] * prim->verts[0].xyz[1] 01129 - plane[2] * prim->verts[0].xyz[2]; 01130 } 01131 break; 01132 case GL2PS_LINE : 01133 v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; 01134 v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; 01135 v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; 01136 if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){ 01137 plane[0] = plane[1] = 0.0F; 01138 plane[2] = 1.0F; 01139 plane[3] = -prim->verts[0].xyz[2]; 01140 } 01141 else{ 01142 if(GL2PS_ZERO(v[0])) w[0] = 1.0F; 01143 else if(GL2PS_ZERO(v[1])) w[1] = 1.0F; 01144 else w[2] = 1.0F; 01145 gl2psGetNormal(v, w, plane); 01146 plane[3] = 01147 - plane[0] * prim->verts[0].xyz[0] 01148 - plane[1] * prim->verts[0].xyz[1] 01149 - plane[2] * prim->verts[0].xyz[2]; 01150 } 01151 break; 01152 case GL2PS_POINT : 01153 case GL2PS_PIXMAP : 01154 case GL2PS_TEXT : 01155 case GL2PS_SPECIAL : 01156 case GL2PS_IMAGEMAP: 01157 plane[0] = plane[1] = 0.0F; 01158 plane[2] = 1.0F; 01159 plane[3] = -prim->verts[0].xyz[2]; 01160 break; 01161 default : 01162 gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree"); 01163 plane[0] = plane[1] = plane[3] = 0.0F; 01164 plane[2] = 1.0F; 01165 break; 01166 } 01167 } 01168 01169 static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane, 01170 GL2PSvertex *c) 01171 { 01172 GL2PSxyz v; 01173 GLfloat sect, psca; 01174 01175 v[0] = b->xyz[0] - a->xyz[0]; 01176 v[1] = b->xyz[1] - a->xyz[1]; 01177 v[2] = b->xyz[2] - a->xyz[2]; 01178 01179 if(!GL2PS_ZERO(psca = gl2psPsca(plane, v))) 01180 sect = -gl2psComparePointPlane(a->xyz, plane) / psca; 01181 else 01182 sect = 0.0F; 01183 01184 c->xyz[0] = a->xyz[0] + v[0] * sect; 01185 c->xyz[1] = a->xyz[1] + v[1] * sect; 01186 c->xyz[2] = a->xyz[2] + v[2] * sect; 01187 01188 c->rgba[0] = (1 - sect) * a->rgba[0] + sect * b->rgba[0]; 01189 c->rgba[1] = (1 - sect) * a->rgba[1] + sect * b->rgba[1]; 01190 c->rgba[2] = (1 - sect) * a->rgba[2] + sect * b->rgba[2]; 01191 c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3]; 01192 } 01193 01194 static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, 01195 GL2PSprimitive *child, GLshort numverts, 01196 GLshort *index0, GLshort *index1) 01197 { 01198 GLshort i; 01199 01200 if(parent->type == GL2PS_IMAGEMAP){ 01201 child->type = GL2PS_IMAGEMAP; 01202 child->data.image = parent->data.image; 01203 } 01204 else{ 01205 if(numverts > 4){ 01206 gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts); 01207 numverts = 4; 01208 } 01209 switch(numverts){ 01210 case 1 : child->type = GL2PS_POINT; break; 01211 case 2 : child->type = GL2PS_LINE; break; 01212 case 3 : child->type = GL2PS_TRIANGLE; break; 01213 case 4 : child->type = GL2PS_QUADRANGLE; break; 01214 default: child->type = GL2PS_NO_TYPE; break; 01215 } 01216 } 01217 01218 child->boundary = 0; /* FIXME: not done! */ 01219 child->culled = parent->culled; 01220 child->offset = parent->offset; 01221 child->pattern = parent->pattern; 01222 child->factor = parent->factor; 01223 child->width = parent->width; 01224 child->numverts = numverts; 01225 child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); 01226 01227 for(i = 0; i < numverts; i++){ 01228 if(index1[i] < 0){ 01229 child->verts[i] = parent->verts[index0[i]]; 01230 } 01231 else{ 01232 gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], 01233 plane, &child->verts[i]); 01234 } 01235 } 01236 } 01237 01238 static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, 01239 GLshort i, GLshort j) 01240 { 01241 GLint k; 01242 01243 for(k = 0; k < *nb; k++){ 01244 if((index0[k] == i && index1[k] == j) || 01245 (index1[k] == i && index0[k] == j)) return; 01246 } 01247 index0[*nb] = i; 01248 index1[*nb] = j; 01249 (*nb)++; 01250 } 01251 01252 static GLshort gl2psGetIndex(GLshort i, GLshort num) 01253 { 01254 return (i < num - 1) ? i + 1 : 0; 01255 } 01256 01257 static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane) 01258 { 01259 GLint type = GL2PS_COINCIDENT; 01260 GLshort i, j; 01261 GLfloat d[5]; 01262 01263 for(i = 0; i < prim->numverts; i++){ 01264 d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); 01265 } 01266 01267 if(prim->numverts < 2){ 01268 return 0; 01269 } 01270 else{ 01271 for(i = 0; i < prim->numverts; i++){ 01272 j = gl2psGetIndex(i, prim->numverts); 01273 if(d[j] > GL2PS_EPSILON){ 01274 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; 01275 else if(type != GL2PS_IN_BACK_OF) return 1; 01276 if(d[i] < -GL2PS_EPSILON) return 1; 01277 } 01278 else if(d[j] < -GL2PS_EPSILON){ 01279 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; 01280 else if(type != GL2PS_IN_FRONT_OF) return 1; 01281 if(d[i] > GL2PS_EPSILON) return 1; 01282 } 01283 } 01284 } 01285 return 0; 01286 } 01287 01288 static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, 01289 GL2PSprimitive **front, GL2PSprimitive **back) 01290 { 01291 GLshort i, j, in = 0, out = 0, in0[5], in1[5], out0[5], out1[5]; 01292 GLint type; 01293 GLfloat d[5]; 01294 01295 type = GL2PS_COINCIDENT; 01296 01297 for(i = 0; i < prim->numverts; i++){ 01298 d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); 01299 } 01300 01301 switch(prim->type){ 01302 case GL2PS_POINT : 01303 if(d[0] > GL2PS_EPSILON) type = GL2PS_IN_BACK_OF; 01304 else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF; 01305 else type = GL2PS_COINCIDENT; 01306 break; 01307 default : 01308 for(i = 0; i < prim->numverts; i++){ 01309 j = gl2psGetIndex(i, prim->numverts); 01310 if(d[j] > GL2PS_EPSILON){ 01311 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; 01312 else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING; 01313 if(d[i] < -GL2PS_EPSILON){ 01314 gl2psAddIndex(in0, in1, &in, i, j); 01315 gl2psAddIndex(out0, out1, &out, i, j); 01316 type = GL2PS_SPANNING; 01317 } 01318 gl2psAddIndex(out0, out1, &out, j, -1); 01319 } 01320 else if(d[j] < -GL2PS_EPSILON){ 01321 if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; 01322 else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING; 01323 if(d[i] > GL2PS_EPSILON){ 01324 gl2psAddIndex(in0, in1, &in, i, j); 01325 gl2psAddIndex(out0, out1, &out, i, j); 01326 type = GL2PS_SPANNING; 01327 } 01328 gl2psAddIndex(in0, in1, &in, j, -1); 01329 } 01330 else{ 01331 gl2psAddIndex(in0, in1, &in, j, -1); 01332 gl2psAddIndex(out0, out1, &out, j, -1); 01333 } 01334 } 01335 break; 01336 } 01337 01338 if(type == GL2PS_SPANNING){ 01339 *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 01340 *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 01341 gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1); 01342 gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1); 01343 } 01344 01345 return type; 01346 } 01347 01348 static void gl2psDivideQuad(GL2PSprimitive *quad, 01349 GL2PSprimitive **t1, GL2PSprimitive **t2) 01350 { 01351 *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 01352 *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 01353 (*t1)->type = (*t2)->type = GL2PS_TRIANGLE; 01354 (*t1)->numverts = (*t2)->numverts = 3; 01355 (*t1)->culled = (*t2)->culled = quad->culled; 01356 (*t1)->offset = (*t2)->offset = quad->offset; 01357 (*t1)->pattern = (*t2)->pattern = quad->pattern; 01358 (*t1)->factor = (*t2)->factor = quad->factor; 01359 (*t1)->width = (*t2)->width = quad->width; 01360 (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); 01361 (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); 01362 (*t1)->verts[0] = quad->verts[0]; 01363 (*t1)->verts[1] = quad->verts[1]; 01364 (*t1)->verts[2] = quad->verts[2]; 01365 (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0); 01366 (*t2)->verts[0] = quad->verts[0]; 01367 (*t2)->verts[1] = quad->verts[2]; 01368 (*t2)->verts[2] = quad->verts[3]; 01369 (*t2)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 8) ? 4 : 0); 01370 } 01371 01372 static int gl2psCompareDepth(const void *a, const void *b) 01373 { 01374 const GL2PSprimitive *q, *w; 01375 GLfloat dq = 0.0F, dw = 0.0F, diff; 01376 int i; 01377 01378 q = *(const GL2PSprimitive* const*)a; 01379 w = *(const GL2PSprimitive* const*)b; 01380 01381 for(i = 0; i < q->numverts; i++){ 01382 dq += q->verts[i].xyz[2]; 01383 } 01384 dq /= (GLfloat)q->numverts; 01385 01386 for(i = 0; i < w->numverts; i++){ 01387 dw += w->verts[i].xyz[2]; 01388 } 01389 dw /= (GLfloat)w->numverts; 01390 01391 diff = dq - dw; 01392 if(diff > 0.){ 01393 return -1; 01394 } 01395 else if(diff < 0.){ 01396 return 1; 01397 } 01398 else{ 01399 return 0; 01400 } 01401 } 01402 01403 static int gl2psTrianglesFirst(const void *a, const void *b) 01404 { 01405 const GL2PSprimitive *q, *w; 01406 01407 q = *(const GL2PSprimitive* const*)a; 01408 w = *(const GL2PSprimitive* const*)b; 01409 return (q->type < w->type ? 1 : -1); 01410 } 01411 01412 static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root) 01413 { 01414 GLint i, j, count, best = 1000000, index = 0; 01415 GL2PSprimitive *prim1, *prim2; 01416 GL2PSplane plane; 01417 GLint maxp; 01418 01419 if(!gl2psListNbr(primitives)){ 01420 gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list"); 01421 return 0; 01422 } 01423 01424 *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0); 01425 01426 if(gl2ps->options & GL2PS_BEST_ROOT){ 01427 maxp = gl2psListNbr(primitives); 01428 if(maxp > gl2ps->maxbestroot){ 01429 maxp = gl2ps->maxbestroot; 01430 } 01431 for(i = 0; i < maxp; i++){ 01432 prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i); 01433 gl2psGetPlane(prim1, plane); 01434 count = 0; 01435 for(j = 0; j < gl2psListNbr(primitives); j++){ 01436 if(j != i){ 01437 prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j); 01438 count += gl2psTestSplitPrimitive(prim2, plane); 01439 } 01440 if(count > best) break; 01441 } 01442 if(count < best){ 01443 best = count; 01444 index = i; 01445 *root = prim1; 01446 if(!count) return index; 01447 } 01448 } 01449 /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */ 01450 return index; 01451 } 01452 else{ 01453 return 0; 01454 } 01455 } 01456 01457 static void gl2psFreeImagemap(GL2PSimagemap *list) 01458 { 01459 GL2PSimagemap *next; 01460 while(list != NULL){ 01461 next = list->next; 01462 gl2psFree(list->image->pixels); 01463 gl2psFree(list->image); 01464 gl2psFree(list); 01465 list = next; 01466 } 01467 } 01468 01469 static void gl2psFreePrimitive(void *data) 01470 { 01471 GL2PSprimitive *q; 01472 01473 q = *(GL2PSprimitive**)data; 01474 gl2psFree(q->verts); 01475 if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){ 01476 gl2psFreeText(q->data.text); 01477 } 01478 else if(q->type == GL2PS_PIXMAP){ 01479 gl2psFreePixmap(q->data.image); 01480 } 01481 gl2psFree(q); 01482 } 01483 01484 static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list) 01485 { 01486 GL2PSprimitive *t1, *t2; 01487 01488 if(prim->type != GL2PS_QUADRANGLE){ 01489 gl2psListAdd(list, &prim); 01490 } 01491 else{ 01492 gl2psDivideQuad(prim, &t1, &t2); 01493 gl2psListAdd(list, &t1); 01494 gl2psListAdd(list, &t2); 01495 gl2psFreePrimitive(&prim); 01496 } 01497 01498 } 01499 01500 static void gl2psFreeBspTree(GL2PSbsptree **tree) 01501 { 01502 if(*tree){ 01503 if((*tree)->back) gl2psFreeBspTree(&(*tree)->back); 01504 if((*tree)->primitives){ 01505 gl2psListAction((*tree)->primitives, gl2psFreePrimitive); 01506 gl2psListDelete((*tree)->primitives); 01507 } 01508 if((*tree)->front) gl2psFreeBspTree(&(*tree)->front); 01509 gl2psFree(*tree); 01510 *tree = NULL; 01511 } 01512 } 01513 01514 static GLboolean gl2psGreater(GLfloat f1, GLfloat f2) 01515 { 01516 if(f1 > f2) return GL_TRUE; 01517 else return GL_FALSE; 01518 } 01519 01520 static GLboolean gl2psLess(GLfloat f1, GLfloat f2) 01521 { 01522 if(f1 < f2) return GL_TRUE; 01523 else return GL_FALSE; 01524 } 01525 01526 static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives) 01527 { 01528 GL2PSprimitive *prim, *frontprim = NULL, *backprim = NULL; 01529 GL2PSlist *frontlist, *backlist; 01530 GLint i, index; 01531 01532 tree->front = NULL; 01533 tree->back = NULL; 01534 tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); 01535 index = gl2psFindRoot(primitives, &prim); 01536 gl2psGetPlane(prim, tree->plane); 01537 gl2psAddPrimitiveInList(prim, tree->primitives); 01538 01539 frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); 01540 backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); 01541 01542 for(i = 0; i < gl2psListNbr(primitives); i++){ 01543 if(i != index){ 01544 prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i); 01545 switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){ 01546 case GL2PS_COINCIDENT: 01547 gl2psAddPrimitiveInList(prim, tree->primitives); 01548 break; 01549 case GL2PS_IN_BACK_OF: 01550 gl2psAddPrimitiveInList(prim, backlist); 01551 break; 01552 case GL2PS_IN_FRONT_OF: 01553 gl2psAddPrimitiveInList(prim, frontlist); 01554 break; 01555 case GL2PS_SPANNING: 01556 gl2psAddPrimitiveInList(backprim, backlist); 01557 gl2psAddPrimitiveInList(frontprim, frontlist); 01558 gl2psFreePrimitive(&prim); 01559 break; 01560 } 01561 } 01562 } 01563 01564 if(gl2psListNbr(tree->primitives)){ 01565 gl2psListSort(tree->primitives, gl2psTrianglesFirst); 01566 } 01567 01568 if(gl2psListNbr(frontlist)){ 01569 gl2psListSort(frontlist, gl2psTrianglesFirst); 01570 tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); 01571 gl2psBuildBspTree(tree->front, frontlist); 01572 } 01573 else{ 01574 gl2psListDelete(frontlist); 01575 } 01576 01577 if(gl2psListNbr(backlist)){ 01578 gl2psListSort(backlist, gl2psTrianglesFirst); 01579 tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); 01580 gl2psBuildBspTree(tree->back, backlist); 01581 } 01582 else{ 01583 gl2psListDelete(backlist); 01584 } 01585 01586 gl2psListDelete(primitives); 01587 } 01588 01589 static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, 01590 GLboolean (*compare)(GLfloat f1, GLfloat f2), 01591 void (*action)(void *data), int inverse) 01592 { 01593 GLfloat result; 01594 01595 if(!tree) return; 01596 01597 result = gl2psComparePointPlane(eye, tree->plane); 01598 01599 if(GL_TRUE == compare(result, epsilon)){ 01600 gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); 01601 if(inverse){ 01602 gl2psListActionInverse(tree->primitives, action); 01603 } 01604 else{ 01605 gl2psListAction(tree->primitives, action); 01606 } 01607 gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); 01608 } 01609 else if(GL_TRUE == compare(-epsilon, result)){ 01610 gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); 01611 if(inverse){ 01612 gl2psListActionInverse(tree->primitives, action); 01613 } 01614 else{ 01615 gl2psListAction(tree->primitives, action); 01616 } 01617 gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); 01618 } 01619 else{ 01620 gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); 01621 gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); 01622 } 01623 } 01624 01625 static void gl2psRescaleAndOffset(void) 01626 { 01627 GL2PSprimitive *prim; 01628 GLfloat minZ, maxZ, rangeZ, scaleZ; 01629 GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ; 01630 int i, j; 01631 01632 if(!gl2psListNbr(gl2ps->primitives)) 01633 return; 01634 01635 /* get z-buffer range */ 01636 prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, 0); 01637 minZ = maxZ = prim->verts[0].xyz[2]; 01638 for(i = 1; i < prim->numverts; i++){ 01639 if(prim->verts[i].xyz[2] < minZ) minZ = prim->verts[i].xyz[2]; 01640 if(prim->verts[i].xyz[2] > maxZ) maxZ = prim->verts[i].xyz[2]; 01641 } 01642 for(i = 1; i < gl2psListNbr(gl2ps->primitives); i++){ 01643 prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); 01644 for(j = 0; j < prim->numverts; j++){ 01645 if(prim->verts[j].xyz[2] < minZ) minZ = prim->verts[j].xyz[2]; 01646 if(prim->verts[j].xyz[2] > maxZ) maxZ = prim->verts[j].xyz[2]; 01647 } 01648 } 01649 rangeZ = (maxZ - minZ); 01650 01651 /* rescale z-buffer coordinate in [0,GL2PS_ZSCALE], to make it of 01652 the same order of magnitude as the x and y coordinates */ 01653 scaleZ = GL2PS_ZERO(rangeZ) ? GL2PS_ZSCALE : (GL2PS_ZSCALE / rangeZ); 01654 /* avoid precision loss (we use floats!) */ 01655 if(scaleZ > 100000.F) scaleZ = 100000.F; 01656 01657 /* apply offsets */ 01658 for(i = 0; i < gl2psListNbr(gl2ps->primitives); i++){ 01659 prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); 01660 for(j = 0; j < prim->numverts; j++){ 01661 prim->verts[j].xyz[2] = (prim->verts[j].xyz[2] - minZ) * scaleZ; 01662 } 01663 if((gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET) && 01664 (prim->type == GL2PS_LINE)){ 01665 if(gl2ps->sort == GL2PS_SIMPLE_SORT){ 01666 prim->verts[0].xyz[2] -= GL2PS_ZOFFSET_LARGE; 01667 prim->verts[1].xyz[2] -= GL2PS_ZOFFSET_LARGE; 01668 } 01669 else{ 01670 prim->verts[0].xyz[2] -= GL2PS_ZOFFSET; 01671 prim->verts[1].xyz[2] -= GL2PS_ZOFFSET; 01672 } 01673 } 01674 else if(prim->offset && (prim->type == GL2PS_TRIANGLE)){ 01675 factor = gl2ps->offset[0]; 01676 units = gl2ps->offset[1]; 01677 area = 01678 (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * 01679 (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) - 01680 (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * 01681 (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]); 01682 if(!GL2PS_ZERO(area)){ 01683 dZdX = 01684 ((prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) * 01685 (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) - 01686 (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) * 01687 (prim->verts[2].xyz[2] - prim->verts[1].xyz[2])) / area; 01688 dZdY = 01689 ((prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * 01690 (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) - 01691 (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * 01692 (prim->verts[1].xyz[2] - prim->verts[0].xyz[2])) / area; 01693 maxdZ = (GLfloat)sqrt(dZdX * dZdX + dZdY * dZdY); 01694 } 01695 else{ 01696 maxdZ = 0.0F; 01697 } 01698 dZ = factor * maxdZ + units; 01699 prim->verts[0].xyz[2] += dZ; 01700 prim->verts[1].xyz[2] += dZ; 01701 prim->verts[2].xyz[2] += dZ; 01702 } 01703 } 01704 } 01705 01706 /********************************************************************* 01707 * 01708 * 2D sorting routines (for occlusion culling) 01709 * 01710 *********************************************************************/ 01711 01712 static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane) 01713 { 01714 GLfloat n; 01715 01716 plane[0] = b[1] - a[1]; 01717 plane[1] = a[0] - b[0]; 01718 n = (GLfloat)sqrt(plane[0]*plane[0] + plane[1]*plane[1]); 01719 plane[2] = 0.0F; 01720 if(!GL2PS_ZERO(n)){ 01721 plane[0] /= n; 01722 plane[1] /= n; 01723 plane[3] = -plane[0]*a[0]-plane[1]*a[1]; 01724 return 1; 01725 } 01726 else{ 01727 plane[0] = -1.0F; 01728 plane[1] = 0.0F; 01729 plane[3] = a[0]; 01730 return 0; 01731 } 01732 } 01733 01734 static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree) 01735 { 01736 if(*tree){ 01737 if((*tree)->back) gl2psFreeBspImageTree(&(*tree)->back); 01738 if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front); 01739 gl2psFree(*tree); 01740 *tree = NULL; 01741 } 01742 } 01743 01744 static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane) 01745 { 01746 GLfloat pt_dis; 01747 01748 pt_dis = gl2psComparePointPlane(point, plane); 01749 if(pt_dis > GL2PS_EPSILON) return GL2PS_POINT_INFRONT; 01750 else if(pt_dis < -GL2PS_EPSILON) return GL2PS_POINT_BACK; 01751 else return GL2PS_POINT_COINCIDENT; 01752 } 01753 01754 static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim, 01755 GL2PSbsptree2d **tree) 01756 { 01757 GLint ret = 0; 01758 GLint i; 01759 GLint offset = 0; 01760 GL2PSbsptree2d *head = NULL, *cur = NULL; 01761 01762 if((*tree == NULL) && (prim->numverts > 2)){ 01763 /* don't cull if transparent 01764 for(i = 0; i < prim->numverts - 1; i++) 01765 if(prim->verts[i].rgba[3] < 1.0F) return; 01766 */ 01767 head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); 01768 for(i = 0; i < prim->numverts-1; i++){ 01769 if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz, 01770 prim->verts[i+1].xyz, 01771 head->plane)){ 01772 if(prim->numverts-i > 3){ 01773 offset++; 01774 } 01775 else{ 01776 gl2psFree(head); 01777 return; 01778 } 01779 } 01780 else{ 01781 break; 01782 } 01783 } 01784 head->back = NULL; 01785 head->front = NULL; 01786 for(i = 2+offset; i < prim->numverts; i++){ 01787 ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane); 01788 if(ret != GL2PS_POINT_COINCIDENT) break; 01789 } 01790 switch(ret){ 01791 case GL2PS_POINT_INFRONT : 01792 cur = head; 01793 for(i = 1+offset; i < prim->numverts-1; i++){ 01794 if(cur->front == NULL){ 01795 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); 01796 } 01797 if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, 01798 prim->verts[i+1].xyz, 01799 cur->front->plane)){ 01800 cur = cur->front; 01801 cur->front = NULL; 01802 cur->back = NULL; 01803 } 01804 } 01805 if(cur->front == NULL){ 01806 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); 01807 } 01808 if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, 01809 prim->verts[offset].xyz, 01810 cur->front->plane)){ 01811 cur->front->front = NULL; 01812 cur->front->back = NULL; 01813 } 01814 else{ 01815 gl2psFree(cur->front); 01816 cur->front = NULL; 01817 } 01818 break; 01819 case GL2PS_POINT_BACK : 01820 for(i = 0; i < 4; i++){ 01821 head->plane[i] = -head->plane[i]; 01822 } 01823 cur = head; 01824 for(i = 1+offset; i < prim->numverts-1; i++){ 01825 if(cur->front == NULL){ 01826 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); 01827 } 01828 if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz, 01829 prim->verts[i].xyz, 01830 cur->front->plane)){ 01831 cur = cur->front; 01832 cur->front = NULL; 01833 cur->back = NULL; 01834 } 01835 } 01836 if(cur->front == NULL){ 01837 cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); 01838 } 01839 if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz, 01840 prim->verts[i].xyz, 01841 cur->front->plane)){ 01842 cur->front->front = NULL; 01843 cur->front->back = NULL; 01844 } 01845 else{ 01846 gl2psFree(cur->front); 01847 cur->front = NULL; 01848 } 01849 break; 01850 default: 01851 gl2psFree(head); 01852 return; 01853 } 01854 (*tree) = head; 01855 } 01856 } 01857 01858 static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane) 01859 { 01860 GLint i; 01861 GLint pos; 01862 01863 pos = gl2psCheckPoint(prim->verts[0].xyz, plane); 01864 for(i = 1; i < prim->numverts; i++){ 01865 pos |= gl2psCheckPoint(prim->verts[i].xyz, plane); 01866 if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING; 01867 } 01868 if(pos & GL2PS_POINT_INFRONT) return GL2PS_IN_FRONT_OF; 01869 else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF; 01870 else return GL2PS_COINCIDENT; 01871 } 01872 01873 static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, 01874 GLshort numverts, 01875 GL2PSvertex *vertx) 01876 { 01877 GLint i; 01878 GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 01879 01880 if(parent->type == GL2PS_IMAGEMAP){ 01881 child->type = GL2PS_IMAGEMAP; 01882 child->data.image = parent->data.image; 01883 } 01884 else { 01885 switch(numverts){ 01886 case 1 : child->type = GL2PS_POINT; break; 01887 case 2 : child->type = GL2PS_LINE; break; 01888 case 3 : child->type = GL2PS_TRIANGLE; break; 01889 case 4 : child->type = GL2PS_QUADRANGLE; break; 01890 default: child->type = GL2PS_NO_TYPE; break; /* FIXME */ 01891 } 01892 } 01893 child->boundary = 0; /* FIXME: not done! */ 01894 child->culled = parent->culled; 01895 child->offset = parent->offset; 01896 child->pattern = parent->pattern; 01897 child->factor = parent->factor; 01898 child->width = parent->width; 01899 child->numverts = numverts; 01900 child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); 01901 for(i = 0; i < numverts; i++){ 01902 child->verts[i] = vertx[i]; 01903 } 01904 return child; 01905 } 01906 01907 static void gl2psSplitPrimitive2D(GL2PSprimitive *prim, 01908 GL2PSplane plane, 01909 GL2PSprimitive **front, 01910 GL2PSprimitive **back) 01911 { 01912 /* cur will hold the position of the current vertex 01913 prev will hold the position of the previous vertex 01914 prev0 will hold the position of the vertex number 0 01915 v1 and v2 represent the current and previous vertices, respectively 01916 flag is set if the current vertex should be checked against the plane */ 01917 GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1; 01918 01919 /* list of vertices that will go in front and back primitive */ 01920 GL2PSvertex *front_list = NULL, *back_list = NULL; 01921 01922 /* number of vertices in front and back list */ 01923 GLshort front_count = 0, back_count = 0; 01924 01925 for(i = 0; i <= prim->numverts; i++){ 01926 v1 = i; 01927 if(v1 == prim->numverts){ 01928 if(prim->numverts < 3) break; 01929 v1 = 0; 01930 v2 = prim->numverts - 1; 01931 cur = prev0; 01932 } 01933 else if(flag){ 01934 cur = gl2psCheckPoint(prim->verts[v1].xyz, plane); 01935 if(i == 0){ 01936 prev0 = cur; 01937 } 01938 } 01939 if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) && 01940 (i < prim->numverts)){ 01941 if(cur == GL2PS_POINT_INFRONT){ 01942 front_count++; 01943 front_list = (GL2PSvertex*)gl2psRealloc(front_list, 01944 sizeof(GL2PSvertex)*front_count); 01945 front_list[front_count-1] = prim->verts[v1]; 01946 } 01947 else if(cur == GL2PS_POINT_BACK){ 01948 back_count++; 01949 back_list = (GL2PSvertex*)gl2psRealloc(back_list, 01950 sizeof(GL2PSvertex)*back_count); 01951 back_list[back_count-1] = prim->verts[v1]; 01952 } 01953 else{ 01954 front_count++; 01955 front_list = (GL2PSvertex*)gl2psRealloc(front_list, 01956 sizeof(GL2PSvertex)*front_count); 01957 front_list[front_count-1] = prim->verts[v1]; 01958 back_count++; 01959 back_list = (GL2PSvertex*)gl2psRealloc(back_list, 01960 sizeof(GL2PSvertex)*back_count); 01961 back_list[back_count-1] = prim->verts[v1]; 01962 } 01963 flag = 1; 01964 } 01965 else if((prev != cur) && (cur != 0) && (prev != 0)){ 01966 if(v1 != 0){ 01967 v2 = v1-1; 01968 i--; 01969 } 01970 front_count++; 01971 front_list = (GL2PSvertex*)gl2psRealloc(front_list, 01972 sizeof(GL2PSvertex)*front_count); 01973 gl2psCutEdge(&prim->verts[v2], &prim->verts[v1], 01974 plane, &front_list[front_count-1]); 01975 back_count++; 01976 back_list = (GL2PSvertex*)gl2psRealloc(back_list, 01977 sizeof(GL2PSvertex)*back_count); 01978 back_list[back_count-1] = front_list[front_count-1]; 01979 flag = 0; 01980 } 01981 prev = cur; 01982 } 01983 *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list); 01984 *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list); 01985 gl2psFree(front_list); 01986 gl2psFree(back_list); 01987 } 01988 01989 static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree) 01990 { 01991 GLint ret = 0; 01992 GL2PSprimitive *frontprim = NULL, *backprim = NULL; 01993 01994 /* FIXME: until we consider the actual extent of text strings and 01995 pixmaps, never cull them. Otherwise the whole string/pixmap gets 01996 culled as soon as the reference point is hidden */ 01997 if(prim->type == GL2PS_PIXMAP || 01998 prim->type == GL2PS_TEXT || 01999 prim->type == GL2PS_SPECIAL){ 02000 return 1; 02001 } 02002 02003 if(*tree == NULL){ 02004 if((prim->type != GL2PS_IMAGEMAP) && (GL_FALSE == gl2ps->zerosurfacearea)){ 02005 gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree); 02006 } 02007 return 1; 02008 } 02009 else{ 02010 switch(gl2psCheckPrimitive(prim, (*tree)->plane)){ 02011 case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back); 02012 case GL2PS_IN_FRONT_OF: 02013 if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front); 02014 else return 0; 02015 case GL2PS_SPANNING: 02016 gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim); 02017 ret = gl2psAddInBspImageTree(backprim, &(*tree)->back); 02018 if((*tree)->front != NULL){ 02019 if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){ 02020 ret = 1; 02021 } 02022 } 02023 gl2psFree(frontprim->verts); 02024 gl2psFree(frontprim); 02025 gl2psFree(backprim->verts); 02026 gl2psFree(backprim); 02027 return ret; 02028 case GL2PS_COINCIDENT: 02029 if((*tree)->back != NULL){ 02030 gl2ps->zerosurfacearea = GL_TRUE; 02031 ret = gl2psAddInBspImageTree(prim, &(*tree)->back); 02032 gl2ps->zerosurfacearea = GL_FALSE; 02033 if(ret) return ret; 02034 } 02035 if((*tree)->front != NULL){ 02036 gl2ps->zerosurfacearea = GL_TRUE; 02037 ret = gl2psAddInBspImageTree(prim, &(*tree)->front); 02038 gl2ps->zerosurfacearea = GL_FALSE; 02039 if(ret) return ret; 02040 } 02041 if(prim->type == GL2PS_LINE) return 1; 02042 else return 0; 02043 } 02044 } 02045 return 0; 02046 } 02047 02048 static void gl2psAddInImageTree(void *data) 02049 { 02050 GL2PSprimitive *prim = *(GL2PSprimitive **)data; 02051 gl2ps->primitivetoadd = prim; 02052 if(prim->type == GL2PS_IMAGEMAP && prim->data.image->format == GL2PS_IMAGEMAP_VISIBLE){ 02053 prim->culled = 1; 02054 } 02055 else if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){ 02056 prim->culled = 1; 02057 } 02058 else if(prim->type == GL2PS_IMAGEMAP){ 02059 prim->data.image->format = GL2PS_IMAGEMAP_VISIBLE; 02060 } 02061 } 02062 02063 /* Boundary construction */ 02064 02065 static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list) 02066 { 02067 GL2PSprimitive *b; 02068 GLshort i; 02069 GL2PSxyz c; 02070 02071 c[0] = c[1] = c[2] = 0.0F; 02072 for(i = 0; i < prim->numverts; i++){ 02073 c[0] += prim->verts[i].xyz[0]; 02074 c[1] += prim->verts[i].xyz[1]; 02075 } 02076 c[0] /= prim->numverts; 02077 c[1] /= prim->numverts; 02078 02079 for(i = 0; i < prim->numverts; i++){ 02080 if(prim->boundary & (GLint)pow(2., i)){ 02081 b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 02082 b->type = GL2PS_LINE; 02083 b->offset = prim->offset; 02084 b->pattern = prim->pattern; 02085 b->factor = prim->factor; 02086 b->culled = prim->culled; 02087 b->width = prim->width; 02088 b->boundary = 0; 02089 b->numverts = 2; 02090 b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex)); 02091 02092 #if 0 /* FIXME: need to work on boundary offset... */ 02093 v[0] = c[0] - prim->verts[i].xyz[0]; 02094 v[1] = c[1] - prim->verts[i].xyz[1]; 02095 v[2] = 0.0F; 02096 norm = gl2psNorm(v); 02097 v[0] /= norm; 02098 v[1] /= norm; 02099 b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0]; 02100 b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1]; 02101 b->verts[0].xyz[2] = prim->verts[i].xyz[2]; 02102 v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; 02103 v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; 02104 norm = gl2psNorm(v); 02105 v[0] /= norm; 02106 v[1] /= norm; 02107 b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0]; 02108 b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1]; 02109 b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; 02110 #else 02111 b->verts[0].xyz[0] = prim->verts[i].xyz[0]; 02112 b->verts[0].xyz[1] = prim->verts[i].xyz[1]; 02113 b->verts[0].xyz[2] = prim->verts[i].xyz[2]; 02114 b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; 02115 b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; 02116 b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; 02117 #endif 02118 02119 b->verts[0].rgba[0] = 0.0F; 02120 b->verts[0].rgba[1] = 0.0F; 02121 b->verts[0].rgba[2] = 0.0F; 02122 b->verts[0].rgba[3] = 0.0F; 02123 b->verts[1].rgba[0] = 0.0F; 02124 b->verts[1].rgba[1] = 0.0F; 02125 b->verts[1].rgba[2] = 0.0F; 02126 b->verts[1].rgba[3] = 0.0F; 02127 gl2psListAdd(list, &b); 02128 } 02129 } 02130 02131 } 02132 02133 static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree) 02134 { 02135 GLint i; 02136 GL2PSprimitive *prim; 02137 02138 if(!tree) return; 02139 gl2psBuildPolygonBoundary(tree->back); 02140 for(i = 0; i < gl2psListNbr(tree->primitives); i++){ 02141 prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i); 02142 if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives); 02143 } 02144 gl2psBuildPolygonBoundary(tree->front); 02145 } 02146 02147 /********************************************************************* 02148 * 02149 * Feedback buffer parser 02150 * 02151 *********************************************************************/ 02152 02153 static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, 02154 GL2PSvertex *verts, GLint offset, 02155 GLushort pattern, GLint factor, 02156 GLfloat width, char boundary) 02157 { 02158 GL2PSprimitive *prim; 02159 02160 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 02161 prim->type = type; 02162 prim->numverts = numverts; 02163 prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); 02164 memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex)); 02165 prim->boundary = boundary; 02166 prim->offset = (char)offset; 02167 prim->pattern = pattern; 02168 prim->factor = factor; 02169 prim->width = width; 02170 prim->culled = 0; 02171 02172 /* FIXME: here we should have an option to split stretched 02173 tris/quads to enhance SIMPLE_SORT */ 02174 02175 gl2psListAdd(gl2ps->primitives, &prim); 02176 } 02177 02178 static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p) 02179 { 02180 GLint i; 02181 02182 v->xyz[0] = p[0]; 02183 v->xyz[1] = p[1]; 02184 v->xyz[2] = p[2]; 02185 02186 if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){ 02187 i = (GLint)(p[3] + 0.5); 02188 v->rgba[0] = gl2ps->colormap[i][0]; 02189 v->rgba[1] = gl2ps->colormap[i][1]; 02190 v->rgba[2] = gl2ps->colormap[i][2]; 02191 v->rgba[3] = gl2ps->colormap[i][3]; 02192 return 4; 02193 } 02194 else{ 02195 v->rgba[0] = p[3]; 02196 v->rgba[1] = p[4]; 02197 v->rgba[2] = p[5]; 02198 v->rgba[3] = p[6]; 02199 return 7; 02200 } 02201 } 02202 02203 static void gl2psParseFeedbackBuffer(GLint used) 02204 { 02205 char flag; 02206 GLushort pattern = 0; 02207 GLboolean boundary; 02208 GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0; 02209 GLfloat lwidth = 1.0F, psize = 1.0F; 02210 GLfloat *current; 02211 GL2PSvertex vertices[3]; 02212 GL2PSprimitive *prim; 02213 GL2PSimagemap *node; 02214 02215 current = gl2ps->feedback; 02216 boundary = gl2ps->boundary = GL_FALSE; 02217 02218 while(used > 0){ 02219 02220 if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE; 02221 02222 switch((GLint)*current){ 02223 case GL_POINT_TOKEN : 02224 current ++; 02225 used --; 02226 i = gl2psGetVertex(&vertices[0], current); 02227 current += i; 02228 used -= i; 02229 gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, 02230 pattern, factor, psize, 0); 02231 break; 02232 case GL_LINE_TOKEN : 02233 case GL_LINE_RESET_TOKEN : 02234 current ++; 02235 used --; 02236 i = gl2psGetVertex(&vertices[0], current); 02237 current += i; 02238 used -= i; 02239 i = gl2psGetVertex(&vertices[1], current); 02240 current += i; 02241 used -= i; 02242 gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, 02243 pattern, factor, lwidth, 0); 02244 break; 02245 case GL_POLYGON_TOKEN : 02246 count = (GLint)current[1]; 02247 current += 2; 02248 used -= 2; 02249 v = vtot = 0; 02250 while(count > 0 && used > 0){ 02251 i = gl2psGetVertex(&vertices[v], current); 02252 gl2psAdaptVertexForBlending(&vertices[v]); 02253 current += i; 02254 used -= i; 02255 count --; 02256 vtot++; 02257 if(v == 2){ 02258 if(GL_TRUE == boundary){ 02259 if(!count && vtot == 2) flag = 1|2|4; 02260 else if(!count) flag = 2|4; 02261 else if(vtot == 2) flag = 1|2; 02262 else flag = 2; 02263 } 02264 else 02265 flag = 0; 02266 gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices, offset, 02267 pattern, factor, 1, flag); 02268 vertices[1] = vertices[2]; 02269 } 02270 else 02271 v ++; 02272 } 02273 break; 02274 case GL_BITMAP_TOKEN : 02275 case GL_DRAW_PIXEL_TOKEN : 02276 case GL_COPY_PIXEL_TOKEN : 02277 current ++; 02278 used --; 02279 i = gl2psGetVertex(&vertices[0], current); 02280 current += i; 02281 used -= i; 02282 break; 02283 case GL_PASS_THROUGH_TOKEN : 02284 switch((GLint)current[1]){ 02285 case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break; 02286 case GL2PS_END_OFFSET_TOKEN : offset = 0; break; 02287 case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break; 02288 case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break; 02289 case GL2PS_END_STIPPLE_TOKEN : pattern = 0; factor = 0; break; 02290 case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break; 02291 case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break; 02292 case GL2PS_BEGIN_STIPPLE_TOKEN : 02293 current += 2; 02294 used -= 2; 02295 pattern = (GLushort)current[1]; 02296 current += 2; 02297 used -= 2; 02298 factor = (GLint)current[1]; 02299 break; 02300 case GL2PS_SRC_BLEND_TOKEN : 02301 current += 2; 02302 used -= 2; 02303 gl2ps->blendfunc[0] = (GLint)current[1]; 02304 break; 02305 case GL2PS_DST_BLEND_TOKEN : 02306 current += 2; 02307 used -= 2; 02308 gl2ps->blendfunc[1] = (GLint)current[1]; 02309 break; 02310 case GL2PS_POINT_SIZE_TOKEN : 02311 current += 2; 02312 used -= 2; 02313 psize = current[1]; 02314 break; 02315 case GL2PS_LINE_WIDTH_TOKEN : 02316 current += 2; 02317 used -= 2; 02318 lwidth = current[1]; 02319 break; 02320 case GL2PS_IMAGEMAP_TOKEN : 02321 prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); 02322 prim->type = GL2PS_IMAGEMAP; 02323 prim->boundary = 0; 02324 prim->numverts = 4; 02325 prim->verts = (GL2PSvertex *)gl2psMalloc(4 * sizeof(GL2PSvertex)); 02326 prim->culled = 0; 02327 prim->offset = 0; 02328 prim->pattern = 0; 02329 prim->factor = 0; 02330 prim->width = 1; 02331 02332 node = (GL2PSimagemap*)gl2psMalloc(sizeof(GL2PSimagemap)); 02333 node->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); 02334 node->image->type = 0; 02335 node->image->format = 0; 02336 node->image->zoom_x = 1.0F; 02337 node->image->zoom_y = 1.0F; 02338 node->next = NULL; 02339 02340 if(gl2ps->imagemap_head == NULL) 02341 gl2ps->imagemap_head = node; 02342 else 02343 gl2ps->imagemap_tail->next = node; 02344 gl2ps->imagemap_tail = node; 02345 prim->data.image = node->image; 02346 02347 current += 2; used -= 2; 02348 i = gl2psGetVertex(&prim->verts[0], ¤t[1]); 02349 current += i; used -= i; 02350 02351 node->image->width = (GLint)current[2]; 02352 current += 2; used -= 2; 02353 node->image->height = (GLint)current[2]; 02354 prim->verts[0].xyz[0] = prim->verts[0].xyz[0] - (int)(node->image->width / 2) + 0.5F; 02355 prim->verts[0].xyz[1] = prim->verts[0].xyz[1] - (int)(node->image->height / 2) + 0.5F; 02356 for(i = 1; i < 4; i++){ 02357 for(v = 0; v < 3; v++){ 02358 prim->verts[i].xyz[v] = prim->verts[0].xyz[v]; 02359 prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; 02360 } 02361 prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; 02362 } 02363 prim->verts[1].xyz[0] = prim->verts[1].xyz[0] + node->image->width; 02364 prim->verts[2].xyz[0] = prim->verts[1].xyz[0]; 02365 prim->verts[2].xyz[1] = prim->verts[2].xyz[1] + node->image->height; 02366 prim->verts[3].xyz[1] = prim->verts[2].xyz[1]; 02367 02368 sizeoffloat = sizeof(GLfloat); 02369 v = 2 * sizeoffloat; 02370 vtot = node->image->height + node->image->height * 02371 ((node->image->width - 1) / 8); 02372 node->image->pixels = (GLfloat*)gl2psMalloc(v + vtot); 02373 node->image->pixels[0] = prim->verts[0].xyz[0]; 02374 node->image->pixels[1] = prim->verts[0].xyz[1]; 02375 02376 for(i = 0; i < vtot; i += sizeoffloat){ 02377 current += 2; used -= 2; 02378 if((vtot - i) >= 4) 02379 memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), sizeoffloat); 02380 else 02381 memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), vtot - i); 02382 } 02383 current++; used--; 02384 gl2psListAdd(gl2ps->primitives, &prim); 02385 break; 02386 case GL2PS_DRAW_PIXELS_TOKEN : 02387 case GL2PS_TEXT_TOKEN : 02388 if(auxindex < gl2psListNbr(gl2ps->auxprimitives)) 02389 gl2psListAdd(gl2ps->primitives, 02390 gl2psListPointer(gl2ps->auxprimitives, auxindex++)); 02391 else 02392 gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer"); 02393 break; 02394 } 02395 current += 2; 02396 used -= 2; 02397 break; 02398 default : 02399 gl2psMsg(GL2PS_WARNING, "Unknown token in buffer"); 02400 current ++; 02401 used --; 02402 break; 02403 } 02404 } 02405 02406 gl2psListReset(gl2ps->auxprimitives); 02407 } 02408 02409 /********************************************************************* 02410 * 02411 * PostScript routines 02412 * 02413 *********************************************************************/ 02414 02415 static void gl2psWriteByte(unsigned char byte) 02416 { 02417 unsigned char h = byte / 16; 02418 unsigned char l = byte % 16; 02419 gl2psPrintf("%x%x", h, l); 02420 } 02421 02422 static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im) 02423 { 02424 GLuint nbhex, nbyte, nrgb, nbits; 02425 GLuint row, col, ibyte, icase; 02426 GLfloat dr, dg, db, fgrey; 02427 unsigned char red = 0, green = 0, blue = 0, b, grey; 02428 GLuint width = (GLuint)im->width; 02429 GLuint height = (GLuint)im->height; 02430 02431 /* FIXME: should we define an option for these? Or just keep the 02432 8-bit per component case? */ 02433 int greyscale = 0; /* set to 1 to output greyscale image */ 02434 int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */ 02435 02436 if((width <= 0) || (height <= 0)) return; 02437 02438 gl2psPrintf("gsave\n"); 02439 gl2psPrintf("%.2f %.2f translate\n", x, y); 02440 gl2psPrintf("%.2f %.2f scale\n", width * im->zoom_x, height * im->zoom_y); 02441 02442 if(greyscale){ /* greyscale */ 02443 gl2psPrintf("/picstr %d string def\n", width); 02444 gl2psPrintf("%d %d %d\n", width, height, 8); 02445 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); 02446 gl2psPrintf("{ currentfile picstr readhexstring pop }\n"); 02447 gl2psPrintf("image\n"); 02448 for(row = 0; row < height; row++){ 02449 for(col = 0; col < width; col++){ 02450 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02451 fgrey = (0.30F * dr + 0.59F * dg + 0.11F * db); 02452 grey = (unsigned char)(255. * fgrey); 02453 gl2psWriteByte(grey); 02454 } 02455 gl2psPrintf("\n"); 02456 } 02457 nbhex = width * height * 2; 02458 gl2psPrintf("%%%% nbhex digit :%d\n", nbhex); 02459 } 02460 else if(nbit == 2){ /* color, 2 bits for r and g and b; rgbs following each other */ 02461 nrgb = width * 3; 02462 nbits = nrgb * nbit; 02463 nbyte = nbits / 8; 02464 if((nbyte * 8) != nbits) nbyte++; 02465 gl2psPrintf("/rgbstr %d string def\n", nbyte); 02466 gl2psPrintf("%d %d %d\n", width, height, nbit); 02467 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); 02468 gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); 02469 gl2psPrintf("false 3\n"); 02470 gl2psPrintf("colorimage\n"); 02471 for(row = 0; row < height; row++){ 02472 icase = 1; 02473 col = 0; 02474 b = 0; 02475 for(ibyte = 0; ibyte < nbyte; ibyte++){ 02476 if(icase == 1) { 02477 if(col < width) { 02478 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02479 } 02480 else { 02481 dr = dg = db = 0; 02482 } 02483 col++; 02484 red = (unsigned char)(3. * dr); 02485 green = (unsigned char)(3. * dg); 02486 blue = (unsigned char)(3. * db); 02487 b = red; 02488 b = (b<<2) + green; 02489 b = (b<<2) + blue; 02490 if(col < width) { 02491 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02492 } 02493 else { 02494 dr = dg = db = 0; 02495 } 02496 col++; 02497 red = (unsigned char)(3. * dr); 02498 green = (unsigned char)(3. * dg); 02499 blue = (unsigned char)(3. * db); 02500 b = (b<<2) + red; 02501 gl2psWriteByte(b); 02502 b = 0; 02503 icase++; 02504 } 02505 else if(icase == 2) { 02506 b = green; 02507 b = (b<<2) + blue; 02508 if(col < width) { 02509 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02510 } 02511 else { 02512 dr = dg = db = 0; 02513 } 02514 col++; 02515 red = (unsigned char)(3. * dr); 02516 green = (unsigned char)(3. * dg); 02517 blue = (unsigned char)(3. * db); 02518 b = (b<<2) + red; 02519 b = (b<<2) + green; 02520 gl2psWriteByte(b); 02521 b = 0; 02522 icase++; 02523 } 02524 else if(icase == 3) { 02525 b = blue; 02526 if(col < width) { 02527 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02528 } 02529 else { 02530 dr = dg = db = 0; 02531 } 02532 col++; 02533 red = (unsigned char)(3. * dr); 02534 green = (unsigned char)(3. * dg); 02535 blue = (unsigned char)(3. * db); 02536 b = (b<<2) + red; 02537 b = (b<<2) + green; 02538 b = (b<<2) + blue; 02539 gl2psWriteByte(b); 02540 b = 0; 02541 icase = 1; 02542 } 02543 } 02544 gl2psPrintf("\n"); 02545 } 02546 } 02547 else if(nbit == 4){ /* color, 4 bits for r and g and b; rgbs following each other */ 02548 nrgb = width * 3; 02549 nbits = nrgb * nbit; 02550 nbyte = nbits / 8; 02551 if((nbyte * 8) != nbits) nbyte++; 02552 gl2psPrintf("/rgbstr %d string def\n", nbyte); 02553 gl2psPrintf("%d %d %d\n", width, height, nbit); 02554 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); 02555 gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); 02556 gl2psPrintf("false 3\n"); 02557 gl2psPrintf("colorimage\n"); 02558 for(row = 0; row < height; row++){ 02559 col = 0; 02560 icase = 1; 02561 for(ibyte = 0; ibyte < nbyte; ibyte++){ 02562 if(icase == 1) { 02563 if(col < width) { 02564 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02565 } 02566 else { 02567 dr = dg = db = 0; 02568 } 02569 col++; 02570 red = (unsigned char)(15. * dr); 02571 green = (unsigned char)(15. * dg); 02572 gl2psPrintf("%x%x", red, green); 02573 icase++; 02574 } 02575 else if(icase == 2) { 02576 blue = (unsigned char)(15. * db); 02577 if(col < width) { 02578 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02579 } 02580 else { 02581 dr = dg = db = 0; 02582 } 02583 col++; 02584 red = (unsigned char)(15. * dr); 02585 gl2psPrintf("%x%x", blue, red); 02586 icase++; 02587 } 02588 else if(icase == 3) { 02589 green = (unsigned char)(15. * dg); 02590 blue = (unsigned char)(15. * db); 02591 gl2psPrintf("%x%x", green, blue); 02592 icase = 1; 02593 } 02594 } 02595 gl2psPrintf("\n"); 02596 } 02597 } 02598 else{ /* 8 bit for r and g and b */ 02599 nbyte = width * 3; 02600 gl2psPrintf("/rgbstr %d string def\n", nbyte); 02601 gl2psPrintf("%d %d %d\n", width, height, 8); 02602 gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); 02603 gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); 02604 gl2psPrintf("false 3\n"); 02605 gl2psPrintf("colorimage\n"); 02606 for(row = 0; row < height; row++){ 02607 for(col = 0; col < width; col++){ 02608 gl2psGetRGB(im, col, row, &dr, &dg, &db); 02609 red = (unsigned char)(255. * dr); 02610 gl2psWriteByte(red); 02611 green = (unsigned char)(255. * dg); 02612 gl2psWriteByte(green); 02613 blue = (unsigned char)(255. * db); 02614 gl2psWriteByte(blue); 02615 } 02616 gl2psPrintf("\n"); 02617 } 02618 } 02619 02620 gl2psPrintf("grestore\n"); 02621 } 02622 02623 static void gl2psPrintPostScriptImagemap(GLfloat x, GLfloat y, 02624 GLsizei width, GLsizei height, 02625 const unsigned char *imagemap){ 02626 int i, size; 02627 02628 if((width <= 0) || (height <= 0)) return; 02629 02630 size = height + height * (width - 1) / 8; 02631 02632 gl2psPrintf("gsave\n"); 02633 gl2psPrintf("%.2f %.2f translate\n", x, y); 02634 gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height); 02635 gl2psPrintf("[ %d 0 0 -%d 0 %d ] {<", width, height); 02636 for(i = 0; i < size; i++){ 02637 gl2psWriteByte(*imagemap); 02638 imagemap++; 02639 } 02640 gl2psPrintf(">} imagemask\ngrestore\n"); 02641 } 02642 02643 static void gl2psPrintPostScriptHeader(void) 02644 { 02645 time_t now; 02646 02647 /* Since compression is not part of the PostScript standard, 02648 compressed PostScript files are just gzipped PostScript files 02649 ("ps.gz" or "eps.gz") */ 02650 gl2psPrintGzipHeader(); 02651 02652 time(&now); 02653 02654 if(gl2ps->format == GL2PS_PS){ 02655 gl2psPrintf("%%!PS-Adobe-3.0\n"); 02656 } 02657 else{ 02658 gl2psPrintf("%%!PS-Adobe-3.0 EPSF-3.0\n"); 02659 } 02660 02661 gl2psPrintf("%%%%Title: %s\n" 02662 "%%%%Creator: GL2PS %d.%d.%d%s, %s\n" 02663 "%%%%For: %s\n" 02664 "%%%%CreationDate: %s" 02665 "%%%%LanguageLevel: 3\n" 02666 "%%%%DocumentData: Clean7Bit\n" 02667 "%%%%Pages: 1\n", 02668 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, 02669 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, 02670 gl2ps->producer, ctime(&now)); 02671 02672 if(gl2ps->format == GL2PS_PS){ 02673 gl2psPrintf("%%%%Orientation: %s\n" 02674 "%%%%DocumentMedia: Default %d %d 0 () ()\n", 02675 (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait", 02676 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : 02677 (int)gl2ps->viewport[2], 02678 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : 02679 (int)gl2ps->viewport[3]); 02680 } 02681 02682 gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n" 02683 "%%%%EndComments\n", 02684 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : 02685 (int)gl2ps->viewport[0], 02686 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] : 02687 (int)gl2ps->viewport[1], 02688 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : 02689 (int)gl2ps->viewport[2], 02690 (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : 02691 (int)gl2ps->viewport[3]); 02692 02693 /* RGB color: r g b C (replace C by G in output to change from rgb to gray) 02694 Grayscale: r g b G 02695 Font choose: size fontname FC 02696 Text string: (string) x y size fontname S?? 02697 Rotated text string: (string) angle x y size fontname S??R 02698 Point primitive: x y size P 02699 Line width: width W 02700 Line start: x y LS 02701 Line joining last point: x y L 02702 Line end: x y LE 02703 Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T 02704 Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */ 02705 02706 gl2psPrintf("%%%%BeginProlog\n" 02707 "/gl2psdict 64 dict def gl2psdict begin\n" 02708 "0 setlinecap 0 setlinejoin\n" 02709 "/tryPS3shading %s def %% set to false to force subdivision\n" 02710 "/rThreshold %g def %% red component subdivision threshold\n" 02711 "/gThreshold %g def %% green component subdivision threshold\n" 02712 "/bThreshold %g def %% blue component subdivision threshold\n", 02713 (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true", 02714 gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]); 02715 02716 gl2psPrintf("/BD { bind def } bind def\n" 02717 "/C { setrgbcolor } BD\n" 02718 "/G { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n" 02719 "/W { setlinewidth } BD\n"); 02720 02721 gl2psPrintf("/FC { findfont exch /SH exch def SH scalefont setfont } BD\n" 02722 "/SW { dup stringwidth pop } BD\n" 02723 "/S { FC moveto show } BD\n" 02724 "/SBC{ FC moveto SW -2 div 0 rmoveto show } BD\n" 02725 "/SBR{ FC moveto SW neg 0 rmoveto show } BD\n" 02726 "/SCL{ FC moveto 0 SH -2 div rmoveto show } BD\n" 02727 "/SCC{ FC moveto SW -2 div SH -2 div rmoveto show } BD\n" 02728 "/SCR{ FC moveto SW neg SH -2 div rmoveto show } BD\n" 02729 "/STL{ FC moveto 0 SH neg rmoveto show } BD\n" 02730 "/STC{ FC moveto SW -2 div SH neg rmoveto show } BD\n" 02731 "/STR{ FC moveto SW neg SH neg rmoveto show } BD\n"); 02732 02733 /* rotated text routines: same nameanem with R appended */ 02734 02735 gl2psPrintf("/FCT { FC translate 0 0 } BD\n" 02736 "/SR { gsave FCT moveto rotate show grestore } BD\n" 02737 "/SBCR{ gsave FCT moveto rotate SW -2 div 0 rmoveto show grestore } BD\n" 02738 "/SBRR{ gsave FCT moveto rotate SW neg 0 rmoveto show grestore } BD\n" 02739 "/SCLR{ gsave FCT moveto rotate 0 SH -2 div rmoveto show grestore} BD\n"); 02740 gl2psPrintf("/SCCR{ gsave FCT moveto rotate SW -2 div SH -2 div rmoveto show grestore} BD\n" 02741 "/SCRR{ gsave FCT moveto rotate SW neg SH -2 div rmoveto show grestore} BD\n" 02742 "/STLR{ gsave FCT moveto rotate 0 SH neg rmoveto show grestore } BD\n" 02743 "/STCR{ gsave FCT moveto rotate SW -2 div SH neg rmoveto show grestore } BD\n" 02744 "/STRR{ gsave FCT moveto rotate SW neg SH neg rmoveto show grestore } BD\n"); 02745 02746 gl2psPrintf("/P { newpath 0.0 360.0 arc closepath fill } BD\n" 02747 "/LS { newpath moveto } BD\n" 02748 "/L { lineto } BD\n" 02749 "/LE { lineto stroke } BD\n" 02750 "/T { newpath moveto lineto lineto closepath fill } BD\n"); 02751 02752 /* Smooth-shaded triangle with PostScript level 3 shfill operator: 02753 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */ 02754 02755 gl2psPrintf("/STshfill {\n" 02756 " /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n" 02757 " /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n" 02758 " /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n" 02759 " gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n" 02760 " /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n" 02761 " shfill grestore } BD\n"); 02762 02763 /* Flat-shaded triangle with middle color: 02764 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */ 02765 02766 gl2psPrintf(/* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */ 02767 "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */ 02768 /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */ 02769 " 3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */ 02770 /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */ 02771 " 3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */ 02772 /* stack : x3 y3 x2 y2 x1 y1 r g b */ 02773 " C T } BD\n"); 02774 02775 /* Split triangle in four sub-triangles (at sides middle points) and call the 02776 STnoshfill procedure on each, interpolating the colors in RGB space: 02777 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit 02778 (in procedure comments key: (Vi) = xi yi ri gi bi) */ 02779 02780 gl2psPrintf("/STsplit {\n" 02781 " 4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */ 02782 " 4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */ 02783 " 4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */ 02784 " 4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */ 02785 " 4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */ 02786 " 5 copy 5 copy 25 15 roll\n"); 02787 02788 /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */ 02789 02790 gl2psPrintf(" 9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */ 02791 " 9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */ 02792 " 9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */ 02793 " 9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */ 02794 " 9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */ 02795 " 5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n"); 02796 02797 /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */ 02798 02799 gl2psPrintf(" 4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */ 02800 " 4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */ 02801 " 4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */ 02802 " 4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */ 02803 " 4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */ 02804 " 5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n"); 02805 02806 /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */ 02807 02808 gl2psPrintf(" STnoshfill STnoshfill STnoshfill STnoshfill } BD\n"); 02809 02810 /* Gouraud shaded triangle using recursive subdivision until the difference 02811 between corner colors does not exceed the thresholds: 02812 x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill */ 02813 02814 gl2psPrintf("/STnoshfill {\n" 02815 " 2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */ 02816 " { STsplit }\n" 02817 " { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */ 02818 " { STsplit }\n" 02819 " { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */ 02820 " { STsplit }\n" 02821 " { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */ 02822 " { STsplit }\n" 02823 " { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */ 02824 " { STsplit }\n" 02825 " { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */ 02826 " { STsplit }\n" 02827 " { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */ 02828 gl2psPrintf(" { STsplit }\n" 02829 " { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */ 02830 " { STsplit }\n" 02831 " { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */ 02832 " { STsplit }\n" 02833 " { Tm }\n" /* all colors sufficiently similar */ 02834 " ifelse }\n" 02835 " ifelse }\n" 02836 " ifelse }\n" 02837 " ifelse }\n" 02838 " ifelse }\n" 02839 " ifelse }\n" 02840 " ifelse }\n" 02841 " ifelse }\n" 02842 " ifelse } BD\n"); 02843 02844 gl2psPrintf("tryPS3shading\n" 02845 "{ /shfill where\n" 02846 " { /ST { STshfill } BD }\n" 02847 " { /ST { STnoshfill } BD }\n" 02848 " ifelse }\n" 02849 "{ /ST { STnoshfill } BD }\n" 02850 "ifelse\n"); 02851 02852 gl2psPrintf("end\n" 02853 "%%%%EndProlog\n" 02854 "%%%%BeginSetup\n" 02855 "/DeviceRGB setcolorspace\n" 02856 "gl2psdict begin\n" 02857 "%%%%EndSetup\n" 02858 "%%%%Page: 1 1\n" 02859 "%%%%BeginPageSetup\n"); 02860 02861 if(gl2ps->options & GL2PS_LANDSCAPE){ 02862 gl2psPrintf("%d 0 translate 90 rotate\n", 02863 (int)gl2ps->viewport[3]); 02864 } 02865 02866 gl2psPrintf("%%%%EndPageSetup\n" 02867 "mark\n" 02868 "gsave\n" 02869 "1.0 1.0 scale\n"); 02870 02871 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 02872 gl2psPrintf("%g %g %g C\n" 02873 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" 02874 "closepath fill\n", 02875 gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2], 02876 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], 02877 (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], 02878 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); 02879 } 02880 } 02881 02882 static void gl2psPrintPostScriptColor(GL2PSrgba rgba) 02883 { 02884 if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ 02885 gl2psSetLastColor(rgba); 02886 gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]); 02887 } 02888 } 02889 02890 static void gl2psResetPostScriptColor(void) 02891 { 02892 gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.; 02893 } 02894 02895 static void gl2psEndPostScriptLine(void) 02896 { 02897 int i; 02898 if(gl2ps->lastvertex.rgba[0] >= 0.){ 02899 gl2psPrintf("%g %g LE\n", gl2ps->lastvertex.xyz[0], gl2ps->lastvertex.xyz[1]); 02900 for(i = 0; i < 3; i++) 02901 gl2ps->lastvertex.xyz[i] = -1.; 02902 for(i = 0; i < 4; i++) 02903 gl2ps->lastvertex.rgba[i] = -1.; 02904 } 02905 } 02906 02907 static void gl2psParseStipplePattern(GLushort pattern, GLint factor, 02908 int *nb, int array[10]) 02909 { 02910 int i, n; 02911 int on[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 02912 int off[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 02913 char tmp[16]; 02914 02915 /* extract the 16 bits from the OpenGL stipple pattern */ 02916 for(n = 15; n >= 0; n--){ 02917 tmp[n] = (char)(pattern & 0x01); 02918 pattern >>= 1; 02919 } 02920 /* compute the on/off pixel sequence */ 02921 n = 0; 02922 for(i = 0; i < 8; i++){ 02923 while(n < 16 && !tmp[n]){ off[i]++; n++; } 02924 while(n < 16 && tmp[n]){ on[i]++; n++; } 02925 if(n >= 15){ i++; break; } 02926 } 02927 02928 /* store the on/off array from right to left, starting with off 02929 pixels. The PostScript specification allows for at most 11 02930 elements in the on/off array, so we limit ourselves to 5 on/off 02931 couples (our longest possible array is thus [on4 off4 on3 off3 02932 on2 off2 on1 off1 on0 off0]) */ 02933 *nb = 0; 02934 for(n = i - 1; n >= 0; n--){ 02935 array[(*nb)++] = factor * on[n]; 02936 array[(*nb)++] = factor * off[n]; 02937 if(*nb == 10) break; 02938 } 02939 } 02940 02941 static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, const char *str) 02942 { 02943 int len = 0, i, n, array[10]; 02944 02945 if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) 02946 return 0; 02947 02948 gl2ps->lastpattern = pattern; 02949 gl2ps->lastfactor = factor; 02950 02951 if(!pattern || !factor){ 02952 /* solid line */ 02953 len += gl2psPrintf("[] 0 %s\n", str); 02954 } 02955 else{ 02956 gl2psParseStipplePattern(pattern, factor, &n, array); 02957 len += gl2psPrintf("["); 02958 for(i = 0; i < n; i++){ 02959 if(i) len += gl2psPrintf(" "); 02960 len += gl2psPrintf("%d", array[i]); 02961 } 02962 len += gl2psPrintf("] 0 %s\n", str); 02963 } 02964 02965 return len; 02966 } 02967 02968 static void gl2psPrintPostScriptPrimitive(void *data) 02969 { 02970 int newline; 02971 GL2PSprimitive *prim; 02972 02973 prim = *(GL2PSprimitive**)data; 02974 02975 if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; 02976 02977 /* Every effort is made to draw lines as connected segments (i.e., 02978 using a single PostScript path): this is the only way to get nice 02979 line joins and to not restart the stippling for every line 02980 segment. So if the primitive to print is not a line we must first 02981 finish the current line (if any): */ 02982 if(prim->type != GL2PS_LINE) gl2psEndPostScriptLine(); 02983 02984 switch(prim->type){ 02985 case GL2PS_POINT : 02986 gl2psPrintPostScriptColor(prim->verts[0].rgba); 02987 gl2psPrintf("%g %g %g P\n", 02988 prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width); 02989 break; 02990 case GL2PS_LINE : 02991 if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || 02992 !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || 02993 gl2ps->lastlinewidth != prim->width || 02994 gl2ps->lastpattern != prim->pattern || 02995 gl2ps->lastfactor != prim->factor){ 02996 /* End the current line if the new segment does not start where 02997 the last one ended, or if the color, the width or the 02998 stippling have changed (multi-stroking lines with changing 02999 colors is necessary until we use /shfill for lines; 03000 unfortunately this means that at the moment we can screw up 03001 line stippling for smooth-shaded lines) */ 03002 gl2psEndPostScriptLine(); 03003 newline = 1; 03004 } 03005 else{ 03006 newline = 0; 03007 } 03008 if(gl2ps->lastlinewidth != prim->width){ 03009 gl2ps->lastlinewidth = prim->width; 03010 gl2psPrintf("%g W\n", gl2ps->lastlinewidth); 03011 } 03012 gl2psPrintPostScriptDash(prim->pattern, prim->factor, "setdash"); 03013 gl2psPrintPostScriptColor(prim->verts[0].rgba); 03014 gl2psPrintf("%g %g %s\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], 03015 newline ? "LS" : "L"); 03016 gl2ps->lastvertex = prim->verts[1]; 03017 break; 03018 case GL2PS_TRIANGLE : 03019 if(!gl2psVertsSameColor(prim)){ 03020 gl2psResetPostScriptColor(); 03021 gl2psPrintf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n", 03022 prim->verts[2].xyz[0], prim->verts[2].xyz[1], 03023 prim->verts[2].rgba[0], prim->verts[2].rgba[1], 03024 prim->verts[2].rgba[2], prim->verts[1].xyz[0], 03025 prim->verts[1].xyz[1], prim->verts[1].rgba[0], 03026 prim->verts[1].rgba[1], prim->verts[1].rgba[2], 03027 prim->verts[0].xyz[0], prim->verts[0].xyz[1], 03028 prim->verts[0].rgba[0], prim->verts[0].rgba[1], 03029 prim->verts[0].rgba[2]); 03030 } 03031 else{ 03032 gl2psPrintPostScriptColor(prim->verts[0].rgba); 03033 gl2psPrintf("%g %g %g %g %g %g T\n", 03034 prim->verts[2].xyz[0], prim->verts[2].xyz[1], 03035 prim->verts[1].xyz[0], prim->verts[1].xyz[1], 03036 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 03037 } 03038 break; 03039 case GL2PS_QUADRANGLE : 03040 gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); 03041 break; 03042 case GL2PS_PIXMAP : 03043 gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1], 03044 prim->data.image); 03045 break; 03046 case GL2PS_IMAGEMAP : 03047 if(prim->data.image->type != GL2PS_IMAGEMAP_WRITTEN){ 03048 gl2psPrintPostScriptColor(prim->verts[0].rgba); 03049 gl2psPrintPostScriptImagemap(prim->data.image->pixels[0], 03050 prim->data.image->pixels[1], 03051 prim->data.image->width, prim->data.image->height, 03052 (const unsigned char*)(&(prim->data.image->pixels[2]))); 03053 prim->data.image->type = GL2PS_IMAGEMAP_WRITTEN; 03054 } 03055 break; 03056 case GL2PS_TEXT : 03057 gl2psPrintPostScriptColor(prim->verts[0].rgba); 03058 gl2psPrintf("(%s) ", prim->data.text->str); 03059 if(prim->data.text->angle) 03060 gl2psPrintf("%g ", prim->data.text->angle); 03061 gl2psPrintf("%g %g %d /%s ", 03062 prim->verts[0].xyz[0], prim->verts[0].xyz[1], 03063 prim->data.text->fontsize, prim->data.text->fontname); 03064 switch(prim->data.text->alignment){ 03065 case GL2PS_TEXT_C: 03066 gl2psPrintf(prim->data.text->angle ? "SCCR\n" : "SCC\n"); 03067 break; 03068 case GL2PS_TEXT_CL: 03069 gl2psPrintf(prim->data.text->angle ? "SCLR\n" : "SCL\n"); 03070 break; 03071 case GL2PS_TEXT_CR: 03072 gl2psPrintf(prim->data.text->angle ? "SCRR\n" : "SCR\n"); 03073 break; 03074 case GL2PS_TEXT_B: 03075 gl2psPrintf(prim->data.text->angle ? "SBCR\n" : "SBC\n"); 03076 break; 03077 case GL2PS_TEXT_BR: 03078 gl2psPrintf(prim->data.text->angle ? "SBRR\n" : "SBR\n"); 03079 break; 03080 case GL2PS_TEXT_T: 03081 gl2psPrintf(prim->data.text->angle ? "STCR\n" : "STC\n"); 03082 break; 03083 case GL2PS_TEXT_TL: 03084 gl2psPrintf(prim->data.text->angle ? "STLR\n" : "STL\n"); 03085 break; 03086 case GL2PS_TEXT_TR: 03087 gl2psPrintf(prim->data.text->angle ? "STRR\n" : "STR\n"); 03088 break; 03089 case GL2PS_TEXT_BL: 03090 default: 03091 gl2psPrintf(prim->data.text->angle ? "SR\n" : "S\n"); 03092 break; 03093 } 03094 break; 03095 case GL2PS_SPECIAL : 03096 /* alignment contains the format for which the special output text 03097 is intended */ 03098 if(prim->data.text->alignment == GL2PS_PS || 03099 prim->data.text->alignment == GL2PS_EPS) 03100 gl2psPrintf("%s\n", prim->data.text->str); 03101 break; 03102 default : 03103 break; 03104 } 03105 } 03106 03107 static void gl2psPrintPostScriptFooter(void) 03108 { 03109 gl2psPrintf("grestore\n" 03110 "showpage\n" 03111 "cleartomark\n" 03112 "%%%%PageTrailer\n" 03113 "%%%%Trailer\n" 03114 "end\n" 03115 "%%%%EOF\n"); 03116 03117 gl2psPrintGzipFooter(); 03118 } 03119 03120 static void gl2psPrintPostScriptBeginViewport(GLint viewport[4]) 03121 { 03122 GLint index; 03123 GLfloat rgba[4]; 03124 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; 03125 03126 glRenderMode(GL_FEEDBACK); 03127 03128 if(gl2ps->header){ 03129 gl2psPrintPostScriptHeader(); 03130 gl2ps->header = GL_FALSE; 03131 } 03132 03133 gl2psPrintf("gsave\n" 03134 "1.0 1.0 scale\n"); 03135 03136 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 03137 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ 03138 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); 03139 } 03140 else{ 03141 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); 03142 rgba[0] = gl2ps->colormap[index][0]; 03143 rgba[1] = gl2ps->colormap[index][1]; 03144 rgba[2] = gl2ps->colormap[index][2]; 03145 rgba[3] = 1.0F; 03146 } 03147 gl2psPrintf("%g %g %g C\n" 03148 "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" 03149 "closepath fill\n", 03150 rgba[0], rgba[1], rgba[2], 03151 x, y, x+w, y, x+w, y+h, x, y+h); 03152 } 03153 03154 gl2psPrintf("newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" 03155 "closepath clip\n", 03156 x, y, x+w, y, x+w, y+h, x, y+h); 03157 03158 } 03159 03160 static GLint gl2psPrintPostScriptEndViewport(void) 03161 { 03162 GLint res; 03163 03164 res = gl2psPrintPrimitives(); 03165 gl2psPrintf("grestore\n"); 03166 return res; 03167 } 03168 03169 static void gl2psPrintPostScriptFinalPrimitive(void) 03170 { 03171 /* End any remaining line, if any */ 03172 gl2psEndPostScriptLine(); 03173 } 03174 03175 /* definition of the PostScript and Encapsulated PostScript backends */ 03176 03177 static GL2PSbackend gl2psPS = { 03178 gl2psPrintPostScriptHeader, 03179 gl2psPrintPostScriptFooter, 03180 gl2psPrintPostScriptBeginViewport, 03181 gl2psPrintPostScriptEndViewport, 03182 gl2psPrintPostScriptPrimitive, 03183 gl2psPrintPostScriptFinalPrimitive, 03184 "ps", 03185 "Postscript" 03186 }; 03187 03188 static GL2PSbackend gl2psEPS = { 03189 gl2psPrintPostScriptHeader, 03190 gl2psPrintPostScriptFooter, 03191 gl2psPrintPostScriptBeginViewport, 03192 gl2psPrintPostScriptEndViewport, 03193 gl2psPrintPostScriptPrimitive, 03194 gl2psPrintPostScriptFinalPrimitive, 03195 "eps", 03196 "Encapsulated Postscript" 03197 }; 03198 03199 /********************************************************************* 03200 * 03201 * LaTeX routines 03202 * 03203 *********************************************************************/ 03204 03205 static void gl2psPrintTeXHeader(void) 03206 { 03207 char name[256]; 03208 time_t now; 03209 int i; 03210 03211 if(gl2ps->filename && strlen(gl2ps->filename) < 256){ 03212 for(i = (int)strlen(gl2ps->filename) - 1; i >= 0; i--){ 03213 if(gl2ps->filename[i] == '.'){ 03214 strncpy(name, gl2ps->filename, i); 03215 name[i] = '\0'; 03216 break; 03217 } 03218 } 03219 if(i <= 0) strcpy(name, gl2ps->filename); 03220 } 03221 else{ 03222 strcpy(name, "untitled"); 03223 } 03224 03225 time(&now); 03226 03227 fprintf(gl2ps->stream, 03228 "%% Title: %s\n" 03229 "%% Creator: GL2PS %d.%d.%d%s, %s\n" 03230 "%% For: %s\n" 03231 "%% CreationDate: %s", 03232 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, 03233 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, 03234 gl2ps->producer, ctime(&now)); 03235 03236 fprintf(gl2ps->stream, 03237 "\\setlength{\\unitlength}{1pt}\n" 03238 "\\begin{picture}(0,0)\n" 03239 "\\includegraphics{%s}\n" 03240 "\\end{picture}%%\n" 03241 "%s\\begin{picture}(%d,%d)(0,0)\n", 03242 name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "", 03243 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); 03244 } 03245 03246 static void gl2psPrintTeXPrimitive(void *data) 03247 { 03248 GL2PSprimitive *prim; 03249 03250 prim = *(GL2PSprimitive**)data; 03251 03252 switch(prim->type){ 03253 case GL2PS_TEXT : 03254 fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", 03255 prim->data.text->fontsize); 03256 fprintf(gl2ps->stream, "\\put(%g,%g)", 03257 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 03258 if(prim->data.text->angle) 03259 fprintf(gl2ps->stream, "{\\rotatebox{%g}", prim->data.text->angle); 03260 fprintf(gl2ps->stream, "{\\makebox(0,0)"); 03261 switch(prim->data.text->alignment){ 03262 case GL2PS_TEXT_C: 03263 fprintf(gl2ps->stream, "{"); 03264 break; 03265 case GL2PS_TEXT_CL: 03266 fprintf(gl2ps->stream, "[l]{"); 03267 break; 03268 case GL2PS_TEXT_CR: 03269 fprintf(gl2ps->stream, "[r]{"); 03270 break; 03271 case GL2PS_TEXT_B: 03272 fprintf(gl2ps->stream, "[b]{"); 03273 break; 03274 case GL2PS_TEXT_BR: 03275 fprintf(gl2ps->stream, "[br]{"); 03276 break; 03277 case GL2PS_TEXT_T: 03278 fprintf(gl2ps->stream, "[t]{"); 03279 break; 03280 case GL2PS_TEXT_TL: 03281 fprintf(gl2ps->stream, "[tl]{"); 03282 break; 03283 case GL2PS_TEXT_TR: 03284 fprintf(gl2ps->stream, "[tr]{"); 03285 break; 03286 case GL2PS_TEXT_BL: 03287 default: 03288 fprintf(gl2ps->stream, "[bl]{"); 03289 break; 03290 } 03291 fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}", 03292 prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2], 03293 prim->data.text->str); 03294 if(prim->data.text->angle) 03295 fprintf(gl2ps->stream, "}"); 03296 fprintf(gl2ps->stream, "}}\n"); 03297 break; 03298 case GL2PS_SPECIAL : 03299 /* alignment contains the format for which the special output text 03300 is intended */ 03301 if (prim->data.text->alignment == GL2PS_TEX) 03302 fprintf(gl2ps->stream, "%s\n", prim->data.text->str); 03303 break; 03304 default : 03305 break; 03306 } 03307 } 03308 03309 static void gl2psPrintTeXFooter(void) 03310 { 03311 fprintf(gl2ps->stream, "\\end{picture}%s\n", 03312 (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : ""); 03313 } 03314 03315 static void gl2psPrintTeXBeginViewport(GLint viewport[4]) 03316 { 03317 (void) viewport; /* not used */ 03318 glRenderMode(GL_FEEDBACK); 03319 03320 if(gl2ps->header){ 03321 gl2psPrintTeXHeader(); 03322 gl2ps->header = GL_FALSE; 03323 } 03324 } 03325 03326 static GLint gl2psPrintTeXEndViewport(void) 03327 { 03328 return gl2psPrintPrimitives(); 03329 } 03330 03331 static void gl2psPrintTeXFinalPrimitive(void) 03332 { 03333 } 03334 03335 /* definition of the LaTeX backend */ 03336 03337 static GL2PSbackend gl2psTEX = { 03338 gl2psPrintTeXHeader, 03339 gl2psPrintTeXFooter, 03340 gl2psPrintTeXBeginViewport, 03341 gl2psPrintTeXEndViewport, 03342 gl2psPrintTeXPrimitive, 03343 gl2psPrintTeXFinalPrimitive, 03344 "tex", 03345 "LaTeX text" 03346 }; 03347 03348 /********************************************************************* 03349 * 03350 * PDF routines 03351 * 03352 *********************************************************************/ 03353 03354 static int gl2psPrintPDFCompressorType(void) 03355 { 03356 #if defined(GL2PS_HAVE_ZLIB) 03357 if(gl2ps->options & GL2PS_COMPRESS){ 03358 return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n"); 03359 } 03360 #endif 03361 return 0; 03362 } 03363 03364 static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba) 03365 { 03366 int i, offs = 0; 03367 03368 gl2psSetLastColor(rgba); 03369 for(i = 0; i < 3; ++i){ 03370 if(GL2PS_ZERO(rgba[i])) 03371 offs += gl2psPrintf("%.0f ", 0.); 03372 else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ 03373 offs += gl2psPrintf("%f ", rgba[i]); 03374 else 03375 offs += gl2psPrintf("%g ", rgba[i]); 03376 } 03377 offs += gl2psPrintf("RG\n"); 03378 return offs; 03379 } 03380 03381 static int gl2psPrintPDFFillColor(GL2PSrgba rgba) 03382 { 03383 int i, offs = 0; 03384 03385 for(i = 0; i < 3; ++i){ 03386 if(GL2PS_ZERO(rgba[i])) 03387 offs += gl2psPrintf("%.0f ", 0.); 03388 else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ 03389 offs += gl2psPrintf("%f ", rgba[i]); 03390 else 03391 offs += gl2psPrintf("%g ", rgba[i]); 03392 } 03393 offs += gl2psPrintf("rg\n"); 03394 return offs; 03395 } 03396 03397 static int gl2psPrintPDFLineWidth(GLfloat lw) 03398 { 03399 if(GL2PS_ZERO(lw)) 03400 return gl2psPrintf("%.0f w\n", 0.); 03401 else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */ 03402 return gl2psPrintf("%f w\n", lw); 03403 else 03404 return gl2psPrintf("%g w\n", lw); 03405 } 03406 03407 static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y) 03408 { 03409 GLfloat rad, crad, srad; 03410 03411 if(text->angle == 0.0F){ 03412 gl2ps->streamlength += gl2psPrintf 03413 ("BT\n" 03414 "/F%d %d Tf\n" 03415 "%f %f Td\n" 03416 "(%s) Tj\n" 03417 "ET\n", 03418 cnt, text->fontsize, x, y, text->str); 03419 } 03420 else{ 03421 rad = (GLfloat)(M_PI * text->angle / 180.0F); 03422 srad = (GLfloat)sin(rad); 03423 crad = (GLfloat)cos(rad); 03424 gl2ps->streamlength += gl2psPrintf 03425 ("BT\n" 03426 "/F%d %d Tf\n" 03427 "%f %f %f %f %f %f Tm\n" 03428 "(%s) Tj\n" 03429 "ET\n", 03430 cnt, text->fontsize, crad, srad, -srad, crad, x, y, text->str); 03431 } 03432 } 03433 03434 static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y) 03435 { 03436 gl2ps->streamlength += gl2psPrintf 03437 ("q\n" 03438 "%d 0 0 %d %f %f cm\n" 03439 "/Im%d Do\n" 03440 "Q\n", 03441 (int)image->width, (int)image->height, x, y, cnt); 03442 } 03443 03444 static void gl2psPDFstacksInit(void) 03445 { 03446 gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1; 03447 gl2ps->extgs_stack = 0; 03448 gl2ps->font_stack = 0; 03449 gl2ps->im_stack = 0; 03450 gl2ps->trgroupobjects_stack = 0; 03451 gl2ps->shader_stack = 0; 03452 gl2ps->mshader_stack = 0; 03453 } 03454 03455 static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro) 03456 { 03457 if(!gro) 03458 return; 03459 03460 gro->ptrlist = NULL; 03461 gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno 03462 = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno 03463 = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1; 03464 } 03465 03466 /* Build up group objects and assign name and object numbers */ 03467 03468 static void gl2psPDFgroupListInit(void) 03469 { 03470 int i; 03471 GL2PSprimitive *p = NULL; 03472 GL2PSpdfgroup gro; 03473 int lasttype = GL2PS_NO_TYPE; 03474 GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F}; 03475 GLushort lastpattern = 0; 03476 GLint lastfactor = 0; 03477 GLfloat lastwidth = 1; 03478 GL2PStriangle lastt, tmpt; 03479 int lastTriangleWasNotSimpleWithSameColor = 0; 03480 03481 if(!gl2ps->pdfprimlist) 03482 return; 03483 03484 gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup)); 03485 gl2psInitTriangle(&lastt); 03486 03487 for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ 03488 p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i); 03489 switch(p->type){ 03490 case GL2PS_PIXMAP: 03491 gl2psPDFgroupObjectInit(&gro); 03492 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); 03493 gro.imno = gl2ps->im_stack++; 03494 gl2psListAdd(gro.ptrlist, &p); 03495 gl2psListAdd(gl2ps->pdfgrouplist, &gro); 03496 break; 03497 case GL2PS_TEXT: 03498 gl2psPDFgroupObjectInit(&gro); 03499 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); 03500 gro.fontno = gl2ps->font_stack++; 03501 gl2psListAdd(gro.ptrlist, &p); 03502 gl2psListAdd(gl2ps->pdfgrouplist, &gro); 03503 break; 03504 case GL2PS_LINE: 03505 if(lasttype != p->type || lastwidth != p->width || 03506 lastpattern != p->pattern || lastfactor != p->factor || 03507 !gl2psSameColor(p->verts[0].rgba, lastrgba)){ 03508 gl2psPDFgroupObjectInit(&gro); 03509 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); 03510 gl2psListAdd(gro.ptrlist, &p); 03511 gl2psListAdd(gl2ps->pdfgrouplist, &gro); 03512 } 03513 else{ 03514 gl2psListAdd(gro.ptrlist, &p); 03515 } 03516 lastpattern = p->pattern; 03517 lastfactor = p->factor; 03518 lastwidth = p->width; 03519 lastrgba[0] = p->verts[0].rgba[0]; 03520 lastrgba[1] = p->verts[0].rgba[1]; 03521 lastrgba[2] = p->verts[0].rgba[2]; 03522 break; 03523 case GL2PS_POINT: 03524 if(lasttype != p->type || lastwidth != p->width || 03525 !gl2psSameColor(p->verts[0].rgba, lastrgba)){ 03526 gl2psPDFgroupObjectInit(&gro); 03527 gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*)); 03528 gl2psListAdd(gro.ptrlist, &p); 03529 gl2psListAdd(gl2ps->pdfgrouplist, &gro); 03530 } 03531 else{ 03532 gl2psListAdd(gro.ptrlist, &p); 03533 } 03534 lastwidth = p->width; 03535 lastrgba[0] = p->verts[0].rgba[0]; 03536 lastrgba[1] = p->verts[0].rgba[1]; 03537 lastrgba[2] = p->verts[0].rgba[2]; 03538 break; 03539 case GL2PS_TRIANGLE: 03540 gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE); 03541 lastTriangleWasNotSimpleWithSameColor = 03542 !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) || 03543 !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba); 03544 if(lasttype == p->type && tmpt.prop == lastt.prop && 03545 lastTriangleWasNotSimpleWithSameColor){ 03546 /* TODO Check here for last alpha */ 03547 gl2psListAdd(gro.ptrlist, &p); 03548 } 03549 else{ 03550 gl2psPDFgroupObjectInit(&gro); 03551 gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); 03552 gl2psListAdd(gro.ptrlist, &p); 03553 gl2psListAdd(gl2ps->pdfgrouplist, &gro); 03554 } 03555 lastt = tmpt; 03556 break; 03557 default: 03558 break; 03559 } 03560 lasttype = p->type; 03561 } 03562 } 03563 03564 static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro) 03565 { 03566 GL2PStriangle t; 03567 GL2PSprimitive *prim = NULL; 03568 03569 if(!gro) 03570 return; 03571 03572 if(!gl2psListNbr(gro->ptrlist)) 03573 return; 03574 03575 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); 03576 03577 if(prim->type != GL2PS_TRIANGLE) 03578 return; 03579 03580 gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); 03581 03582 if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ 03583 gro->gsno = gl2ps->extgs_stack++; 03584 gro->gsobjno = gl2ps->objects_stack ++; 03585 } 03586 else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ 03587 gro->gsno = gl2ps->extgs_stack++; 03588 gro->gsobjno = gl2ps->objects_stack++; 03589 gro->trgroupno = gl2ps->trgroupobjects_stack++; 03590 gro->trgroupobjno = gl2ps->objects_stack++; 03591 gro->maskshno = gl2ps->mshader_stack++; 03592 gro->maskshobjno = gl2ps->objects_stack++; 03593 } 03594 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ 03595 gro->shno = gl2ps->shader_stack++; 03596 gro->shobjno = gl2ps->objects_stack++; 03597 } 03598 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ 03599 gro->gsno = gl2ps->extgs_stack++; 03600 gro->gsobjno = gl2ps->objects_stack++; 03601 gro->shno = gl2ps->shader_stack++; 03602 gro->shobjno = gl2ps->objects_stack++; 03603 } 03604 else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ 03605 gro->gsno = gl2ps->extgs_stack++; 03606 gro->gsobjno = gl2ps->objects_stack++; 03607 gro->shno = gl2ps->shader_stack++; 03608 gro->shobjno = gl2ps->objects_stack++; 03609 gro->trgroupno = gl2ps->trgroupobjects_stack++; 03610 gro->trgroupobjno = gl2ps->objects_stack++; 03611 gro->maskshno = gl2ps->mshader_stack++; 03612 gro->maskshobjno = gl2ps->objects_stack++; 03613 } 03614 } 03615 03616 /* Main stream data */ 03617 03618 static void gl2psPDFgroupListWriteMainStream(void) 03619 { 03620 int i, j, lastel; 03621 GL2PSprimitive *prim = NULL, *prev = NULL; 03622 GL2PSpdfgroup *gro; 03623 GL2PStriangle t; 03624 03625 if(!gl2ps->pdfgrouplist) 03626 return; 03627 03628 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 03629 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 03630 03631 lastel = gl2psListNbr(gro->ptrlist) - 1; 03632 if(lastel < 0) 03633 continue; 03634 03635 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); 03636 03637 switch(prim->type){ 03638 case GL2PS_POINT: 03639 gl2ps->streamlength += gl2psPrintf("1 J\n"); 03640 gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); 03641 gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); 03642 for(j = 0; j <= lastel; ++j){ 03643 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 03644 gl2ps->streamlength += 03645 gl2psPrintf("%f %f m %f %f l\n", 03646 prim->verts[0].xyz[0], prim->verts[0].xyz[1], 03647 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 03648 } 03649 gl2ps->streamlength += gl2psPrintf("S\n"); 03650 gl2ps->streamlength += gl2psPrintf("0 J\n"); 03651 break; 03652 case GL2PS_LINE: 03653 /* We try to use as few paths as possible to draw lines, in 03654 order to get nice stippling even when the individual segments 03655 are smaller than the stipple */ 03656 gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); 03657 gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); 03658 gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d"); 03659 /* start new path */ 03660 gl2ps->streamlength += 03661 gl2psPrintf("%f %f m\n", 03662 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 03663 03664 for(j = 1; j <= lastel; ++j){ 03665 prev = prim; 03666 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 03667 if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){ 03668 /* the starting point of the new segment does not match the 03669 end point of the previous line, so we end the current 03670 path and start a new one */ 03671 gl2ps->streamlength += 03672 gl2psPrintf("%f %f l\n", 03673 prev->verts[1].xyz[0], prev->verts[1].xyz[1]); 03674 gl2ps->streamlength += 03675 gl2psPrintf("%f %f m\n", 03676 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 03677 } 03678 else{ 03679 /* the two segements are connected, so we just append to the 03680 current path */ 03681 gl2ps->streamlength += 03682 gl2psPrintf("%f %f l\n", 03683 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 03684 } 03685 } 03686 /* end last path */ 03687 gl2ps->streamlength += 03688 gl2psPrintf("%f %f l\n", 03689 prim->verts[1].xyz[0], prim->verts[1].xyz[1]); 03690 gl2ps->streamlength += gl2psPrintf("S\n"); 03691 break; 03692 case GL2PS_TRIANGLE: 03693 gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); 03694 gl2psSortOutTrianglePDFgroup(gro); 03695 03696 /* No alpha and const color: Simple PDF draw orders */ 03697 if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){ 03698 gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba); 03699 for(j = 0; j <= lastel; ++j){ 03700 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 03701 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); 03702 gl2ps->streamlength 03703 += gl2psPrintf("%f %f m\n" 03704 "%f %f l\n" 03705 "%f %f l\n" 03706 "h f\n", 03707 t.vertex[0].xyz[0], t.vertex[0].xyz[1], 03708 t.vertex[1].xyz[0], t.vertex[1].xyz[1], 03709 t.vertex[2].xyz[0], t.vertex[2].xyz[1]); 03710 } 03711 } 03712 /* Const alpha < 1 and const color: Simple PDF draw orders 03713 and an extra extended Graphics State for the alpha const */ 03714 else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ 03715 gl2ps->streamlength += gl2psPrintf("q\n" 03716 "/GS%d gs\n", 03717 gro->gsno); 03718 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); 03719 for(j = 0; j <= lastel; ++j){ 03720 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 03721 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); 03722 gl2ps->streamlength 03723 += gl2psPrintf("%f %f m\n" 03724 "%f %f l\n" 03725 "%f %f l\n" 03726 "h f\n", 03727 t.vertex[0].xyz[0], t.vertex[0].xyz[1], 03728 t.vertex[1].xyz[0], t.vertex[1].xyz[1], 03729 t.vertex[2].xyz[0], t.vertex[2].xyz[1]); 03730 } 03731 gl2ps->streamlength += gl2psPrintf("Q\n"); 03732 } 03733 /* Variable alpha and const color: Simple PDF draw orders 03734 and an extra extended Graphics State + Xobject + Shader 03735 object for the alpha mask */ 03736 else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ 03737 gl2ps->streamlength += gl2psPrintf("q\n" 03738 "/GS%d gs\n" 03739 "/TrG%d Do\n", 03740 gro->gsno, gro->trgroupno); 03741 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); 03742 for(j = 0; j <= lastel; ++j){ 03743 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 03744 gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); 03745 gl2ps->streamlength 03746 += gl2psPrintf("%f %f m\n" 03747 "%f %f l\n" 03748 "%f %f l\n" 03749 "h f\n", 03750 t.vertex[0].xyz[0], t.vertex[0].xyz[1], 03751 t.vertex[1].xyz[0], t.vertex[1].xyz[1], 03752 t.vertex[2].xyz[0], t.vertex[2].xyz[1]); 03753 } 03754 gl2ps->streamlength += gl2psPrintf("Q\n"); 03755 } 03756 /* Variable color and no alpha: Shader Object for the colored 03757 triangle(s) */ 03758 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ 03759 gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno); 03760 } 03761 /* Variable color and const alpha < 1: Shader Object for the 03762 colored triangle(s) and an extra extended Graphics State 03763 for the alpha const */ 03764 else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ 03765 gl2ps->streamlength += gl2psPrintf("q\n" 03766 "/GS%d gs\n" 03767 "/Sh%d sh\n" 03768 "Q\n", 03769 gro->gsno, gro->shno); 03770 } 03771 /* Variable alpha and color: Shader Object for the colored 03772 triangle(s) and an extra extended Graphics State 03773 + Xobject + Shader object for the alpha mask */ 03774 else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ 03775 gl2ps->streamlength += gl2psPrintf("q\n" 03776 "/GS%d gs\n" 03777 "/TrG%d Do\n" 03778 "/Sh%d sh\n" 03779 "Q\n", 03780 gro->gsno, gro->trgroupno, gro->shno); 03781 } 03782 break; 03783 case GL2PS_PIXMAP: 03784 for(j = 0; j <= lastel; ++j){ 03785 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 03786 gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], 03787 prim->verts[0].xyz[1]); 03788 } 03789 break; 03790 case GL2PS_TEXT: 03791 for(j = 0; j <= lastel; ++j){ 03792 prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 03793 gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); 03794 gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0], 03795 prim->verts[0].xyz[1]); 03796 } 03797 break; 03798 default: 03799 break; 03800 } 03801 } 03802 } 03803 03804 /* Graphics State names */ 03805 03806 static int gl2psPDFgroupListWriteGStateResources(void) 03807 { 03808 GL2PSpdfgroup *gro; 03809 int offs = 0; 03810 int i; 03811 03812 offs += fprintf(gl2ps->stream, 03813 "/ExtGState\n" 03814 "<<\n" 03815 "/GSa 7 0 R\n"); 03816 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 03817 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 03818 if(gro->gsno >= 0) 03819 offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno); 03820 } 03821 offs += fprintf(gl2ps->stream, ">>\n"); 03822 return offs; 03823 } 03824 03825 /* Main Shader names */ 03826 03827 static int gl2psPDFgroupListWriteShaderResources(void) 03828 { 03829 GL2PSpdfgroup *gro; 03830 int offs = 0; 03831 int i; 03832 03833 offs += fprintf(gl2ps->stream, 03834 "/Shading\n" 03835 "<<\n"); 03836 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 03837 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 03838 if(gro->shno >= 0) 03839 offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno); 03840 if(gro->maskshno >= 0) 03841 offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno); 03842 } 03843 offs += fprintf(gl2ps->stream,">>\n"); 03844 return offs; 03845 } 03846 03847 /* Images & Mask Shader XObject names */ 03848 03849 static int gl2psPDFgroupListWriteXObjectResources(void) 03850 { 03851 int i; 03852 GL2PSprimitive *p = NULL; 03853 GL2PSpdfgroup *gro; 03854 int offs = 0; 03855 03856 offs += fprintf(gl2ps->stream, 03857 "/XObject\n" 03858 "<<\n"); 03859 03860 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 03861 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 03862 if(!gl2psListNbr(gro->ptrlist)) 03863 continue; 03864 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); 03865 switch(p->type){ 03866 case GL2PS_PIXMAP: 03867 gro->imobjno = gl2ps->objects_stack++; 03868 if(GL_RGBA == p->data.image->format) /* reserve one object for image mask */ 03869 gl2ps->objects_stack++; 03870 offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno); 03871 case GL2PS_TRIANGLE: 03872 if(gro->trgroupno >=0) 03873 offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno); 03874 break; 03875 default: 03876 break; 03877 } 03878 } 03879 offs += fprintf(gl2ps->stream,">>\n"); 03880 return offs; 03881 } 03882 03883 /* Font names */ 03884 03885 static int gl2psPDFgroupListWriteFontResources(void) 03886 { 03887 int i; 03888 GL2PSpdfgroup *gro; 03889 int offs = 0; 03890 03891 offs += fprintf(gl2ps->stream, "/Font\n<<\n"); 03892 03893 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 03894 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 03895 if(gro->fontno < 0) 03896 continue; 03897 gro->fontobjno = gl2ps->objects_stack++; 03898 offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno); 03899 } 03900 offs += fprintf(gl2ps->stream, ">>\n"); 03901 03902 return offs; 03903 } 03904 03905 static void gl2psPDFgroupListDelete(void) 03906 { 03907 int i; 03908 GL2PSpdfgroup *gro = NULL; 03909 03910 if(!gl2ps->pdfgrouplist) 03911 return; 03912 03913 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 03914 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i); 03915 gl2psListDelete(gro->ptrlist); 03916 } 03917 03918 gl2psListDelete(gl2ps->pdfgrouplist); 03919 gl2ps->pdfgrouplist = NULL; 03920 } 03921 03922 /* Print 1st PDF object - file info */ 03923 03924 static int gl2psPrintPDFInfo(void) 03925 { 03926 int offs; 03927 time_t now; 03928 struct tm *newtime; 03929 03930 time(&now); 03931 newtime = gmtime(&now); 03932 03933 offs = fprintf(gl2ps->stream, 03934 "1 0 obj\n" 03935 "<<\n" 03936 "/Title (%s)\n" 03937 "/Creator (GL2PS %d.%d.%d%s, %s)\n" 03938 "/Producer (%s)\n", 03939 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, 03940 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, 03941 gl2ps->producer); 03942 03943 if(!newtime){ 03944 offs += fprintf(gl2ps->stream, 03945 ">>\n" 03946 "endobj\n"); 03947 return offs; 03948 } 03949 03950 offs += fprintf(gl2ps->stream, 03951 "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n" 03952 ">>\n" 03953 "endobj\n", 03954 newtime->tm_year+1900, 03955 newtime->tm_mon+1, 03956 newtime->tm_mday, 03957 newtime->tm_hour, 03958 newtime->tm_min, 03959 newtime->tm_sec); 03960 return offs; 03961 } 03962 03963 /* Create catalog and page structure - 2nd and 3th PDF object */ 03964 03965 static int gl2psPrintPDFCatalog(void) 03966 { 03967 return fprintf(gl2ps->stream, 03968 "2 0 obj\n" 03969 "<<\n" 03970 "/Type /Catalog\n" 03971 "/Pages 3 0 R\n" 03972 ">>\n" 03973 "endobj\n"); 03974 } 03975 03976 static int gl2psPrintPDFPages(void) 03977 { 03978 return fprintf(gl2ps->stream, 03979 "3 0 obj\n" 03980 "<<\n" 03981 "/Type /Pages\n" 03982 "/Kids [6 0 R]\n" 03983 "/Count 1\n" 03984 ">>\n" 03985 "endobj\n"); 03986 } 03987 03988 /* Open stream for data - graphical objects, fonts etc. PDF object 4 */ 03989 03990 static int gl2psOpenPDFDataStream(void) 03991 { 03992 int offs = 0; 03993 03994 offs += fprintf(gl2ps->stream, 03995 "4 0 obj\n" 03996 "<<\n" 03997 "/Length 5 0 R\n" ); 03998 offs += gl2psPrintPDFCompressorType(); 03999 offs += fprintf(gl2ps->stream, 04000 ">>\n" 04001 "stream\n"); 04002 return offs; 04003 } 04004 04005 /* Stream setup - Graphics state, fill background if allowed */ 04006 04007 static int gl2psOpenPDFDataStreamWritePreface(void) 04008 { 04009 int offs; 04010 04011 offs = gl2psPrintf("/GSa gs\n"); 04012 04013 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 04014 offs += gl2psPrintPDFFillColor(gl2ps->bgcolor); 04015 offs += gl2psPrintf("%d %d %d %d re\n", 04016 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 04017 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); 04018 offs += gl2psPrintf("f\n"); 04019 } 04020 return offs; 04021 } 04022 04023 /* Use the functions above to create the first part of the PDF*/ 04024 04025 static void gl2psPrintPDFHeader(void) 04026 { 04027 int offs = 0; 04028 gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); 04029 gl2psPDFstacksInit(); 04030 04031 gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); 04032 04033 #if defined(GL2PS_HAVE_ZLIB) 04034 if(gl2ps->options & GL2PS_COMPRESS){ 04035 gl2psSetupCompress(); 04036 } 04037 #endif 04038 gl2ps->xreflist[0] = 0; 04039 offs += fprintf(gl2ps->stream, "%%PDF-1.4\n"); 04040 gl2ps->xreflist[1] = offs; 04041 04042 offs += gl2psPrintPDFInfo(); 04043 gl2ps->xreflist[2] = offs; 04044 04045 offs += gl2psPrintPDFCatalog(); 04046 gl2ps->xreflist[3] = offs; 04047 04048 offs += gl2psPrintPDFPages(); 04049 gl2ps->xreflist[4] = offs; 04050 04051 offs += gl2psOpenPDFDataStream(); 04052 gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */ 04053 gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface(); 04054 } 04055 04056 /* The central primitive drawing */ 04057 04058 static void gl2psPrintPDFPrimitive(void *data) 04059 { 04060 GL2PSprimitive *prim = *(GL2PSprimitive**)data; 04061 04062 if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) 04063 return; 04064 04065 prim = gl2psCopyPrimitive(prim); /* deep copy */ 04066 gl2psListAdd(gl2ps->pdfprimlist, &prim); 04067 } 04068 04069 /* close stream and ... */ 04070 04071 static int gl2psClosePDFDataStream(void) 04072 { 04073 int offs = 0; 04074 04075 #if defined(GL2PS_HAVE_ZLIB) 04076 if(gl2ps->options & GL2PS_COMPRESS){ 04077 if(Z_OK != gl2psDeflate()) 04078 gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); 04079 else 04080 fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream); 04081 gl2ps->streamlength += gl2ps->compress->destLen; 04082 04083 offs += gl2ps->streamlength; 04084 gl2psFreeCompress(); 04085 } 04086 #endif 04087 04088 offs += fprintf(gl2ps->stream, 04089 "endstream\n" 04090 "endobj\n"); 04091 return offs; 04092 } 04093 04094 /* ... write the now known length object */ 04095 04096 static int gl2psPrintPDFDataStreamLength(int val) 04097 { 04098 return fprintf(gl2ps->stream, 04099 "5 0 obj\n" 04100 "%d\n" 04101 "endobj\n", val); 04102 } 04103 04104 /* Put the info created before in PDF objects */ 04105 04106 static int gl2psPrintPDFOpenPage(void) 04107 { 04108 int offs; 04109 04110 /* Write fixed part */ 04111 04112 offs = fprintf(gl2ps->stream, 04113 "6 0 obj\n" 04114 "<<\n" 04115 "/Type /Page\n" 04116 "/Parent 3 0 R\n" 04117 "/MediaBox [%d %d %d %d]\n", 04118 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 04119 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); 04120 04121 if(gl2ps->options & GL2PS_LANDSCAPE) 04122 offs += fprintf(gl2ps->stream, "/Rotate -90\n"); 04123 04124 offs += fprintf(gl2ps->stream, 04125 "/Contents 4 0 R\n" 04126 "/Resources\n" 04127 "<<\n" 04128 "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n"); 04129 04130 return offs; 04131 04132 /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */ 04133 } 04134 04135 static int gl2psPDFgroupListWriteVariableResources(void) 04136 { 04137 int offs = 0; 04138 04139 /* a) Graphics States for shader alpha masks*/ 04140 offs += gl2psPDFgroupListWriteGStateResources(); 04141 04142 /* b) Shader and shader masks */ 04143 offs += gl2psPDFgroupListWriteShaderResources(); 04144 04145 /* c) XObjects (Images & Shader Masks) */ 04146 offs += gl2psPDFgroupListWriteXObjectResources(); 04147 04148 /* d) Fonts */ 04149 offs += gl2psPDFgroupListWriteFontResources(); 04150 04151 /* End resources and page */ 04152 offs += fprintf(gl2ps->stream, 04153 ">>\n" 04154 ">>\n" 04155 "endobj\n"); 04156 return offs; 04157 } 04158 04159 /* Standard Graphics State */ 04160 04161 static int gl2psPrintPDFGSObject(void) 04162 { 04163 return fprintf(gl2ps->stream, 04164 "7 0 obj\n" 04165 "<<\n" 04166 "/Type /ExtGState\n" 04167 "/SA false\n" 04168 "/SM 0.02\n" 04169 "/OP false\n" 04170 "/op false\n" 04171 "/OPM 0\n" 04172 "/BG2 /Default\n" 04173 "/UCR2 /Default\n" 04174 "/TR2 /Default\n" 04175 ">>\n" 04176 "endobj\n"); 04177 } 04178 04179 /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */ 04180 04181 static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, 04182 int (*action)(unsigned long data, int size), 04183 GLfloat dx, GLfloat dy, 04184 GLfloat xmin, GLfloat ymin) 04185 { 04186 int offs = 0; 04187 unsigned long imap; 04188 GLfloat diff; 04189 double dmax = ~1UL; 04190 char edgeflag = 0; 04191 04192 /* FIXME: temp bux fix for 64 bit archs: */ 04193 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; 04194 04195 offs += (*action)(edgeflag, 1); 04196 04197 /* The Shader stream in PDF requires to be in a 'big-endian' 04198 order */ 04199 04200 if(GL2PS_ZERO(dx * dy)){ 04201 offs += (*action)(0, 4); 04202 offs += (*action)(0, 4); 04203 } 04204 else{ 04205 diff = (vertex->xyz[0] - xmin) / dx; 04206 if(diff > 1) 04207 diff = 1.0F; 04208 else if(diff < 0) 04209 diff = 0.0F; 04210 imap = (unsigned long)(diff * dmax); 04211 offs += (*action)(imap, 4); 04212 04213 diff = (vertex->xyz[1] - ymin) / dy; 04214 if(diff > 1) 04215 diff = 1.0F; 04216 else if(diff < 0) 04217 diff = 0.0F; 04218 imap = (unsigned long)(diff * dmax); 04219 offs += (*action)(imap, 4); 04220 } 04221 04222 return offs; 04223 } 04224 04225 /* Put vertex' rgb value (8bit for every component) in shader stream */ 04226 04227 static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex, 04228 int (*action)(unsigned long data, int size)) 04229 { 04230 int offs = 0; 04231 unsigned long imap; 04232 double dmax = ~1UL; 04233 04234 /* FIXME: temp bux fix for 64 bit archs: */ 04235 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; 04236 04237 imap = (unsigned long)((vertex->rgba[0]) * dmax); 04238 offs += (*action)(imap, 1); 04239 04240 imap = (unsigned long)((vertex->rgba[1]) * dmax); 04241 offs += (*action)(imap, 1); 04242 04243 imap = (unsigned long)((vertex->rgba[2]) * dmax); 04244 offs += (*action)(imap, 1); 04245 04246 return offs; 04247 } 04248 04249 /* Put vertex' alpha (8/16bit) in shader stream */ 04250 04251 static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, 04252 int (*action)(unsigned long data, int size), 04253 int sigbyte) 04254 { 04255 int offs = 0; 04256 unsigned long imap; 04257 double dmax = ~1UL; 04258 04259 /* FIXME: temp bux fix for 64 bit archs: */ 04260 if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; 04261 04262 if(sigbyte != 8 && sigbyte != 16) 04263 sigbyte = 8; 04264 04265 sigbyte /= 8; 04266 04267 imap = (unsigned long)((vertex->rgba[3]) * dmax); 04268 04269 offs += (*action)(imap, sigbyte); 04270 04271 return offs; 04272 } 04273 04274 /* Put a triangles raw data in shader stream */ 04275 04276 static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle, 04277 GLfloat dx, GLfloat dy, 04278 GLfloat xmin, GLfloat ymin, 04279 int (*action)(unsigned long data, int size), 04280 int gray) 04281 { 04282 int i, offs = 0; 04283 GL2PSvertex v; 04284 04285 if(gray && gray != 8 && gray != 16) 04286 gray = 8; 04287 04288 for(i = 0; i < 3; ++i){ 04289 offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action, 04290 dx, dy, xmin, ymin); 04291 if(gray){ 04292 v = triangle->vertex[i]; 04293 offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); 04294 } 04295 else{ 04296 offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action); 04297 } 04298 } 04299 04300 return offs; 04301 } 04302 04303 static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, 04304 GLfloat *ymin, GLfloat *ymax, 04305 GL2PStriangle *triangles, int cnt) 04306 { 04307 int i, j; 04308 04309 *xmin = triangles[0].vertex[0].xyz[0]; 04310 *xmax = triangles[0].vertex[0].xyz[0]; 04311 *ymin = triangles[0].vertex[0].xyz[1]; 04312 *ymax = triangles[0].vertex[0].xyz[1]; 04313 04314 for(i = 0; i < cnt; ++i){ 04315 for(j = 0; j < 3; ++j){ 04316 if(*xmin > triangles[i].vertex[j].xyz[0]) 04317 *xmin = triangles[i].vertex[j].xyz[0]; 04318 if(*xmax < triangles[i].vertex[j].xyz[0]) 04319 *xmax = triangles[i].vertex[j].xyz[0]; 04320 if(*ymin > triangles[i].vertex[j].xyz[1]) 04321 *ymin = triangles[i].vertex[j].xyz[1]; 04322 if(*ymax < triangles[i].vertex[j].xyz[1]) 04323 *ymax = triangles[i].vertex[j].xyz[1]; 04324 } 04325 } 04326 } 04327 04328 /* Writes shaded triangle 04329 gray == 0 means write RGB triangles 04330 gray == 8 8bit-grayscale (for alpha masks) 04331 gray == 16 16bit-grayscale (for alpha masks) */ 04332 04333 static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, 04334 int size, int gray) 04335 { 04336 int i, offs = 0, vertexbytes, done = 0; 04337 GLfloat xmin, xmax, ymin, ymax; 04338 04339 switch(gray){ 04340 case 0: 04341 vertexbytes = 1+4+4+1+1+1; 04342 break; 04343 case 8: 04344 vertexbytes = 1+4+4+1; 04345 break; 04346 case 16: 04347 vertexbytes = 1+4+4+2; 04348 break; 04349 default: 04350 gray = 8; 04351 vertexbytes = 1+4+4+1; 04352 break; 04353 } 04354 04355 gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size); 04356 04357 offs += fprintf(gl2ps->stream, 04358 "%d 0 obj\n" 04359 "<< " 04360 "/ShadingType 4 " 04361 "/ColorSpace %s " 04362 "/BitsPerCoordinate 32 " 04363 "/BitsPerComponent %d " 04364 "/BitsPerFlag 8 " 04365 "/Decode [%f %f %f %f 0 1 %s] ", 04366 obj, 04367 (gray) ? "/DeviceGray" : "/DeviceRGB", 04368 (gray) ? gray : 8, 04369 xmin, xmax, ymin, ymax, 04370 (gray) ? "" : "0 1 0 1"); 04371 04372 #if defined(GL2PS_HAVE_ZLIB) 04373 if(gl2ps->options & GL2PS_COMPRESS){ 04374 gl2psAllocCompress(vertexbytes * size * 3); 04375 04376 for(i = 0; i < size; ++i) 04377 gl2psPrintPDFShaderStreamData(&triangles[i], 04378 xmax-xmin, ymax-ymin, xmin, ymin, 04379 gl2psWriteBigEndianCompress, gray); 04380 04381 if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ 04382 offs += gl2psPrintPDFCompressorType(); 04383 offs += fprintf(gl2ps->stream, 04384 "/Length %d " 04385 ">>\n" 04386 "stream\n", 04387 (int)gl2ps->compress->destLen); 04388 offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, 04389 gl2ps->compress->destLen, 04390 1, gl2ps->stream); 04391 done = 1; 04392 } 04393 gl2psFreeCompress(); 04394 } 04395 #endif 04396 04397 if(!done){ 04398 /* no compression, or too long after compression, or compress error 04399 -> write non-compressed entry */ 04400 offs += fprintf(gl2ps->stream, 04401 "/Length %d " 04402 ">>\n" 04403 "stream\n", 04404 vertexbytes * 3 * size); 04405 for(i = 0; i < size; ++i) 04406 offs += gl2psPrintPDFShaderStreamData(&triangles[i], 04407 xmax-xmin, ymax-ymin, xmin, ymin, 04408 gl2psWriteBigEndian, gray); 04409 } 04410 04411 offs += fprintf(gl2ps->stream, 04412 "\nendstream\n" 04413 "endobj\n"); 04414 04415 return offs; 04416 } 04417 04418 /* Writes a XObject for a shaded triangle mask */ 04419 04420 static int gl2psPrintPDFShaderMask(int obj, int childobj) 04421 { 04422 int offs = 0, len; 04423 04424 offs += fprintf(gl2ps->stream, 04425 "%d 0 obj\n" 04426 "<<\n" 04427 "/Type /XObject\n" 04428 "/Subtype /Form\n" 04429 "/BBox [ %d %d %d %d ]\n" 04430 "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n" 04431 ">>\n", 04432 obj, 04433 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 04434 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); 04435 04436 len = (childobj>0) 04437 ? (int)strlen("/TrSh sh\n") + (int)log10((double)childobj)+1 04438 : (int)strlen("/TrSh0 sh\n"); 04439 04440 offs += fprintf(gl2ps->stream, 04441 "/Length %d\n" 04442 ">>\n" 04443 "stream\n", 04444 len); 04445 offs += fprintf(gl2ps->stream, 04446 "/TrSh%d sh\n", 04447 childobj); 04448 offs += fprintf(gl2ps->stream, 04449 "endstream\n" 04450 "endobj\n"); 04451 04452 return offs; 04453 } 04454 04455 /* Writes a Extended graphics state for a shaded triangle mask if 04456 simplealpha ist true the childobj argument is ignored and a /ca 04457 statement will be written instead */ 04458 04459 static int gl2psPrintPDFShaderExtGS(int obj, int childobj) 04460 { 04461 int offs = 0; 04462 04463 offs += fprintf(gl2ps->stream, 04464 "%d 0 obj\n" 04465 "<<\n", 04466 obj); 04467 04468 offs += fprintf(gl2ps->stream, 04469 "/SMask << /S /Alpha /G %d 0 R >> ", 04470 childobj); 04471 04472 offs += fprintf(gl2ps->stream, 04473 ">>\n" 04474 "endobj\n"); 04475 return offs; 04476 } 04477 04478 /* a simple graphics state */ 04479 04480 static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha) 04481 { 04482 int offs = 0; 04483 04484 offs += fprintf(gl2ps->stream, 04485 "%d 0 obj\n" 04486 "<<\n" 04487 "/ca %g" 04488 ">>\n" 04489 "endobj\n", 04490 obj, alpha); 04491 return offs; 04492 } 04493 04494 /* Similar groups of functions for pixmaps and text */ 04495 04496 static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im, 04497 int (*action)(unsigned long data, int size), 04498 int gray) 04499 { 04500 int x, y, shift; 04501 GLfloat r, g, b, a; 04502 04503 if(im->format != GL_RGBA && gray) 04504 return 0; 04505 04506 if(gray && gray != 8 && gray != 16) 04507 gray = 8; 04508 04509 gray /= 8; 04510 04511 shift = (sizeof(unsigned long) - 1) * 8; 04512 04513 for(y = 0; y < im->height; ++y){ 04514 for(x = 0; x < im->width; ++x){ 04515 a = gl2psGetRGB(im, x, y, &r, &g, &b); 04516 if(im->format == GL_RGBA && gray){ 04517 (*action)((unsigned long)(a * 255) << shift, gray); 04518 } 04519 else{ 04520 (*action)((unsigned long)(r * 255) << shift, 1); 04521 (*action)((unsigned long)(g * 255) << shift, 1); 04522 (*action)((unsigned long)(b * 255) << shift, 1); 04523 } 04524 } 04525 } 04526 04527 switch(gray){ 04528 case 0: return 3 * im->width * im->height; 04529 case 1: return im->width * im->height; 04530 case 2: return 2 * im->width * im->height; 04531 default: return 3 * im->width * im->height; 04532 } 04533 } 04534 04535 static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray) 04536 { 04537 int offs = 0, done = 0, sigbytes = 3; 04538 04539 if(gray && gray !=8 && gray != 16) 04540 gray = 8; 04541 04542 if(gray) 04543 sigbytes = gray / 8; 04544 04545 offs += fprintf(gl2ps->stream, 04546 "%d 0 obj\n" 04547 "<<\n" 04548 "/Type /XObject\n" 04549 "/Subtype /Image\n" 04550 "/Width %d\n" 04551 "/Height %d\n" 04552 "/ColorSpace %s \n" 04553 "/BitsPerComponent 8\n", 04554 obj, 04555 (int)im->width, (int)im->height, 04556 (gray) ? "/DeviceGray" : "/DeviceRGB" ); 04557 if(GL_RGBA == im->format && gray == 0){ 04558 offs += fprintf(gl2ps->stream, 04559 "/SMask %d 0 R\n", 04560 childobj); 04561 } 04562 04563 #if defined(GL2PS_HAVE_ZLIB) 04564 if(gl2ps->options & GL2PS_COMPRESS){ 04565 gl2psAllocCompress((int)(im->width * im->height * sigbytes)); 04566 04567 gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray); 04568 04569 if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ 04570 offs += gl2psPrintPDFCompressorType(); 04571 offs += fprintf(gl2ps->stream, 04572 "/Length %d " 04573 ">>\n" 04574 "stream\n", 04575 (int)gl2ps->compress->destLen); 04576 offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 04577 1, gl2ps->stream); 04578 done = 1; 04579 } 04580 gl2psFreeCompress(); 04581 } 04582 #endif 04583 04584 if(!done){ 04585 /* no compression, or too long after compression, or compress error 04586 -> write non-compressed entry */ 04587 offs += fprintf(gl2ps->stream, 04588 "/Length %d " 04589 ">>\n" 04590 "stream\n", 04591 (int)(im->width * im->height * sigbytes)); 04592 offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray); 04593 } 04594 04595 offs += fprintf(gl2ps->stream, 04596 "\nendstream\n" 04597 "endobj\n"); 04598 04599 return offs; 04600 } 04601 04602 static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber) 04603 { 04604 int offs = 0; 04605 04606 offs += fprintf(gl2ps->stream, 04607 "%d 0 obj\n" 04608 "<<\n" 04609 "/Type /Font\n" 04610 "/Subtype /Type1\n" 04611 "/Name /F%d\n" 04612 "/BaseFont /%s\n" 04613 "/Encoding /MacRomanEncoding\n" 04614 ">>\n" 04615 "endobj\n", 04616 obj, fontnumber, s->fontname); 04617 return offs; 04618 } 04619 04620 /* Write the physical objects */ 04621 04622 static int gl2psPDFgroupListWriteObjects(int entryoffs) 04623 { 04624 int i,j; 04625 GL2PSprimitive *p = NULL; 04626 GL2PSpdfgroup *gro; 04627 int offs = entryoffs; 04628 GL2PStriangle *triangles; 04629 int size = 0; 04630 04631 if(!gl2ps->pdfgrouplist) 04632 return offs; 04633 04634 for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ 04635 gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); 04636 if(!gl2psListNbr(gro->ptrlist)) 04637 continue; 04638 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); 04639 switch(p->type){ 04640 case GL2PS_POINT: 04641 break; 04642 case GL2PS_LINE: 04643 break; 04644 case GL2PS_TRIANGLE: 04645 size = gl2psListNbr(gro->ptrlist); 04646 triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size); 04647 for(j = 0; j < size; ++j){ 04648 p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); 04649 gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE); 04650 } 04651 if(triangles[0].prop & T_VAR_COLOR){ 04652 gl2ps->xreflist[gro->shobjno] = offs; 04653 offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0); 04654 } 04655 if(triangles[0].prop & T_ALPHA_LESS_1){ 04656 gl2ps->xreflist[gro->gsobjno] = offs; 04657 offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]); 04658 } 04659 if(triangles[0].prop & T_VAR_ALPHA){ 04660 gl2ps->xreflist[gro->gsobjno] = offs; 04661 offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno); 04662 gl2ps->xreflist[gro->trgroupobjno] = offs; 04663 offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno); 04664 gl2ps->xreflist[gro->maskshobjno] = offs; 04665 offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8); 04666 } 04667 gl2psFree(triangles); 04668 break; 04669 case GL2PS_PIXMAP: 04670 gl2ps->xreflist[gro->imobjno] = offs; 04671 offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0); 04672 if(p->data.image->format == GL_RGBA){ 04673 gl2ps->xreflist[gro->imobjno+1] = offs; 04674 offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8); 04675 } 04676 break; 04677 case GL2PS_TEXT: 04678 gl2ps->xreflist[gro->fontobjno] = offs; 04679 offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno); 04680 break; 04681 case GL2PS_SPECIAL : 04682 /* alignment contains the format for which the special output text 04683 is intended */ 04684 if(p->data.text->alignment == GL2PS_PDF) 04685 offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str); 04686 break; 04687 default: 04688 break; 04689 } 04690 } 04691 return offs; 04692 } 04693 04694 /* All variable data has been written at this point and all required 04695 functioninality has been gathered, so we can write now file footer 04696 with cross reference table and trailer */ 04697 04698 static void gl2psPrintPDFFooter(void) 04699 { 04700 int i, offs; 04701 04702 gl2psPDFgroupListInit(); 04703 gl2psPDFgroupListWriteMainStream(); 04704 04705 offs = gl2ps->xreflist[5] + gl2ps->streamlength; 04706 offs += gl2psClosePDFDataStream(); 04707 gl2ps->xreflist[5] = offs; 04708 04709 offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength); 04710 gl2ps->xreflist[6] = offs; 04711 gl2ps->streamlength = 0; 04712 04713 offs += gl2psPrintPDFOpenPage(); 04714 offs += gl2psPDFgroupListWriteVariableResources(); 04715 gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist, 04716 sizeof(int) * (gl2ps->objects_stack + 1)); 04717 gl2ps->xreflist[7] = offs; 04718 04719 offs += gl2psPrintPDFGSObject(); 04720 gl2ps->xreflist[8] = offs; 04721 04722 gl2ps->xreflist[gl2ps->objects_stack] = 04723 gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]); 04724 04725 /* Start cross reference table. The file has to been opened in 04726 binary mode to preserve the 20 digit string length! */ 04727 fprintf(gl2ps->stream, 04728 "xref\n" 04729 "0 %d\n" 04730 "%010d 65535 f \n", gl2ps->objects_stack, 0); 04731 04732 for(i = 1; i < gl2ps->objects_stack; ++i) 04733 fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]); 04734 04735 fprintf(gl2ps->stream, 04736 "trailer\n" 04737 "<<\n" 04738 "/Size %d\n" 04739 "/Info 1 0 R\n" 04740 "/Root 2 0 R\n" 04741 ">>\n" 04742 "startxref\n%d\n" 04743 "%%%%EOF\n", 04744 gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]); 04745 04746 /* Free auxiliary lists and arrays */ 04747 gl2psFree(gl2ps->xreflist); 04748 gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive); 04749 gl2psListDelete(gl2ps->pdfprimlist); 04750 gl2psPDFgroupListDelete(); 04751 04752 #if defined(GL2PS_HAVE_ZLIB) 04753 if(gl2ps->options & GL2PS_COMPRESS){ 04754 gl2psFreeCompress(); 04755 gl2psFree(gl2ps->compress); 04756 gl2ps->compress = NULL; 04757 } 04758 #endif 04759 } 04760 04761 /* PDF begin viewport */ 04762 04763 static void gl2psPrintPDFBeginViewport(GLint viewport[4]) 04764 { 04765 int offs = 0; 04766 GLint index; 04767 GLfloat rgba[4]; 04768 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; 04769 04770 glRenderMode(GL_FEEDBACK); 04771 04772 if(gl2ps->header){ 04773 gl2psPrintPDFHeader(); 04774 gl2ps->header = GL_FALSE; 04775 } 04776 04777 offs += gl2psPrintf("q\n"); 04778 04779 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 04780 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ 04781 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); 04782 } 04783 else{ 04784 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); 04785 rgba[0] = gl2ps->colormap[index][0]; 04786 rgba[1] = gl2ps->colormap[index][1]; 04787 rgba[2] = gl2ps->colormap[index][2]; 04788 rgba[3] = 1.0F; 04789 } 04790 offs += gl2psPrintPDFFillColor(rgba); 04791 offs += gl2psPrintf("%d %d %d %d re\n" 04792 "W\n" 04793 "f\n", 04794 x, y, w, h); 04795 } 04796 else{ 04797 offs += gl2psPrintf("%d %d %d %d re\n" 04798 "W\n" 04799 "n\n", 04800 x, y, w, h); 04801 } 04802 04803 gl2ps->streamlength += offs; 04804 } 04805 04806 static GLint gl2psPrintPDFEndViewport(void) 04807 { 04808 GLint res; 04809 04810 res = gl2psPrintPrimitives(); 04811 gl2ps->streamlength += gl2psPrintf("Q\n"); 04812 return res; 04813 } 04814 04815 static void gl2psPrintPDFFinalPrimitive(void) 04816 { 04817 } 04818 04819 /* definition of the PDF backend */ 04820 04821 static GL2PSbackend gl2psPDF = { 04822 gl2psPrintPDFHeader, 04823 gl2psPrintPDFFooter, 04824 gl2psPrintPDFBeginViewport, 04825 gl2psPrintPDFEndViewport, 04826 gl2psPrintPDFPrimitive, 04827 gl2psPrintPDFFinalPrimitive, 04828 "pdf", 04829 "Portable Document Format" 04830 }; 04831 04832 /********************************************************************* 04833 * 04834 * SVG routines 04835 * 04836 *********************************************************************/ 04837 04838 static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, 04839 GL2PSxyz *xyz, GL2PSrgba *rgba) 04840 { 04841 int i, j; 04842 04843 for(i = 0; i < n; i++){ 04844 xyz[i][0] = verts[i].xyz[0]; 04845 xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1]; 04846 xyz[i][2] = 0.0F; 04847 for(j = 0; j < 4; j++) 04848 rgba[i][j] = verts[i].rgba[j]; 04849 } 04850 } 04851 04852 static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32]) 04853 { 04854 int r = (int)(255. * rgba[0]); 04855 int g = (int)(255. * rgba[1]); 04856 int b = (int)(255. * rgba[2]); 04857 int rc = (r < 0) ? 0 : (r > 255) ? 255 : r; 04858 int gc = (g < 0) ? 0 : (g > 255) ? 255 : g; 04859 int bc = (b < 0) ? 0 : (b > 255) ? 255 : b; 04860 sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc); 04861 } 04862 04863 static void gl2psPrintSVGHeader(void) 04864 { 04865 int x, y, width, height; 04866 char col[32]; 04867 time_t now; 04868 04869 time(&now); 04870 04871 if (gl2ps->options & GL2PS_LANDSCAPE){ 04872 x = (int)gl2ps->viewport[1]; 04873 y = (int)gl2ps->viewport[0]; 04874 width = (int)gl2ps->viewport[3]; 04875 height = (int)gl2ps->viewport[2]; 04876 } 04877 else{ 04878 x = (int)gl2ps->viewport[0]; 04879 y = (int)gl2ps->viewport[1]; 04880 width = (int)gl2ps->viewport[2]; 04881 height = (int)gl2ps->viewport[3]; 04882 } 04883 04884 /* Compressed SVG files (.svgz) are simply gzipped SVG files */ 04885 gl2psPrintGzipHeader(); 04886 04887 gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); 04888 gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n"); 04889 gl2psPrintf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n" 04890 " width=\"%dpx\" height=\"%dpx\" viewBox=\"%d %d %d %d\">\n", 04891 width, height, x, y, width, height); 04892 gl2psPrintf("<title>%s</title>\n", gl2ps->title); 04893 gl2psPrintf("<desc>\n"); 04894 gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n" 04895 "For: %s\n" 04896 "CreationDate: %s", 04897 GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, 04898 GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); 04899 gl2psPrintf("</desc>\n"); 04900 gl2psPrintf("<defs>\n"); 04901 gl2psPrintf("</defs>\n"); 04902 04903 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 04904 gl2psSVGGetColorString(gl2ps->bgcolor, col); 04905 gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, 04906 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 04907 (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], 04908 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], 04909 (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); 04910 } 04911 04912 /* group all the primitives and disable antialiasing */ 04913 gl2psPrintf("<g shape-rendering=\"crispEdges\">\n"); 04914 } 04915 04916 static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3]) 04917 { 04918 int i; 04919 GL2PSxyz xyz2[3]; 04920 GL2PSrgba rgba2[3]; 04921 char col[32]; 04922 04923 /* Apparently there is no easy way to do Gouraud shading in SVG 04924 without explicitly pre-defining gradients, so for now we just do 04925 recursive subdivision */ 04926 04927 if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){ 04928 gl2psSVGGetColorString(rgba[0], col); 04929 gl2psPrintf("<polygon fill=\"%s\" ", col); 04930 if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]); 04931 gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1], 04932 xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]); 04933 } 04934 else{ 04935 /* subdivide into 4 subtriangles */ 04936 for(i = 0; i < 3; i++){ 04937 xyz2[0][i] = xyz[0][i]; 04938 xyz2[1][i] = 0.5F * (xyz[0][i] + xyz[1][i]); 04939 xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); 04940 } 04941 for(i = 0; i < 4; i++){ 04942 rgba2[0][i] = rgba[0][i]; 04943 rgba2[1][i] = 0.5F * (rgba[0][i] + rgba[1][i]); 04944 rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); 04945 } 04946 gl2psPrintSVGSmoothTriangle(xyz2, rgba2); 04947 for(i = 0; i < 3; i++){ 04948 xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); 04949 xyz2[1][i] = xyz[1][i]; 04950 xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); 04951 } 04952 for(i = 0; i < 4; i++){ 04953 rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); 04954 rgba2[1][i] = rgba[1][i]; 04955 rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); 04956 } 04957 gl2psPrintSVGSmoothTriangle(xyz2, rgba2); 04958 for(i = 0; i < 3; i++){ 04959 xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[2][i]); 04960 xyz2[1][i] = xyz[2][i]; 04961 xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); 04962 } 04963 for(i = 0; i < 4; i++){ 04964 rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[2][i]); 04965 rgba2[1][i] = rgba[2][i]; 04966 rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); 04967 } 04968 gl2psPrintSVGSmoothTriangle(xyz2, rgba2); 04969 for(i = 0; i < 3; i++){ 04970 xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); 04971 xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]); 04972 xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); 04973 } 04974 for(i = 0; i < 4; i++){ 04975 rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); 04976 rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]); 04977 rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); 04978 } 04979 gl2psPrintSVGSmoothTriangle(xyz2, rgba2); 04980 } 04981 } 04982 04983 static void gl2psPrintSVGDash(GLushort pattern, GLint factor) 04984 { 04985 int i, n, array[10]; 04986 04987 if(!pattern || !factor) return; /* solid line */ 04988 04989 gl2psParseStipplePattern(pattern, factor, &n, array); 04990 gl2psPrintf("stroke-dasharray=\""); 04991 for(i = 0; i < n; i++){ 04992 if(i) gl2psPrintf(","); 04993 gl2psPrintf("%d", array[i]); 04994 } 04995 gl2psPrintf("\" "); 04996 } 04997 04998 static void gl2psEndSVGLine(void) 04999 { 05000 int i; 05001 if(gl2ps->lastvertex.rgba[0] >= 0.){ 05002 gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], 05003 gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]); 05004 for(i = 0; i < 3; i++) 05005 gl2ps->lastvertex.xyz[i] = -1.; 05006 for(i = 0; i < 4; i++) 05007 gl2ps->lastvertex.rgba[i] = -1.; 05008 } 05009 } 05010 05011 static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap) 05012 { 05013 #if defined(GL2PS_HAVE_LIBPNG) 05014 GL2PSlist *png; 05015 unsigned char c; 05016 int i; 05017 05018 /* The only image types supported by the SVG standard are JPEG, PNG 05019 and SVG. Here we choose PNG, and since we want to embed the image 05020 directly in the SVG stream (and not link to an external image 05021 file), we need to encode the pixmap into PNG in memory, then 05022 encode it into base64. */ 05023 05024 png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, 05025 sizeof(unsigned char)); 05026 gl2psConvertPixmapToPNG(pixmap, png); 05027 gl2psListEncodeBase64(png); 05028 gl2psPrintf("<image x=\"%g\" y=\"%g\" width=\"%d\" height=\"%d\"\n", 05029 x, y - pixmap->height, pixmap->width, pixmap->height); 05030 gl2psPrintf("xlink:href=\"data:image/png;base64,"); 05031 for(i = 0; i < gl2psListNbr(png); i++){ 05032 gl2psListRead(png, i, &c); 05033 gl2psPrintf("%c", c); 05034 } 05035 gl2psPrintf("\"/>\n"); 05036 gl2psListDelete(png); 05037 #else 05038 gl2psMsg(GL2PS_WARNING, "GL2PS must be compiled with PNG support in " 05039 "order to embed images in SVG streams"); 05040 #endif 05041 } 05042 05043 static void gl2psPrintSVGPrimitive(void *data) 05044 { 05045 GL2PSprimitive *prim; 05046 GL2PSxyz xyz[4]; 05047 GL2PSrgba rgba[4]; 05048 char col[32]; 05049 int newline; 05050 05051 prim = *(GL2PSprimitive**)data; 05052 05053 if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; 05054 05055 /* We try to draw connected lines as a single path to get nice line 05056 joins and correct stippling. So if the primitive to print is not 05057 a line we must first finish the current line (if any): */ 05058 if(prim->type != GL2PS_LINE) gl2psEndSVGLine(); 05059 05060 gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba); 05061 05062 switch(prim->type){ 05063 case GL2PS_POINT : 05064 gl2psSVGGetColorString(rgba[0], col); 05065 gl2psPrintf("<circle fill=\"%s\" ", col); 05066 if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]); 05067 gl2psPrintf("cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n", 05068 xyz[0][0], xyz[0][1], 0.5 * prim->width); 05069 break; 05070 case GL2PS_LINE : 05071 if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || 05072 !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || 05073 gl2ps->lastlinewidth != prim->width || 05074 gl2ps->lastpattern != prim->pattern || 05075 gl2ps->lastfactor != prim->factor){ 05076 /* End the current line if the new segment does not start where 05077 the last one ended, or if the color, the width or the 05078 stippling have changed (we will need to use multi-point 05079 gradients for smooth-shaded lines) */ 05080 gl2psEndSVGLine(); 05081 newline = 1; 05082 } 05083 else{ 05084 newline = 0; 05085 } 05086 gl2ps->lastvertex = prim->verts[1]; 05087 gl2psSetLastColor(prim->verts[0].rgba); 05088 gl2ps->lastlinewidth = prim->width; 05089 gl2ps->lastpattern = prim->pattern; 05090 gl2ps->lastfactor = prim->factor; 05091 if(newline){ 05092 gl2psSVGGetColorString(rgba[0], col); 05093 gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ", 05094 col, prim->width); 05095 if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]); 05096 gl2psPrintSVGDash(prim->pattern, prim->factor); 05097 gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]); 05098 } 05099 else{ 05100 gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]); 05101 } 05102 break; 05103 case GL2PS_TRIANGLE : 05104 gl2psPrintSVGSmoothTriangle(xyz, rgba); 05105 break; 05106 case GL2PS_QUADRANGLE : 05107 gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); 05108 break; 05109 case GL2PS_PIXMAP : 05110 gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image); 05111 break; 05112 case GL2PS_TEXT : 05113 gl2psSVGGetColorString(prim->verts[0].rgba, col); 05114 gl2psPrintf("<text fill=\"%s\" x=\"%g\" y=\"%g\" font-size=\"%d\" ", 05115 col, xyz[0][0], xyz[0][1], prim->data.text->fontsize); 05116 if(prim->data.text->angle) 05117 gl2psPrintf("transform=\"rotate(%g, %g, %g)\" ", 05118 -prim->data.text->angle, xyz[0][0], xyz[0][1]); 05119 switch(prim->data.text->alignment){ 05120 case GL2PS_TEXT_C: 05121 gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"%d\" ", 05122 -prim->data.text->fontsize / 2); 05123 break; 05124 case GL2PS_TEXT_CL: 05125 gl2psPrintf("text-anchor=\"start\" baseline-shift=\"%d\" ", 05126 -prim->data.text->fontsize / 2); 05127 break; 05128 case GL2PS_TEXT_CR: 05129 gl2psPrintf("text-anchor=\"end\" baseline-shift=\"%d\" ", 05130 -prim->data.text->fontsize / 2); 05131 break; 05132 case GL2PS_TEXT_B: 05133 gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"0\" "); 05134 break; 05135 case GL2PS_TEXT_BR: 05136 gl2psPrintf("text-anchor=\"end\" baseline-shift=\"0\" "); 05137 break; 05138 case GL2PS_TEXT_T: 05139 gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"%d\" ", 05140 -prim->data.text->fontsize); 05141 break; 05142 case GL2PS_TEXT_TL: 05143 gl2psPrintf("text-anchor=\"start\" baseline-shift=\"%d\" ", 05144 -prim->data.text->fontsize); 05145 break; 05146 case GL2PS_TEXT_TR: 05147 gl2psPrintf("text-anchor=\"end\" baseline-shift=\"%d\" ", 05148 -prim->data.text->fontsize); 05149 break; 05150 case GL2PS_TEXT_BL: 05151 default: /* same as GL2PS_TEXT_BL */ 05152 gl2psPrintf("text-anchor=\"start\" baseline-shift=\"0\" "); 05153 break; 05154 } 05155 if(!strcmp(prim->data.text->fontname, "Times-Roman")) 05156 gl2psPrintf("font-family=\"Times\">"); 05157 else if(!strcmp(prim->data.text->fontname, "Times-Bold")) 05158 gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">"); 05159 else if(!strcmp(prim->data.text->fontname, "Times-Italic")) 05160 gl2psPrintf("font-family=\"Times\" font-style=\"italic\">"); 05161 else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic")) 05162 gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">"); 05163 else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold")) 05164 gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">"); 05165 else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique")) 05166 gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">"); 05167 else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique")) 05168 gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">"); 05169 else if(!strcmp(prim->data.text->fontname, "Courier-Bold")) 05170 gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">"); 05171 else if(!strcmp(prim->data.text->fontname, "Courier-Oblique")) 05172 gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">"); 05173 else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique")) 05174 gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">"); 05175 else 05176 gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname); 05177 gl2psPrintf("%s</text>\n", prim->data.text->str); 05178 break; 05179 case GL2PS_SPECIAL : 05180 /* alignment contains the format for which the special output text 05181 is intended */ 05182 if(prim->data.text->alignment == GL2PS_SVG) 05183 gl2psPrintf("%s\n", prim->data.text->str); 05184 break; 05185 default : 05186 break; 05187 } 05188 } 05189 05190 static void gl2psPrintSVGFooter(void) 05191 { 05192 gl2psPrintf("</g>\n"); 05193 gl2psPrintf("</svg>\n"); 05194 05195 gl2psPrintGzipFooter(); 05196 } 05197 05198 static void gl2psPrintSVGBeginViewport(GLint viewport[4]) 05199 { 05200 GLint index; 05201 char col[32]; 05202 GLfloat rgba[4]; 05203 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; 05204 05205 glRenderMode(GL_FEEDBACK); 05206 05207 if(gl2ps->header){ 05208 gl2psPrintSVGHeader(); 05209 gl2ps->header = GL_FALSE; 05210 } 05211 05212 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 05213 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ 05214 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); 05215 } 05216 else{ 05217 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); 05218 rgba[0] = gl2ps->colormap[index][0]; 05219 rgba[1] = gl2ps->colormap[index][1]; 05220 rgba[2] = gl2ps->colormap[index][2]; 05221 rgba[3] = 1.0F; 05222 } 05223 gl2psSVGGetColorString(rgba, col); 05224 gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, 05225 x, gl2ps->viewport[3] - y, 05226 x + w, gl2ps->viewport[3] - y, 05227 x + w, gl2ps->viewport[3] - (y + h), 05228 x, gl2ps->viewport[3] - (y + h)); 05229 } 05230 05231 gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h); 05232 gl2psPrintf(" <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", 05233 x, gl2ps->viewport[3] - y, 05234 x + w, gl2ps->viewport[3] - y, 05235 x + w, gl2ps->viewport[3] - (y + h), 05236 x, gl2ps->viewport[3] - (y + h)); 05237 gl2psPrintf("</clipPath>\n"); 05238 gl2psPrintf("<g clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h); 05239 } 05240 05241 static GLint gl2psPrintSVGEndViewport(void) 05242 { 05243 GLint res; 05244 05245 res = gl2psPrintPrimitives(); 05246 gl2psPrintf("</g>\n"); 05247 return res; 05248 } 05249 05250 static void gl2psPrintSVGFinalPrimitive(void) 05251 { 05252 /* End any remaining line, if any */ 05253 gl2psEndSVGLine(); 05254 } 05255 05256 /* definition of the SVG backend */ 05257 05258 static GL2PSbackend gl2psSVG = { 05259 gl2psPrintSVGHeader, 05260 gl2psPrintSVGFooter, 05261 gl2psPrintSVGBeginViewport, 05262 gl2psPrintSVGEndViewport, 05263 gl2psPrintSVGPrimitive, 05264 gl2psPrintSVGFinalPrimitive, 05265 "svg", 05266 "Scalable Vector Graphics" 05267 }; 05268 05269 /********************************************************************* 05270 * 05271 * PGF routines 05272 * 05273 *********************************************************************/ 05274 05275 static void gl2psPrintPGFColor(GL2PSrgba rgba) 05276 { 05277 if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ 05278 gl2psSetLastColor(rgba); 05279 fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]); 05280 } 05281 } 05282 05283 static void gl2psPrintPGFHeader(void) 05284 { 05285 time_t now; 05286 05287 time(&now); 05288 05289 fprintf(gl2ps->stream, 05290 "%% Title: %s\n" 05291 "%% Creator: GL2PS %d.%d.%d%s, %s\n" 05292 "%% For: %s\n" 05293 "%% CreationDate: %s", 05294 gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, 05295 GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, 05296 gl2ps->producer, ctime(&now)); 05297 05298 fprintf(gl2ps->stream, "\\begin{pgfpicture}\n"); 05299 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 05300 gl2psPrintPGFColor(gl2ps->bgcolor); 05301 fprintf(gl2ps->stream, 05302 "\\pgfpathrectanglecorners{" 05303 "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n" 05304 "\\pgfusepath{fill}\n", 05305 (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], 05306 (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); 05307 } 05308 } 05309 05310 static void gl2psPrintPGFDash(GLushort pattern, GLint factor) 05311 { 05312 int i, n, array[10]; 05313 05314 if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) 05315 return; 05316 05317 gl2ps->lastpattern = pattern; 05318 gl2ps->lastfactor = factor; 05319 05320 if(!pattern || !factor){ 05321 /* solid line */ 05322 fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n"); 05323 } 05324 else{ 05325 gl2psParseStipplePattern(pattern, factor, &n, array); 05326 fprintf(gl2ps->stream, "\\pgfsetdash{"); 05327 for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]); 05328 fprintf(gl2ps->stream, "}{0pt}\n"); 05329 } 05330 } 05331 05332 static const char *gl2psPGFTextAlignment(int align) 05333 { 05334 switch(align){ 05335 case GL2PS_TEXT_C : return "center"; 05336 case GL2PS_TEXT_CL : return "west"; 05337 case GL2PS_TEXT_CR : return "east"; 05338 case GL2PS_TEXT_B : return "south"; 05339 case GL2PS_TEXT_BR : return "south east"; 05340 case GL2PS_TEXT_T : return "north"; 05341 case GL2PS_TEXT_TL : return "north west"; 05342 case GL2PS_TEXT_TR : return "north east"; 05343 case GL2PS_TEXT_BL : 05344 default : return "south west"; 05345 } 05346 } 05347 05348 static void gl2psPrintPGFPrimitive(void *data) 05349 { 05350 GL2PSprimitive *prim; 05351 05352 prim = *(GL2PSprimitive**)data; 05353 05354 switch(prim->type){ 05355 case GL2PS_POINT : 05356 /* Points in openGL are rectangular */ 05357 gl2psPrintPGFColor(prim->verts[0].rgba); 05358 fprintf(gl2ps->stream, 05359 "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}" 05360 "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n", 05361 prim->verts[0].xyz[0]-0.5*prim->width, 05362 prim->verts[0].xyz[1]-0.5*prim->width, 05363 prim->width,prim->width); 05364 break; 05365 case GL2PS_LINE : 05366 gl2psPrintPGFColor(prim->verts[0].rgba); 05367 if(gl2ps->lastlinewidth != prim->width){ 05368 gl2ps->lastlinewidth = prim->width; 05369 fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth); 05370 } 05371 gl2psPrintPGFDash(prim->pattern, prim->factor); 05372 fprintf(gl2ps->stream, 05373 "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" 05374 "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" 05375 "\\pgfusepath{stroke}\n", 05376 prim->verts[1].xyz[0], prim->verts[1].xyz[1], 05377 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 05378 break; 05379 case GL2PS_TRIANGLE : 05380 if(gl2ps->lastlinewidth != 0){ 05381 gl2ps->lastlinewidth = 0; 05382 fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n"); 05383 } 05384 gl2psPrintPGFColor(prim->verts[0].rgba); 05385 fprintf(gl2ps->stream, 05386 "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" 05387 "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" 05388 "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" 05389 "\\pgfpathclose\n" 05390 "\\pgfusepath{fill,stroke}\n", 05391 prim->verts[2].xyz[0], prim->verts[2].xyz[1], 05392 prim->verts[1].xyz[0], prim->verts[1].xyz[1], 05393 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 05394 break; 05395 case GL2PS_TEXT : 05396 fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n", 05397 prim->verts[0].xyz[0], prim->verts[0].xyz[1]); 05398 05399 if(prim->data.text->angle) 05400 fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle); 05401 05402 fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont", 05403 gl2psPGFTextAlignment(prim->data.text->alignment), 05404 prim->data.text->fontsize); 05405 05406 fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}", 05407 prim->verts[0].rgba[0], prim->verts[0].rgba[1], 05408 prim->verts[0].rgba[2], prim->data.text->str); 05409 05410 fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n"); 05411 break; 05412 case GL2PS_SPECIAL : 05413 /* alignment contains the format for which the special output text 05414 is intended */ 05415 if (prim->data.text->alignment == GL2PS_PGF) 05416 fprintf(gl2ps->stream, "%s\n", prim->data.text->str); 05417 break; 05418 default : 05419 break; 05420 } 05421 } 05422 05423 static void gl2psPrintPGFFooter(void) 05424 { 05425 fprintf(gl2ps->stream, "\\end{pgfpicture}\n"); 05426 } 05427 05428 static void gl2psPrintPGFBeginViewport(GLint viewport[4]) 05429 { 05430 GLint index; 05431 GLfloat rgba[4]; 05432 int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; 05433 05434 glRenderMode(GL_FEEDBACK); 05435 05436 if(gl2ps->header){ 05437 gl2psPrintPGFHeader(); 05438 gl2ps->header = GL_FALSE; 05439 } 05440 05441 fprintf(gl2ps->stream, "\\begin{pgfscope}\n"); 05442 if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ 05443 if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ 05444 glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); 05445 } 05446 else{ 05447 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); 05448 rgba[0] = gl2ps->colormap[index][0]; 05449 rgba[1] = gl2ps->colormap[index][1]; 05450 rgba[2] = gl2ps->colormap[index][2]; 05451 rgba[3] = 1.0F; 05452 } 05453 gl2psPrintPGFColor(rgba); 05454 fprintf(gl2ps->stream, 05455 "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" 05456 "{\\pgfpoint{%dpt}{%dpt}}\n" 05457 "\\pgfusepath{fill}\n", 05458 x, y, w, h); 05459 } 05460 05461 fprintf(gl2ps->stream, 05462 "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" 05463 "{\\pgfpoint{%dpt}{%dpt}}\n" 05464 "\\pgfusepath{clip}\n", 05465 x, y, w, h); 05466 } 05467 05468 static GLint gl2psPrintPGFEndViewport(void) 05469 { 05470 GLint res; 05471 res = gl2psPrintPrimitives(); 05472 fprintf(gl2ps->stream, "\\end{pgfscope}\n"); 05473 return res; 05474 } 05475 05476 static void gl2psPrintPGFFinalPrimitive(void) 05477 { 05478 } 05479 05480 /* definition of the PGF backend */ 05481 05482 static GL2PSbackend gl2psPGF = { 05483 gl2psPrintPGFHeader, 05484 gl2psPrintPGFFooter, 05485 gl2psPrintPGFBeginViewport, 05486 gl2psPrintPGFEndViewport, 05487 gl2psPrintPGFPrimitive, 05488 gl2psPrintPGFFinalPrimitive, 05489 "tex", 05490 "PGF Latex Graphics" 05491 }; 05492 05493 /********************************************************************* 05494 * 05495 * General primitive printing routine 05496 * 05497 *********************************************************************/ 05498 05499 /* Warning: the ordering of the backends must match the format 05500 #defines in gl2ps.h */ 05501 05502 static GL2PSbackend *gl2psbackends[] = { 05503 &gl2psPS, /* 0 */ 05504 &gl2psEPS, /* 1 */ 05505 &gl2psTEX, /* 2 */ 05506 &gl2psPDF, /* 3 */ 05507 &gl2psSVG, /* 4 */ 05508 &gl2psPGF /* 5 */ 05509 }; 05510 05511 static void gl2psComputeTightBoundingBox(void *data) 05512 { 05513 GL2PSprimitive *prim; 05514 int i; 05515 05516 prim = *(GL2PSprimitive**)data; 05517 05518 for(i = 0; i < prim->numverts; i++){ 05519 if(prim->verts[i].xyz[0] < gl2ps->viewport[0]) 05520 gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0]; 05521 if(prim->verts[i].xyz[0] > gl2ps->viewport[2]) 05522 gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F); 05523 if(prim->verts[i].xyz[1] < gl2ps->viewport[1]) 05524 gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1]; 05525 if(prim->verts[i].xyz[1] > gl2ps->viewport[3]) 05526 gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F); 05527 } 05528 } 05529 05530 static GLint gl2psPrintPrimitives(void) 05531 { 05532 GL2PSbsptree *root; 05533 GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE}; 05534 GLint used; 05535 05536 used = glRenderMode(GL_RENDER); 05537 05538 if(used < 0){ 05539 gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow"); 05540 return GL2PS_OVERFLOW; 05541 } 05542 05543 if(used > 0) 05544 gl2psParseFeedbackBuffer(used); 05545 05546 gl2psRescaleAndOffset(); 05547 05548 if(gl2ps->header){ 05549 if(gl2psListNbr(gl2ps->primitives) && 05550 (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){ 05551 gl2ps->viewport[0] = gl2ps->viewport[1] = 100000; 05552 gl2ps->viewport[2] = gl2ps->viewport[3] = -100000; 05553 gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox); 05554 } 05555 (gl2psbackends[gl2ps->format]->printHeader)(); 05556 gl2ps->header = GL_FALSE; 05557 } 05558 05559 if(!gl2psListNbr(gl2ps->primitives)){ 05560 /* empty feedback buffer and/or nothing else to print */ 05561 return GL2PS_NO_FEEDBACK; 05562 } 05563 05564 switch(gl2ps->sort){ 05565 case GL2PS_NO_SORT : 05566 gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); 05567 gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); 05568 /* reset the primitive list, waiting for the next viewport */ 05569 gl2psListReset(gl2ps->primitives); 05570 break; 05571 case GL2PS_SIMPLE_SORT : 05572 gl2psListSort(gl2ps->primitives, gl2psCompareDepth); 05573 if(gl2ps->options & GL2PS_OCCLUSION_CULL){ 05574 gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree); 05575 gl2psFreeBspImageTree(&gl2ps->imagetree); 05576 } 05577 gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); 05578 gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); 05579 /* reset the primitive list, waiting for the next viewport */ 05580 gl2psListReset(gl2ps->primitives); 05581 break; 05582 case GL2PS_BSP_SORT : 05583 root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); 05584 gl2psBuildBspTree(root, gl2ps->primitives); 05585 if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root); 05586 if(gl2ps->options & GL2PS_OCCLUSION_CULL){ 05587 gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess, 05588 gl2psAddInImageTree, 1); 05589 gl2psFreeBspImageTree(&gl2ps->imagetree); 05590 } 05591 gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, 05592 gl2psbackends[gl2ps->format]->printPrimitive, 0); 05593 gl2psFreeBspTree(&root); 05594 /* reallocate the primitive list (it's been deleted by 05595 gl2psBuildBspTree) in case there is another viewport */ 05596 gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); 05597 break; 05598 } 05599 gl2psbackends[gl2ps->format]->printFinalPrimitive(); 05600 05601 return GL2PS_SUCCESS; 05602 } 05603 05604 /********************************************************************* 05605 * 05606 * Public routines 05607 * 05608 *********************************************************************/ 05609 05610 GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, 05611 GLint viewport[4], GLint format, GLint sort, 05612 GLint options, GLint colormode, 05613 GLint colorsize, GL2PSrgba *colormap, 05614 GLint nr, GLint ng, GLint nb, GLint buffersize, 05615 FILE *stream, const char *filename) 05616 { 05617 GLint index; 05618 int i; 05619 05620 if(gl2ps){ 05621 gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state"); 05622 return GL2PS_ERROR; 05623 } 05624 05625 gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext)); 05626 05627 if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))){ 05628 gl2ps->format = format; 05629 } 05630 else { 05631 gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format); 05632 gl2psFree(gl2ps); 05633 gl2ps = NULL; 05634 return GL2PS_ERROR; 05635 } 05636 05637 switch(sort){ 05638 case GL2PS_NO_SORT : 05639 case GL2PS_SIMPLE_SORT : 05640 case GL2PS_BSP_SORT : 05641 gl2ps->sort = sort; 05642 break; 05643 default : 05644 gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort); 05645 gl2psFree(gl2ps); 05646 gl2ps = NULL; 05647 return GL2PS_ERROR; 05648 } 05649 05650 if(stream){ 05651 gl2ps->stream = stream; 05652 } 05653 else{ 05654 gl2psMsg(GL2PS_ERROR, "Bad file pointer"); 05655 gl2psFree(gl2ps); 05656 gl2ps = NULL; 05657 return GL2PS_ERROR; 05658 } 05659 05660 gl2ps->header = GL_TRUE; 05661 gl2ps->maxbestroot = 10; 05662 gl2ps->options = options; 05663 gl2ps->compress = NULL; 05664 gl2ps->imagemap_head = NULL; 05665 gl2ps->imagemap_tail = NULL; 05666 05667 if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){ 05668 glGetIntegerv(GL_VIEWPORT, gl2ps->viewport); 05669 } 05670 else{ 05671 for(i = 0; i < 4; i++){ 05672 gl2ps->viewport[i] = viewport[i]; 05673 } 05674 } 05675 05676 if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){ 05677 gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)", 05678 gl2ps->viewport[0], gl2ps->viewport[1], 05679 gl2ps->viewport[2], gl2ps->viewport[3]); 05680 gl2psFree(gl2ps); 05681 gl2ps = NULL; 05682 return GL2PS_ERROR; 05683 } 05684 05685 gl2ps->threshold[0] = nr ? 1.0F / (GLfloat)nr : 0.064F; 05686 gl2ps->threshold[1] = ng ? 1.0F / (GLfloat)ng : 0.034F; 05687 gl2ps->threshold[2] = nb ? 1.0F / (GLfloat)nb : 0.100F; 05688 gl2ps->colormode = colormode; 05689 gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048; 05690 for(i = 0; i < 3; i++){ 05691 gl2ps->lastvertex.xyz[i] = -1.0F; 05692 } 05693 for(i = 0; i < 4; i++){ 05694 gl2ps->lastvertex.rgba[i] = -1.0F; 05695 gl2ps->lastrgba[i] = -1.0F; 05696 } 05697 gl2ps->lastlinewidth = -1.0F; 05698 gl2ps->lastpattern = 0; 05699 gl2ps->lastfactor = 0; 05700 gl2ps->imagetree = NULL; 05701 gl2ps->primitivetoadd = NULL; 05702 gl2ps->zerosurfacearea = GL_FALSE; 05703 gl2ps->pdfprimlist = NULL; 05704 gl2ps->pdfgrouplist = NULL; 05705 gl2ps->xreflist = NULL; 05706 05707 /* get default blending mode from current OpenGL state (enabled by 05708 default for SVG) */ 05709 gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND); 05710 glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]); 05711 glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]); 05712 05713 if(gl2ps->colormode == GL_RGBA){ 05714 gl2ps->colorsize = 0; 05715 gl2ps->colormap = NULL; 05716 glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor); 05717 } 05718 else if(gl2ps->colormode == GL_COLOR_INDEX){ 05719 if(!colorsize || !colormap){ 05720 gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering"); 05721 gl2psFree(gl2ps); 05722 gl2ps = NULL; 05723 return GL2PS_ERROR; 05724 } 05725 gl2ps->colorsize = colorsize; 05726 gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba)); 05727 memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba)); 05728 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); 05729 gl2ps->bgcolor[0] = gl2ps->colormap[index][0]; 05730 gl2ps->bgcolor[1] = gl2ps->colormap[index][1]; 05731 gl2ps->bgcolor[2] = gl2ps->colormap[index][2]; 05732 gl2ps->bgcolor[3] = 1.0F; 05733 } 05734 else{ 05735 gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage"); 05736 gl2psFree(gl2ps); 05737 gl2ps = NULL; 05738 return GL2PS_ERROR; 05739 } 05740 05741 if(!title){ 05742 gl2ps->title = (char*)gl2psMalloc(sizeof(char)); 05743 gl2ps->title[0] = '\0'; 05744 } 05745 else{ 05746 gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char)); 05747 strcpy(gl2ps->title, title); 05748 } 05749 05750 if(!producer){ 05751 gl2ps->producer = (char*)gl2psMalloc(sizeof(char)); 05752 gl2ps->producer[0] = '\0'; 05753 } 05754 else{ 05755 gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char)); 05756 strcpy(gl2ps->producer, producer); 05757 } 05758 05759 if(!filename){ 05760 gl2ps->filename = (char*)gl2psMalloc(sizeof(char)); 05761 gl2ps->filename[0] = '\0'; 05762 } 05763 else{ 05764 gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char)); 05765 strcpy(gl2ps->filename, filename); 05766 } 05767 05768 gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); 05769 gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*)); 05770 gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat)); 05771 glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback); 05772 glRenderMode(GL_FEEDBACK); 05773 05774 return GL2PS_SUCCESS; 05775 } 05776 05777 GL2PSDLL_API GLint gl2psEndPage(void) 05778 { 05779 GLint res; 05780 05781 if(!gl2ps) return GL2PS_UNINITIALIZED; 05782 05783 res = gl2psPrintPrimitives(); 05784 05785 if(res != GL2PS_OVERFLOW) 05786 (gl2psbackends[gl2ps->format]->printFooter)(); 05787 05788 fflush(gl2ps->stream); 05789 05790 gl2psListDelete(gl2ps->primitives); 05791 gl2psListDelete(gl2ps->auxprimitives); 05792 gl2psFreeImagemap(gl2ps->imagemap_head); 05793 gl2psFree(gl2ps->colormap); 05794 gl2psFree(gl2ps->title); 05795 gl2psFree(gl2ps->producer); 05796 gl2psFree(gl2ps->filename); 05797 gl2psFree(gl2ps->feedback); 05798 gl2psFree(gl2ps); 05799 gl2ps = NULL; 05800 05801 return res; 05802 } 05803 05804 GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]) 05805 { 05806 if(!gl2ps) return GL2PS_UNINITIALIZED; 05807 05808 (gl2psbackends[gl2ps->format]->beginViewport)(viewport); 05809 05810 return GL2PS_SUCCESS; 05811 } 05812 05813 GL2PSDLL_API GLint gl2psEndViewport(void) 05814 { 05815 GLint res; 05816 05817 if(!gl2ps) return GL2PS_UNINITIALIZED; 05818 05819 res = (gl2psbackends[gl2ps->format]->endViewport)(); 05820 05821 /* reset last used colors, line widths */ 05822 gl2ps->lastlinewidth = -1.0F; 05823 05824 return res; 05825 } 05826 05827 GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, 05828 GLshort fontsize, GLint alignment, GLfloat angle) 05829 { 05830 return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle); 05831 } 05832 05833 GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize) 05834 { 05835 return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F); 05836 } 05837 05838 GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str) 05839 { 05840 return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F); 05841 } 05842 05843 GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, 05844 GLint xorig, GLint yorig, 05845 GLenum format, GLenum type, 05846 const void *pixels) 05847 { 05848 int size, i; 05849 const GLfloat *piv; 05850 GLfloat pos[4], zoom_x, zoom_y; 05851 GL2PSprimitive *prim; 05852 GLboolean valid; 05853 05854 if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED; 05855 05856 if((width <= 0) || (height <= 0)) return GL2PS_ERROR; 05857 05858 if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS; 05859 05860 if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){ 05861 gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for " 05862 "GL_RGB/GL_RGBA, GL_FLOAT pixels"); 05863 return GL2PS_ERROR; 05864 } 05865 05866 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); 05867 if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ 05868 05869 glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); 05870 glGetFloatv(GL_ZOOM_X, &zoom_x); 05871 glGetFloatv(GL_ZOOM_Y, &zoom_y); 05872 05873 prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); 05874 prim->type = GL2PS_PIXMAP; 05875 prim->boundary = 0; 05876 prim->numverts = 1; 05877 prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); 05878 prim->verts[0].xyz[0] = pos[0] + xorig; 05879 prim->verts[0].xyz[1] = pos[1] + yorig; 05880 prim->verts[0].xyz[2] = pos[2]; 05881 prim->culled = 0; 05882 prim->offset = 0; 05883 prim->pattern = 0; 05884 prim->factor = 0; 05885 prim->width = 1; 05886 glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); 05887 prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); 05888 prim->data.image->width = width; 05889 prim->data.image->height = height; 05890 prim->data.image->zoom_x = zoom_x; 05891 prim->data.image->zoom_y = zoom_y; 05892 prim->data.image->format = format; 05893 prim->data.image->type = type; 05894 05895 switch(format){ 05896 case GL_RGBA: 05897 if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ 05898 /* special case: blending turned off */ 05899 prim->data.image->format = GL_RGB; 05900 size = height * width * 3; 05901 prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); 05902 piv = (const GLfloat*)pixels; 05903 for(i = 0; i < size; ++i, ++piv){ 05904 prim->data.image->pixels[i] = *piv; 05905 if(!((i + 1) % 3)) 05906 ++piv; 05907 } 05908 } 05909 else{ 05910 size = height * width * 4; 05911 prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); 05912 memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); 05913 } 05914 break; 05915 case GL_RGB: 05916 default: 05917 size = height * width * 3; 05918 prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); 05919 memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); 05920 break; 05921 } 05922 05923 gl2psListAdd(gl2ps->auxprimitives, &prim); 05924 glPassThrough(GL2PS_DRAW_PIXELS_TOKEN); 05925 05926 return GL2PS_SUCCESS; 05927 } 05928 05929 GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, 05930 const GLfloat position[3], 05931 const unsigned char *imagemap){ 05932 int size, i; 05933 int sizeoffloat = sizeof(GLfloat); 05934 05935 if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED; 05936 05937 if((width <= 0) || (height <= 0)) return GL2PS_ERROR; 05938 05939 size = height + height * ((width - 1) / 8); 05940 glPassThrough(GL2PS_IMAGEMAP_TOKEN); 05941 glBegin(GL_POINTS); 05942 glVertex3f(position[0], position[1],position[2]); 05943 glEnd(); 05944 glPassThrough((GLfloat)width); 05945 glPassThrough((GLfloat)height); 05946 for(i = 0; i < size; i += sizeoffloat){ 05947 const float *value = (const float*)imagemap; 05948 glPassThrough(*value); 05949 imagemap += sizeoffloat; 05950 } 05951 return GL2PS_SUCCESS; 05952 } 05953 05954 GL2PSDLL_API GLint gl2psEnable(GLint mode) 05955 { 05956 GLint tmp; 05957 05958 if(!gl2ps) return GL2PS_UNINITIALIZED; 05959 05960 switch(mode){ 05961 case GL2PS_POLYGON_OFFSET_FILL : 05962 glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN); 05963 glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]); 05964 glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]); 05965 break; 05966 case GL2PS_POLYGON_BOUNDARY : 05967 glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN); 05968 break; 05969 case GL2PS_LINE_STIPPLE : 05970 glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN); 05971 glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp); 05972 glPassThrough((GLfloat)tmp); 05973 glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp); 05974 glPassThrough((GLfloat)tmp); 05975 break; 05976 case GL2PS_BLEND : 05977 glPassThrough(GL2PS_BEGIN_BLEND_TOKEN); 05978 break; 05979 default : 05980 gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode); 05981 return GL2PS_WARNING; 05982 } 05983 05984 return GL2PS_SUCCESS; 05985 } 05986 05987 GL2PSDLL_API GLint gl2psDisable(GLint mode) 05988 { 05989 if(!gl2ps) return GL2PS_UNINITIALIZED; 05990 05991 switch(mode){ 05992 case GL2PS_POLYGON_OFFSET_FILL : 05993 glPassThrough(GL2PS_END_OFFSET_TOKEN); 05994 break; 05995 case GL2PS_POLYGON_BOUNDARY : 05996 glPassThrough(GL2PS_END_BOUNDARY_TOKEN); 05997 break; 05998 case GL2PS_LINE_STIPPLE : 05999 glPassThrough(GL2PS_END_STIPPLE_TOKEN); 06000 break; 06001 case GL2PS_BLEND : 06002 glPassThrough(GL2PS_END_BLEND_TOKEN); 06003 break; 06004 default : 06005 gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode); 06006 return GL2PS_WARNING; 06007 } 06008 06009 return GL2PS_SUCCESS; 06010 } 06011 06012 GL2PSDLL_API GLint gl2psPointSize(GLfloat value) 06013 { 06014 if(!gl2ps) return GL2PS_UNINITIALIZED; 06015 06016 glPassThrough(GL2PS_POINT_SIZE_TOKEN); 06017 glPassThrough(value); 06018 06019 return GL2PS_SUCCESS; 06020 } 06021 06022 GL2PSDLL_API GLint gl2psLineWidth(GLfloat value) 06023 { 06024 if(!gl2ps) return GL2PS_UNINITIALIZED; 06025 06026 glPassThrough(GL2PS_LINE_WIDTH_TOKEN); 06027 glPassThrough(value); 06028 06029 return GL2PS_SUCCESS; 06030 } 06031 06032 GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor) 06033 { 06034 if(!gl2ps) return GL2PS_UNINITIALIZED; 06035 06036 if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor)) 06037 return GL2PS_WARNING; 06038 06039 glPassThrough(GL2PS_SRC_BLEND_TOKEN); 06040 glPassThrough((GLfloat)sfactor); 06041 glPassThrough(GL2PS_DST_BLEND_TOKEN); 06042 glPassThrough((GLfloat)dfactor); 06043 06044 return GL2PS_SUCCESS; 06045 } 06046 06047 GL2PSDLL_API GLint gl2psSetOptions(GLint options) 06048 { 06049 if(!gl2ps) return GL2PS_UNINITIALIZED; 06050 06051 gl2ps->options = options; 06052 06053 return GL2PS_SUCCESS; 06054 } 06055 06056 GL2PSDLL_API GLint gl2psGetOptions(GLint *options) 06057 { 06058 if(!gl2ps) { 06059 *options = 0; 06060 return GL2PS_UNINITIALIZED; 06061 } 06062 06063 *options = gl2ps->options; 06064 06065 return GL2PS_SUCCESS; 06066 } 06067 06068 GL2PSDLL_API const char *gl2psGetFileExtension(GLint format) 06069 { 06070 if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) 06071 return gl2psbackends[format]->file_extension; 06072 else 06073 return "Unknown format"; 06074 } 06075 06076 GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format) 06077 { 06078 if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) 06079 return gl2psbackends[format]->description; 06080 else 06081 return "Unknown format"; 06082 }