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