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