Warning, /include/Geant4/tools/gl2ps is written in an unsupported language. File is not indexed.
0001 #ifndef tools_gl2ps
0002 #define tools_gl2ps
0003
0004 // This version of gl2ps-1.4.2 contains four main changes:
0005 // - it is pure header.
0006 // - the code had been "namespace protected" by changing :
0007 // gl2ps_<xxx> to tools_gl2ps_<xxx>
0008 // and :
0009 // GL2PS_<xxx> to TOOLS_GL2PS_<xxx>
0010 // - the code had been made thread safe by avoiding the internal writeable
0011 // static singleton gl2ps context object. With this version, you have to
0012 // create yourself a context, and pass it as first argument to all public
0013 // tools_gl2ps functions that you want to use with some code as:
0014 // ....
0015 // #include <tools/gl2ps>
0016 // ....
0017 // tools_GL2PScontext* gl2ps_context = tools_gl2psCreateContext();
0018 // ....
0019 // tools_gl2psBeginPage(gl2ps_context,...);
0020 // ...
0021 // tools_gl2psEndPage(gl2ps_context);
0022 // ....
0023 // tools_gl2psDeleteContext(gl2ps_context);
0024 // ....
0025 // - it does not call directly OpenGL functions
0026 // glIsEnabled,glBegin,glEnd,glGetFloatv,glVertex3f,glGetBooleanv,
0027 // glGetIntegerv,glRenderMode,glFeedbackBuffer,glPassThrough
0028 // but pointer to functions with the same signature. This permits to
0029 // use tools_gl2ps in a non OpenGL context, for example on primitives declared
0030 // by using tools_gl2psAddPolyPrimitive. If you want to use tools_gl2ps on primitives
0031 // got by using the OpenGL FEEDBACK mode (the "original way"), you have first
0032 // to declare the OpenGL upper functions on a tools_GL2PScontext with:
0033 // ....
0034 // #include <tools/gl2ps>
0035 // ....
0036 // #include <GL/gl.h>
0037 // ....
0038 // tools_GL2PScontext* gl2ps_context = tools_gl2psCreateContext();
0039 // ...
0040 // tools_gl2ps_gl_funcs_t _funcs = {
0041 // glIsEnabled,
0042 // glBegin,
0043 // glEnd,
0044 // glGetFloatv,
0045 // glVertex3f,
0046 // glGetBooleanv,
0047 // glGetIntegerv,
0048 // glRenderMode,
0049 // glFeedbackBuffer,
0050 // glPassThrough
0051 // };
0052 // tools_gl2ps_set_gl_funcs(gl2ps_context,&_funcs);
0053 // ...
0054 //
0055 // Guy Barrand. 15/March/2022
0056 //
0057
0058 /*
0059 * GL2PS, an OpenGL to PostScript Printing Library
0060 * Copyright (C) 1999-2020 C. Geuzaine
0061 *
0062 * This program is free software; you can redistribute it and/or
0063 * modify it under the terms of either:
0064 *
0065 * a) the GNU Library General Public License as published by the Free
0066 * Software Foundation, either version 2 of the License, or (at your
0067 * option) any later version; or
0068 *
0069 * b) the GL2PS License as published by Christophe Geuzaine, either
0070 * version 2 of the License, or (at your option) any later version.
0071 *
0072 * This program is distributed in the hope that it will be useful, but
0073 * WITHOUT ANY WARRANTY; without even the implied warranty of
0074 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either
0075 * the GNU Library General Public License or the GL2PS License for
0076 * more details.
0077 *
0078 * You should have received a copy of the GNU Library General Public
0079 * License along with this library in the file named "COPYING.LGPL";
0080 * if not, write to the Free Software Foundation, Inc., 51 Franklin
0081 * Street, Fifth Floor, Boston, MA 02110-1301, USA.
0082 *
0083 * You should have received a copy of the GL2PS License with this
0084 * library in the file named "COPYING.GL2PS"; if not, I will be glad
0085 * to provide one.
0086 *
0087 * For the latest info about gl2ps and a full list of contributors,
0088 * see http://www.geuz.org/gl2ps/.
0089 *
0090 * Please report all bugs and problems to <gl2ps@geuz.org>.
0091 */
0092
0093 #include "gl2ps_def.h"
0094
0095 #include <stdlib.h>
0096 #include <stdio.h>
0097
0098 #include <math.h>
0099 #include <string.h>
0100 #include <sys/types.h>
0101 #include <stdarg.h>
0102 #include <time.h>
0103 #include <float.h>
0104
0105 #if defined(TOOLS_GL2PS_HAVE_ZLIB)
0106 #include <zlib.h>
0107 #endif
0108
0109 #if defined(TOOLS_GL2PS_HAVE_LIBPNG)
0110 #include <png.h>
0111 #endif
0112
0113 /*********************************************************************
0114 *
0115 * Private definitions, data structures and prototypes
0116 *
0117 *********************************************************************/
0118
0119 /* Magic numbers (assuming that the order of magnitude of window
0120 coordinates is 10^3) */
0121
0122 #define TOOLS_GL2PS_EPSILON 5.0e-3F
0123 #define TOOLS_GL2PS_ZSCALE 1000.0F
0124 #define TOOLS_GL2PS_ZOFFSET 5.0e-2F
0125 #define TOOLS_GL2PS_ZOFFSET_LARGE 20.0F
0126 #define TOOLS_GL2PS_ZERO(arg) (fabs(arg) < 1.e-20)
0127
0128 /* BSP tree primitive comparison */
0129
0130 #define TOOLS_GL2PS_COINCIDENT 1
0131 #define TOOLS_GL2PS_IN_FRONT_OF 2
0132 #define TOOLS_GL2PS_IN_BACK_OF 3
0133 #define TOOLS_GL2PS_SPANNING 4
0134
0135 /* 2D BSP tree primitive comparison */
0136
0137 #define TOOLS_GL2PS_POINT_COINCIDENT 0
0138 #define TOOLS_GL2PS_POINT_INFRONT 1
0139 #define TOOLS_GL2PS_POINT_BACK 2
0140
0141 /* Internal feedback buffer pass-through tokens */
0142
0143 #define TOOLS_GL2PS_BEGIN_OFFSET_TOKEN 1
0144 #define TOOLS_GL2PS_END_OFFSET_TOKEN 2
0145 #define TOOLS_GL2PS_BEGIN_BOUNDARY_TOKEN 3
0146 #define TOOLS_GL2PS_END_BOUNDARY_TOKEN 4
0147 #define TOOLS_GL2PS_BEGIN_STIPPLE_TOKEN 5
0148 #define TOOLS_GL2PS_END_STIPPLE_TOKEN 6
0149 #define TOOLS_GL2PS_POINT_SIZE_TOKEN 7
0150 #define TOOLS_GL2PS_LINE_CAP_TOKEN 8
0151 #define TOOLS_GL2PS_LINE_JOIN_TOKEN 9
0152 #define TOOLS_GL2PS_LINE_WIDTH_TOKEN 10
0153 #define TOOLS_GL2PS_BEGIN_BLEND_TOKEN 11
0154 #define TOOLS_GL2PS_END_BLEND_TOKEN 12
0155 #define TOOLS_GL2PS_SRC_BLEND_TOKEN 13
0156 #define TOOLS_GL2PS_DST_BLEND_TOKEN 14
0157 #define TOOLS_GL2PS_IMAGEMAP_TOKEN 15
0158 #define TOOLS_GL2PS_DRAW_PIXELS_TOKEN 16
0159 #define TOOLS_GL2PS_TEXT_TOKEN 17
0160
0161 typedef enum {
0162 T_UNDEFINED = -1,
0163 T_CONST_COLOR = 1,
0164 T_VAR_COLOR = 1<<1,
0165 T_ALPHA_1 = 1<<2,
0166 T_ALPHA_LESS_1 = 1<<3,
0167 T_VAR_ALPHA = 1<<4
0168 } TOOLS_GL2PS_TRIANGLE_PROPERTY;
0169
0170 typedef tools_GLfloat tools_GL2PSplane[4];
0171
0172 typedef struct tools_GL2PSbsptree2d_ tools_GL2PSbsptree2d;
0173
0174 struct tools_GL2PSbsptree2d_ {
0175 tools_GL2PSplane plane;
0176 tools_GL2PSbsptree2d *front, *back;
0177 };
0178
0179 typedef struct {
0180 tools_GLint nmax, size, incr, n;
0181 char *array;
0182 } tools_GL2PSlist;
0183
0184 typedef struct tools_GL2PSbsptree_ tools_GL2PSbsptree;
0185
0186 struct tools_GL2PSbsptree_ {
0187 tools_GL2PSplane plane;
0188 tools_GL2PSlist *primitives;
0189 tools_GL2PSbsptree *front, *back;
0190 };
0191
0192 typedef struct {
0193 tools_GL2PSvertex vertex[3];
0194 int prop;
0195 } tools_GL2PStriangle;
0196
0197 typedef struct {
0198 tools_GLshort fontsize;
0199 char *str, *fontname;
0200 /* Note: for a 'special' string, 'alignment' holds the format
0201 (PostScript, PDF, etc.) of the special string */
0202 tools_GLint alignment;
0203 tools_GLfloat angle;
0204 } tools_GL2PSstring;
0205
0206 typedef struct {
0207 tools_GLsizei width, height;
0208 /* Note: for an imagemap, 'type' indicates if it has already been
0209 written to the file or not, and 'format' indicates if it is
0210 visible or not */
0211 tools_GLenum format, type;
0212 tools_GLfloat zoom_x, zoom_y;
0213 tools_GLfloat *pixels;
0214 } tools_GL2PSimage;
0215
0216 typedef struct tools_GL2PSimagemap_ tools_GL2PSimagemap;
0217
0218 struct tools_GL2PSimagemap_ {
0219 tools_GL2PSimage *image;
0220 tools_GL2PSimagemap *next;
0221 };
0222
0223 typedef struct {
0224 tools_GLshort type, numverts;
0225 tools_GLushort pattern;
0226 char boundary, offset, culled;
0227 tools_GLint factor, linecap, linejoin, sortid;
0228 tools_GLfloat width, ofactor, ounits;
0229 tools_GL2PSvertex *verts;
0230 union {
0231 tools_GL2PSstring *text;
0232 tools_GL2PSimage *image;
0233 } data;
0234 } tools_GL2PSprimitive;
0235
0236 typedef struct {
0237 #if defined(TOOLS_GL2PS_HAVE_ZLIB)
0238 Bytef *dest, *src, *start;
0239 uLongf destLen, srcLen;
0240 #else
0241 int dummy;
0242 #endif
0243 } tools_GL2PScompress;
0244
0245 typedef struct{
0246 tools_GL2PSlist* ptrlist;
0247 int gsno, fontno, imno, shno, maskshno, trgroupno;
0248 int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno;
0249 } tools_GL2PSpdfgroup;
0250
0251 typedef struct tools_GL2PScontextRec {
0252 /* General */
0253 tools_GLint format, sort, options, colorsize, colormode, buffersize;
0254 tools_GLint lastlinecap, lastlinejoin;
0255 char *title, *producer, *filename;
0256 tools_GLboolean boundary, blending;
0257 tools_GLfloat *feedback, lastlinewidth;
0258 tools_GLint viewport[4], blendfunc[2], lastfactor;
0259 tools_GL2PSrgba *colormap, lastrgba, threshold, bgcolor;
0260 tools_GLushort lastpattern;
0261 tools_GL2PSvertex lastvertex;
0262 tools_GL2PSlist *primitives, *auxprimitives;
0263 FILE *stream;
0264 tools_GL2PScompress *compress;
0265 tools_GLboolean header;
0266 tools_GL2PSvertex rasterpos;
0267 tools_GLboolean forcerasterpos;
0268
0269 /* BSP-specific */
0270 tools_GLint maxbestroot;
0271
0272 /* Occlusion culling-specific */
0273 tools_GLboolean zerosurfacearea;
0274 tools_GL2PSbsptree2d *imagetree;
0275 tools_GL2PSprimitive *primitivetoadd;
0276
0277 /* PDF-specific */
0278 int streamlength;
0279 tools_GL2PSlist *pdfprimlist, *pdfgrouplist;
0280 int *xreflist;
0281 int objects_stack; /* available objects */
0282 int extgs_stack; /* graphics state object number */
0283 int font_stack; /* font object number */
0284 int im_stack; /* image object number */
0285 int trgroupobjects_stack; /* xobject numbers */
0286 int shader_stack; /* shader object numbers */
0287 int mshader_stack; /* mask shader object numbers */
0288
0289 /* for image map list */
0290 tools_GL2PSimagemap *imagemap_head;
0291 tools_GL2PSimagemap *imagemap_tail;
0292
0293 /* for TEX scaling */
0294 tools_GLfloat tex_scaling;
0295
0296 /*G.Barrand : OpenGL functions:*/
0297 tools_gl2ps_gl_funcs_t m_gl_funcs;
0298 } tools_GL2PScontext;
0299
0300 typedef struct {
0301 void (*printHeader)(tools_GL2PScontext*);
0302 void (*printFooter)(tools_GL2PScontext*);
0303 void (*beginViewport)(tools_GL2PScontext*,tools_GLint viewport[4]);
0304 tools_GLint (*endViewport)(tools_GL2PScontext*);
0305 void (*printPrimitive)(tools_GL2PScontext*,void *data);
0306 void (*printFinalPrimitive)(tools_GL2PScontext*);
0307 const char *file_extension;
0308 const char *description;
0309 } tools_GL2PSbackend;
0310
0311 /* The gl2ps context. gl2ps is not thread safe (we should create a
0312 local GL2PScontext during tools_gl2psBeginPage) */
0313
0314 //static GL2PScontext *gl2ps = NULL;
0315
0316 /* Need to forward-declare this one */
0317
0318 inline tools_GLint tools_gl2psPrintPrimitives(tools_GL2PScontext*);
0319
0320 /*********************************************************************
0321 *
0322 * Utility routines
0323 *
0324 *********************************************************************/
0325
0326 inline void tools_gl2psMsg(tools_GLint level, const char *fmt, ...)
0327 {
0328 va_list args;
0329
0330 /*if(!(gl2ps->options & TOOLS_GL2PS_SILENT))*/{
0331 switch(level){
0332 case TOOLS_GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break;
0333 case TOOLS_GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break;
0334 case TOOLS_GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break;
0335 }
0336 va_start(args, fmt);
0337 vfprintf(stderr, fmt, args);
0338 va_end(args);
0339 fprintf(stderr, "\n");
0340 }
0341 /* if(level == TOOLS_GL2PS_ERROR) exit(1); */
0342 }
0343
0344 inline void *tools_gl2psMalloc(size_t size)
0345 {
0346 void *ptr;
0347
0348 if(!size) return NULL;
0349 ptr = malloc(size);
0350 if(!ptr){
0351 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Couldn't allocate requested memory");
0352 return NULL;
0353 }
0354 return ptr;
0355 }
0356
0357 inline void *tools_gl2psRealloc(void *ptr, size_t size)
0358 {
0359 void *orig = ptr;
0360 if(!size) return NULL;
0361 ptr = realloc(orig, size);
0362 if(!ptr){
0363 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Couldn't reallocate requested memory");
0364 free(orig);
0365 return NULL;
0366 }
0367 return ptr;
0368 }
0369
0370 inline void tools_gl2psFree(void *ptr)
0371 {
0372 if(!ptr) return;
0373 free(ptr);
0374 }
0375
0376 /*G.Barrand: begin*/
0377 inline tools_GLboolean tools_dummy_glIsEnabled (tools_GLenum) {return TOOLS_GL_FALSE;}
0378 inline void tools_dummy_glBegin (tools_GLenum) {
0379 /*printf("debug : tools_dummy_glBegin.\n");*/
0380 }
0381 inline void tools_dummy_glEnd () {}
0382 inline void tools_dummy_glGetFloatv (tools_GLenum,tools_GLfloat*) {}
0383 inline void tools_dummy_glVertex3f (tools_GLfloat,tools_GLfloat,tools_GLfloat) {}
0384 inline void tools_dummy_glGetBooleanv (tools_GLenum,tools_GLboolean*) {}
0385 inline void tools_dummy_glGetIntegerv (tools_GLenum,tools_GLint*) {}
0386 inline tools_GLint tools_dummy_glRenderMode (tools_GLenum) {
0387 /*printf("debug : tools_dummy_glRenderMode.\n");*/
0388 return 0;
0389 }
0390 inline void tools_dummy_glFeedbackBuffer (tools_GLsizei,tools_GLenum,tools_GLfloat*) {}
0391 inline void tools_dummy_glPassThrough (tools_GLfloat ) {}
0392
0393 inline tools_GL2PScontext* tools_gl2psCreateContext(void) {
0394 tools_GL2PScontext* gl2ps = (tools_GL2PScontext*)tools_gl2psMalloc(sizeof(tools_GL2PScontext));
0395 if(!gl2ps) return 0;
0396
0397 gl2ps->format = 0;
0398 gl2ps->sort = 0;
0399 gl2ps->options = 0;
0400 gl2ps->colorsize = 0;
0401 gl2ps->colormode = 0;
0402 gl2ps->buffersize = 0;
0403 gl2ps->lastlinecap = 0;
0404 gl2ps->lastlinejoin = 0;
0405 gl2ps->title = NULL;
0406 gl2ps->producer = NULL;
0407 gl2ps->filename = NULL;
0408 gl2ps->boundary = TOOLS_GL_FALSE;
0409 gl2ps->blending = TOOLS_GL_FALSE;
0410 gl2ps->feedback = NULL;
0411 gl2ps->lastlinewidth = 0;
0412 gl2ps->viewport[0] = 0;
0413 gl2ps->viewport[1] = 0;
0414 gl2ps->viewport[2] = 0;
0415 gl2ps->viewport[3] = 0;
0416
0417 gl2ps->blendfunc[0] = 0;
0418 gl2ps->blendfunc[1] = 0;
0419
0420 gl2ps->lastfactor = 0;
0421 gl2ps->colormap = NULL;
0422 gl2ps->lastrgba[0] = 0;
0423 gl2ps->lastrgba[1] = 0;
0424 gl2ps->lastrgba[2] = 0;
0425 gl2ps->lastrgba[3] = 0;
0426 gl2ps->threshold[0] = 0;
0427 gl2ps->threshold[1] = 0;
0428 gl2ps->threshold[2] = 0;
0429 gl2ps->threshold[3] = 0;
0430 gl2ps->bgcolor[0] = 0;
0431 gl2ps->bgcolor[1] = 0;
0432 gl2ps->bgcolor[2] = 0;
0433 gl2ps->bgcolor[3] = 0;
0434
0435 gl2ps->lastpattern = 0;
0436 gl2ps->lastvertex.xyz[0] = 0;
0437 gl2ps->lastvertex.xyz[1] = 0;
0438 gl2ps->lastvertex.xyz[2] = 0;
0439 gl2ps->lastvertex.rgba[0] = 0;
0440 gl2ps->lastvertex.rgba[1] = 0;
0441 gl2ps->lastvertex.rgba[2] = 0;
0442 gl2ps->lastvertex.rgba[3] = 0;
0443
0444 gl2ps->primitives = NULL;
0445 gl2ps->auxprimitives = NULL;
0446 gl2ps->stream = NULL;
0447 gl2ps->compress = NULL;
0448 gl2ps->header = TOOLS_GL_FALSE;
0449 gl2ps->rasterpos.xyz[0] = 0;
0450 gl2ps->rasterpos.xyz[1] = 0;
0451 gl2ps->rasterpos.xyz[2] = 0;
0452 gl2ps->rasterpos.rgba[0] = 0;
0453 gl2ps->rasterpos.rgba[1] = 0;
0454 gl2ps->rasterpos.rgba[2] = 0;
0455 gl2ps->rasterpos.rgba[3] = 0;
0456
0457 gl2ps->forcerasterpos = TOOLS_GL_FALSE;
0458 gl2ps->maxbestroot = 0;
0459 gl2ps->zerosurfacearea = TOOLS_GL_FALSE;
0460 gl2ps->imagetree = NULL;
0461 gl2ps->primitivetoadd = NULL;
0462
0463 gl2ps->streamlength = 0;
0464 gl2ps->pdfprimlist = NULL;
0465 gl2ps->pdfgrouplist = NULL;
0466 gl2ps->xreflist = NULL;
0467
0468 gl2ps->objects_stack = 0;
0469 gl2ps->extgs_stack = 0;
0470 gl2ps->font_stack = 0;
0471 gl2ps->im_stack = 0;
0472 gl2ps->trgroupobjects_stack = 0;
0473 gl2ps->shader_stack = 0;
0474 gl2ps->mshader_stack = 0;
0475 gl2ps->imagemap_head = NULL;
0476 gl2ps->imagemap_tail = NULL;
0477
0478 gl2ps->m_gl_funcs.m_glIsEnabled = tools_dummy_glIsEnabled;
0479 gl2ps->m_gl_funcs.m_glBegin = tools_dummy_glBegin;
0480 gl2ps->m_gl_funcs.m_glEnd = tools_dummy_glEnd;
0481 gl2ps->m_gl_funcs.m_glGetFloatv = tools_dummy_glGetFloatv;
0482 gl2ps->m_gl_funcs.m_glVertex3f = tools_dummy_glVertex3f;
0483 gl2ps->m_gl_funcs.m_glGetBooleanv = tools_dummy_glGetBooleanv;
0484 gl2ps->m_gl_funcs.m_glGetIntegerv = tools_dummy_glGetIntegerv;
0485 gl2ps->m_gl_funcs.m_glRenderMode = tools_dummy_glRenderMode;
0486 gl2ps->m_gl_funcs.m_glFeedbackBuffer = tools_dummy_glFeedbackBuffer;
0487 gl2ps->m_gl_funcs.m_glPassThrough = tools_dummy_glPassThrough;
0488
0489 return gl2ps;
0490 }
0491 inline void tools_gl2psDeleteContext(tools_GL2PScontext* a_context) {
0492 tools_gl2psFree(a_context);
0493 }
0494
0495 inline void tools_gl2ps_set_gl_funcs(tools_GL2PScontext* gl2ps, tools_gl2ps_gl_funcs_t* a_funcs) {
0496 gl2ps->m_gl_funcs.m_glIsEnabled = a_funcs->m_glIsEnabled;
0497 gl2ps->m_gl_funcs.m_glBegin = a_funcs->m_glBegin;
0498 gl2ps->m_gl_funcs.m_glEnd = a_funcs->m_glEnd;
0499 gl2ps->m_gl_funcs.m_glGetFloatv = a_funcs->m_glGetFloatv;
0500 gl2ps->m_gl_funcs.m_glVertex3f = a_funcs->m_glVertex3f;
0501 gl2ps->m_gl_funcs.m_glGetBooleanv = a_funcs->m_glGetBooleanv;
0502 gl2ps->m_gl_funcs.m_glGetIntegerv = a_funcs->m_glGetIntegerv;
0503 gl2ps->m_gl_funcs.m_glRenderMode = a_funcs->m_glRenderMode;
0504 gl2ps->m_gl_funcs.m_glFeedbackBuffer = a_funcs->m_glFeedbackBuffer;
0505 gl2ps->m_gl_funcs.m_glPassThrough = a_funcs->m_glPassThrough;
0506 }
0507
0508 inline void tools_gl2ps_reset_gl_funcs(tools_GL2PScontext* gl2ps) {
0509 gl2ps->m_gl_funcs.m_glIsEnabled = tools_dummy_glIsEnabled;
0510 gl2ps->m_gl_funcs.m_glBegin = tools_dummy_glBegin;
0511 gl2ps->m_gl_funcs.m_glEnd = tools_dummy_glEnd;
0512 gl2ps->m_gl_funcs.m_glGetFloatv = tools_dummy_glGetFloatv;
0513 gl2ps->m_gl_funcs.m_glVertex3f = tools_dummy_glVertex3f;
0514 gl2ps->m_gl_funcs.m_glGetBooleanv = tools_dummy_glGetBooleanv;
0515 gl2ps->m_gl_funcs.m_glGetIntegerv = tools_dummy_glGetIntegerv;
0516 gl2ps->m_gl_funcs.m_glRenderMode = tools_dummy_glRenderMode;
0517 gl2ps->m_gl_funcs.m_glFeedbackBuffer = tools_dummy_glFeedbackBuffer;
0518 gl2ps->m_gl_funcs.m_glPassThrough = tools_dummy_glPassThrough;
0519 }
0520
0521 #define tools_glIsEnabled gl2ps->m_gl_funcs.m_glIsEnabled
0522 #define tools_glBegin gl2ps->m_gl_funcs.m_glBegin
0523 #define tools_glEnd gl2ps->m_gl_funcs.m_glEnd
0524 #define tools_glGetFloatv gl2ps->m_gl_funcs.m_glGetFloatv
0525 #define tools_glVertex3f gl2ps->m_gl_funcs.m_glVertex3f
0526 #define tools_glGetBooleanv gl2ps->m_gl_funcs.m_glGetBooleanv
0527 #define tools_glGetIntegerv gl2ps->m_gl_funcs.m_glGetIntegerv
0528 #define tools_glRenderMode gl2ps->m_gl_funcs.m_glRenderMode
0529 #define tools_glFeedbackBuffer gl2ps->m_gl_funcs.m_glFeedbackBuffer
0530 #define tools_glPassThrough gl2ps->m_gl_funcs.m_glPassThrough
0531
0532 /*G.Barrand: end*/
0533
0534 inline int tools_gl2psWriteBigEndian(tools_GL2PScontext* gl2ps, unsigned long data, int bytes)
0535 {
0536 int i;
0537 int size = sizeof(unsigned long);
0538 for(i = 1; i <= bytes; ++i){
0539 fputc(0xff & (data >> (size - i) * 8), gl2ps->stream);
0540 }
0541 return bytes;
0542 }
0543
0544 /* zlib compression helper routines */
0545
0546 #if defined(TOOLS_GL2PS_HAVE_ZLIB)
0547
0548 inline void tools_gl2psSetupCompress(tools_GL2PScontext* gl2ps)
0549 {
0550 gl2ps->compress = (tools_GL2PScompress*)tools_gl2psMalloc(sizeof(tools_GL2PScompress));
0551 gl2ps->compress->src = NULL;
0552 gl2ps->compress->start = NULL;
0553 gl2ps->compress->dest = NULL;
0554 gl2ps->compress->srcLen = 0;
0555 gl2ps->compress->destLen = 0;
0556 }
0557
0558 inline void tools_gl2psFreeCompress(tools_GL2PScontext* gl2ps)
0559 {
0560 if(!gl2ps->compress)
0561 return;
0562 tools_gl2psFree(gl2ps->compress->start);
0563 tools_gl2psFree(gl2ps->compress->dest);
0564 gl2ps->compress->src = NULL;
0565 gl2ps->compress->start = NULL;
0566 gl2ps->compress->dest = NULL;
0567 gl2ps->compress->srcLen = 0;
0568 gl2ps->compress->destLen = 0;
0569 }
0570
0571 inline int tools_gl2psAllocCompress(tools_GL2PScontext* gl2ps, unsigned int srcsize)
0572 {
0573 tools_gl2psFreeCompress(gl2ps);
0574
0575 if(!gl2ps->compress || !srcsize)
0576 return TOOLS_GL2PS_ERROR;
0577
0578 gl2ps->compress->srcLen = srcsize;
0579 gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
0580 gl2ps->compress->src = (Bytef*)tools_gl2psMalloc(gl2ps->compress->srcLen);
0581 gl2ps->compress->start = gl2ps->compress->src;
0582 gl2ps->compress->dest = (Bytef*)tools_gl2psMalloc(gl2ps->compress->destLen);
0583
0584 return TOOLS_GL2PS_SUCCESS;
0585 }
0586
0587 inline void *tools_gl2psReallocCompress(tools_GL2PScontext* gl2ps, unsigned int srcsize)
0588 {
0589 if(!gl2ps->compress || !srcsize)
0590 return NULL;
0591
0592 if(srcsize < gl2ps->compress->srcLen)
0593 return gl2ps->compress->start;
0594
0595 gl2ps->compress->srcLen = srcsize;
0596 gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12);
0597 gl2ps->compress->src = (Bytef*)tools_gl2psRealloc(gl2ps->compress->src,
0598 gl2ps->compress->srcLen);
0599 gl2ps->compress->start = gl2ps->compress->src;
0600 gl2ps->compress->dest = (Bytef*)tools_gl2psRealloc(gl2ps->compress->dest,
0601 gl2ps->compress->destLen);
0602
0603 return gl2ps->compress->start;
0604 }
0605
0606 inline int tools_gl2psWriteBigEndianCompress(tools_GL2PScontext* gl2ps, unsigned long data, int bytes)
0607 {
0608 int i;
0609 int size = sizeof(unsigned long);
0610 for(i = 1; i <= bytes; ++i){
0611 *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8));
0612 ++gl2ps->compress->src;
0613 }
0614 return bytes;
0615 }
0616
0617 inline int tools_gl2psDeflate(tools_GL2PScontext* gl2ps)
0618 {
0619 /* For compatibility with older zlib versions, we use compress(...)
0620 instead of compress2(..., Z_BEST_COMPRESSION) */
0621 return compress(gl2ps->compress->dest, &gl2ps->compress->destLen,
0622 gl2ps->compress->start, gl2ps->compress->srcLen);
0623 }
0624
0625 #endif
0626
0627 inline int tools_gl2psPrintf(tools_GL2PScontext* gl2ps, const char* fmt, ...)
0628 {
0629 int ret;
0630 va_list args;
0631
0632 #if defined(TOOLS_GL2PS_HAVE_ZLIB)
0633 //static char buf[1024]; //G.Barrand: avoid this writeable static.
0634 //char *bufptr = buf;
0635 //tools_GLboolean freebuf = TOOLS_GL_FALSE;
0636 char* bufptr = (char *)tools_gl2psMalloc(1024);
0637 tools_GLboolean freebuf = TOOLS_GL_TRUE;
0638 unsigned int oldsize = 0;
0639 #if !defined(TOOLS_GL2PS_HAVE_NO_VSNPRINTF)
0640 /* Try writing the string to a 1024 byte buffer. If it is too small to fit,
0641 keep trying larger sizes until it does. */
0642 //int bufsize = sizeof(buf);
0643 int bufsize = 1024;
0644 #endif
0645 if(gl2ps->options & TOOLS_GL2PS_COMPRESS){
0646 va_start(args, fmt);
0647 #if defined(TOOLS_GL2PS_HAVE_NO_VSNPRINTF)
0648 ret = vsprintf(buf, fmt, args);
0649 #else
0650 ret = vsnprintf(bufptr, bufsize, fmt, args);
0651 #endif
0652 va_end(args);
0653 #if !defined(TOOLS_GL2PS_HAVE_NO_VSNPRINTF)
0654 while(ret >= (bufsize - 1) || ret < 0){
0655 /* Too big. Allocate a new buffer. */
0656 bufsize *= 2;
0657 if(freebuf == TOOLS_GL_TRUE) tools_gl2psFree(bufptr);
0658 bufptr = (char *)tools_gl2psMalloc(bufsize);
0659 freebuf = TOOLS_GL_TRUE;
0660 va_start(args, fmt);
0661 ret = vsnprintf(bufptr, bufsize, fmt, args);
0662 va_end(args);
0663 }
0664 #endif
0665 oldsize = gl2ps->compress->srcLen;
0666 gl2ps->compress->start = (Bytef*)tools_gl2psReallocCompress(gl2ps, oldsize + ret);
0667 memcpy(gl2ps->compress->start + oldsize, bufptr, ret);
0668 if(freebuf == TOOLS_GL_TRUE) tools_gl2psFree(bufptr);
0669 ret = 0;
0670 }
0671 else{
0672 #endif
0673 va_start(args, fmt);
0674 ret = vfprintf(gl2ps->stream, fmt, args);
0675 va_end(args);
0676 #if defined(TOOLS_GL2PS_HAVE_ZLIB)
0677 }
0678 #endif
0679 return ret;
0680 }
0681
0682 inline void tools_gl2psPrintGzipHeader(tools_GL2PScontext* gl2ps)
0683 {
0684 #if defined(TOOLS_GL2PS_HAVE_ZLIB)
0685 char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */
0686 8, /* compression method: Z_DEFLATED */
0687 0, /* flags */
0688 0, 0, 0, 0, /* time */
0689 2, /* extra flags: max compression */
0690 '\x03'}; /* OS code: 0x03 (Unix) */
0691
0692 if(gl2ps->options & TOOLS_GL2PS_COMPRESS){
0693 tools_gl2psSetupCompress(gl2ps);
0694 /* add the gzip file header */
0695 fwrite(tmp, 10, 1, gl2ps->stream);
0696 }
0697 #endif
0698 (void)gl2ps;
0699 }
0700
0701 inline void tools_gl2psPrintGzipFooter(tools_GL2PScontext* gl2ps)
0702 {
0703 #if defined(TOOLS_GL2PS_HAVE_ZLIB)
0704 int n;
0705 uLong crc, len;
0706 char tmp[8];
0707
0708 if(gl2ps->options & TOOLS_GL2PS_COMPRESS){
0709 if(Z_OK != tools_gl2psDeflate(gl2ps)){
0710 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Zlib deflate error");
0711 }
0712 else{
0713 /* determine the length of the header in the zlib stream */
0714 n = 2; /* CMF+FLG */
0715 if(gl2ps->compress->dest[1] & (1<<5)){
0716 n += 4; /* DICTID */
0717 }
0718 /* write the data, without the zlib header and footer */
0719 fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4),
0720 1, gl2ps->stream);
0721 /* add the gzip file footer */
0722 crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen);
0723 for(n = 0; n < 4; ++n){
0724 tmp[n] = (char)(crc & 0xff);
0725 crc >>= 8;
0726 }
0727 len = gl2ps->compress->srcLen;
0728 for(n = 4; n < 8; ++n){
0729 tmp[n] = (char)(len & 0xff);
0730 len >>= 8;
0731 }
0732 fwrite(tmp, 8, 1, gl2ps->stream);
0733 }
0734 tools_gl2psFreeCompress(gl2ps);
0735 tools_gl2psFree(gl2ps->compress);
0736 gl2ps->compress = NULL;
0737 }
0738 #endif
0739 (void)gl2ps;
0740 }
0741
0742 /* The list handling routines */
0743
0744 inline void tools_gl2psListRealloc(tools_GL2PSlist *list, tools_GLint n)
0745 {
0746 if(!list){
0747 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Cannot reallocate NULL list");
0748 return;
0749 }
0750 if(n <= 0) return;
0751 if(!list->array){
0752 list->nmax = n;
0753 list->array = (char*)tools_gl2psMalloc(list->nmax * list->size);
0754 }
0755 else{
0756 if(n > list->nmax){
0757 list->nmax = ((n - 1) / list->incr + 1) * list->incr;
0758 list->array = (char*)tools_gl2psRealloc(list->array,
0759 list->nmax * list->size);
0760 }
0761 }
0762 }
0763
0764 inline tools_GL2PSlist *tools_gl2psListCreate(tools_GLint n, tools_GLint incr, tools_GLint size)
0765 {
0766 tools_GL2PSlist *list;
0767
0768 if(n < 0) n = 0;
0769 if(incr <= 0) incr = 1;
0770 list = (tools_GL2PSlist*)tools_gl2psMalloc(sizeof(tools_GL2PSlist));
0771 list->nmax = 0;
0772 list->incr = incr;
0773 list->size = size;
0774 list->n = 0;
0775 list->array = NULL;
0776 tools_gl2psListRealloc(list, n);
0777 return list;
0778 }
0779
0780 inline void tools_gl2psListReset(tools_GL2PSlist *list)
0781 {
0782 if(!list) return;
0783 list->n = 0;
0784 }
0785
0786 inline void tools_gl2psListDelete(tools_GL2PSlist *list)
0787 {
0788 if(!list) return;
0789 tools_gl2psFree(list->array);
0790 tools_gl2psFree(list);
0791 }
0792
0793 inline void tools_gl2psListAdd(tools_GL2PSlist *list, void *data)
0794 {
0795 if(!list){
0796 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Cannot add into unallocated list");
0797 return;
0798 }
0799 list->n++;
0800 tools_gl2psListRealloc(list, list->n);
0801 memcpy(&list->array[(list->n - 1) * list->size], data, list->size);
0802 }
0803
0804 inline int tools_gl2psListNbr(tools_GL2PSlist *list)
0805 {
0806 if(!list)
0807 return 0;
0808 return list->n;
0809 }
0810
0811 inline void *tools_gl2psListPointer(tools_GL2PSlist *list, tools_GLint idx)
0812 {
0813 if(!list){
0814 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Cannot point into unallocated list");
0815 return NULL;
0816 }
0817 if((idx < 0) || (idx >= list->n)){
0818 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Wrong list index in tools_gl2psListPointer");
0819 return NULL;
0820 }
0821 return &list->array[idx * list->size];
0822 }
0823
0824 //G.Barrand: begin:
0825 inline bool tools_gl2psPortableSort(void* a_items,size_t a_nitem,size_t a_item_size,int(*a_cmp)(const void*,const void*)) {
0826 // We observed that qsort on macOS/clang, Linux/gcc, Windows/VisualC++
0827 // does not produce the same output list for objects considered as "the same".
0828 // "Same objects" are put correctly contiguously but not in the same order
0829 // according the platform. In case of gl2ps, if using qsort we have, at end,
0830 // primitives in the output file which are not in the same order according the platform.
0831 // Then, we let the possibility to use a portable sort algorithm that will
0832 // give the same sorted list, and then the same output file, on all platforms.
0833 if(a_nitem<=1) return true;
0834 if(!a_item_size) return true;
0835 void* tmp = ::malloc(a_item_size);
0836 if(!tmp) return false;
0837 char* p = (char*)a_items;
0838 size_t i,j;
0839 char* a = p;char* b;
0840 for(i=0;i<a_nitem;i++,a+=a_item_size) {
0841 b = p+a_item_size*(i+1);
0842 for(j=i+1;j<a_nitem;j++,b+=a_item_size) {
0843 if(a_cmp(b,a)>=0) continue; //b>=a
0844 ::memcpy(tmp,a,a_item_size);
0845 ::memcpy(a,b,a_item_size);
0846 ::memcpy(b,tmp,a_item_size);
0847 }
0848 }
0849 ::free(tmp);
0850 return true;
0851 }
0852 //G.Barrand: end.
0853
0854 inline void tools_gl2psListSort(tools_GL2PScontext* gl2ps,
0855 tools_GL2PSlist *list,
0856 int (*fcmp)(const void *a, const void *b))
0857 {
0858 if(!list) return;
0859 if(gl2ps->options & TOOLS_GL2PS_PORTABLE_SORT) {
0860 tools_gl2psPortableSort(list->array, list->n, list->size, fcmp);
0861 } else {
0862 ::qsort(list->array, list->n, list->size, fcmp);
0863 }
0864 }
0865
0866 /* Must be a list of tools_GL2PSprimitives. */
0867 inline void tools_gl2psListAssignSortIds(tools_GL2PSlist *list)
0868 {
0869 tools_GLint i;
0870 for(i = 0; i < tools_gl2psListNbr(list); i++){
0871 (*(tools_GL2PSprimitive**)tools_gl2psListPointer(list, i))->sortid = i;
0872 }
0873 }
0874
0875 inline void tools_gl2psListAction(tools_GL2PSlist *list, void (*action)(void *data))
0876 {
0877 tools_GLint i;
0878
0879 for(i = 0; i < tools_gl2psListNbr(list); i++){
0880 (*action)(tools_gl2psListPointer(list, i));
0881 }
0882 }
0883
0884 inline void tools_gl2psListActionInverse(tools_GL2PSlist *list, void (*action)(void *data))
0885 {
0886 tools_GLint i;
0887
0888 for(i = tools_gl2psListNbr(list); i > 0; i--){
0889 (*action)(tools_gl2psListPointer(list, i-1));
0890 }
0891 }
0892
0893 inline void tools_gl2psListActionContext(tools_GL2PScontext* gl2ps, tools_GL2PSlist *list, void (*action)(tools_GL2PScontext*, void *data))
0894 {
0895 tools_GLint i;
0896
0897 for(i = 0; i < tools_gl2psListNbr(list); i++){
0898 (*action)(gl2ps, tools_gl2psListPointer(list, i));
0899 }
0900 }
0901
0902 inline void tools_gl2psListActionInverseContext(tools_GL2PScontext* gl2ps, tools_GL2PSlist *list, void (*action)(tools_GL2PScontext*, void *data))
0903 {
0904 tools_GLint i;
0905
0906 for(i = tools_gl2psListNbr(list); i > 0; i--){
0907 (*action)(gl2ps, tools_gl2psListPointer(list, i-1));
0908 }
0909 }
0910
0911 #if defined(TOOLS_GL2PS_HAVE_LIBPNG)
0912
0913 inline void tools_gl2psListRead(tools_GL2PSlist *list, int index, void *data)
0914 {
0915 if((index < 0) || (index >= list->n))
0916 tools_gl2psMsg(TOOLS_GL2PS_ERROR, "Wrong list index in tools_gl2psListRead");
0917 memcpy(data, &list->array[index * list->size], list->size);
0918 }
0919
0920 inline void tools_gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len)
0921 {
0922 static const char cb64[] =
0923 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
0924
0925 out[0] = cb64[ in[0] >> 2 ];
0926 out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
0927 out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=';
0928 out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '=';
0929 }
0930
0931 inline void tools_gl2psListEncodeBase64(tools_GL2PSlist *list)
0932 {
0933 unsigned char *buffer, in[3], out[4];
0934 int i, n, index, len;
0935
0936 n = list->n * list->size;
0937 buffer = (unsigned char*)tools_gl2psMalloc(n * sizeof(unsigned char));
0938 memcpy(buffer, list->array, n * sizeof(unsigned char));
0939 tools_gl2psListReset(list);
0940
0941 index = 0;
0942 while(index < n) {
0943 len = 0;
0944 for(i = 0; i < 3; i++) {
0945 if(index < n){
0946 in[i] = buffer[index];
0947 len++;
0948 }
0949 else{
0950 in[i] = 0;
0951 }
0952 index++;
0953 }
0954 if(len) {
0955 tools_gl2psEncodeBase64Block(in, out, len);
0956 for(i = 0; i < 4; i++)
0957 tools_gl2psListAdd(list, &out[i]);
0958 }
0959 }
0960 tools_gl2psFree(buffer);
0961 }
0962
0963 #endif
0964
0965 /* Helpers for rgba colors */
0966
0967 inline tools_GLboolean tools_gl2psSameColor(tools_GL2PSrgba rgba1, tools_GL2PSrgba rgba2)
0968 {
0969 if(!TOOLS_GL2PS_ZERO(rgba1[0] - rgba2[0]) ||
0970 !TOOLS_GL2PS_ZERO(rgba1[1] - rgba2[1]) ||
0971 !TOOLS_GL2PS_ZERO(rgba1[2] - rgba2[2]))
0972 return TOOLS_GL_FALSE;
0973 return TOOLS_GL_TRUE;
0974 }
0975
0976 inline tools_GLboolean tools_gl2psVertsSameColor(const tools_GL2PSprimitive *prim)
0977 {
0978 int i;
0979
0980 for(i = 1; i < prim->numverts; i++){
0981 if(!tools_gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){
0982 return TOOLS_GL_FALSE;
0983 }
0984 }
0985 return TOOLS_GL_TRUE;
0986 }
0987
0988 inline tools_GLboolean tools_gl2psSameColorThreshold(int n, tools_GL2PSrgba rgba[],
0989 tools_GL2PSrgba threshold)
0990 {
0991 int i;
0992
0993 if(n < 2) return TOOLS_GL_TRUE;
0994
0995 for(i = 1; i < n; i++){
0996 if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] ||
0997 fabs(rgba[0][1] - rgba[i][1]) > threshold[1] ||
0998 fabs(rgba[0][2] - rgba[i][2]) > threshold[2])
0999 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*/