From ef11b5ccb56cbe925e09ee7ed621b601dc25b137 Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Sun, 9 May 2004 19:00:11 +0000 Subject: [PATCH] upgrade gl2ps to 1.2.0 --- Graphics/CreateFile.cpp | 4 +- Graphics/gl2ps.cpp | 2528 +++++++++++++++++++++++++++------------ Graphics/gl2ps.h | 210 +--- 3 files changed, 1819 insertions(+), 923 deletions(-) diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp index d2ae3bee0f..7e4e5915fd 100644 --- a/Graphics/CreateFile.cpp +++ b/Graphics/CreateFile.cpp @@ -1,4 +1,4 @@ -// $Id: CreateFile.cpp,v 1.58 2004-05-08 00:19:47 geuzaine Exp $ +// $Id: CreateFile.cpp,v 1.59 2004-05-09 19:00:11 geuzaine Exp $ // // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle // @@ -254,7 +254,7 @@ void CreateOutputFile(char *name, int format) pssort = (CTX.print.eps_quality == 1) ? GL2PS_SIMPLE_SORT : GL2PS_BSP_SORT; psoptions = - GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | + GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | GL2PS_NO_BLENDING | (CTX.print.eps_occlusion_culling ? GL2PS_OCCLUSION_CULL : 0) | (CTX.print.eps_best_root ? GL2PS_BEST_ROOT : 0) | (CTX.print.eps_background ? GL2PS_DRAW_BACKGROUND : 0) | diff --git a/Graphics/gl2ps.cpp b/Graphics/gl2ps.cpp index e2462147d0..113e9dc4d6 100644 --- a/Graphics/gl2ps.cpp +++ b/Graphics/gl2ps.cpp @@ -1,7 +1,7 @@ -/* $Id: gl2ps.cpp,v 1.84 2004-03-05 23:47:35 geuzaine Exp $ */ +/* $Id: gl2ps.cpp,v 1.85 2004-05-09 19:00:11 geuzaine Exp $ */ /* * GL2PS, an OpenGL to PostScript Printing Library - * Copyright (C) 1999-2003 Christophe Geuzaine <geuz@geuz.org> + * Copyright (C) 1999-2004 Christophe Geuzaine <geuz@geuz.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of either: @@ -31,9 +31,9 @@ * Contributors: * Michael Sweet <mike@easysw.com> * Marc Ume <marc.ume@digitalgraphics.be> - * Jean-Francois Remacle <remacle@scorec.rpi.edu> + * Jean-Francois Remacle <remacle@gce.ucl.ac.be> * Bart Kaptein <B.L.Kaptein@lumc.nl> - * Quy Nguyen-Dai<quy@vnilux.com> + * Quy Nguyen-Dai <quy@nguyendai.org> * Sam Buss <sbuss@ucsd.edu> * Shane Hill <Shane.Hill@dsto.defence.gov.au> * Romain Boman <r_boman@yahoo.fr> @@ -56,10 +56,165 @@ #include <float.h> #include "gl2ps.h" +/********************************************************************* + * + * Private definitions, data structures and prototypes + * + *********************************************************************/ + +/* Magic numbers */ + +#define GL2PS_EPSILON 5.0e-3F +#define GL2PS_DEPTH_FACT 1000.0F +#define GL2PS_SIMPLE_OFFSET 0.05F +#define GL2PS_SIMPLE_OFFSET_LARGE 1.0F +#define GL2PS_ZERO(arg) (fabs(arg)<1.e-20) +#define GL2PS_FIXED_XREF_ENTRIES 7 + +/* Primitive types */ + +#define GL2PS_NOTYPE -1 +#define GL2PS_TEXT 1 +#define GL2PS_POINT 2 +#define GL2PS_LINE 3 +#define GL2PS_QUADRANGLE 4 +#define GL2PS_TRIANGLE 5 +#define GL2PS_PIXMAP 6 + +/* BSP tree primitive comparison */ + +#define GL2PS_COINCIDENT 1 +#define GL2PS_IN_FRONT_OF 2 +#define GL2PS_IN_BACK_OF 3 +#define GL2PS_SPANNING 4 + +/* 2D BSP tree primitive comparison */ + +#define GL2PS_POINT_COINCIDENT 0 +#define GL2PS_POINT_INFRONT 1 +#define GL2PS_POINT_BACK 2 + +typedef enum { + T_UNDEFINED = -1, + T_CONST_COLOR = 1, + T_VAR_COLOR = 1<<1, + T_ALPHA_1 = 1<<2, + T_ALPHA_LESS_1 = 1<<3, + T_VAR_ALPHA = 1<<4 +} GL2PS_TRIANGLE_PROPERTY; + +typedef GLfloat GL2PSxyz[3]; +typedef GLfloat GL2PSplane[4]; + +typedef struct _GL2PSbsptree2d GL2PSbsptree2d; + +struct _GL2PSbsptree2d { + GL2PSplane plane; + GL2PSbsptree2d *front, *back; +}; + +typedef struct { + GLint nmax, size, incr, n; + char *array; +} GL2PSlist; + +typedef struct _GL2PSbsptree GL2PSbsptree; + +struct _GL2PSbsptree { + GL2PSplane plane; + GL2PSlist *primitives; + GL2PSbsptree *front, *back; +}; + +typedef struct { + GL2PSxyz xyz; + GL2PSrgba rgba; +} GL2PSvertex; + +typedef struct { + GL2PSvertex vertex[3]; + int prop; +} GL2PStriangle; + +typedef struct { + GLshort fontsize; + char *str, *fontname; + GLint alignment; +} GL2PSstring; + +typedef struct { + GLsizei width, height; + GLenum format, type; + GLfloat *pixels; +} GL2PSimage; + +typedef struct { + GLshort type, numverts; + char boundary, dash, culled; + GLfloat width, depth; + GL2PSvertex *verts; + union { + GL2PSstring *text; + GL2PSimage *image; + } data; +} GL2PSprimitive; + +typedef struct { +#ifdef GL2PS_HAVE_ZLIB + Bytef *dest, *src, *start; + uLongf destLen, srcLen; +#else + int dummy; +#endif +} GL2PScompress; + +typedef struct{ + GL2PSlist* ptrlist; + int gsno, fontno, imno, shno, maskshno, trgroupno; + int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno; +} GL2PSpdfgroup; + +typedef struct { + /* General */ + GLint format, sort, options, colorsize, colormode, buffersize; + char *title, *producer, *filename; + GLboolean boundary, blending; + GLfloat *feedback, offset[2], lastlinewidth; + GLint viewport[4], blendfunc[2]; + GL2PSrgba *colormap, lastrgba, threshold; + GL2PSlist *primitives; + FILE *stream; + GL2PScompress *compress; + + /* BSP-specific */ + GLint maxbestroot; + + /* Occlusion culling-specific */ + GLboolean zerosurfacearea; + GL2PSbsptree2d *imagetree; + GL2PSprimitive *primitivetoadd; + + /* PDF-specific */ + int streamlength; + GL2PSlist *pdfprimlist, *pdfgrouplist; + int *xreflist; + int objects_stack; /* available objects */ + int extgs_stack; /* graphics state object number */ + int font_stack; /* font object number */ + int im_stack; /* image object number */ + int trgroupobjects_stack; /* xobject numbers */ + int shader_stack; /* shader object numbers */ + int mshader_stack; /* mask shader object numbers */ +} GL2PScontext; + /* The gl2ps context. gl2ps is not thread safe (we should create a local GL2PScontext during gl2psBeginPage) */ -GL2PScontext *gl2ps = NULL; +static GL2PScontext *gl2ps = NULL; + +/* Need to forward declare this one */ + +static GLint gl2psPrintPrimitives(void); /********************************************************************* * @@ -67,7 +222,8 @@ GL2PScontext *gl2ps = NULL; * *********************************************************************/ -void gl2psMsg(GLint level, char *fmt, ...){ +static void gl2psMsg(GLint level, char *fmt, ...) +{ va_list args; if(!(gl2ps->options & GL2PS_SILENT)){ @@ -84,7 +240,8 @@ void gl2psMsg(GLint level, char *fmt, ...){ /* if(level == GL2PS_ERROR) exit(1); */ } -void *gl2psMalloc(size_t size){ +static void *gl2psMalloc(size_t size) +{ void *ptr; if(!size) return(NULL); @@ -96,7 +253,8 @@ void *gl2psMalloc(size_t size){ return(ptr); } -void *gl2psRealloc(void *ptr, size_t size){ +static void *gl2psRealloc(void *ptr, size_t size) +{ if(!size) return(NULL); ptr = realloc(ptr, size); if(!ptr){ @@ -106,7 +264,8 @@ void *gl2psRealloc(void *ptr, size_t size){ return(ptr); } -void gl2psFree(void *ptr){ +static void gl2psFree(void *ptr) +{ if(!ptr) return; free(ptr); } @@ -115,7 +274,8 @@ void gl2psFree(void *ptr){ #ifdef GL2PS_HAVE_ZLIB -void gl2psSetupCompress(){ +static void gl2psSetupCompress(void) +{ gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress)); gl2ps->compress->src = NULL; gl2ps->compress->start = NULL; @@ -124,7 +284,8 @@ void gl2psSetupCompress(){ gl2ps->compress->destLen = 0; } -void gl2psFreeCompress(){ +static void gl2psFreeCompress(void) +{ if(!gl2ps->compress) return; gl2psFree(gl2ps->compress->start); @@ -136,7 +297,8 @@ void gl2psFreeCompress(){ gl2ps->compress->destLen = 0; } -int gl2psAllocCompress(unsigned int srcsize){ +static int gl2psAllocCompress(unsigned int srcsize) +{ gl2psFreeCompress(); if(!gl2ps->compress || !srcsize) @@ -151,7 +313,8 @@ int gl2psAllocCompress(unsigned int srcsize){ return GL2PS_SUCCESS; } -void* gl2psReallocCompress(unsigned int srcsize){ +static void *gl2psReallocCompress(unsigned int srcsize) +{ if(!gl2ps->compress || !srcsize) return NULL; @@ -160,14 +323,17 @@ void* gl2psReallocCompress(unsigned int srcsize){ gl2ps->compress->srcLen = srcsize; gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); - gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, gl2ps->compress->srcLen); + gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, + gl2ps->compress->srcLen); gl2ps->compress->start = gl2ps->compress->src; - gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, gl2ps->compress->destLen); + gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, + gl2ps->compress->destLen); return gl2ps->compress->start; } -size_t gl2psWriteBigEndianCompress(unsigned long data, size_t bytes){ +static size_t gl2psWriteBigEndianCompress(unsigned long data, size_t bytes) +{ size_t i; size_t size = sizeof(unsigned long); for(i = 1; i <= bytes; ++i){ @@ -177,7 +343,8 @@ size_t gl2psWriteBigEndianCompress(unsigned long data, size_t bytes){ return bytes; } -int gl2psDeflate(){ +static int gl2psDeflate(void) +{ /* For compatibility with older zlib versions, we use compress(...) instead of compress2(..., Z_BEST_COMPRESSION) */ return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, @@ -186,21 +353,22 @@ int gl2psDeflate(){ #endif -int gl2psPrintf(const char* fmt, ...){ - int ret = 0; +static int gl2psPrintf(const char* fmt, ...) +{ + int ret; va_list args; #ifdef GL2PS_HAVE_ZLIB - unsigned int bufsize = 0; unsigned int oldsize = 0; static char buf[1000]; if(gl2ps->options & GL2PS_COMPRESS){ va_start(args, fmt); - bufsize = vsprintf(buf, fmt, args); + ret = vsprintf(buf, fmt, args); va_end(args); oldsize = gl2ps->compress->srcLen; - gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + bufsize); - memcpy(gl2ps->compress->start+oldsize, buf, bufsize); + gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret); + memcpy(gl2ps->compress->start+oldsize, buf, ret); + ret = 0; } else{ #endif @@ -213,7 +381,8 @@ int gl2psPrintf(const char* fmt, ...){ return ret; } -size_t gl2psWriteBigEndian(unsigned long data, size_t bytes){ +static size_t gl2psWriteBigEndian(unsigned long data, size_t bytes) +{ size_t i; size_t size = sizeof(unsigned long); for(i = 1; i <= bytes; ++i){ @@ -222,29 +391,78 @@ size_t gl2psWriteBigEndian(unsigned long data, size_t bytes){ return bytes; } +static void gl2psAssignTriangleProperties(GL2PStriangle *t) +{ + /* int i; */ + + t->prop = T_VAR_COLOR; + + /* Uncommenting the following lines activates an even more fine + grained distinction between triangle types - please don't delete, + a remarkable amount of PDF handling code inside this file depends + on it if activated */ + /* + t->prop = T_CONST_COLOR; + for(i = 0; i < 3; ++i){ + if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || + !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){ + t->prop = T_VAR_COLOR; + break; + } + } + */ + + if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || + !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){ + t->prop |= T_VAR_ALPHA; + } + else{ + if(t->vertex[0].rgba[3] < 1) + t->prop |= T_ALPHA_LESS_1; + else + t->prop |= T_ALPHA_1; + } +} + +static void gl2psFillTriangleFromPrimitive(GL2PStriangle* t, GL2PSprimitive* p, + GLboolean assignprops) +{ + t->vertex[0] = p->verts[0]; + t->vertex[1] = p->verts[1]; + t->vertex[2] = p->verts[2]; + if(GL_TRUE == assignprops) + gl2psAssignTriangleProperties(t); +} + /* The list handling routines */ -void gl2psListRealloc(GL2PSlist *list, GLint n){ +static void gl2psListRealloc(GL2PSlist *list, GLint n) +{ + if(!list){ + gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list"); + return; + } if(n <= 0) return; if(!list->array){ list->nmax = ((n - 1) / list->incr + 1) * list->incr; - list->array = (char *)gl2psMalloc(list->nmax * list->size); + list->array = (char*)gl2psMalloc(list->nmax * list->size); } else{ if(n > list->nmax){ list->nmax = ((n - 1) / list->incr + 1) * list->incr; - list->array = (char *)gl2psRealloc(list->array, - list->nmax * list->size); + list->array = (char*)gl2psRealloc(list->array, + list->nmax * list->size); } } } -GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size){ +static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size) +{ GL2PSlist *list; if(n < 0) n = 0; if(incr <= 0) incr = 1; - list = (GL2PSlist *)gl2psMalloc(sizeof(GL2PSlist)); + list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist)); list->nmax = 0; list->incr = incr; list->size = size; @@ -254,49 +472,60 @@ GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size){ return(list); } -void gl2psListReset(GL2PSlist *list){ +static void gl2psListReset(GL2PSlist *list) +{ + if(!list) return; list->n = 0; } -void gl2psListDelete(GL2PSlist *list){ +static void gl2psListDelete(GL2PSlist *list) +{ + if(!list) return; gl2psFree(list->array); gl2psFree(list); } -void gl2psListAdd(GL2PSlist *list, void *data){ +static void gl2psListAdd(GL2PSlist *list, void *data) +{ + if(!list){ + gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list"); + return; + } list->n++; gl2psListRealloc(list, list->n); memcpy(&list->array[(list->n - 1) * list->size], data, list->size); } -int gl2psListNbr(GL2PSlist *list){ +static int gl2psListNbr(GL2PSlist *list) +{ + if(!list) + return 0; return(list->n); } -void *gl2psListPointer(GL2PSlist *list, GLint index){ +static void *gl2psListPointer(GL2PSlist *list, GLint index) +{ + if(!list){ + gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list"); + return NULL; + } if((index < 0) || (index >= list->n)){ gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer"); - return(&list->array[0]); + return NULL; } return(&list->array[index * list->size]); } -void gl2psListRead(GL2PSlist *list, GLint index, void *data){ - if((index < 0) || (index >= list->n)){ - gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead"); - data = 0; - } - else{ - memcpy(data, &list->array[index * list->size], list->size); - } -} - -void gl2psListSort(GL2PSlist *list, - int (*fcmp)(const void *a, const void *b)){ +static void gl2psListSort(GL2PSlist *list, + int (*fcmp)(const void *a, const void *b)) +{ + if(!list) + return; qsort(list->array, list->n, list->size, fcmp); } -void gl2psListAction(GL2PSlist *list, void (*action)(void *data)){ +static void gl2psListAction(GL2PSlist *list, void (*action)(void *data)) +{ GLint i; for(i = 0; i < gl2psListNbr(list); i++){ @@ -304,7 +533,8 @@ void gl2psListAction(GL2PSlist *list, void (*action)(void *data)){ } } -void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)){ +static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)) +{ GLint i; for(i = gl2psListNbr(list); i > 0; i--){ @@ -314,17 +544,25 @@ void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)){ /* Helper for pixmaps and strings */ -GL2PSimage* gl2psCopyPixmap(GL2PSimage* im){ +static GL2PSimage *gl2psCopyPixmap(GL2PSimage* im) +{ int size; - GL2PSimage* image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); + GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); image->width = im->width; image->height = im->height; image->format = im->format; image->type = im->type; - /* FIXME: handle other types/formats */ - size = image->height*image->width*3*sizeof(GLfloat); + switch(image->format){ + case GL_RGBA: + size = image->height * image->width * 4 * sizeof(GLfloat); + break; + case GL_RGB: + default: + size = image->height * image->width * 3 * sizeof(GLfloat); + break; + } image->pixels = (GLfloat*)gl2psMalloc(size); memcpy(image->pixels, im->pixels, size); @@ -332,16 +570,17 @@ GL2PSimage* gl2psCopyPixmap(GL2PSimage* im){ return image; } -void gl2psFreePixmap(GL2PSimage* im){ +static void gl2psFreePixmap(GL2PSimage* im) +{ if(!im) return; - if(im->pixels) - gl2psFree(im->pixels); + gl2psFree(im->pixels); gl2psFree(im); } -GL2PSstring* gl2psCopyText(GL2PSstring* t){ - GL2PSstring* text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); +static GL2PSstring *gl2psCopyText(GL2PSstring* t) +{ + GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char)); strcpy(text->str, t->str); text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char)); @@ -352,79 +591,149 @@ GL2PSstring* gl2psCopyText(GL2PSstring* t){ return text; } -void gl2psFreeText(GL2PSstring* text){ +static void gl2psFreeText(GL2PSstring* text) +{ if(!text) return; - if(text->str) - gl2psFree(text->str); - if(text->fontname) - gl2psFree(text->fontname); + gl2psFree(text->str); + gl2psFree(text->fontname); gl2psFree(text); } -/* Helpers for rgba colors */ +static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive* p) +{ + GL2PSprimitive *prim; -GLfloat gl2psColorDiff(GL2PSrgba rgba1, GL2PSrgba rgba2){ - int i; - GLfloat res = 0; - for(i = 0; i < 3; ++i){ - res += (rgba1[i] - rgba2[i]) * (rgba1[i] - rgba2[i]); + if(!p){ + gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive"); + return NULL; } - return res; + + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + + prim->type = p->type; + prim->numverts = p->numverts; + prim->boundary = p->boundary; + prim->dash = p->dash; + prim->culled = p->culled; + prim->width = p->width; + prim->depth = p->depth; + prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex)); + memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex)); + + switch(prim->type){ + case GL2PS_PIXMAP : + prim->data.image = gl2psCopyPixmap(p->data.image); + break; + case GL2PS_TEXT : + prim->data.text = gl2psCopyText(p->data.text); + break; + default: + break; + } + + return prim; } -GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2){ - return !(rgba1[0] != rgba2[0] || - rgba1[1] != rgba2[1] || - rgba1[2] != rgba2[2]); +/* Helpers for rgba colors and PDF blending */ + +static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2) +{ + if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) || + !GL2PS_ZERO(rgba1[1] - rgba2[1]) || + !GL2PS_ZERO(rgba1[2] - rgba2[2])) + return GL_FALSE; + return GL_TRUE; } -GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim){ +static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim) +{ int i; for(i = 1; i < prim->numverts; i++){ if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){ - return 0; + return GL_FALSE; } } - return 1; + return GL_TRUE; } -void gl2psSetLastColor(GL2PSrgba rgba){ +static void gl2psSetLastColor(GL2PSrgba rgba) +{ int i; for(i = 0; i < 3; ++i){ gl2ps->lastrgba[i] = rgba[i]; } } +/* returns TRUE if gl2ps supports the argument combination: only two + blending modes have been implemented so far */ + +static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor) +{ + if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || + (sfactor == GL_ONE && dfactor == GL_ZERO) ) + return GL_TRUE; + return GL_FALSE; +} + +/* Transforms vertex depending on the actual blending function - + currently the vertex v is considered as source vertex and his alpha + value is changed to 1.0 if source blending GL_ONE is active. This + might be extended in the future */ + +static void gl2psAdaptVertexForBlending(GL2PSvertex *v) +{ + if(!v || !gl2ps) + return; + + if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ + v->rgba[3] = 1.0F; + return; + } + + switch(gl2ps->blendfunc[0]){ + case GL_ONE: + v->rgba[3] = 1.0F; + break; + default: + break; + } +} + /********************************************************************* * * 3D sorting routines * *********************************************************************/ -GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane){ +static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane) +{ return(plane[0] * point[0] + plane[1] * point[1] + plane[2] * point[2] + plane[3]); } -GLfloat gl2psPsca(GLfloat *a, GLfloat *b){ +static GLfloat gl2psPsca(GLfloat *a, GLfloat *b) +{ return(a[0]*b[0] + a[1]*b[1] + a[2]*b[2]); } -void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c){ +static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c) +{ c[0] = a[1]*b[2] - a[2]*b[1]; c[1] = a[2]*b[0] - a[0]*b[2]; c[2] = a[0]*b[1] - a[1]*b[0]; } -GLfloat gl2psNorm(GLfloat *a){ +static GLfloat gl2psNorm(GLfloat *a) +{ return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); } -void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c){ +static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c) +{ GLfloat norm; gl2psPvec(a, b, c); @@ -442,7 +751,8 @@ void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c){ } } -void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane){ +static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane) +{ GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F}; switch(prim->type){ @@ -503,8 +813,9 @@ void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane){ } } -void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane, - GL2PSvertex *c){ +static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane, + GL2PSvertex *c) +{ GL2PSxyz v; GLfloat sect; @@ -523,9 +834,10 @@ void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane, c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3]; } -void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, - GL2PSprimitive *child, GLshort numverts, - GLshort *index0, GLshort *index1){ +static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, + GL2PSprimitive *child, GLshort numverts, + GLshort *index0, GLshort *index1) +{ GLshort i; if(numverts > 4){ @@ -545,7 +857,7 @@ void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, child->dash = parent->dash; child->width = parent->width; child->numverts = numverts; - child->verts = (GL2PSvertex *)gl2psMalloc(numverts * sizeof(GL2PSvertex)); + child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); for(i = 0; i < numverts; i++){ if(index1[i] < 0){ @@ -558,8 +870,9 @@ void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, } } -void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, - GLshort i, GLshort j){ +static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, + GLshort i, GLshort j) +{ GLint k; for(k = 0; k < *nb; k++){ @@ -571,11 +884,13 @@ void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, (*nb)++; } -GLshort gl2psGetIndex(GLshort i, GLshort num){ +static GLshort gl2psGetIndex(GLshort i, GLshort num) +{ return(i < num-1) ? i+1 : 0; } -GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane){ +static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane) +{ GLint type = GL2PS_COINCIDENT; GLshort i, j; GLfloat d[5]; @@ -605,9 +920,10 @@ GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane){ return 0; } -GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, - GL2PSprimitive **front, GL2PSprimitive **back){ - GLshort i, j, in=0, out=0, in0[5], in1[5], out0[5], out1[5]; +static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, + GL2PSprimitive **front, GL2PSprimitive **back) +{ + GLshort i, j, in = 0, out = 0, in0[5], in1[5], out0[5], out1[5]; GLint type; GLfloat d[5]; @@ -664,8 +980,9 @@ GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, return type; } -void gl2psDivideQuad(GL2PSprimitive *quad, - GL2PSprimitive **t1, GL2PSprimitive **t2){ +static void gl2psDivideQuad(GL2PSprimitive *quad, + GL2PSprimitive **t1, GL2PSprimitive **t2) +{ *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); (*t1)->type = (*t2)->type = GL2PS_TRIANGLE; @@ -674,8 +991,8 @@ void gl2psDivideQuad(GL2PSprimitive *quad, (*t1)->culled = (*t2)->culled = quad->culled; (*t1)->dash = (*t2)->dash = quad->dash; (*t1)->width = (*t2)->width = quad->width; - (*t1)->verts = (GL2PSvertex *)gl2psMalloc(3 * sizeof(GL2PSvertex)); - (*t2)->verts = (GL2PSvertex *)gl2psMalloc(3 * sizeof(GL2PSvertex)); + (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); + (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); (*t1)->verts[0] = quad->verts[0]; (*t1)->verts[1] = quad->verts[1]; (*t1)->verts[2] = quad->verts[2]; @@ -686,7 +1003,8 @@ void gl2psDivideQuad(GL2PSprimitive *quad, (*t1)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 4) ? 2 : 0); } -int gl2psCompareDepth(const void *a, const void *b){ +static int gl2psCompareDepth(const void *a, const void *b) +{ GL2PSprimitive *q, *w; GLfloat diff; @@ -704,7 +1022,8 @@ int gl2psCompareDepth(const void *a, const void *b){ } } -int gl2psTrianglesFirst(const void *a, const void *b){ +static int gl2psTrianglesFirst(const void *a, const void *b) +{ GL2PSprimitive *q, *w; q = *(GL2PSprimitive**)a; @@ -712,14 +1031,21 @@ int gl2psTrianglesFirst(const void *a, const void *b){ return(q->type < w->type ? 1 : -1); } -GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root){ +static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root) +{ GLint i, j, count, best = 1000000, index = 0; GL2PSprimitive *prim1, *prim2; GL2PSplane plane; GLint maxp; + if(!gl2psListNbr(primitives)){ + gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list"); + return 0; + } + + *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0); + if(gl2ps->options & GL2PS_BEST_ROOT){ - *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0); maxp = gl2psListNbr(primitives); if(maxp > gl2ps->maxbestroot){ maxp = gl2ps->maxbestroot; @@ -746,29 +1072,27 @@ GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root){ return index; } else{ - *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0); return 0; } } -void gl2psFreePrimitive(void *data){ +static void gl2psFreePrimitive(void *data) +{ GL2PSprimitive *q; q = *(GL2PSprimitive**)data; gl2psFree(q->verts); if(q->type == GL2PS_TEXT){ - gl2psFree(q->data.text->str); - gl2psFree(q->data.text->fontname); - gl2psFree(q->data.text); + gl2psFreeText(q->data.text); } - if(q->type == GL2PS_PIXMAP){ - gl2psFree(q->data.image->pixels); - gl2psFree(q->data.image); + else if(q->type == GL2PS_PIXMAP){ + gl2psFreePixmap(q->data.image); } gl2psFree(q); } -void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list){ +static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list) +{ GL2PSprimitive *t1, *t2; if(prim->type != GL2PS_QUADRANGLE){ @@ -783,7 +1107,8 @@ void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list){ } -void gl2psFreeBspTree(GL2PSbsptree **tree){ +static void gl2psFreeBspTree(GL2PSbsptree **tree) +{ if(*tree){ if((*tree)->back) gl2psFreeBspTree(&(*tree)->back); if((*tree)->primitives){ @@ -796,17 +1121,20 @@ void gl2psFreeBspTree(GL2PSbsptree **tree){ } } -GLboolean gl2psGreater(GLfloat f1, GLfloat f2){ - if(f1 > f2) return 1; - else return 0; +static GLboolean gl2psGreater(GLfloat f1, GLfloat f2) +{ + if(f1 > f2) return GL_TRUE; + else return GL_FALSE; } -GLboolean gl2psLess(GLfloat f1, GLfloat f2){ - if(f1 < f2) return 1; - else return 0; +static GLboolean gl2psLess(GLfloat f1, GLfloat f2) +{ + if(f1 < f2) return GL_TRUE; + else return GL_FALSE; } -void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives){ +static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives) +{ GL2PSprimitive *prim, *frontprim, *backprim; GL2PSlist *frontlist, *backlist; GLint i, index; @@ -868,16 +1196,17 @@ void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives){ gl2psListDelete(primitives); } -void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, - GLboolean (*compare)(GLfloat f1, GLfloat f2), - void (*action)(void *data), int inverse){ +static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, + GLboolean (*compare)(GLfloat f1, GLfloat f2), + void (*action)(void *data), int inverse) +{ GLfloat result; if(!tree) return; result = gl2psComparePointPlane(eye, tree->plane); - if(compare(result, epsilon)){ + if(GL_TRUE == compare(result, epsilon)){ gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); if(inverse){ gl2psListActionInverse(tree->primitives, action); @@ -887,7 +1216,7 @@ void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, } gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); } - else if(compare(-epsilon, result)){ + else if(GL_TRUE == compare(-epsilon, result)){ gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); if(inverse){ gl2psListActionInverse(tree->primitives, action); @@ -909,7 +1238,8 @@ void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, * *********************************************************************/ -GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane){ +static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane) +{ GLfloat n; plane[0] = b[1] - a[1]; @@ -930,7 +1260,8 @@ GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane){ } } -void gl2psFreeBspImageTree(GL2PSbsptree2d **tree){ +static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree) +{ if(*tree){ if((*tree)->back) gl2psFreeBspImageTree(&(*tree)->back); if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front); @@ -939,7 +1270,8 @@ void gl2psFreeBspImageTree(GL2PSbsptree2d **tree){ } } -GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane){ +static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane) +{ GLfloat pt_dis; pt_dis = gl2psComparePointPlane(point, plane); @@ -948,8 +1280,9 @@ GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane){ else return GL2PS_POINT_COINCIDENT; } -void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim, - GL2PSbsptree2d **tree){ +static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim, + GL2PSbsptree2d **tree) +{ GLint ret = 0; GLint i; GLint offset = 0; @@ -1047,7 +1380,8 @@ void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim, } } -GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane){ +static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane) +{ GLint i; GLint pos; @@ -1061,9 +1395,10 @@ GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane){ else return GL2PS_COINCIDENT; } -GL2PSprimitive* gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, - GLshort numverts, - GL2PSvertex *vertx){ +static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, + GLshort numverts, + GL2PSvertex *vertx) +{ GLint i; GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); @@ -1079,18 +1414,18 @@ GL2PSprimitive* gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, child->dash = parent->dash; child->width = parent->width; child->numverts = numverts; - child->verts = (GL2PSvertex *)gl2psMalloc(numverts * sizeof(GL2PSvertex)); + child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); for(i = 0; i < numverts; i++){ child->verts[i] = vertx[i]; } return child; } -void gl2psSplitPrimitive2D(GL2PSprimitive *prim, - GL2PSplane plane, - GL2PSprimitive **front, - GL2PSprimitive **back){ - +static void gl2psSplitPrimitive2D(GL2PSprimitive *prim, + GL2PSplane plane, + GL2PSprimitive **front, + GL2PSprimitive **back) +{ /* cur will hold the position of the current vertex prev will hold the position of the previous vertex prev0 will hold the position of the vertex number 0 @@ -1170,7 +1505,8 @@ void gl2psSplitPrimitive2D(GL2PSprimitive *prim, gl2psFree(back_list); } -GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree){ +static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree) +{ GLint ret = 0; GL2PSprimitive *frontprim = NULL, *backprim = NULL; @@ -1182,7 +1518,7 @@ GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree){ } if(*tree == NULL){ - if(!gl2ps->zerosurfacearea){ + if(GL_FALSE == gl2ps->zerosurfacearea){ gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree); } return 1; @@ -1208,15 +1544,15 @@ GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree){ return ret; case GL2PS_COINCIDENT: if((*tree)->back != NULL){ - gl2ps->zerosurfacearea = 1; + gl2ps->zerosurfacearea = GL_TRUE; ret = gl2psAddInBspImageTree(prim, &(*tree)->back); - gl2ps->zerosurfacearea = 0; + gl2ps->zerosurfacearea = GL_FALSE; if(ret) return ret; } if((*tree)->front != NULL){ - gl2ps->zerosurfacearea = 1; + gl2ps->zerosurfacearea = GL_TRUE; ret = gl2psAddInBspImageTree(prim, &(*tree)->front); - gl2ps->zerosurfacearea = 0; + gl2ps->zerosurfacearea = GL_FALSE; if(ret) return ret; } if(prim->type == GL2PS_LINE) return 1; @@ -1226,7 +1562,8 @@ GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree){ return 0; } -void gl2psAddInImageTree(void *data){ +static void gl2psAddInImageTree(void *data) +{ GL2PSprimitive *prim = *(GL2PSprimitive **)data; gl2ps->primitivetoadd = prim; if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){ @@ -1234,9 +1571,10 @@ void gl2psAddInImageTree(void *data){ } } -/* Boundary contruction */ +/* Boundary construction */ -void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list){ +static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list) +{ GL2PSprimitive *b; GLshort i; GL2PSxyz c; @@ -1259,7 +1597,7 @@ void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list){ b->width = prim->width; b->boundary = 0; b->numverts = 2; - b->verts = (GL2PSvertex *)gl2psMalloc(2 * sizeof(GL2PSvertex)); + b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex)); #if 0 /* FIXME: need to work on boundary offset... */ v[0] = c[0] - prim->verts[i].xyz[0]; @@ -1302,14 +1640,14 @@ void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list){ } -void gl2psBuildPolygonBoundary(GL2PSbsptree *tree){ - GLint i, n; +static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree) +{ + GLint i; GL2PSprimitive *prim; if(!tree) return; gl2psBuildPolygonBoundary(tree->back); - n = gl2psListNbr(tree->primitives); - for(i = 0; i < n; i++){ + for(i = 0; i < gl2psListNbr(tree->primitives); i++){ prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i); if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives); } @@ -1322,18 +1660,19 @@ void gl2psBuildPolygonBoundary(GL2PSbsptree *tree){ * *********************************************************************/ -void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, - GL2PSvertex *verts, GLint offset, - char dash, GLfloat width, - char boundary){ +static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, + GL2PSvertex *verts, GLint offset, + char dash, GLfloat width, + char boundary) +{ GLshort i; GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ; GL2PSprimitive *prim; - prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = type; prim->numverts = numverts; - prim->verts = (GL2PSvertex *)gl2psMalloc(numverts * sizeof(GL2PSvertex)); + prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex)); prim->boundary = boundary; prim->dash = dash; @@ -1403,7 +1742,8 @@ void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, gl2psListAdd(gl2ps->primitives, &prim); } -GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p){ +static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p) +{ GLint i; v->xyz[0] = p[0]; @@ -1427,20 +1767,21 @@ GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p){ } } -void gl2psParseFeedbackBuffer(GLint used){ +static void gl2psParseFeedbackBuffer(GLint used) +{ char flag, dash = 0; - GLshort boundary; + GLboolean boundary; GLint i, count, v, vtot, offset = 0; GLfloat lwidth = 1.0F, psize = 1.0F; GLfloat *current; GL2PSvertex vertices[3]; current = gl2ps->feedback; - boundary = gl2ps->boundary = 0; + boundary = gl2ps->boundary = GL_FALSE; while(used > 0){ - if(boundary) gl2ps->boundary = 1; + if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE; switch((GLint)*current){ case GL_POINT_TOKEN : @@ -1470,12 +1811,13 @@ void gl2psParseFeedbackBuffer(GLint used){ v = vtot = 0; while(count > 0 && used > 0){ i = gl2psGetVertex(&vertices[v], current); + gl2psAdaptVertexForBlending(&vertices[v]); current += i; used -= i; count --; vtot++; if(v == 2){ - if(boundary){ + if(GL_TRUE == boundary){ if(!count && vtot == 2) flag = 1|2|4; else if(!count) flag = 2|4; else if(vtot == 2) flag = 1|2; @@ -1504,10 +1846,22 @@ void gl2psParseFeedbackBuffer(GLint used){ switch((GLint)current[1]){ case GL2PS_BEGIN_POLYGON_OFFSET_FILL : offset = 1; break; case GL2PS_END_POLYGON_OFFSET_FILL : offset = 0; break; - case GL2PS_BEGIN_POLYGON_BOUNDARY : boundary = 1; break; - case GL2PS_END_POLYGON_BOUNDARY : boundary = 0; break; + case GL2PS_BEGIN_POLYGON_BOUNDARY : boundary = GL_TRUE; break; + case GL2PS_END_POLYGON_BOUNDARY : boundary = GL_FALSE; break; case GL2PS_BEGIN_LINE_STIPPLE : dash = 4; break; case GL2PS_END_LINE_STIPPLE : dash = 0; break; + case GL2PS_BEGIN_BLEND : gl2ps->blending = GL_TRUE; break; + case GL2PS_END_BLEND : gl2ps->blending = GL_FALSE; break; + case GL2PS_SRC_BLEND : + current += 2; + used -= 2; + gl2ps->blendfunc[0] = (GLint)current[1]; + break; + case GL2PS_DST_BLEND : + current += 2; + used -= 2; + gl2ps->blendfunc[1] = (GLint)current[1]; + break; case GL2PS_SET_POINT_SIZE : current += 2; used -= 2; @@ -1537,30 +1891,49 @@ void gl2psParseFeedbackBuffer(GLint used){ * *********************************************************************/ -void gl2psGetRGB(GLfloat *pixels, GLsizei width, GLsizei height, GLuint x, GLuint y, - GLfloat *red, GLfloat *green, GLfloat *blue){ - /* OpenGL image is from down to up, PS image is up to down */ +static GLfloat gl2psGetRGB(GL2PSimage* im, GLuint x, GLuint y, + GLfloat *red, GLfloat *green, GLfloat *blue) +{ + + GLsizei width = im->width; + GLsizei height = im->height; + GLfloat *pixels = im->pixels; GLfloat *pimag; - pimag = pixels + 3 * (width * (height - 1 - y) + x); - *red = *pimag; pimag++; + + /* OpenGL image is from down to up, PS image is up to down */ + switch(im->format){ + case GL_RGBA: + pimag = pixels + 4 * (width * (height - 1 - y) + x); + break; + case GL_RGB: + default: + pimag = pixels + 3 * (width * (height - 1 - y) + x); + break; + } + *red = *pimag; pimag++; *green = *pimag; pimag++; - *blue = *pimag; pimag++; + *blue = *pimag; pimag++; + + return (im->format == GL_RGBA) ? *pimag : 1.0F; } -void gl2psWriteByte(unsigned char byte){ +static void gl2psWriteByte(unsigned char byte) +{ unsigned char h = byte / 16; unsigned char l = byte % 16; gl2psPrintf("%x%x", h, l); } -void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei height, - GLfloat *pixels){ +static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im) +{ int nbhex, nbyte2, nbyte4, nbyte8; GLsizei row, col, col_max; GLfloat dr, dg, db; unsigned char red, green, blue, b, grey; + GLsizei width = im->width; + GLsizei height = im->height; - /* FIXME: define an option for these? */ + /* FIXME: should we define an option for these? */ int greyscale = 0; /* set to 1 to output greyscale image */ int nbits = 8; /* number of bits per color compoment (2, 4 or 8) */ @@ -1578,7 +1951,7 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei gl2psPrintf("image\n"); for(row = 0; row < height; row++){ for(col = 0; col < width; col++){ - gl2psGetRGB(pixels, width, height, col, row, &dr, &dg, &db); + gl2psGetRGB(im, col, row, &dr, &dg, &db); grey = (unsigned char)(255.0 * (0.30 * dr + 0.59 * dg + 0.11 * db)); gl2psWriteByte(grey); } @@ -1600,14 +1973,14 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei gl2psPrintf("colorimage\n" ); for(row = 0; row < height; row++){ for(col = 0; col < col_max; col+=4){ - gl2psGetRGB(pixels, width, height, col, row, &dr, &dg, &db); + gl2psGetRGB(im, col, row, &dr, &dg, &db); red = (unsigned char)(3.0 * dr); green = (unsigned char)(3.0 * dg); blue = (unsigned char)(3.0 * db); b = red; b = (b<<2)+green; b = (b<<2)+blue; - gl2psGetRGB(pixels, width, height, col+1, row, &dr, &dg, &db); + gl2psGetRGB(im, col+1, row, &dr, &dg, &db); red = (unsigned char)(3.0 * dr); green = (unsigned char)(3.0 * dg); blue = (unsigned char)(3.0 * db); @@ -1615,7 +1988,7 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei gl2psWriteByte(b); b = green; b = (b<<2)+blue; - gl2psGetRGB(pixels, width, height, col+2, row, &dr, &dg, &db); + gl2psGetRGB(im, col+2, row, &dr, &dg, &db); red = (unsigned char)(3.0 * dr); green = (unsigned char)(3.0 * dg); blue = (unsigned char)(3.0 * db); @@ -1623,7 +1996,7 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei b = (b<<2)+green; gl2psWriteByte(b); b = blue; - gl2psGetRGB(pixels, width, height, col+3, row, &dr, &dg, &db); + gl2psGetRGB(im, col+3, row, &dr, &dg, &db); red = (unsigned char)(3.0 * dr); green = (unsigned char)(3.0 * dg); blue = (unsigned char)(3.0 * db); @@ -1648,12 +2021,12 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei gl2psPrintf("colorimage\n"); for(row = 0; row < height; row++){ for(col = 0; col < col_max; col+=2){ - gl2psGetRGB(pixels, width, height, col, row, &dr, &dg, &db); + gl2psGetRGB(im, col, row, &dr, &dg, &db); red = (unsigned char)(15. * dr); green = (unsigned char)(15. * dg); gl2psPrintf("%x%x", red, green); blue = (unsigned char)(15. * db); - gl2psGetRGB(pixels, width, height, col+1, row, &dr, &dg, &db); + gl2psGetRGB(im, col+1, row, &dr, &dg, &db); red = (unsigned char)(15. * dr); gl2psPrintf("%x%x",blue,red); green = (unsigned char)(15. * dg); @@ -1673,7 +2046,7 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei gl2psPrintf("colorimage\n"); for(row = 0; row < height; row++){ for(col = 0; col < width; col++){ - gl2psGetRGB(pixels, width, height, col, row, &dr, &dg, &db); + gl2psGetRGB(im, col, row, &dr, &dg, &db); red = (unsigned char)(255.0 * dr); gl2psWriteByte(red); green = (unsigned char)(255.0 * dg); @@ -1688,12 +2061,17 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei gl2psPrintf("grestore\n"); } -void gl2psPrintPostScriptHeader(void){ +static void gl2psPrintPostScriptHeader(void) +{ GLint index; GLfloat rgba[4]; time_t now; #ifdef GL2PS_HAVE_ZLIB + /* since compression is not part of the PostScript standard, we + simply generate a gzipped PostScript file ("ps.gz" or + "eps.gz") */ + char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */ 8, /* compression method: Z_DEFLATED */ 0, /* flags */ @@ -1703,7 +2081,6 @@ void gl2psPrintPostScriptHeader(void){ if(gl2ps->options & GL2PS_COMPRESS){ gl2psSetupCompress(); - /* add the gzip file header */ fwrite(tmp, 10, 1, gl2ps->stream); } @@ -1719,7 +2096,7 @@ void gl2psPrintPostScriptHeader(void){ } gl2psPrintf("%%%%Title: %s\n" - "%%%%Creator: GL2PS %d.%d.%d, (C) 1999-2003 Christophe Geuzaine <geuz@geuz.org>\n" + "%%%%Creator: GL2PS %d.%d.%d, (C) 1999-2004 Christophe Geuzaine <geuz@geuz.org>\n" "%%%%For: %s\n" "%%%%CreationDate: %s" "%%%%LanguageLevel: 3\n" @@ -1766,8 +2143,11 @@ void gl2psPrintPostScriptHeader(void){ "/tryPS3shading %s def %% set to false to force subdivision\n" "/rThreshold %g def %% red component subdivision threshold\n" "/gThreshold %g def %% green component subdivision threshold\n" - "/bThreshold %g def %% blue component subdivision threshold\n" - "/BD { bind def } bind def\n" + "/bThreshold %g def %% blue component subdivision threshold\n", + (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true", + gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]); + + gl2psPrintf("/BD { bind def } bind def\n" "/C { setrgbcolor } BD\n" "/G { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n" "/W { setlinewidth } BD\n" @@ -1776,9 +2156,7 @@ void gl2psPrintPostScriptHeader(void){ "/P { newpath 0.0 360.0 arc closepath fill } BD\n" "/L { newpath moveto lineto stroke } BD\n" "/SL { C moveto C lineto stroke } BD\n" - "/T { newpath moveto lineto lineto closepath fill } BD\n", - (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true", - gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]); + "/T { newpath moveto lineto lineto closepath fill } BD\n"); /* Smooth-shaded triangle with PostScript level 3 shfill operator: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */ @@ -1814,23 +2192,29 @@ void gl2psPrintPostScriptHeader(void){ " 4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */ " 4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */ " 4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */ - " 5 copy 5 copy 25 15 roll\n" - /* stack : (V3) (V13) (V13) (V13) (V2) (V1) */ - " 9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */ + " 5 copy 5 copy 25 15 roll\n"); + + /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */ + + gl2psPrintf(" 9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */ " 9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */ " 9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */ " 9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */ " 9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */ - " 5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n" - /* stack : (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */ - " 4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */ + " 5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n"); + + /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */ + + gl2psPrintf(" 4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */ " 4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */ " 4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */ " 4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */ " 4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */ - " 5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n" - /* stack : (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */ - " STnoshfill STnoshfill STnoshfill STnoshfill } BD\n"); + " 5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n"); + + /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */ + + gl2psPrintf(" STnoshfill STnoshfill STnoshfill STnoshfill } BD\n"); /* Gouraud shaded triangle using recursive subdivision until the difference between corner colors does not exceed the thresholds: @@ -1849,8 +2233,8 @@ void gl2psPrintPostScriptHeader(void){ " { STsplit }\n" " { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */ " { STsplit }\n" - " { 7 index 13 index sub abs rThreshold gt\n" /* |r2-r3|>rht */ - " { STsplit }\n" + " { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */ + gl2psPrintf(" { STsplit }\n" " { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */ " { STsplit }\n" " { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */ @@ -1914,18 +2298,21 @@ void gl2psPrintPostScriptHeader(void){ } } -void gl2psPrintPostScriptColor(GL2PSrgba rgba){ +static void gl2psPrintPostScriptColor(GL2PSrgba rgba) +{ if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ gl2psSetLastColor(rgba); gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]); } } -void gl2psResetPostScriptColor(void){ +static void gl2psResetPostScriptColor(void) +{ gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.; } -void gl2psPrintPostScriptPrimitive(void *data){ +static void gl2psPrintPostScriptPrimitive(void *data) +{ GL2PSprimitive *prim; prim = *(GL2PSprimitive**)data; @@ -1935,8 +2322,7 @@ void gl2psPrintPostScriptPrimitive(void *data){ switch(prim->type){ case GL2PS_PIXMAP : gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1], - prim->data.image->width, prim->data.image->height, - prim->data.image->pixels); + prim->data.image); break; case GL2PS_TEXT : gl2psPrintPostScriptColor(prim->verts[0].rgba); @@ -2006,7 +2392,8 @@ void gl2psPrintPostScriptPrimitive(void *data){ } } -void gl2psPrintPostScriptFooter(void){ +static void gl2psPrintPostScriptFooter(void) +{ #ifdef GL2PS_HAVE_ZLIB int n; uLong crc, len; @@ -2037,12 +2424,12 @@ void gl2psPrintPostScriptFooter(void){ 1, gl2ps->stream); /* add the gzip file footer */ crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen); - for(n = 0; n < 4; ++n) { + for(n = 0; n < 4; ++n){ tmp[n] = (char)(crc & 0xff); crc >>= 8; } len = gl2ps->compress->srcLen; - for(n = 4; n < 8; ++n) { + for(n = 4; n < 8; ++n){ tmp[n] = (char)(len & 0xff); len >>= 8; } @@ -2055,7 +2442,8 @@ void gl2psPrintPostScriptFooter(void){ #endif } -void gl2psPrintPostScriptBeginViewport(GLint viewport[4]){ +static void gl2psPrintPostScriptBeginViewport(GLint viewport[4]) +{ GLint index; GLfloat rgba[4]; int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; @@ -2088,7 +2476,8 @@ void gl2psPrintPostScriptBeginViewport(GLint viewport[4]){ } -GLint gl2psPrintPostScriptEndViewport(void){ +static GLint gl2psPrintPostScriptEndViewport(void) +{ GLint res; res = gl2psPrintPrimitives(); @@ -2102,7 +2491,8 @@ GLint gl2psPrintPostScriptEndViewport(void){ * *********************************************************************/ -void gl2psPrintTeXHeader(void){ +static void gl2psPrintTeXHeader(void) +{ char name[256]; int i; @@ -2130,7 +2520,8 @@ void gl2psPrintTeXHeader(void){ (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); } -void gl2psPrintTeXPrimitive(void *data){ +static void gl2psPrintTeXPrimitive(void *data) +{ GL2PSprimitive *prim; prim = *(GL2PSprimitive**)data; @@ -2141,7 +2532,7 @@ void gl2psPrintTeXPrimitive(void *data){ prim->data.text->fontsize); fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - switch (prim->data.text->alignment) { + switch(prim->data.text->alignment){ case GL2PS_TEXT_CL: fprintf(gl2ps->stream, "[l]"); break; @@ -2178,7 +2569,8 @@ void gl2psPrintTeXPrimitive(void *data){ } } -void gl2psPrintTeXFooter(void){ +static void gl2psPrintTeXFooter(void) +{ fprintf(gl2ps->stream, "\\end{picture}%s\n", (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : ""); } @@ -2189,7 +2581,8 @@ void gl2psPrintTeXFooter(void){ * *********************************************************************/ -int gl2psPrintPDFCompressorType(){ +static int gl2psPrintPDFCompressorType(void) +{ #ifdef GL2PS_HAVE_ZLIB if(gl2ps->options & GL2PS_COMPRESS){ return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n"); @@ -2198,9 +2591,9 @@ int gl2psPrintPDFCompressorType(){ return 0; } -int gl2psPrintPDFStrokeColor(GL2PSrgba rgba){ - int offs = 0; - int i; +static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba) +{ + int i, offs = 0; gl2psSetLastColor(rgba); for(i = 0; i < 3; ++i){ @@ -2215,9 +2608,9 @@ int gl2psPrintPDFStrokeColor(GL2PSrgba rgba){ return offs; } -int gl2psPrintPDFFillColor(GL2PSrgba rgba){ - int offs = 0; - int i; +static int gl2psPrintPDFFillColor(GL2PSrgba rgba) +{ + int i, offs = 0; for(i = 0; i < 3; ++i){ if(GL2PS_ZERO(rgba[i])) @@ -2231,7 +2624,8 @@ int gl2psPrintPDFFillColor(GL2PSrgba rgba){ return offs; } -int gl2psPrintPDFLineWidth(GLfloat lw){ +static int gl2psPrintPDFLineWidth(GLfloat lw) +{ if(GL2PS_ZERO(lw)) return gl2psPrintf("%.0f w\n", 0.); else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */ @@ -2240,284 +2634,644 @@ int gl2psPrintPDFLineWidth(GLfloat lw){ return gl2psPrintf("%g w\n", lw); } -/* Print 1st PDF object - file info */ - -int gl2psPrintPDFInfo(){ - int offs; - time_t now; - struct tm *newtime; - - time(&now); - newtime = gmtime(&now); - - offs = fprintf(gl2ps->stream, - "1 0 obj\n" - "<<\n" - "/Title (%s)\n" - "/Creator (%s)\n" - "/Producer (GL2PS %d.%d.%d, (C) 1999-2003 Christophe Geuzaine <geuz@geuz.org>)\n", - gl2ps->title, gl2ps->producer, - GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION); - - if(!newtime){ - offs += fprintf(gl2ps->stream, - ">>\n" - "endobj\n"); - return offs; - } - - offs += fprintf(gl2ps->stream, - "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n" - ">>\n" - "endobj\n", - newtime->tm_year+1900, - newtime->tm_mon+1, - newtime->tm_mday, - newtime->tm_hour, - newtime->tm_min, - newtime->tm_sec); - return offs; +static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y) +{ + gl2ps->streamlength += + gl2psPrintf("BT\n" + "/F%d %d Tf\n" + "%f %f Td\n" + "(%s) Tj\n" + "ET\n", + cnt, text->fontsize, x, y, text->str); } -/* Create catalog and page structure - 2nd and 3th PDF object */ +static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y) +{ + gl2ps->streamlength += + gl2psPrintf("q\n" + "%d 0 0 %d %f %f cm\n" + "/Im%d Do\n" + "Q\n", + (int)image->width, (int)image->height, x, y, cnt); +} -int gl2psPrintPDFCatalog(){ - return fprintf(gl2ps->stream, - "2 0 obj\n" - "<<\n" - "/Type /Catalog\n" - "/Pages 3 0 R\n" - ">>\n" - "endobj\n"); +static void gl2psPDFstacksInit(void) +{ + gl2ps->objects_stack = GL2PS_FIXED_XREF_ENTRIES + 1; + gl2ps->extgs_stack = 0; + gl2ps->font_stack = 0; + gl2ps->im_stack = 0; + gl2ps->trgroupobjects_stack = 0; + gl2ps->shader_stack = 0; + gl2ps->mshader_stack = 0; } -int gl2psPrintPDFPages(){ - return fprintf(gl2ps->stream, - "3 0 obj\n" - "<<\n" - "/Type /Pages\n" - "/Kids [6 0 R]\n" - "/Count 1\n" - ">>\n" - "endobj\n"); +static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro) +{ + if(!gro) + return; + + gro->ptrlist = NULL; + gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno + = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno + = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1; } -/* Open stream for data - graphical objects, fonts etc. PDF object 4*/ +/* Build up group objects and assign name and object numbers */ -int gl2psOpenPDFDataStream(){ - int offs = 0; - - offs += fprintf(gl2ps->stream, - "4 0 obj\n" - "<<\n" - "/Length 5 0 R\n" ); - offs += gl2psPrintPDFCompressorType(); - offs += fprintf(gl2ps->stream, - ">>\n" - "stream\n"); - return offs; +static void gl2psPDFgroupListInit(void) +{ + int i; + GL2PSprimitive *p = NULL; + GL2PSpdfgroup gro; + int lasttype = GL2PS_NOTYPE; + GL2PSrgba lastrgba; + char lastdash = 0; + GLfloat lastwidth = 1; + GL2PStriangle tmpt, lastt; + int lastTriangleWasNotSimpleWithSameColor = 0; + + if(!gl2ps->pdfprimlist) + return; + + gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup)); + + for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ + p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i); + switch(p->type){ + case GL2PS_PIXMAP: + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gro.imno = gl2ps->im_stack++; + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + break; + case GL2PS_TEXT: + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gro.fontno = gl2ps->font_stack++; + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + break; + case GL2PS_LINE: + if(lasttype != p->type || lastwidth != p->width || lastdash != p->dash || + !gl2psSameColor(p->verts[0].rgba, lastrgba)){ + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + } + else{ + gl2psListAdd(gro.ptrlist, &p); + } + lastdash = p->dash; + lastwidth = p->width; + lastrgba[0] = p->verts[0].rgba[0]; + lastrgba[1] = p->verts[0].rgba[1]; + lastrgba[2] = p->verts[0].rgba[2]; + break; + case GL2PS_POINT: + if(lasttype != p->type || lastwidth != p->width || + !gl2psSameColor(p->verts[0].rgba, lastrgba)){ + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*)); + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + } + else{ + gl2psListAdd(gro.ptrlist, &p); + } + lastwidth = p->width; + lastrgba[0] = p->verts[0].rgba[0]; + lastrgba[1] = p->verts[0].rgba[1]; + lastrgba[2] = p->verts[0].rgba[2]; + break; + case GL2PS_TRIANGLE: + gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE); + lastTriangleWasNotSimpleWithSameColor = + !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) || + !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba); + if(lasttype == p->type && tmpt.prop == lastt.prop && + lastTriangleWasNotSimpleWithSameColor){ + /* TODO Check here for last alpha */ + gl2psListAdd(gro.ptrlist, &p); + } + else{ + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + } + lastt.prop = tmpt.prop; + break; + default: + break; + } + lasttype = p->type; + } } -/* Stream setup - Graphics state, fill background if allowed */ +static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro) +{ + GL2PStriangle t; + GL2PSprimitive *prim = NULL; + + if(!gro) + return; -int gl2psOpenPDFDataStreamWritePreface(){ - int offs; - GLint index; - GLfloat rgba[4]; + if(!gl2psListNbr(gro->ptrlist)) + return; + + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); + + if(prim->type != GL2PS_TRIANGLE) + return; - offs = gl2psPrintf("/GS1 gs\n"); + gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); - if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ - if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ - glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); - } - else{ - glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); - rgba[0] = gl2ps->colormap[index][0]; - rgba[1] = gl2ps->colormap[index][1]; - rgba[2] = gl2ps->colormap[index][2]; - rgba[3] = 0.0F; - } - offs += gl2psPrintPDFFillColor(rgba); - offs += gl2psPrintf("%d %d %d %d re\n", - (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], - (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - offs += gl2psPrintf("f\n"); + if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ + gro->gsno = gl2ps->extgs_stack++; + gro->gsobjno = gl2ps->objects_stack ++; + } + else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ + gro->gsno = gl2ps->extgs_stack++; + gro->gsobjno = gl2ps->objects_stack++; + gro->trgroupno = gl2ps->trgroupobjects_stack++; + gro->trgroupobjno = gl2ps->objects_stack++; + gro->maskshno = gl2ps->mshader_stack++; + gro->maskshobjno = gl2ps->objects_stack++; + } + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ + gro->shno = gl2ps->shader_stack++; + gro->shobjno = gl2ps->objects_stack++; + } + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ + gro->gsno = gl2ps->extgs_stack++; + gro->gsobjno = gl2ps->objects_stack++; + gro->shno = gl2ps->shader_stack++; + gro->shobjno = gl2ps->objects_stack++; + } + else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ + gro->gsno = gl2ps->extgs_stack++; + gro->gsobjno = gl2ps->objects_stack++; + gro->shno = gl2ps->shader_stack++; + gro->shobjno = gl2ps->objects_stack++; + gro->trgroupno = gl2ps->trgroupobjects_stack++; + gro->trgroupobjno = gl2ps->objects_stack++; + gro->maskshno = gl2ps->mshader_stack++; + gro->maskshobjno = gl2ps->objects_stack++; } - return offs; } -/* Use the functions above to create the first part of the PDF*/ +/* Main stream data */ -void gl2psPrintPDFHeader(){ - int offs; +static void gl2psPDFgroupListWriteMainStream(void) +{ + int i, j, lastel; + GL2PSprimitive *prim = NULL; + GL2PSpdfgroup *gro; + GL2PStriangle t; -#ifdef GL2PS_HAVE_ZLIB - if(gl2ps->options & GL2PS_COMPRESS){ - gl2psSetupCompress(); - } -#endif + if(!gl2ps->pdfgrouplist) + return; - /* tlist, tidxlist, ilist and slist contain triangles, indexes for - consecutive triangles, images and strings */ - gl2ps->tlist = gl2psListCreate(100, 100, sizeof(GL2PStriangle)); - gl2ps->tidxlist = gl2psListCreate(100, 100, sizeof(int)); - gl2ps->ilist = gl2psListCreate(100, 100, sizeof(GL2PSimage*)); - gl2ps->slist = gl2psListCreate(100, 100, sizeof(GL2PSstring*)); - - gl2ps->lasttype = GL2PS_NOTYPE; - gl2ps->consec_cnt = 0; - gl2ps->consec_inner_cnt = 0; - - offs = fprintf(gl2ps->stream, "%%PDF-1.3\n"); - gl2ps->cref[0] = offs; - - offs += gl2psPrintPDFInfo(); - gl2ps->cref[1] = offs; - - offs += gl2psPrintPDFCatalog(); - gl2ps->cref[2] = offs; - - offs += gl2psPrintPDFPages(); - gl2ps->cref[3] = offs; - - offs += gl2psOpenPDFDataStream(); - gl2ps->cref[4] = offs; /* finished in gl2psPrintPDFFooter */ - gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface(); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + + lastel = gl2psListNbr(gro->ptrlist) - 1; + if(lastel < 0) + continue; + + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); + + switch(prim->type){ + case GL2PS_PIXMAP: + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], + prim->verts[0].xyz[1]); + } + break; + case GL2PS_TEXT: + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); + gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0], + prim->verts[0].xyz[1]); + } + break; + case GL2PS_LINE: + gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); + gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); + if(prim->dash){ + gl2ps->streamlength += gl2psPrintf("[%d] 0 d\n", prim->dash); + } + else{ + gl2ps->streamlength += gl2psPrintf("[] 0 d\n"); + } + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2ps->streamlength += + gl2psPrintf("%f %f m %f %f l\n", + prim->verts[0].xyz[0], prim->verts[0].xyz[1], + prim->verts[1].xyz[0], prim->verts[1].xyz[1]); + } + gl2ps->streamlength += gl2psPrintf("S\n"); + break; + case GL2PS_POINT: + gl2ps->streamlength += gl2psPrintf("1 J\n"); + gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); + gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2ps->streamlength += + gl2psPrintf("%f %f m %f %f l\n", + prim->verts[0].xyz[0], prim->verts[0].xyz[1], + prim->verts[0].xyz[0], prim->verts[0].xyz[1]); + } + gl2ps->streamlength += gl2psPrintf("S\n"); + gl2ps->streamlength += gl2psPrintf("0 J\n"); + break; + case GL2PS_TRIANGLE: + gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); + gl2psSortOutTrianglePDFgroup(gro); + + /* No alpha and const color: Simple PDF draw orders */ + if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){ + gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba); + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); + gl2ps->streamlength + += gl2psPrintf("%f %f m\n" + "%f %f l\n" + "%f %f l\n" + "h f\n", + t.vertex[0].xyz[0], t.vertex[0].xyz[1], + t.vertex[1].xyz[0], t.vertex[1].xyz[1], + t.vertex[2].xyz[0], t.vertex[2].xyz[1]); + } + } + /* Const alpha < 1 and const color: Simple PDF draw orders + and an extra extended Graphics State for the alpha const */ + else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ + gl2ps->streamlength += gl2psPrintf("q\n" + "/GS%d gs\n", + gro->gsno); + gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); + gl2ps->streamlength + += gl2psPrintf("%f %f m\n" + "%f %f l\n" + "%f %f l\n" + "h f\n", + t.vertex[0].xyz[0], t.vertex[0].xyz[1], + t.vertex[1].xyz[0], t.vertex[1].xyz[1], + t.vertex[2].xyz[0], t.vertex[2].xyz[1]); + } + gl2ps->streamlength += gl2psPrintf("Q\n"); + } + /* Variable alpha and const color: Simple PDF draw orders + and an extra extended Graphics State + Xobject + Shader + object for the alpha mask */ + else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ + gl2ps->streamlength += gl2psPrintf("q\n" + "/GS%d gs\n" + "/TrG%d Do\n", + gro->gsno, gro->trgroupno); + gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); + gl2ps->streamlength + += gl2psPrintf("%f %f m\n" + "%f %f l\n" + "%f %f l\n" + "h f\n", + t.vertex[0].xyz[0], t.vertex[0].xyz[1], + t.vertex[1].xyz[0], t.vertex[1].xyz[1], + t.vertex[2].xyz[0], t.vertex[2].xyz[1]); + } + gl2ps->streamlength += gl2psPrintf("Q\n"); + } + /* Variable color and no alpha: Shader Object for the colored + triangle(s) */ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ + gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno); + } + /* Variable color and const alpha < 1: Shader Object for the + colored triangle(s) and an extra extended Graphics State + for the alpha const */ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ + gl2ps->streamlength += gl2psPrintf("q\n" + "/GS%d gs\n" + "/Sh%d sh\n" + "Q\n", + gro->gsno, gro->shno); + } + /* Variable alpha and color: Shader Object for the colored + triangle(s) and an extra extended Graphics State + + Xobject + Shader object for the alpha mask */ + else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ + gl2ps->streamlength += gl2psPrintf("q\n" + "/GS%d gs\n" + "/TrG%d Do\n" + "/Sh%d sh\n" + "Q\n", + gro->gsno, gro->trgroupno, gro->shno); + } + break; + default: + break; + } + } } -int gl2psFlushPDFTriangles(){ +/* Graphics State names */ + +static int gl2psPDFgroupListWriteGStateResources(void) +{ + GL2PSpdfgroup *gro; int offs = 0; + int i; - if(gl2ps->lasttype == GL2PS_TRIANGLE && !gl2ps->last_triangle_finished){ - gl2psListAdd(gl2ps->tidxlist, &gl2ps->consec_inner_cnt); - offs = gl2psPrintf("/Sh%d sh\n", gl2ps->consec_cnt++); - gl2ps->consec_inner_cnt = 0; - gl2ps->streamlength += offs; - gl2ps->last_triangle_finished = 1; + offs += fprintf(gl2ps->stream, + "/ExtGState\n" + "<<\n" + "/GSa 7 0 R\n"); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + if(gro->gsno >= 0) + offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno); } + offs += fprintf(gl2ps->stream, ">>\n"); + return offs; +} + +/* Main Shader names */ + +static int gl2psPDFgroupListWriteShaderResources(void) +{ + GL2PSpdfgroup *gro; + int offs = 0; + int i; + + offs += fprintf(gl2ps->stream, + "/Shading\n" + "<<\n"); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + if(gro->shno >= 0) + offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno); + if(gro->maskshno >= 0) + offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno); + } + offs += fprintf(gl2ps->stream,">>\n"); return offs; } -int gl2psFlushPDFLines(){ +/* Images & Mask Shader XObject names */ + +static int gl2psPDFgroupListWriteXObjectResources(void) +{ + int i; + GL2PSprimitive *p = NULL; + GL2PSpdfgroup *gro; int offs = 0; - if(gl2ps->lasttype == GL2PS_LINE && !gl2ps->last_line_finished){ - offs = gl2psPrintf("S\n"); - gl2ps->streamlength += offs; - gl2ps->last_line_finished = 1; + offs += fprintf(gl2ps->stream, + "/XObject\n" + "<<\n"); + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + if(!gl2psListNbr(gro->ptrlist)) + continue; + p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); + switch(p->type){ + case GL2PS_PIXMAP: + gro->imobjno = gl2ps->objects_stack++; + if(GL_RGBA == p->data.image->format) /* reserve one object for image mask */ + gl2ps->objects_stack++; + offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno); + case GL2PS_TRIANGLE: + if(gro->trgroupno >=0) + offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno); + break; + default: + break; + } } + offs += fprintf(gl2ps->stream,">>\n"); return offs; } -/* The central primitive drawing */ +/* Font names */ -void gl2psPrintPDFPrimitive(void *data){ - GL2PSprimitive *prim; - GL2PStriangle t; - GL2PSimage* image; - GL2PSstring* str; +static int gl2psPDFgroupListWriteFontResources(void) +{ + int i; + GL2PSpdfgroup *gro; + int offs = 0; - prim = *(GL2PSprimitive**)data; + offs += fprintf(gl2ps->stream, "/Font\n<<\n"); + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + if(gro->fontno < 0) + continue; + gro->fontobjno = gl2ps->objects_stack++; + offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno); + } + offs += fprintf(gl2ps->stream, ">>\n"); + + return offs; +} + +static void gl2psPDFgroupListDelete(void) +{ + int i; + GL2PSpdfgroup *gro = NULL; - if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; + if(!gl2ps->pdfgrouplist) + return; + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i); + gl2psListDelete(gro->ptrlist); + } + + gl2psListDelete(gl2ps->pdfgrouplist); + gl2ps->pdfgrouplist = NULL; +} + +/* Print 1st PDF object - file info */ + +static int gl2psPrintPDFInfo(void) +{ + int offs; + time_t now; + struct tm *newtime; - if(prim->type != GL2PS_TRIANGLE) - gl2psFlushPDFTriangles(); - if(prim->type != GL2PS_LINE) - gl2psFlushPDFLines(); + time(&now); + newtime = gmtime(&now); - switch(prim->type){ - case GL2PS_PIXMAP : - image = gl2psCopyPixmap(prim->data.image); - gl2psListAdd(gl2ps->ilist, &image); - gl2ps->streamlength += gl2psPrintf("q\n" - "%d 0 0 %d %f %f cm\n" - "/Im%d Do\n" - "Q\n", - (int)prim->data.image->width, (int)prim->data.image->height, - prim->verts[0].xyz[0], prim->verts[0].xyz[1], - gl2psListNbr(gl2ps->ilist)-1); - break; - case GL2PS_TEXT : - str = gl2psCopyText(prim->data.text); - gl2psListAdd(gl2ps->slist, &str); - gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); - gl2ps->streamlength += gl2psPrintf("BT\n" - "/F%d %d Tf\n" - "%f %f Td\n" - "(%s) Tj\n" - "ET\n", - gl2psListNbr(gl2ps->slist)-1, - prim->data.text->fontsize, prim->verts[0].xyz[0], - prim->verts[0].xyz[1], prim->data.text->str); - break; - case GL2PS_POINT : - if(gl2ps->lastlinewidth != prim->width){ - gl2ps->lastlinewidth = prim->width; - gl2ps->streamlength += gl2psPrintPDFLineWidth(gl2ps->lastlinewidth); - } - gl2ps->streamlength += gl2psPrintf("1 J\n"); - gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); - gl2ps->streamlength += gl2psPrintf("%f %f m %f %f l S\n", - prim->verts[0].xyz[0], prim->verts[0].xyz[1], - prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - gl2ps->streamlength += gl2psPrintf("0 J\n"); - break; - case GL2PS_LINE : - gl2ps->line_width_diff = gl2ps->lastlinewidth != prim->width; - gl2ps->line_rgb_diff = !GL2PS_ZERO(gl2psColorDiff(prim->verts[0].rgba, gl2ps->lastrgba)); - - if(gl2ps->line_width_diff || gl2ps->line_rgb_diff || prim->dash){ - gl2psFlushPDFLines(); - } - if(gl2ps->line_width_diff){ - gl2ps->lastlinewidth = prim->width; - gl2ps->streamlength += gl2psPrintPDFLineWidth(gl2ps->lastlinewidth); - } - if(gl2ps->line_rgb_diff){ - gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); - } - if(prim->dash){ - gl2ps->streamlength += gl2psPrintf("[%d] 0 d\n", prim->dash); + offs = fprintf(gl2ps->stream, + "1 0 obj\n" + "<<\n" + "/Title (%s)\n" + "/Creator (%s)\n" + "/Producer (GL2PS %d.%d.%d, " + "(C) 1999-2004 Christophe Geuzaine <geuz@geuz.org>)\n", + gl2ps->title, gl2ps->producer, + GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION); + + if(!newtime){ + offs += fprintf(gl2ps->stream, + ">>\n" + "endobj\n"); + return offs; + } + + offs += fprintf(gl2ps->stream, + "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n" + ">>\n" + "endobj\n", + newtime->tm_year+1900, + newtime->tm_mon+1, + newtime->tm_mday, + newtime->tm_hour, + newtime->tm_min, + newtime->tm_sec); + return offs; +} + +/* Create catalog and page structure - 2nd and 3th PDF object */ + +static int gl2psPrintPDFCatalog(void) +{ + return fprintf(gl2ps->stream, + "2 0 obj\n" + "<<\n" + "/Type /Catalog\n" + "/Pages 3 0 R\n" + ">>\n" + "endobj\n"); +} + +static int gl2psPrintPDFPages(void) +{ + return fprintf(gl2ps->stream, + "3 0 obj\n" + "<<\n" + "/Type /Pages\n" + "/Kids [6 0 R]\n" + "/Count 1\n" + ">>\n" + "endobj\n"); +} + +/* Open stream for data - graphical objects, fonts etc. PDF object 4 */ + +static int gl2psOpenPDFDataStream(void) +{ + int offs = 0; + + offs += fprintf(gl2ps->stream, + "4 0 obj\n" + "<<\n" + "/Length 5 0 R\n" ); + offs += gl2psPrintPDFCompressorType(); + offs += fprintf(gl2ps->stream, + ">>\n" + "stream\n"); + return offs; +} + +/* Stream setup - Graphics state, fill background if allowed */ + +static int gl2psOpenPDFDataStreamWritePreface(void) +{ + int offs; + GLint index; + GLfloat rgba[4]; + + offs = gl2psPrintf("/GSa gs\n"); + + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ + if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ + glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); } - gl2ps->streamlength += gl2psPrintf("%f %f m %f %f l \n", - prim->verts[0].xyz[0], prim->verts[0].xyz[1], - prim->verts[1].xyz[0], prim->verts[1].xyz[1]); - gl2ps->last_line_finished = 0; - - if(prim->dash){ - gl2ps->streamlength += gl2psPrintf("S\n[] 0 d\n"); - gl2ps->last_line_finished = 1; + else{ + glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); + rgba[0] = gl2ps->colormap[index][0]; + rgba[1] = gl2ps->colormap[index][1]; + rgba[2] = gl2ps->colormap[index][2]; + rgba[3] = 0.0F; } - break; - case GL2PS_TRIANGLE : - t[0] = prim->verts[0]; - t[1] = prim->verts[1]; - t[2] = prim->verts[2]; - - gl2psListAdd(gl2ps->tlist, t); - ++gl2ps->consec_inner_cnt; - gl2ps->last_triangle_finished = 0; - break; - case GL2PS_QUADRANGLE : - gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); - break; - default : - gl2psMsg(GL2PS_ERROR, "Unknown type of primitive to print"); - break; + offs += gl2psPrintPDFFillColor(rgba); + offs += gl2psPrintf("%d %d %d %d re\n", + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); + offs += gl2psPrintf("f\n"); } - gl2ps->lasttype = prim->type; + return offs; +} + +/* Use the functions above to create the first part of the PDF*/ + +static void gl2psPrintPDFHeader(void) +{ + int offs = 0; + gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); + gl2psPDFstacksInit(); + + gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); + +#ifdef GL2PS_HAVE_ZLIB + if(gl2ps->options & GL2PS_COMPRESS){ + gl2psSetupCompress(); + } +#endif + gl2ps->xreflist[0] = 0; + offs += fprintf(gl2ps->stream, "%%PDF-1.4\n"); + gl2ps->xreflist[1] = offs; + + offs += gl2psPrintPDFInfo(); + gl2ps->xreflist[2] = offs; + + offs += gl2psPrintPDFCatalog(); + gl2ps->xreflist[3] = offs; + + offs += gl2psPrintPDFPages(); + gl2ps->xreflist[4] = offs; + + offs += gl2psOpenPDFDataStream(); + gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */ + gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface(); +} + +/* The central primitive drawing */ + +static void gl2psPrintPDFPrimitive(void *data) +{ + GL2PSprimitive *prim = *(GL2PSprimitive**)data; + + if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) + return; + + prim = gl2psCopyPrimitive(prim); /* deep copy */ + gl2psListAdd(gl2ps->pdfprimlist, &prim); } /* close stream and ... */ -int gl2psClosePDFDataStream(){ +static int gl2psClosePDFDataStream(void) +{ int offs = 0; - offs += gl2psFlushPDFTriangles(); - offs += gl2psFlushPDFLines(); - #ifdef GL2PS_HAVE_ZLIB if(gl2ps->options & GL2PS_COMPRESS){ if(Z_OK != gl2psDeflate()) @@ -2539,66 +3293,22 @@ int gl2psClosePDFDataStream(){ /* ... write the now known length object */ -int gl2psPrintPDFDataStreamLength(int val){ +static int gl2psPrintPDFDataStreamLength(int val) +{ return fprintf(gl2ps->stream, "5 0 obj\n" "%d\n" "endobj\n", val); } -/* Create named shader objects */ - -int gl2psPrintPDFShaderResources(int firstObject, int size){ - int offs = 0; - int i; - - offs += fprintf(gl2ps->stream, - "/Shading\n" - "<<\n"); - for(i = 0; i < size; ++i){ - offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", i, firstObject+i); - } - offs += fprintf(gl2ps->stream, ">>\n"); - return offs; -} - -/* Create named pixmap objects */ - -int gl2psPrintPDFPixmapResources(int firstObject, int size){ - int offs = 0; - int i; - - offs += fprintf(gl2ps->stream, - "/XObject\n" - "<<\n"); - for(i = 0; i < size; ++i){ - offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", i, firstObject + i); - } - offs += fprintf(gl2ps->stream, ">>\n"); - return offs; -} - -/* Create named font objects */ - -int gl2psPrintPDFTextResources(int firstObject, int size){ - int offs = 0; - int i; - - offs += fprintf(gl2ps->stream, - "/Font\n" - "<<\n"); - for(i = 0; i < size; ++i){ - offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", i, firstObject + i); - } - offs += fprintf(gl2ps->stream, ">>\n"); - return offs; -} - /* Put the info created before in PDF objects */ -int gl2psPrintPDFSinglePage(){ +static int gl2psPrintPDFOpenPage(void) +{ int offs; - + + /* Write fixed part */ + offs = fprintf(gl2ps->stream, "6 0 obj\n" "<<\n" @@ -2615,31 +3325,41 @@ int gl2psPrintPDFSinglePage(){ "/Contents 4 0 R\n" "/Resources\n" "<<\n" - "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n" - "/ExtGState\n" - "<<\n" - "/GS1 7 0 R\n" - ">>\n"); - - offs += gl2psPrintPDFShaderResources(GL2PS_FIXED_XREF_ENTRIES + 1, - gl2psListNbr(gl2ps->tidxlist)); - offs += gl2psPrintPDFPixmapResources(GL2PS_FIXED_XREF_ENTRIES + 1 - + gl2psListNbr(gl2ps->tidxlist), - gl2psListNbr(gl2ps->ilist)); - offs += gl2psPrintPDFTextResources(GL2PS_FIXED_XREF_ENTRIES + 1 - + gl2psListNbr(gl2ps->tidxlist) - + gl2psListNbr(gl2ps->ilist), - gl2psListNbr(gl2ps->slist)); - offs += fprintf(gl2ps->stream, + "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n"); + + return offs; + + /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */ +} + +static int gl2psPDFgroupListWriteVariableResources(void) +{ + int offs = 0; + + /* a) Graphics States for shader alpha masks*/ + offs += gl2psPDFgroupListWriteGStateResources(); + + /* b) Shader and shader masks */ + offs += gl2psPDFgroupListWriteShaderResources(); + + /* c) XObjects (Images & Shader Masks) */ + offs += gl2psPDFgroupListWriteXObjectResources(); + + /* d) Fonts */ + offs += gl2psPDFgroupListWriteFontResources(); + + /* End resources and page */ + offs += fprintf(gl2ps->stream, ">>\n" ">>\n" "endobj\n"); return offs; } -/* Extended graphics state for shading */ +/* Standard Graphics State */ -int gl2psPrintPDFExtGState(){ +static int gl2psPrintPDFGSObject(void) +{ return fprintf(gl2ps->stream, "7 0 obj\n" "<<\n" @@ -2656,88 +3376,202 @@ int gl2psPrintPDFExtGState(){ "endobj\n"); } -/* Put a triangles raw data in shader stream */ +/* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */ -int gl2psPrintPDFShaderStreamData(GL2PStriangle triangle, - size_t (*action)(unsigned long data, size_t size)){ +static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex* vertex, + size_t (*action)(unsigned long data, + size_t size), + GLfloat dx, GLfloat dy, + GLfloat xmin, GLfloat ymin) +{ int offs = 0; - int i; unsigned long imap; - GLfloat diff, dx, dy; + GLfloat diff; + double dmax = ~1UL; char edgeflag = 0; + + offs += (*action)(edgeflag, 1); + + /* The Shader stream in PDF requires to be in a 'big-endian' + order */ + + if(GL2PS_ZERO(dx*dy)){ + offs += (*action)(0, 4); + offs += (*action)(0, 4); + } + else{ + diff = (vertex->xyz[0] - xmin) / dx; + if(diff > 1) + diff = 1.0F; + else if(diff < 0) + diff = 0.0F; + imap = (unsigned long)(diff * dmax); + offs += (*action)(imap, 4); + + diff = (vertex->xyz[1] - ymin) / dy; + if(diff > 1) + diff = 1.0F; + else if(diff < 0) + diff = 0.0F; + imap = (unsigned long)(diff * dmax); + offs += (*action)(imap, 4); + } + + return offs; +} + +/* Put vertex' rgb value (8bit for every component) in shader stream */ + +static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex, + size_t (*action)(unsigned long data, + size_t size)) +{ + int offs = 0; + unsigned long imap; + double dmax = ~1UL; + + imap = (unsigned long)((vertex->rgba[0]) * dmax); + offs += (*action)(imap, 1); + + imap = (unsigned long)((vertex->rgba[1]) * dmax); + offs += (*action)(imap, 1); + + imap = (unsigned long)((vertex->rgba[2]) * dmax); + offs += (*action)(imap, 1); + + return offs; +} + +/* Put vertex' alpha (8/16bit) in shader stream */ + +static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex* vertex, + size_t (*action)(unsigned long data, + size_t size), + int sigbyte) +{ + int offs = 0; + unsigned long imap; double dmax = ~1UL; + + if(sigbyte!=8 && sigbyte!=16) + sigbyte = 8; + + sigbyte /= 8; - dx = (GLfloat)(gl2ps->viewport[2] - gl2ps->viewport[0]); - dy = (GLfloat)(gl2ps->viewport[3] - gl2ps->viewport[1]); + imap = (unsigned long)((vertex->rgba[3]) * dmax); - for(i = 0; i < 3; ++i){ - offs += (*action)(edgeflag, 1); + offs += (*action)(imap, sigbyte); + + return offs; +} - /* The Shader stream in PDF requires to be in a 'big-endian' - order */ - - if(fabs(dx*dy) < FLT_MIN){ - offs += (*action)(0, 4); - offs += (*action)(0, 4); +/* Put a triangles raw data in shader stream */ + +static int gl2psPrintPDFShaderStreamData(GL2PStriangle* triangle, + GLfloat dx, GLfloat dy, + GLfloat xmin, GLfloat ymin, + size_t (*action)(unsigned long data, + size_t size), + int gray) +{ + int i, offs = 0; + GL2PSvertex v; + + if(gray && gray != 8 && gray != 16) + gray = 8; + + for(i = 0; i < 3; ++i){ + offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action, + dx, dy, xmin, ymin); + if(gray){ + v = triangle->vertex[i]; + offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); } else{ - diff = (triangle[i].xyz[0] - gl2ps->viewport[0]) / dx; - if(diff > 1) - diff = 1; - else if(diff < 0) - diff = 0; - imap = (unsigned long)(diff * dmax); - offs += (*action)(imap, 4); - - diff = (triangle[i].xyz[1] - gl2ps->viewport[1]) / dy; - if(diff > 1) - diff = 1; - else if(diff < 0) - diff = 0; - imap = (unsigned long)(diff * dmax); - offs += (*action)(imap, 4); + offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action); } - - imap = (unsigned long)(triangle[i].rgba[0] * dmax); - offs += (*action)(imap, 1); - - imap = (unsigned long)(triangle[i].rgba[1] * dmax); - offs += (*action)(imap, 1); - - imap = (unsigned long)(triangle[i].rgba[2] * dmax); - offs += (*action)(imap, 1); } + return offs; } +static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, + GLfloat *ymin, GLfloat *ymax, + GL2PStriangle *triangles, int cnt) +{ + int i, j; -/* Writes shaded triangle */ + *xmin = triangles[0].vertex[0].xyz[0]; + *xmax = triangles[0].vertex[0].xyz[0]; + *ymin = triangles[0].vertex[0].xyz[1]; + *ymax = triangles[0].vertex[0].xyz[1]; + + for(i = 0; i < cnt; ++i){ + for(j = 0; j < 3; ++j){ + if(*xmin > triangles[i].vertex[j].xyz[0]) + *xmin = triangles[i].vertex[j].xyz[0]; + if(*xmax < triangles[i].vertex[j].xyz[0]) + *xmax = triangles[i].vertex[j].xyz[0]; + if(*ymin > triangles[i].vertex[j].xyz[1]) + *ymin = triangles[i].vertex[j].xyz[1]; + if(*ymax < triangles[i].vertex[j].xyz[1]) + *ymax = triangles[i].vertex[j].xyz[1]; + } + } +} -int gl2psPrintPDFShader(int obj, GL2PSlist* triangles, int idx, int cnt ){ - int offs = 0; - int vertexbytes = 1+4+4+1+1+1; - int i, done = 0; +/* Writes shaded triangle + gray == 0 means write RGB triangles + gray == 8 8bit-grayscale (for alpha masks) + gray == 16 16bit-grayscale (for alpha masks) */ + +static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, + int size, int gray) +{ + int i, offs = 0, vertexbytes, done = 0; + GLfloat xmin, xmax, ymin, ymax; + switch(gray){ + case 0: + vertexbytes = 1+4+4+1+1+1; + break; + case 8: + vertexbytes = 1+4+4+1; + break; + case 16: + vertexbytes = 1+4+4+2; + break; + default: + gray = 8; + vertexbytes = 1+4+4+1; + break; + } + + gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size); + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<< " "/ShadingType 4 " - "/ColorSpace /DeviceRGB " + "/ColorSpace %s " "/BitsPerCoordinate 32 " - "/BitsPerComponent 8 " + "/BitsPerComponent %d " "/BitsPerFlag 8 " - "/Decode [%d %d %d %d 0 1 0 1 0 1] ", + "/Decode [%f %f %f %f 0 1 %s] ", obj, - (int)gl2ps->viewport[0], (int)gl2ps->viewport[2], - (int)gl2ps->viewport[1], (int)gl2ps->viewport[3]); + (gray) ? "/DeviceGray" : "/DeviceRGB", + (gray) ? gray : 8, + xmin, xmax, ymin, ymax, + (gray) ? "" : "0 1 0 1"); #ifdef GL2PS_HAVE_ZLIB if(gl2ps->options & GL2PS_COMPRESS){ - gl2psAllocCompress(vertexbytes * cnt * 3); + gl2psAllocCompress(vertexbytes * size * 3); - for(i = 0; i < cnt; ++i) - gl2psPrintPDFShaderStreamData((GL2PSvertex*)gl2psListPointer(triangles, idx+i), - gl2psWriteBigEndianCompress); + for(i = 0; i < size; ++i) + gl2psPrintPDFShaderStreamData(&triangles[i], + xmax-xmin, ymax-ymin, xmin, ymin, + gl2psWriteBigEndianCompress,gray); if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ offs += gl2psPrintPDFCompressorType(); @@ -2746,7 +3580,8 @@ int gl2psPrintPDFShader(int obj, GL2PSlist* triangles, int idx, int cnt ){ ">>\n" "stream\n", (int)gl2ps->compress->destLen); - offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, + offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, + gl2ps->compress->destLen, 1, gl2ps->stream); done = 1; } @@ -2761,62 +3596,145 @@ int gl2psPrintPDFShader(int obj, GL2PSlist* triangles, int idx, int cnt ){ "/Length %d " ">>\n" "stream\n", - vertexbytes * 3 * cnt); - for(i = 0; i < cnt; ++i) - offs += gl2psPrintPDFShaderStreamData((GL2PSvertex*)gl2psListPointer(triangles, idx+i), - gl2psWriteBigEndian); + vertexbytes * 3 * size); + for(i = 0; i < size; ++i) + offs += gl2psPrintPDFShaderStreamData(&triangles[i], + xmax-xmin, ymax-ymin, xmin, ymin, + gl2psWriteBigEndian,gray); } offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); + + return offs; +} + +/* Writes a XObject for a shaded triangle mask */ +static int gl2psPrintPDFShaderMask(int obj, int childobj) +{ + int offs = 0, len; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n" + "/Type /XObject\n" + "/Subtype /Form\n" + "/BBox [ %d %d %d %d ]\n" + "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n" + ">>\n", + obj, + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); + + len = (childobj>0) + ? strlen("/TrSh sh\n") + (int)log10(childobj)+1 + : strlen("/TrSh0 sh\n"); + + offs += fprintf(gl2ps->stream, + "/Length %d\n" + ">>\n" + "stream\n", + len); + offs += fprintf(gl2ps->stream, + "/TrSh%d sh\n", + childobj); + offs += fprintf(gl2ps->stream, + "endstream\n" + "endobj\n"); + return offs; } -/* Writes all triangles and returns field of offsets for the PDF cross - reference table */ +/* Writes a Extended graphics state for a shaded triangle mask if + simplealpha ist true the childobj argument is ignored and a /ca + statement will be written instead */ -int* gl2psPrintPDFShaderObjects(int firstObjnumber, int firstOffs){ - int size; - int* offs; - int i; - int idx = 0; - int tmp; +static int gl2psPrintPDFShaderExtGS(int obj, int childobj) +{ + int offs = 0; - size = gl2psListNbr(gl2ps->tidxlist); - offs = (int*)gl2psMalloc(sizeof(int) * (size+1)); + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n", + obj); - offs[0] = firstOffs; + offs += fprintf(gl2ps->stream, + "/SMask << /S /Alpha /G %d 0 R >> ", + childobj); - for(i = 0; i < size; ++i){ - gl2psListRead(gl2ps->tidxlist, i, &tmp); - firstOffs += gl2psPrintPDFShader(i+firstObjnumber, gl2ps->tlist, idx, tmp); - offs[i+1] = firstOffs; - idx += tmp; - } + offs += fprintf(gl2ps->stream, + ">>\n" + "endobj\n"); + return offs; +} + +/* a simple graphics state */ + +static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha) +{ + int offs = 0; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n" + "/ca %g" + ">>\n" + "endobj\n", + obj, alpha); return offs; } /* Similar groups of functions for pixmaps and text */ -int gl2psPrintPDFPixmapStreamData(GL2PSimage* im, - size_t (*action)(unsigned long data, size_t size)){ +static int gl2psPrintPDFPixmapStreamData(GL2PSimage* im, + size_t (*action)(unsigned long data, + size_t size), + int gray) +{ int x, y; - GLfloat r, g, b; + GLfloat r, g, b, a; + + if(im->format != GL_RGBA && gray) + return 0; + + if(gray && gray !=8 && gray != 16) + gray = 8; + + gray /= 8; - for(y = 0; y < im->height; ++y) + for(y = 0; y < im->height; ++y){ for(x = 0; x < im->width; ++x){ - gl2psGetRGB(im->pixels, im->width, im->height, x, y, &r, &g, &b); - (*action)((unsigned long)(r*255) << 24,1); - (*action)((unsigned long)(g*255) << 24,1); - (*action)((unsigned long)(b*255) << 24,1); + a = gl2psGetRGB(im, x, y, &r, &g, &b); + if(im->format == GL_RGBA && gray){ + (*action)((unsigned long)(a*255) << 24, gray); + } + else{ + (*action)((unsigned long)(r*255) << 24, 1); + (*action)((unsigned long)(g*255) << 24, 1); + (*action)((unsigned long)(b*255) << 24, 1); + } } - return 3 * im->width * im->height; + } + + switch(gray){ + case 0: return 3 * im->width * im->height; + case 1: return im->width * im->height; + case 2: return 2 * im->width * im->height; + default: return 3 * im->width * im->height; + } } -int gl2psPrintPDFPixmap(int obj, GL2PSimage* im){ - int offs = 0, done = 0; +static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray) +{ + int offs = 0, done = 0, sigbytes = 3; + + if(gray && gray !=8 && gray != 16) + gray = 8; + + if(gray) + sigbytes = gray / 8; offs += fprintf(gl2ps->stream, "%d 0 obj\n" @@ -2825,15 +3743,22 @@ int gl2psPrintPDFPixmap(int obj, GL2PSimage* im){ "/Subtype /Image\n" "/Width %d\n" "/Height %d\n" - "/ColorSpace /DeviceRGB\n" + "/ColorSpace %s \n" "/BitsPerComponent 8\n", - obj, (int)im->width, (int)im->height); - + obj, + (int)im->width, (int)im->height, + (gray) ? "/DeviceGray" : "/DeviceRGB" ); + if(GL_RGBA == im->format && gray == 0){ + offs += fprintf(gl2ps->stream, + "/SMask %d 0 R\n", + childobj); + } + #ifdef GL2PS_HAVE_ZLIB if(gl2ps->options & GL2PS_COMPRESS){ - gl2psAllocCompress((int)(im->width * im->height * 3)); + gl2psAllocCompress((int)(im->width * im->height * sigbytes)); - gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress); + gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray); if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ offs += gl2psPrintPDFCompressorType(); @@ -2857,36 +3782,19 @@ int gl2psPrintPDFPixmap(int obj, GL2PSimage* im){ "/Length %d " ">>\n" "stream\n", - (int)(im->width * im->height * 3)); - offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian); + (int)(im->width * im->height * sigbytes)); + offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray); } offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); - - return offs; -} - -int* gl2psPrintPDFPixmapObjects(int firstObjnumber, int firstOffs){ - int size; - int* offs; - int i; - size = gl2psListNbr(gl2ps->ilist); - offs = (int*)gl2psMalloc(sizeof(int) * (size+1)); - - offs[0] = firstOffs; - - for(i = 0; i < size; ++i){ - firstOffs += gl2psPrintPDFPixmap(i+firstObjnumber, - *(GL2PSimage**)gl2psListPointer(gl2ps->ilist, i)); - offs[i+1] = firstOffs; - } return offs; } -int gl2psPrintPDFText(int obj, GL2PSstring* s, int fontnumber){ +static int gl2psPrintPDFText(int obj, GL2PSstring* s, int fontnumber) +{ int offs = 0; offs += fprintf(gl2ps->stream, @@ -2903,79 +3811,114 @@ int gl2psPrintPDFText(int obj, GL2PSstring* s, int fontnumber){ return offs; } -int* gl2psPrintPDFTextObjects(int firstObjnumber, int firstOffs){ - int size; - int* offs; - int i; - - size = gl2psListNbr(gl2ps->slist); - offs = (int*)gl2psMalloc(sizeof(int) * (size+1)); - - offs[0] = firstOffs; +/* Write the physical objects */ + +static int gl2psPDFgroupListWriteObjects(int entryoffs) +{ + int i,j; + GL2PSprimitive *p = NULL; + GL2PSpdfgroup *gro; + int offs = entryoffs; + GL2PStriangle *triangles; + int size = 0; + + if(!gl2ps->pdfgrouplist) + return offs; - for(i = 0; i < size; ++i){ - firstOffs += gl2psPrintPDFText(i+firstObjnumber, - *(GL2PSstring**)gl2psListPointer(gl2ps->slist, i), i); - offs[i+1] = firstOffs; + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + if(!gl2psListNbr(gro->ptrlist)) + continue; + p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); + switch(p->type){ + case GL2PS_PIXMAP: + gl2ps->xreflist[gro->imobjno] = offs; + offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0); + if(p->data.image->format == GL_RGBA){ + gl2ps->xreflist[gro->imobjno+1] = offs; + offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8); + } + break; + case GL2PS_TEXT: + gl2ps->xreflist[gro->fontobjno] = offs; + offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno); + break; + case GL2PS_TRIANGLE: + size = gl2psListNbr(gro->ptrlist); + triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size); + for(j = 0; j < size; ++j){ + p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE); + } + if(triangles[0].prop & T_VAR_COLOR){ + gl2ps->xreflist[gro->shobjno] = offs; + offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0); + } + if(triangles[0].prop & T_ALPHA_LESS_1){ + gl2ps->xreflist[gro->gsobjno] = offs; + offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]); + } + if(triangles[0].prop & T_VAR_ALPHA){ + gl2ps->xreflist[gro->gsobjno] = offs; + offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno); + gl2ps->xreflist[gro->trgroupobjno] = offs; + offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno); + gl2ps->xreflist[gro->maskshobjno] = offs; + offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8); + } + gl2psFree(triangles); + break; + case GL2PS_LINE: + break; + case GL2PS_POINT: + break; + default: + break; + } } return offs; } -/* All variable data is written at this point and all required - functioninality has been gathered: Writes file footer with cross - reference table and trailer */ +/* All variable data has been written at this point and all required + functioninality has been gathered, so we can write now file footer + with cross reference table and trailer */ -void gl2psPrintPDFFooter(){ - int offs; - int i; - int *shader_offs, *image_offs, *text_offs; - int shader_size, image_size, text_size, objnumber, lastoffset; - - offs = gl2ps->cref[4] + gl2ps->streamlength; +static void gl2psPrintPDFFooter(void) +{ + int i, offs; + + gl2psPDFgroupListInit(); + gl2psPDFgroupListWriteMainStream(); + + offs = gl2ps->xreflist[5] + gl2ps->streamlength; offs += gl2psClosePDFDataStream(); - gl2ps->cref[4] = offs; + gl2ps->xreflist[5] = offs; offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength); - gl2ps->cref[5] = offs; + gl2ps->xreflist[6] = offs; gl2ps->streamlength = 0; - offs += gl2psPrintPDFSinglePage(); - gl2ps->cref[6] = offs; - - offs += gl2psPrintPDFExtGState(); - - shader_size = gl2psListNbr(gl2ps->tidxlist); - image_size = gl2psListNbr(gl2ps->ilist); - text_size = gl2psListNbr(gl2ps->slist); + offs += gl2psPrintPDFOpenPage(); + offs += gl2psPDFgroupListWriteVariableResources(); + gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist, + sizeof(int) * (gl2ps->objects_stack + 1)); + gl2ps->xreflist[7] = offs; - shader_offs = gl2psPrintPDFShaderObjects(GL2PS_FIXED_XREF_ENTRIES + 1, offs); - image_offs = gl2psPrintPDFPixmapObjects(GL2PS_FIXED_XREF_ENTRIES + 1 + shader_size, - shader_offs[shader_size]); - text_offs = gl2psPrintPDFTextObjects(GL2PS_FIXED_XREF_ENTRIES + 1 + shader_size + image_size, - image_offs[image_size]); - - lastoffset = text_offs[text_size]; - objnumber = GL2PS_FIXED_XREF_ENTRIES + shader_size + image_size + text_size + 1; + offs += gl2psPrintPDFGSObject(); + gl2ps->xreflist[8] = offs; + gl2ps->xreflist[gl2ps->objects_stack] = + gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]); + /* Start cross reference table. The file has to been opened in binary mode to preserve the 20 digit string length! */ fprintf(gl2ps->stream, "xref\n" "0 %d\n" - "%010d 65535 f \n", objnumber, 0); + "%010d 65535 f \n", gl2ps->objects_stack, 0); - for(i = 0; i < GL2PS_FIXED_XREF_ENTRIES; ++i){ - fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->cref[i]); - } - for(i = 0; i < shader_size; ++i){ - fprintf(gl2ps->stream, "%010d 00000 n \n", shader_offs[i]); - } - for(i = 0; i < image_size; ++i){ - fprintf(gl2ps->stream, "%010d 00000 n \n", image_offs[i]); - } - for(i = 0; i < text_size; ++i){ - fprintf(gl2ps->stream, "%010d 00000 n \n", text_offs[i]); - } + for(i = 1; i < gl2ps->objects_stack; ++i) + fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]); fprintf(gl2ps->stream, "trailer\n" @@ -2986,21 +3929,13 @@ void gl2psPrintPDFFooter(){ ">>\n" "startxref\n%d\n" "%%%%EOF\n", - objnumber, lastoffset); - - /* Free auxiliary lists and arrays */ - gl2psFree(shader_offs); - gl2psFree(image_offs); - gl2psFree(text_offs); - gl2psListDelete(gl2ps->tlist); - gl2psListDelete(gl2ps->tidxlist); - for(i = 0; i < gl2psListNbr(gl2ps->ilist); ++i) - gl2psFreePixmap(*(GL2PSimage**)gl2psListPointer(gl2ps->ilist, i)); - gl2psListDelete(gl2ps->ilist); - for(i = 0; i < gl2psListNbr(gl2ps->slist); ++i) - gl2psFreeText(*(GL2PSstring**)gl2psListPointer(gl2ps->slist, i)); - gl2psListDelete(gl2ps->slist); - + gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]); + + /* Free auxiliary lists and arrays */ + gl2psFree(gl2ps->xreflist); + gl2psListDelete(gl2ps->pdfprimlist); + gl2psPDFgroupListDelete(); + #ifdef GL2PS_HAVE_ZLIB if(gl2ps->options & GL2PS_COMPRESS){ gl2psFreeCompress(); @@ -3012,7 +3947,8 @@ void gl2psPrintPDFFooter(){ /* PDF begin viewport */ -void gl2psPrintPDFBeginViewport(GLint viewport[4]){ +static void gl2psPrintPDFBeginViewport(GLint viewport[4]) +{ int offs; GLint index; GLfloat rgba[4]; @@ -3035,11 +3971,11 @@ void gl2psPrintPDFBeginViewport(GLint viewport[4]){ rgba[2] = gl2ps->colormap[index][2]; rgba[3] = 0.; } - offs += gl2psPrintf("%f %f %f rg\n" - "%d %d %d %d re\n" + offs += gl2psPrintPDFFillColor(rgba); + offs += gl2psPrintf("%d %d %d %d re\n" "W\n" "f\n", - rgba[0], rgba[1], rgba[2], x, y, w, h); + x, y, w, h); } else{ offs += gl2psPrintf("%d %d %d %d re\n" @@ -3047,16 +3983,15 @@ void gl2psPrintPDFBeginViewport(GLint viewport[4]){ "n\n", x, y, w, h); } - + gl2ps->streamlength += offs; } -GLint gl2psPrintPDFEndViewport(){ +static GLint gl2psPrintPDFEndViewport(void) +{ GLint res; res = gl2psPrintPrimitives(); - res += gl2psFlushPDFTriangles(); - res += gl2psFlushPDFLines(); gl2ps->streamlength += gl2psPrintf("Q\n"); @@ -3069,11 +4004,12 @@ GLint gl2psPrintPDFEndViewport(){ * *********************************************************************/ -GLint gl2psPrintPrimitives(void){ +static GLint gl2psPrintPrimitives(void) +{ GL2PSbsptree *root; GL2PSxyz eye = {0.0F, 0.0F, 100000.0F}; GLint used; - void (*pprim)(void *data) = 0; + void (*pprim)(void *data) = NULL; used = glRenderMode(GL_RENDER); @@ -3129,7 +4065,7 @@ GLint gl2psPrintPrimitives(void){ case GL2PS_BSP_SORT : root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); gl2psBuildBspTree(root, gl2ps->primitives); - if(gl2ps->boundary) gl2psBuildPolygonBoundary(root); + if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root); if(gl2ps->options & GL2PS_OCCLUSION_CULL){ gl2psTraverseBspTree(root, eye, -(float)GL2PS_EPSILON, gl2psLess, gl2psAddInImageTree, 1); @@ -3163,15 +4099,18 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint options, GLint colormode, GLint colorsize, GL2PSrgba *colormap, GLint nr, GLint ng, GLint nb, GLint buffersize, - FILE *stream, const char *filename){ + FILE *stream, const char *filename) +{ int i; + if(gl2ps){ + gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state"); + return GL2PS_ERROR; + } + gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext)); gl2ps->maxbestroot = 10; gl2ps->format = format; - gl2ps->title = title; - gl2ps->producer = producer; - gl2ps->filename = filename; gl2ps->sort = sort; gl2ps->options = options; gl2ps->compress = NULL; @@ -3195,7 +4134,14 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, gl2ps->lastlinewidth = -1.0F; gl2ps->imagetree = NULL; gl2ps->primitivetoadd = NULL; - gl2ps->zerosurfacearea = 0; + gl2ps->zerosurfacearea = GL_FALSE; + gl2ps->pdfprimlist = NULL; + gl2ps->pdfgrouplist = NULL; + gl2ps->xreflist = NULL; + + gl2ps->blending = glIsEnabled(GL_BLEND); + glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]); + glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]); if(gl2ps->colormode == GL_RGBA){ gl2ps->colorsize = 0; @@ -3233,14 +4179,12 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, rewind(gl2ps->stream); } - /* only used for PDF output... */ - gl2ps->lasttype = -1; - gl2ps->consec_cnt = 0; - gl2ps->consec_inner_cnt = 1; - gl2ps->line_width_diff = 1; - gl2ps->line_rgb_diff = 1; - gl2ps->last_line_finished = 0; - gl2ps->last_triangle_finished = 0; + gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char)); + strcpy(gl2ps->title, title); + gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char)); + strcpy(gl2ps->producer, producer); + gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char)); + strcpy(gl2ps->filename, filename); switch(gl2ps->format){ case GL2PS_TEX : @@ -3255,6 +4199,10 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, break; default : gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", gl2ps->format); + gl2psFree(gl2ps->colormap); + gl2psFree(gl2ps->title); + gl2psFree(gl2ps->producer); + gl2psFree(gl2ps->filename); gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; @@ -3268,7 +4216,8 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, return GL2PS_SUCCESS; } -GL2PSDLL_API GLint gl2psEndPage(void){ +GL2PSDLL_API GLint gl2psEndPage(void) +{ GLint res; if(!gl2ps) return GL2PS_UNINITIALIZED; @@ -3294,6 +4243,9 @@ GL2PSDLL_API GLint gl2psEndPage(void){ gl2psListDelete(gl2ps->primitives); gl2psFree(gl2ps->colormap); + gl2psFree(gl2ps->title); + gl2psFree(gl2ps->producer); + gl2psFree(gl2ps->filename); gl2psFree(gl2ps->feedback); gl2psFree(gl2ps); gl2ps = NULL; @@ -3301,7 +4253,8 @@ GL2PSDLL_API GLint gl2psEndPage(void){ return res; } -GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]){ +GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]) +{ if(!gl2ps) return GL2PS_UNINITIALIZED; switch(gl2ps->format){ @@ -3319,7 +4272,8 @@ GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]){ return GL2PS_SUCCESS; } -GL2PSDLL_API GLint gl2psEndViewport(void){ +GL2PSDLL_API GLint gl2psEndViewport(void) +{ GLint res; if(!gl2ps) return GL2PS_UNINITIALIZED; @@ -3340,8 +4294,10 @@ GL2PSDLL_API GLint gl2psEndViewport(void){ return res; } -GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, - GLint alignment, GL2PSrgba rgba){ +GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, + GLshort fontsize, GLint alignment, + GL2PSrgba rgba) +{ GLfloat pos[4]; GL2PSprimitive *prim; GLboolean valid; @@ -3351,15 +4307,15 @@ GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort f if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS; glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); - if(!valid) return GL2PS_SUCCESS; /* the primitive is culled */ + if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); - prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = GL2PS_TEXT; prim->boundary = 0; prim->numverts = 1; - prim->verts = (GL2PSvertex *)gl2psMalloc(sizeof(GL2PSvertex)); + prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); prim->verts[0].xyz[0] = pos[0]; prim->verts[0].xyz[1] = pos[1]; prim->verts[0].xyz[2] = GL2PS_DEPTH_FACT * pos[2]; @@ -3389,16 +4345,19 @@ GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort f return GL2PS_SUCCESS; } -GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize){ +GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, + GLshort fontsize) +{ return gl2psTextOpt(str, fontname, fontsize, GL2PS_TEXT_BL, NULL); } GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, GLenum format, GLenum type, - const void *pixels){ - int size; - GLfloat pos[4]; + const void *pixels) +{ + int size, i; + GLfloat pos[4], *piv; GL2PSprimitive *prim; GLboolean valid; @@ -3408,21 +4367,22 @@ GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS; - if(format != GL_RGB || type != GL_FLOAT){ - gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for GL_RGB, GL_FLOAT pixels"); + if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){ + gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for " + "GL_RGB/GL_RGBA, GL_FLOAT pixels"); return GL2PS_ERROR; } glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); - if(!valid) return GL2PS_SUCCESS; /* the primitive is culled */ + if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); - prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = GL2PS_PIXMAP; prim->boundary = 0; prim->numverts = 1; - prim->verts = (GL2PSvertex *)gl2psMalloc(sizeof(GL2PSvertex)); + prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); prim->verts[0].xyz[0] = pos[0] + xorig; prim->verts[0].xyz[1] = pos[1] + yorig; prim->verts[0].xyz[2] = GL2PS_DEPTH_FACT * pos[2]; @@ -3436,16 +4396,42 @@ GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, prim->data.image->height = height; prim->data.image->format = format; prim->data.image->type = type; - size = height*width*3*sizeof(GLfloat); /* FIXME: handle other types/formats */ - prim->data.image->pixels = (GLfloat*)gl2psMalloc(size); - memcpy(prim->data.image->pixels, pixels, size); + + switch(format){ + case GL_RGBA: + if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ + /* special case: blending turned off */ + prim->data.image->format = GL_RGB; + size = height * width * 3; + prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); + piv = (GLfloat*)pixels; + for(i = 0; i < size; ++i, ++piv){ + prim->data.image->pixels[i] = *piv; + if(!((i+1)%3)) + ++piv; + } + } + else{ + size = height * width * 4; + prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); + memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); + } + break; + case GL_RGB: + default: + size = height * width * 3; + prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); + memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); + break; + } gl2psListAdd(gl2ps->primitives, &prim); return GL2PS_SUCCESS; } -GL2PSDLL_API GLint gl2psEnable(GLint mode){ +GL2PSDLL_API GLint gl2psEnable(GLint mode) +{ if(!gl2ps) return GL2PS_UNINITIALIZED; switch(mode){ @@ -3460,6 +4446,9 @@ GL2PSDLL_API GLint gl2psEnable(GLint mode){ case GL2PS_LINE_STIPPLE : glPassThrough(GL2PS_BEGIN_LINE_STIPPLE); break; + case GL2PS_BLEND : + glPassThrough(GL2PS_BEGIN_BLEND); + break; default : gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode); return GL2PS_WARNING; @@ -3468,7 +4457,8 @@ GL2PSDLL_API GLint gl2psEnable(GLint mode){ return GL2PS_SUCCESS; } -GL2PSDLL_API GLint gl2psDisable(GLint mode){ +GL2PSDLL_API GLint gl2psDisable(GLint mode) +{ if(!gl2ps) return GL2PS_UNINITIALIZED; switch(mode){ @@ -3481,6 +4471,9 @@ GL2PSDLL_API GLint gl2psDisable(GLint mode){ case GL2PS_LINE_STIPPLE : glPassThrough(GL2PS_END_LINE_STIPPLE); break; + case GL2PS_BLEND : + glPassThrough(GL2PS_END_BLEND); + break; default : gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode); return GL2PS_WARNING; @@ -3489,7 +4482,8 @@ GL2PSDLL_API GLint gl2psDisable(GLint mode){ return GL2PS_SUCCESS; } -GL2PSDLL_API GLint gl2psPointSize(GLfloat value){ +GL2PSDLL_API GLint gl2psPointSize(GLfloat value) +{ if(!gl2ps) return GL2PS_UNINITIALIZED; glPassThrough(GL2PS_SET_POINT_SIZE); @@ -3498,7 +4492,8 @@ GL2PSDLL_API GLint gl2psPointSize(GLfloat value){ return GL2PS_SUCCESS; } -GL2PSDLL_API GLint gl2psLineWidth(GLfloat value){ +GL2PSDLL_API GLint gl2psLineWidth(GLfloat value) +{ if(!gl2ps) return GL2PS_UNINITIALIZED; glPassThrough(GL2PS_SET_LINE_WIDTH); @@ -3506,3 +4501,18 @@ GL2PSDLL_API GLint gl2psLineWidth(GLfloat value){ return GL2PS_SUCCESS; } + +GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor) +{ + if(!gl2ps) return GL2PS_UNINITIALIZED; + + if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor)) + return GL2PS_WARNING; + + glPassThrough(GL2PS_SRC_BLEND); + glPassThrough((GLfloat)sfactor); + glPassThrough(GL2PS_DST_BLEND); + glPassThrough((GLfloat)dfactor); + + return GL2PS_SUCCESS; +} diff --git a/Graphics/gl2ps.h b/Graphics/gl2ps.h index 111618fb83..edb7ff423c 100644 --- a/Graphics/gl2ps.h +++ b/Graphics/gl2ps.h @@ -1,7 +1,7 @@ -/* $Id: gl2ps.h,v 1.52 2003-11-16 16:49:37 geuzaine Exp $ */ +/* $Id: gl2ps.h,v 1.53 2004-05-09 19:00:11 geuzaine Exp $ */ /* * GL2PS, an OpenGL to PostScript Printing Library - * Copyright (C) 1999-2003 Christophe Geuzaine <geuz@geuz.org> + * Copyright (C) 1999-2004 Christophe Geuzaine <geuz@geuz.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of either: @@ -39,12 +39,17 @@ #include <stdlib.h> #include <math.h> -/* To generate a Windows dll, define GL2PSDLL at compile time */ +/* To generate a Windows dll, you should define GL2PSDLL at compile + time */ -#ifdef WIN32 +#if defined (WIN32) || defined(_WIN32) +/* Shut up warning due to bad windows header file */ +# if defined(_MSC_VER) +# pragma warning(disable:4115) +# endif # include <windows.h> -# ifdef GL2PSDLL -# ifdef GL2PSDLL_EXPORTS +# if defined(GL2PSDLL) +# if defined(GL2PSDLL_EXPORTS) # define GL2PSDLL_API __declspec(dllexport) # else # define GL2PSDLL_API __declspec(dllimport) @@ -56,17 +61,17 @@ # define GL2PSDLL_API #endif -#ifdef __APPLE__ +#if defined(__APPLE__) # include <OpenGL/gl.h> #else # include <GL/gl.h> #endif -/* Support for compressed PDF */ +/* Support for compressed PostScript/PDF */ #if defined(HAVE_ZLIB) || defined(HAVE_LIBZ) || defined(GL2PS_HAVE_ZLIB) # include <zlib.h> -# ifndef GL2PS_HAVE_ZLIB +# if !defined(GL2PS_HAVE_ZLIB) # define GL2PS_HAVE_ZLIB # endif #endif @@ -74,8 +79,8 @@ /* Version number */ #define GL2PS_MAJOR_VERSION 1 -#define GL2PS_MINOR_VERSION 1 -#define GL2PS_PATCH_VERSION 2 +#define GL2PS_MINOR_VERSION 2 +#define GL2PS_PATCH_VERSION 0 #define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \ 0.01 * GL2PS_MINOR_VERSION + \ @@ -94,6 +99,16 @@ #define GL2PS_SIMPLE_SORT 2 #define GL2PS_BSP_SORT 3 +/* Message levels and error codes */ + +#define GL2PS_SUCCESS 0 +#define GL2PS_INFO 1 +#define GL2PS_WARNING 2 +#define GL2PS_ERROR 3 +#define GL2PS_NO_FEEDBACK 4 +#define GL2PS_OVERFLOW 5 +#define GL2PS_UNINITIALIZED 6 + /* Options for gl2psBeginPage */ #define GL2PS_NONE 0 @@ -108,66 +123,26 @@ #define GL2PS_NO_PIXMAP (1<<8) #define GL2PS_USE_CURRENT_VIEWPORT (1<<9) #define GL2PS_COMPRESS (1<<10) +#define GL2PS_NO_BLENDING (1<<11) /* Arguments for gl2psEnable/gl2psDisable */ #define GL2PS_POLYGON_OFFSET_FILL 1 #define GL2PS_POLYGON_BOUNDARY 2 #define GL2PS_LINE_STIPPLE 3 - -/* Magic numbers */ - -#define GL2PS_EPSILON 5.0e-3F -#define GL2PS_DEPTH_FACT 1000.0F -#define GL2PS_SIMPLE_OFFSET 0.05F -#define GL2PS_SIMPLE_OFFSET_LARGE 1.0F -#define GL2PS_ZERO(arg) (fabs(arg)<1.e-20) -#define GL2PS_FIXED_XREF_ENTRIES 7 - -/* Message levels and error codes */ - -#define GL2PS_SUCCESS 0 -#define GL2PS_INFO 1 -#define GL2PS_WARNING 2 -#define GL2PS_ERROR 3 -#define GL2PS_NO_FEEDBACK 4 -#define GL2PS_OVERFLOW 5 -#define GL2PS_UNINITIALIZED 6 - -/* Primitive types */ - -#define GL2PS_NOTYPE -1 -#define GL2PS_TEXT 1 -#define GL2PS_POINT 2 -#define GL2PS_LINE 3 -#define GL2PS_QUADRANGLE 4 -#define GL2PS_TRIANGLE 5 -#define GL2PS_PIXMAP 6 +#define GL2PS_BLEND 4 /* Text alignment */ -#define GL2PS_TEXT_C 1 -#define GL2PS_TEXT_CL 2 -#define GL2PS_TEXT_CR 3 -#define GL2PS_TEXT_B 4 -#define GL2PS_TEXT_BL 5 -#define GL2PS_TEXT_BR 6 -#define GL2PS_TEXT_T 7 -#define GL2PS_TEXT_TL 8 -#define GL2PS_TEXT_TR 9 - -/* BSP tree primitive comparison */ - -#define GL2PS_COINCIDENT 1 -#define GL2PS_IN_FRONT_OF 2 -#define GL2PS_IN_BACK_OF 3 -#define GL2PS_SPANNING 4 - -/* 2D BSP tree primitive comparison */ - -#define GL2PS_POINT_COINCIDENT 0 -#define GL2PS_POINT_INFRONT 1 -#define GL2PS_POINT_BACK 2 +#define GL2PS_TEXT_C 1 +#define GL2PS_TEXT_CL 2 +#define GL2PS_TEXT_CR 3 +#define GL2PS_TEXT_B 4 +#define GL2PS_TEXT_BL 5 +#define GL2PS_TEXT_BR 6 +#define GL2PS_TEXT_T 7 +#define GL2PS_TEXT_TL 8 +#define GL2PS_TEXT_TR 9 /* Pass through options */ @@ -179,105 +154,14 @@ #define GL2PS_END_LINE_STIPPLE 6 #define GL2PS_SET_POINT_SIZE 7 #define GL2PS_SET_LINE_WIDTH 8 +#define GL2PS_BEGIN_BLEND 9 +#define GL2PS_END_BLEND 10 +#define GL2PS_SRC_BLEND 11 +#define GL2PS_DST_BLEND 12 typedef GLfloat GL2PSrgba[4]; -typedef GLfloat GL2PSxyz[3]; -typedef GLfloat GL2PSplane[4]; - -typedef struct _GL2PSbsptree2d GL2PSbsptree2d; - -struct _GL2PSbsptree2d { - GL2PSplane plane; - GL2PSbsptree2d *front, *back; -}; - -typedef struct { - GLint nmax, size, incr, n; - char *array; -} GL2PSlist; - -typedef struct _GL2PSbsptree GL2PSbsptree; - -struct _GL2PSbsptree { - GL2PSplane plane; - GL2PSlist *primitives; - GL2PSbsptree *front, *back; -}; - -typedef struct { - GL2PSxyz xyz; - GL2PSrgba rgba; -} GL2PSvertex; - -typedef GL2PSvertex GL2PStriangle[3]; - -typedef struct { - GLshort fontsize; - char *str, *fontname; - GLint alignment; -} GL2PSstring; - -typedef struct { - GLsizei width, height; - GLenum format, type; - GLfloat *pixels; -} GL2PSimage; - -typedef struct { - GLshort type, numverts; - char boundary, dash, culled; - GLfloat width, depth; - GL2PSvertex *verts; - union { - GL2PSstring *text; - GL2PSimage *image; - } data; -} GL2PSprimitive; - -typedef struct { -#ifdef GL2PS_HAVE_ZLIB - Bytef *dest, *src, *start; - uLongf destLen, srcLen; -#else - int dummy; -#endif -} GL2PScompress; - -typedef struct { - /* general */ - GLint format, sort, options, colorsize, colormode, buffersize; - const char *title, *producer, *filename; - GLboolean boundary; - GLfloat *feedback, offset[2], lastlinewidth; - GLint viewport[4]; - GL2PSrgba *colormap, lastrgba, threshold; - GL2PSlist *primitives; - FILE *stream; - GL2PScompress *compress; - - /* BSP-specific */ - GLint maxbestroot; - - /* occlusion culling-specific */ - GLboolean zerosurfacearea; - GL2PSbsptree2d *imagetree; - GL2PSprimitive *primitivetoadd; - - /* PDF-specific */ - int cref[GL2PS_FIXED_XREF_ENTRIES]; - int streamlength; - GL2PSlist *tlist, *tidxlist, *ilist, *slist; - int lasttype, consec_cnt, consec_inner_cnt; - int line_width_diff, line_rgb_diff, last_line_finished, last_triangle_finished; -} GL2PScontext; - -/* private prototypes */ - -GLint gl2psPrintPrimitives(void); - -/* public functions */ -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif @@ -290,7 +174,8 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GL2PSDLL_API GLint gl2psEndPage(void); GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]); GL2PSDLL_API GLint gl2psEndViewport(void); -GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize); +GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, + GLshort fontsize); GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, GLenum format, GLenum type, const void *pixels); @@ -298,12 +183,13 @@ GL2PSDLL_API GLint gl2psEnable(GLint mode); GL2PSDLL_API GLint gl2psDisable(GLint mode); GL2PSDLL_API GLint gl2psPointSize(GLfloat value); GL2PSDLL_API GLint gl2psLineWidth(GLfloat value); +GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor); /* Undocumented */ -GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, - GLint align, GL2PSrgba color); +GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, + GLshort fontsize, GLint align, GL2PSrgba color); -#ifdef __cplusplus +#if defined(__cplusplus) }; #endif -- GitLab