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