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