diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index 825245ee602eb8e2b7e73b3b553c809f8c3e2d88..9df72bd4921f90acd03d95ac6b49f84277974915 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -1349,7 +1349,7 @@ StringXNumber PrintOptions_Number[] = { { F|O, "EpsPS3Shading" , opt_print_eps_ps3shading , 0. , "Enable PostScript Level 3 shading" }, { F|O, "EpsQuality" , opt_print_eps_quality , 1. , - "PostScript/PDF quality (0=bitmap, 1=vector (simple sort), 2=vector (accurate sort)" }, + "PostScript/PDF quality (0=bitmap, 1=vector (simple sort), 2=vector (accurate sort), 3=vector (unsorted)" }, { F|O, "Format" , opt_print_format , FORMAT_AUTO , "File format (10=automatic)" }, diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h index 51dd647f5c41423120019feb5da9b2240c6c3c06..f09eacc03e71f23790f7bd4951ff3a1cb5b5753d 100644 --- a/Common/GmshDefines.h +++ b/Common/GmshDefines.h @@ -28,6 +28,7 @@ #define FORMAT_LC 26 #define FORMAT_STL 27 #define FORMAT_P3D 28 +#define FORMAT_SVG 29 #define CONV_VALUE 0.8 diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp index 330198107e6c214b4c897dd02920c57473a28cd9..03a6b3b43db2e7bb93cf1fbc843f1777a1c4ee90 100644 --- a/Fltk/Callbacks.cpp +++ b/Fltk/Callbacks.cpp @@ -1,4 +1,4 @@ -// $Id: Callbacks.cpp,v 1.419 2006-07-14 12:17:05 geuzaine Exp $ +// $Id: Callbacks.cpp,v 1.420 2006-07-24 14:05:50 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -704,6 +704,11 @@ int _save_pdftex(char *name) return gl2ps_dialog(name, "PDF Options", 2, 1); } +int _save_svg(char *name) +{ + return gl2ps_dialog(name, "SVG Options", 3, 0); +} + int _save_jpegtex(char *name) { return jpeg_dialog(name, 1); @@ -759,6 +764,7 @@ int _save_auto(char *name) case FORMAT_EPSTEX : return _save_epstex(name); case FORMAT_PDF : return _save_pdf(name); case FORMAT_PDFTEX : return _save_pdftex(name); + case FORMAT_SVG : return _save_svg(name); case FORMAT_JPEGTEX : return _save_jpegtex(name); case FORMAT_JPEG : return _save_jpeg(name); case FORMAT_GIF : return _save_gif(name); @@ -778,7 +784,7 @@ void file_save_as_cb(CALLBACK_ARGS) int i, nbformats; static char *pat = NULL; static patXfunc formats[] = { - {"By extension (*)", _save_auto}, + {"Guess from extension (*.*)", _save_auto}, {"Gmsh options (*.opt)", _save_options}, {"Gmsh unrolled geometry (*.geo)", _save_geo}, {"Gmsh mesh (*.msh)", _save_msh}, @@ -795,18 +801,19 @@ void file_save_as_cb(CALLBACK_ARGS) #if defined(HAVE_LIBPNG) {"PNG (*.png)", _save_png}, #endif - {"PS (*.ps)", _save_ps}, - {"EPS (*.eps)", _save_eps}, + {"PostScript (*.ps)", _save_ps}, + {"Encapsulated PostScript (*.eps)", _save_eps}, {"PDF (*.pdf)", _save_pdf}, + {"SVG (*.svg)", _save_svg}, {"PPM (*.ppm)", _save_ppm}, #if defined(HAVE_LIBJPEG) - {"LaTeX JPEG part w/o text (*.jpg)", _save_jpegtex}, + {"LaTeX JPEG part without text (*.jpg)", _save_jpegtex}, #endif #if defined(HAVE_LIBPNG) - {"LaTeX PNG part w/o text (*.png)", _save_pngtex}, + {"LaTeX PNG part without text (*.png)", _save_pngtex}, #endif - {"LaTeX EPS part w/o text (*.eps)", _save_epstex}, - {"LaTeX PDF part w/o text (*.pdf)", _save_pdftex}, + {"LaTeX EPS part without text (*.eps)", _save_epstex}, + {"LaTeX PDF part without text (*.pdf)", _save_pdftex}, {"LaTeX text part (*.tex)", _save_tex}, {"YUV (*.yuv)", _save_yuv} }; diff --git a/Fltk/GUI_Extras.cpp b/Fltk/GUI_Extras.cpp index 378cbe734f4581a0e38e93a3ad5d61d16948b9b9..efbbcbcbe931f5272afab014943983cb88c54263 100644 --- a/Fltk/GUI_Extras.cpp +++ b/Fltk/GUI_Extras.cpp @@ -1,4 +1,4 @@ -// $Id: GUI_Extras.cpp,v 1.15 2006-04-24 00:26:48 geuzaine Exp $ +// $Id: GUI_Extras.cpp,v 1.16 2006-07-24 14:05:50 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -339,25 +339,38 @@ int gif_dialog(char *name) // ps/eps/pdf dialog -static void activate_gl2ps_choices(int format, Fl_Check_Button *b[5]) +static void activate_gl2ps_choices(int format, int quality, Fl_Check_Button *b[5]) { #if defined(HAVE_LIBZ) b[0]->activate(); #else b[0]->deactivate(); #endif - switch(format){ - case 0: - b[1]->deactivate(); b[2]->deactivate(); - b[3]->deactivate(); b[4]->deactivate(); + switch(quality){ + case 0: // raster + b[1]->deactivate(); + b[2]->deactivate(); + b[3]->deactivate(); + b[4]->deactivate(); break; - case 1: - b[1]->activate(); b[2]->activate(); - b[3]->deactivate(); b[4]->activate(); + case 1: // simple sort + case 3: // unsorted + b[1]->activate(); + b[2]->activate(); + b[3]->deactivate(); + if(format == 2 || format == 3) // pdf or svg + b[4]->deactivate(); + else + b[4]->activate(); break; - case 2: - b[1]->activate(); b[2]->activate(); - b[3]->activate(); b[4]->activate(); + case 2: // bsp sort + b[1]->activate(); + b[2]->activate(); + b[3]->activate(); + if(format == 2 || format == 3) // pdf or svg + b[4]->deactivate(); + else + b[4]->activate(); break; } } @@ -376,6 +389,7 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX) {"Raster image", 0, 0, 0}, {"Vector simple sort", 0, 0, 0}, {"Vector accurate sort", 0, 0, 0}, + {"Vector unsorted", 0, 0, 0}, {0} }; @@ -412,7 +426,9 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX) dialog->b[2]->value(CTX.print.eps_occlusion_culling); dialog->b[3]->value(CTX.print.eps_best_root); dialog->b[4]->value(CTX.print.eps_ps3shading); - activate_gl2ps_choices(CTX.print.eps_quality, dialog->b); + + activate_gl2ps_choices(format, CTX.print.eps_quality, dialog->b); + dialog->window->show(); while(dialog->window->shown()){ @@ -422,7 +438,7 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX) if (!o) break; if (o == dialog->c){ - activate_gl2ps_choices(dialog->c->value(), dialog->b); + activate_gl2ps_choices(format, dialog->c->value(), dialog->b); } if (o == dialog->ok) { opt_print_eps_quality(0, GMSH_SET | GMSH_GUI, dialog->c->value()); @@ -432,6 +448,7 @@ int gl2ps_dialog(char *name, char *title, int format, int TeX) opt_print_eps_best_root(0, GMSH_SET | GMSH_GUI, dialog->b[3]->value()); opt_print_eps_ps3shading(0, GMSH_SET | GMSH_GUI, dialog->b[4]->value()); CreateOutputFile(name, + (format == 3) ? FORMAT_SVG : (format == 2) ? (TeX ? FORMAT_PDFTEX : FORMAT_PDF) : (format == 1) ? (TeX ? FORMAT_EPSTEX : FORMAT_EPS) : FORMAT_PS); diff --git a/Geo/gmshEdge.cpp b/Geo/gmshEdge.cpp index 478650250a56d7299ced3905062769dd49e0b40a..e5a954f34a3547b7af80359a001afc95f0946098 100644 --- a/Geo/gmshEdge.cpp +++ b/Geo/gmshEdge.cpp @@ -145,5 +145,8 @@ int gmshEdge::minimumMeshSegments () const int gmshEdge::minimumDrawSegments () const { - return CTX.geom.circle_points; + if(geomType() == Line) + return GEdge::minimumDrawSegments () ; + else + return CTX.geom.circle_points; } diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp index e023b841559c7318ec9e17025d277ffd0ee29853..4981a1ea8f5ee547c819bfe8d59286329d035a53 100644 --- a/Graphics/CreateFile.cpp +++ b/Graphics/CreateFile.cpp @@ -1,4 +1,4 @@ -// $Id: CreateFile.cpp,v 1.82 2006-07-14 12:17:06 geuzaine Exp $ +// $Id: CreateFile.cpp,v 1.83 2006-07-24 14:05:50 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -68,6 +68,7 @@ int GuessFileFormatFromFileName(char *name) else if(!strcmp(ext, ".epstex")) return FORMAT_EPSTEX; else if(!strcmp(ext, ".pdftex")) return FORMAT_PDFTEX; else if(!strcmp(ext, ".jpegtex")) return FORMAT_JPEGTEX; + else if(!strcmp(ext, ".svg")) return FORMAT_SVG; else if(!strcmp(ext, ".ppm")) return FORMAT_PPM; else if(!strcmp(ext, ".yuv")) return FORMAT_YUV; else if(!strcmp(ext, ".gref")) return FORMAT_GREF; @@ -91,6 +92,7 @@ char *GetStringForFileFormat(int format) case FORMAT_EPSTEX: return "EPS"; case FORMAT_PDF: return "PDF"; case FORMAT_PDFTEX: return "PDF"; + case FORMAT_SVG: return "SVG"; default: return ""; } } @@ -151,13 +153,16 @@ void CreateOutputFile(char *name, int format) return; } + PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE); + + int old_bg_gradient = CTX.bg_gradient; + if(format == FORMAT_GIF && CTX.print.gif_transparent) + CTX.bg_gradient = 0; if(format == FORMAT_JPEGTEX || format == FORMAT_PNGTEX) CTX.print.gl_fonts = 0; - - PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE); buffer.Fill(CTX.batch); - CTX.print.gl_fonts = 1; + CTX.bg_gradient = old_bg_gradient; Msg(INFO, "Writing %s file '%s'", GetStringForFileFormat(format), name); if(format == FORMAT_PPM){ @@ -194,6 +199,7 @@ void CreateOutputFile(char *name, int format) case FORMAT_EPSTEX: case FORMAT_PDF: case FORMAT_PDFTEX: + case FORMAT_SVG: { FILE *fp; if(!(fp = fopen(name, "wb"))) { @@ -210,10 +216,16 @@ void CreateOutputFile(char *name, int format) case FORMAT_PS: psformat = GL2PS_PS; break; + case FORMAT_SVG: + psformat = GL2PS_SVG; + break; default: psformat = GL2PS_EPS; break; } + + int old_bg_gradient = CTX.bg_gradient; + if(!CTX.print.eps_background) CTX.bg_gradient = 0; PixelBuffer buffer(width, height, GL_RGB, GL_FLOAT); @@ -224,9 +236,12 @@ void CreateOutputFile(char *name, int format) CTX.print.gl_fonts = 1; } - int pssort = (CTX.print.eps_quality == 2) ? GL2PS_BSP_SORT : GL2PS_SIMPLE_SORT; + int pssort = + (CTX.print.eps_quality == 3) ? GL2PS_NO_SORT : + (CTX.print.eps_quality == 2) ? GL2PS_BSP_SORT : + GL2PS_SIMPLE_SORT; int psoptions = - GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | GL2PS_NO_BLENDING | + GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | (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) | @@ -237,13 +252,13 @@ void CreateOutputFile(char *name, int format) Msg(INFO, "Writing %s file '%s'", GetStringForFileFormat(format), name); - GLint size3d = 0; + GLint buffsize = 0; int res = GL2PS_OVERFLOW; while(res == GL2PS_OVERFLOW) { - size3d += 2048 * 2048; + buffsize += 2048 * 2048; gl2psBeginPage(CTX.base_filename, "Gmsh", viewport, psformat, pssort, psoptions, GL_RGBA, 0, NULL, - 15, 20, 10, size3d, fp, name); + 15, 20, 10, buffsize, fp, name); if(CTX.print.eps_quality == 0){ double modelview[16], projection[16]; glGetDoublev(GL_PROJECTION_MATRIX, projection); @@ -269,6 +284,8 @@ void CreateOutputFile(char *name, int format) res = gl2psEndPage(); } + CTX.bg_gradient = old_bg_gradient; + Msg(INFO, "Wrote %s file '%s'", GetStringForFileFormat(format), name); Msg(STATUS2N, "Wrote '%s'", name); fclose(fp); @@ -283,14 +300,20 @@ void CreateOutputFile(char *name, int format) return; } Msg(INFO, "Writing TEX file '%s'", name); - gl2psBeginPage(CTX.base_filename, "Gmsh", viewport, - GL2PS_TEX, GL2PS_NO_SORT, GL2PS_SILENT, GL_RGBA, 0, NULL, - 0, 0, 0, 1000, fp, name); - CTX.print.gl_fonts = 0; - PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE); - buffer.Fill(CTX.batch); - CTX.print.gl_fonts = 1; - gl2psEndPage(); + + GLint buffsize = 0; + int res = GL2PS_OVERFLOW; + while(res == GL2PS_OVERFLOW) { + buffsize += 2048 * 2048; + gl2psBeginPage(CTX.base_filename, "Gmsh", viewport, + GL2PS_TEX, GL2PS_NO_SORT, GL2PS_NONE, GL_RGBA, 0, NULL, + 0, 0, 0, buffsize, fp, name); + PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE); + CTX.print.gl_fonts = 0; + buffer.Fill(CTX.batch); + CTX.print.gl_fonts = 1; + res = gl2psEndPage(); + } Msg(INFO, "Wrote TEX file '%s'", name); Msg(STATUS2N, "Wrote '%s'", name); fclose(fp); @@ -303,4 +326,5 @@ void CreateOutputFile(char *name, int format) } CTX.print.format = oldformat; + Draw(); } diff --git a/Graphics/Geom.cpp b/Graphics/Geom.cpp index 6eff60b973fd438bc78738d3661b51bcb3434776..fc5c431287e96182bc4b1da59e2dc76f21e737bd 100644 --- a/Graphics/Geom.cpp +++ b/Graphics/Geom.cpp @@ -1,4 +1,4 @@ -// $Id: Geom.cpp,v 1.100 2006-07-14 12:17:06 geuzaine Exp $ +// $Id: Geom.cpp,v 1.101 2006-07-24 14:05:50 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -39,7 +39,7 @@ extern GModel *GMODEL; // Points -void Draw_Geo_Vertex(GVertex *v) +void drawGeoVertex(GVertex *v) { if(!(v->drawAttributes.Visible & VIS_GEOM)) return; @@ -105,7 +105,7 @@ void Draw_Geo_Vertex(GVertex *v) // Curves -void Draw_Geo_Edge(GEdge *c) +void drawGeoEdge(GEdge *c) { if(c->tag() < 0 || !(c->drawAttributes.Visible & VIS_GEOM)) return; @@ -532,7 +532,7 @@ void Draw_NonPlane_Surface(Surface * s) } } -void Draw_Geo_Face(GFace *s) +void drawGeoFace(GFace *s) { if(!(s->drawAttributes.Visible & VIS_GEOM)) return; @@ -573,7 +573,7 @@ void Draw_Geo_Face(GFace *s) // Volumes -void Draw_Geo_Region(GRegion *v) +void drawGeoRegion(GRegion *v) { } @@ -585,19 +585,19 @@ void Draw_Geom() if(CTX.geom.points || CTX.geom.points_num) for(GModel::viter it = GMODEL->firstVertex(); it != GMODEL->lastVertex(); it++) - Draw_Geo_Vertex(*it); + drawGeoVertex(*it); if(CTX.geom.lines || CTX.geom.lines_num || CTX.geom.tangents) for(GModel::eiter it = GMODEL->firstEdge(); it != GMODEL->lastEdge(); it++) - Draw_Geo_Edge(*it); + drawGeoEdge(*it); if(CTX.geom.surfaces || CTX.geom.surfaces_num || CTX.geom.normals) for(GModel::fiter it = GMODEL->firstFace(); it != GMODEL->lastFace(); it++) - Draw_Geo_Face(*it); + drawGeoFace(*it); if(CTX.geom.volumes || CTX.geom.volumes_num) for(GModel::riter it = GMODEL->firstRegion(); it != GMODEL->lastRegion(); it++) - Draw_Geo_Region(*it); + drawGeoRegion(*it); } // Highlight routines (Note: in Gmsh < 1.61, we used to draw permanent diff --git a/Graphics/gl2ps.cpp b/Graphics/gl2ps.cpp index 86d290e4e245c84ddfa1ff62ae62c5efaa740b9c..4dbfc499722aa05faf3c4299b70115a999812682 100644 --- a/Graphics/gl2ps.cpp +++ b/Graphics/gl2ps.cpp @@ -1,4 +1,4 @@ -/* $Id: gl2ps.cpp,v 1.104 2006-02-27 18:39:45 geuzaine Exp $ */ +/* $Id: gl2ps.cpp,v 1.105 2006-07-24 14:05:50 geuzaine Exp $ */ /* * GL2PS, an OpenGL to PostScript Printing Library * Copyright (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org> @@ -47,6 +47,8 @@ * Olivier Couet <couet@mail.cern.ch> * Shai Ayal <shaiay@gmail.com> * Fabian Wenzel <wenzel@tu-harburg.de> + * Ian D. Gay <gay@sfu.ca> + * Cosmin Truta and Baiju Devani <cosmin@cs.toronto.edu> * * For the latest info about gl2ps, see http://www.geuz.org/gl2ps/. * Please report all bugs and problems to <gl2ps@geuz.org>. @@ -61,6 +63,14 @@ #include <time.h> #include <float.h> +#if defined(GL2PS_HAVE_ZLIB) +#include <zlib.h> +#endif + +#if defined(GL2PS_HAVE_LIBPNG) +#include <png.h> +#endif + /********************************************************************* * * Private definitions, data structures and prototypes @@ -78,7 +88,7 @@ /* Primitive types */ -#define GL2PS_NOTYPE -1 +#define GL2PS_NO_TYPE -1 #define GL2PS_TEXT 1 #define GL2PS_POINT 2 #define GL2PS_LINE 3 @@ -88,6 +98,7 @@ #define GL2PS_IMAGEMAP 7 #define GL2PS_IMAGEMAP_WRITTEN 8 #define GL2PS_IMAGEMAP_VISIBLE 9 +#define GL2PS_SPECIAL 10 /* BSP tree primitive comparison */ @@ -102,21 +113,24 @@ #define GL2PS_POINT_INFRONT 1 #define GL2PS_POINT_BACK 2 -/* Pass through options */ - -#define GL2PS_BEGIN_POLYGON_OFFSET_FILL 1 -#define GL2PS_END_POLYGON_OFFSET_FILL 2 -#define GL2PS_BEGIN_POLYGON_BOUNDARY 3 -#define GL2PS_END_POLYGON_BOUNDARY 4 -#define GL2PS_BEGIN_LINE_STIPPLE 5 -#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 -#define GL2PS_DRAW_IMAGEMAP_TOKEN 13 +/* Internal feedback buffer pass-through tokens */ + +#define GL2PS_BEGIN_OFFSET_TOKEN 1 +#define GL2PS_END_OFFSET_TOKEN 2 +#define GL2PS_BEGIN_BOUNDARY_TOKEN 3 +#define GL2PS_END_BOUNDARY_TOKEN 4 +#define GL2PS_BEGIN_STIPPLE_TOKEN 5 +#define GL2PS_END_STIPPLE_TOKEN 6 +#define GL2PS_POINT_SIZE_TOKEN 7 +#define GL2PS_LINE_WIDTH_TOKEN 8 +#define GL2PS_BEGIN_BLEND_TOKEN 9 +#define GL2PS_END_BLEND_TOKEN 10 +#define GL2PS_SRC_BLEND_TOKEN 11 +#define GL2PS_DST_BLEND_TOKEN 12 +#define GL2PS_IMAGEMAP_TOKEN 13 +#define GL2PS_DRAW_PIXELS_TOKEN 14 +#define GL2PS_TEXT_TOKEN 15 +#define GL2PS_SPECIAL_TOKEN 16 typedef enum { T_UNDEFINED = -1, @@ -163,15 +177,17 @@ typedef struct { typedef struct { GLshort fontsize; char *str, *fontname; + /* Note: for a 'special' string, 'alignment' holds the format + (PostScript, PDF, etc.) of the special string */ GLint alignment; GLfloat angle; } GL2PSstring; -/* FIXME: in the case of an image map, "type" indicates if this image - map has already been written to the PostScript file or not, and - "format" indicates if this image map is visible or not */ typedef struct { GLsizei width, height; + /* Note: for an imagemap, 'type' indicates if it has already been + written to the file or not, and 'format' indicates if it is + visible or not */ GLenum format, type; GLfloat *pixels; } GL2PSimage; @@ -197,7 +213,7 @@ typedef struct { } GL2PSprimitive; typedef struct { -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) Bytef *dest, *src, *start; uLongf destLen, srcLen; #else @@ -221,7 +237,7 @@ typedef struct { GL2PSrgba *colormap, lastrgba, threshold, bgcolor; GLushort lastpattern; GL2PSvertex lastvertex; - GL2PSlist *primitives; + GL2PSlist *primitives, *auxprimitives; FILE *stream; GL2PScompress *compress; GLboolean header; @@ -267,7 +283,7 @@ typedef struct { static GL2PScontext *gl2ps = NULL; -/* Need to forward declare this one */ +/* Need to forward-declare this one */ static GLint gl2psPrintPrimitives(void); @@ -277,7 +293,7 @@ static GLint gl2psPrintPrimitives(void); * *********************************************************************/ -static void gl2psMsg(GLint level, char *fmt, ...) +static void gl2psMsg(GLint level, const char *fmt, ...) { va_list args; @@ -325,9 +341,19 @@ static void gl2psFree(void *ptr) free(ptr); } +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){ + fputc(0xff & (data >> (size-i) * 8), gl2ps->stream); + } + return bytes; +} + /* zlib compression helper routines */ -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) static void gl2psSetupCompress(void) { @@ -413,7 +439,7 @@ static int gl2psPrintf(const char* fmt, ...) int ret; va_list args; -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) unsigned int oldsize = 0; static char buf[1000]; if(gl2ps->options & GL2PS_COMPRESS){ @@ -430,72 +456,68 @@ static int gl2psPrintf(const char* fmt, ...) va_start(args, fmt); ret = vfprintf(gl2ps->stream, fmt, args); va_end(args); -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) } #endif return ret; } -static size_t gl2psWriteBigEndian(unsigned long data, size_t bytes) +static void gl2psPrintGzipHeader() { - size_t i; - size_t size = sizeof(unsigned long); - for(i = 1; i <= bytes; ++i){ - fputc(0xff & (data >> (size-i) * 8), gl2ps->stream); +#if defined(GL2PS_HAVE_ZLIB) + char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */ + 8, /* compression method: Z_DEFLATED */ + 0, /* flags */ + 0, 0, 0, 0, /* time */ + 2, /* extra flags: max compression */ + '\x03'}; /* OS code: 0x03 (Unix) */ + + if(gl2ps->options & GL2PS_COMPRESS){ + gl2psSetupCompress(); + /* add the gzip file header */ + fwrite(tmp, 10, 1, gl2ps->stream); } - return bytes; +#endif } -static void gl2psAssignTriangleProperties(GL2PStriangle *t) +static void gl2psPrintGzipFooter() { - /* int i; */ - - t->prop = T_VAR_COLOR; +#if defined(GL2PS_HAVE_ZLIB) + int n; + uLong crc, len; + char tmp[8]; - /* 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->options & GL2PS_COMPRESS){ + if(Z_OK != gl2psDeflate()){ + gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); } + else{ + /* determine the length of the header in the zlib stream */ + n = 2; /* CMF+FLG */ + if(gl2ps->compress->dest[1] & (1<<5)){ + n += 4; /* DICTID */ + } + /* write the data, without the zlib header and footer */ + fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), + 1, gl2ps->stream); + /* add the gzip file footer */ + crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen); + for(n = 0; n < 4; ++n){ + tmp[n] = (char)(crc & 0xff); + crc >>= 8; + } + len = gl2ps->compress->srcLen; + for(n = 4; n < 8; ++n){ + tmp[n] = (char)(len & 0xff); + len >>= 8; + } + fwrite(tmp, 8, 1, gl2ps->stream); + } + gl2psFreeCompress(); + gl2psFree(gl2ps->compress); + gl2ps->compress = NULL; } - */ - - 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); -} - -static void gl2psInitTriangle(GL2PStriangle *t) -{ - int i; - GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} }; - for(i = 0; i < 3; i++) - t->vertex[i] = vertex; - t->prop = T_UNDEFINED; +#endif } /* The list handling routines */ @@ -606,7 +628,133 @@ static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)) } } -/* Helper for pixmaps and strings */ +#if defined(GL2PS_HAVE_LIBPNG) + +static void gl2psListRead(GL2PSlist *list, int index, void *data) +{ + if((index < 0) || (index >= list->n)) + gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead"); + memcpy(data, &list->array[index * list->size], list->size); +} + +static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len) +{ + static const char cb64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + out[0] = cb64[ in[0] >> 2 ]; + out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; + out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | + ((in[2] & 0xc0) >> 6) ] : '='); + out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); +} + +static void gl2psListEncodeBase64(GL2PSlist *list) +{ + unsigned char *buffer, in[3], out[4]; + int i, n, index, len; + + n = list->n * list->size; + buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned int)); + memcpy(buffer, list->array, n * sizeof(unsigned int)); + gl2psListReset(list); + + index = 0; + while(index < n) { + len = 0; + for(i = 0; i < 3; i++) { + in[i] = buffer[index++]; + if(index < n) + len++; + else + in[i] = 0; + } + if(len) { + gl2psEncodeBase64Block(in, out, len); + for(i = 0; i < 4; i++) + gl2psListAdd(list, &out[i]); + } + } + gl2psFree(buffer); +} + +#endif + +/* Helpers for rgba colors */ + +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; +} + +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 GL_FALSE; + } + } + return GL_TRUE; +} + +static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[], + GL2PSrgba threshold) +{ + int i; + + if(n < 2) return GL_TRUE; + + for(i = 1; i < n; i++){ + if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] || + fabs(rgba[0][1] - rgba[i][1]) > threshold[1] || + fabs(rgba[0][2] - rgba[i][2]) > threshold[2]) + return GL_FALSE; + } + + return GL_TRUE; +} + +static void gl2psSetLastColor(GL2PSrgba rgba) +{ + int i; + for(i = 0; i < 3; ++i){ + gl2ps->lastrgba[i] = rgba[i]; + } +} + +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; + + /* 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++; + + return (im->format == GL_RGBA) ? *pimag : 1.0F; +} + +/* Helper routines for pixmaps */ static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im) { @@ -642,117 +790,166 @@ static void gl2psFreePixmap(GL2PSimage *im) gl2psFree(im); } -static GL2PSstring *gl2psCopyText(GL2PSstring *t) +#if defined(GL2PS_HAVE_LIBPNG) + +#if !defined(png_jmpbuf) +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length) { - 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)); - strcpy(text->fontname, t->fontname); - text->fontsize = t->fontsize; - text->alignment = t->alignment; - text->angle = t->angle; - - return text; + unsigned int i; + GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr); + for(i = 0; i < length; i++) + gl2psListAdd(png, &data[i]); } -static void gl2psFreeText(GL2PSstring *text) +static void gl2psUserFlushPNG(png_structp png_ptr) { - if(!text) - return; - gl2psFree(text->str); - gl2psFree(text->fontname); - gl2psFree(text); } -static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p) +static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png) { - GL2PSprimitive *prim; + png_structp png_ptr; + png_infop info_ptr; + unsigned char *row_data; + GLfloat dr, dg, db; + int row, col; - if(!p){ - gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive"); - return NULL; + if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) + return; + + if(!(info_ptr = png_create_info_struct(png_ptr))){ + png_destroy_write_struct(&png_ptr, NULL); + return; } - - prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - prim->type = p->type; - prim->numverts = p->numverts; - prim->boundary = p->boundary; - prim->offset = p->offset; - prim->pattern = p->pattern; - prim->factor = p->factor; - prim->culled = p->culled; - prim->width = p->width; - 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; + if(setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + return; + } + + png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG); + png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + png_write_info(png_ptr, info_ptr); + + row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char)); + for(row = 0; row < pixmap->height; row++){ + for(col = 0; col < pixmap->width; col++){ + gl2psGetRGB(pixmap, col, row, &dr, &dg, &db); + row_data[3*col] = (unsigned char)(255. * dr); + row_data[3*col+1] = (unsigned char)(255. * dg); + row_data[3*col+2] = (unsigned char)(255. * db); + } + png_write_row(png_ptr, (png_bytep)row_data); } + gl2psFree(row_data); - return prim; + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); } -/* Helpers for rgba colors and PDF blending */ +#endif -static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2) +/* Helper routines for text strings */ + +static GLint gl2psAddText(GLint type, const char *str, const char *fontname, + GLshort fontsize, GLint alignment, GLfloat angle) { - 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; + GLfloat pos[4]; + GL2PSprimitive *prim; + GLboolean valid; + + if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED; + + if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS; + + glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); + if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ + + glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); + + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + prim->type = type; + prim->boundary = 0; + prim->numverts = 1; + 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] = pos[2]; + prim->culled = 0; + prim->offset = 0; + prim->pattern = 0; + prim->factor = 0; + prim->width = 1; + glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); + prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); + prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char)); + strcpy(prim->data.text->str, str); + prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); + strcpy(prim->data.text->fontname, fontname); + prim->data.text->fontsize = fontsize; + prim->data.text->alignment = alignment; + prim->data.text->angle = angle; + + gl2psListAdd(gl2ps->auxprimitives, &prim); + if(type == GL2PS_TEXT) + glPassThrough(GL2PS_TEXT_TOKEN); + else + glPassThrough(GL2PS_SPECIAL_TOKEN); + + return GL2PS_SUCCESS; } - -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 GL_FALSE; - } - } - return GL_TRUE; +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)); + strcpy(text->fontname, t->fontname); + text->fontsize = t->fontsize; + text->alignment = t->alignment; + text->angle = t->angle; + + return text; } -static void gl2psSetLastColor(GL2PSrgba rgba) +static void gl2psFreeText(GL2PSstring *text) { - int i; - for(i = 0; i < 3; ++i){ - gl2ps->lastrgba[i] = rgba[i]; - } + if(!text) + return; + gl2psFree(text->str); + gl2psFree(text->fontname); + gl2psFree(text); } -/* returns TRUE if gl2ps supports the argument combination: only two - blending modes have been implemented so far */ +/* Helpers for blending modes */ static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor) { + /* returns TRUE if gl2ps supports the argument combination: only two + blending modes have been implemented so far */ + 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) { + /* 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 */ + if(!v || !gl2ps) return; - + if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ v->rgba[3] = 1.0F; return; @@ -767,30 +964,95 @@ static void gl2psAdaptVertexForBlending(GL2PSvertex *v) } } -static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y, - GLfloat *red, GLfloat *green, GLfloat *blue) +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); +} + +static void gl2psInitTriangle(GL2PStriangle *t) +{ + int i; + GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} }; + for(i = 0; i < 3; i++) + t->vertex[i] = vertex; + t->prop = T_UNDEFINED; +} + +/* Miscellaneous helper routines */ + +static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p) { + GL2PSprimitive *prim; + + if(!p){ + gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive"); + return NULL; + } + + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - GLsizei width = im->width; - GLsizei height = im->height; - GLfloat *pixels = im->pixels; - GLfloat *pimag; + prim->type = p->type; + prim->numverts = p->numverts; + prim->boundary = p->boundary; + prim->offset = p->offset; + prim->pattern = p->pattern; + prim->factor = p->factor; + prim->culled = p->culled; + prim->width = p->width; + prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex)); + memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex)); - /* 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); + switch(prim->type){ + case GL2PS_PIXMAP : + prim->data.image = gl2psCopyPixmap(p->data.image); + break; + case GL2PS_TEXT : + case GL2PS_SPECIAL : + prim->data.text = gl2psCopyText(p->data.text); break; - case GL_RGB: default: - pimag = pixels + 3 * (width * (height - 1 - y) + x); break; } - *red = *pimag; pimag++; - *green = *pimag; pimag++; - *blue = *pimag; pimag++; - return (im->format == GL_RGBA) ? *pimag : 1.0F; + return prim; } static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2) @@ -844,9 +1106,9 @@ static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c) c[2] = c[2] / norm; } else{ - /* FIXME: the plane is still wrong, despite our tests in - gl2psGetPlane... Let's return a dummy value for now (this is a - hack: we should do more tests in GetPlane) */ + /* The plane is still wrong despite our tests in gl2psGetPlane. + Let's return a dummy value for now (this is a hack: we should + do more intelligent tests in GetPlane) */ c[0] = c[1] = 0.0F; c[2] = 1.0F; } @@ -902,6 +1164,7 @@ static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane) case GL2PS_POINT : case GL2PS_PIXMAP : case GL2PS_TEXT : + case GL2PS_SPECIAL : case GL2PS_IMAGEMAP: plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; @@ -957,7 +1220,7 @@ static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, case 2 : child->type = GL2PS_LINE; break; case 3 : child->type = GL2PS_TRIANGLE; break; case 4 : child->type = GL2PS_QUADRANGLE; break; - default: child->type = GL2PS_NOTYPE; break; + default: child->type = GL2PS_NO_TYPE; break; } } @@ -1217,7 +1480,7 @@ static void gl2psFreePrimitive(void *data) q = *(GL2PSprimitive**)data; gl2psFree(q->verts); - if(q->type == GL2PS_TEXT){ + if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){ gl2psFreeText(q->data.text); } else if(q->type == GL2PS_PIXMAP){ @@ -1623,7 +1886,7 @@ static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, case 2 : child->type = GL2PS_LINE; break; case 3 : child->type = GL2PS_TRIANGLE; break; case 4 : child->type = GL2PS_QUADRANGLE; break; - default: child->type = GL2PS_NOTYPE; break; /* FIXME */ + default: child->type = GL2PS_NO_TYPE; break; /* FIXME */ } } child->boundary = 0; /* FIXME: not done! */ @@ -1732,7 +1995,9 @@ static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree) /* FIXME: until we consider the actual extent of text strings and pixmaps, never cull them. Otherwise the whole string/pixmap gets culled as soon as the reference point is hidden */ - if(prim->type == GL2PS_PIXMAP || prim->type == GL2PS_TEXT){ + if(prim->type == GL2PS_PIXMAP || + prim->type == GL2PS_TEXT || + prim->type == GL2PS_SPECIAL){ return 1; } @@ -1941,7 +2206,7 @@ static void gl2psParseFeedbackBuffer(GLint used) char flag; GLushort pattern = 0; GLboolean boundary; - GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0; + GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0; GLfloat lwidth = 1.0F, psize = 1.0F; GLfloat *current; GL2PSvertex vertices[3]; @@ -2018,14 +2283,14 @@ static void gl2psParseFeedbackBuffer(GLint used) break; case GL_PASS_THROUGH_TOKEN : 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 = GL_TRUE; break; - case GL2PS_END_POLYGON_BOUNDARY : boundary = GL_FALSE; break; - case GL2PS_END_LINE_STIPPLE : pattern = factor = 0; break; - case GL2PS_BEGIN_BLEND : gl2ps->blending = GL_TRUE; break; - case GL2PS_END_BLEND : gl2ps->blending = GL_FALSE; break; - case GL2PS_BEGIN_LINE_STIPPLE : + case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break; + case GL2PS_END_OFFSET_TOKEN : offset = 0; break; + case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break; + case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break; + case GL2PS_END_STIPPLE_TOKEN : pattern = factor = 0; break; + case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break; + case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break; + case GL2PS_BEGIN_STIPPLE_TOKEN : current += 2; used -= 2; pattern = (GLushort)current[1]; @@ -2033,27 +2298,27 @@ static void gl2psParseFeedbackBuffer(GLint used) used -= 2; factor = (GLint)current[1]; break; - case GL2PS_SRC_BLEND : + case GL2PS_SRC_BLEND_TOKEN : current += 2; used -= 2; gl2ps->blendfunc[0] = (GLint)current[1]; break; - case GL2PS_DST_BLEND : + case GL2PS_DST_BLEND_TOKEN : current += 2; used -= 2; gl2ps->blendfunc[1] = (GLint)current[1]; break; - case GL2PS_SET_POINT_SIZE : + case GL2PS_POINT_SIZE_TOKEN : current += 2; used -= 2; psize = current[1]; break; - case GL2PS_SET_LINE_WIDTH : + case GL2PS_LINE_WIDTH_TOKEN : current += 2; used -= 2; lwidth = current[1]; break; - case GL2PS_DRAW_IMAGEMAP_TOKEN : + case GL2PS_IMAGEMAP_TOKEN : prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = GL2PS_IMAGEMAP; prim->boundary = 0; @@ -2117,6 +2382,15 @@ static void gl2psParseFeedbackBuffer(GLint used) current++; used--; gl2psListAdd(gl2ps->primitives, &prim); break; + case GL2PS_DRAW_PIXELS_TOKEN : + case GL2PS_TEXT_TOKEN : + case GL2PS_SPECIAL_TOKEN : + if(auxindex < gl2psListNbr(gl2ps->auxprimitives)) + gl2psListAdd(gl2ps->primitives, + gl2psListPointer(gl2ps->auxprimitives, auxindex++)); + else + gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer"); + break; } current += 2; used -= 2; @@ -2128,6 +2402,8 @@ static void gl2psParseFeedbackBuffer(GLint used) break; } } + + gl2psListReset(gl2ps->auxprimitives); } /********************************************************************* @@ -2152,7 +2428,8 @@ static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im) GLuint width = (GLuint)im->width; GLuint height = (GLuint)im->height; - /* FIXME: should we define an option for these? */ + /* FIXME: should we define an option for these? Or just keep the + 8-bit per component case? */ int greyscale = 0; /* set to 1 to output greyscale image */ int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */ @@ -2367,24 +2644,10 @@ static void gl2psPrintPostScriptHeader(void) { 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 */ - 0, 0, 0, 0, /* time */ - 2, /* extra flags: max compression */ - '\x03'}; /* OS code: 0x03 (Unix) */ - - if(gl2ps->options & GL2PS_COMPRESS){ - gl2psSetupCompress(); - /* add the gzip file header */ - fwrite(tmp, 10, 1, gl2ps->stream); - } -#endif + /* Since compression is not part of the PostScript standard, + compressed PostScript files are just gzipped PostScript files + ("ps.gz" or "eps.gz") */ + gl2psPrintGzipHeader(); time(&now); @@ -2396,14 +2659,14 @@ static void gl2psPrintPostScriptHeader(void) } gl2psPrintf("%%%%Title: %s\n" - "%%%%Creator: GL2PS %d.%d.%d, (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>\n" + "%%%%Creator: GL2PS %d.%d.%d%s, (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>\n" "%%%%For: %s\n" "%%%%CreationDate: %s" "%%%%LanguageLevel: 3\n" "%%%%DocumentData: Clean7Bit\n" "%%%%Pages: 1\n", gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, - gl2ps->producer, ctime(&now)); + GL2PS_EXTRA_VERSION, gl2ps->producer, ctime(&now)); if(gl2ps->format == GL2PS_PS){ gl2psPrintf("%%%%Orientation: %s\n" @@ -2640,10 +2903,39 @@ static void gl2psEndPostScriptLine(void) } } +static void gl2psParseStipplePattern(GLushort pattern, GLint factor, + int *nb, int array[10]) +{ + int i, n, on[5] = {0, 0, 0, 0, 0}, off[5] = {0, 0, 0, 0, 0}; + char tmp[16]; + + /* extract the 16 bits from the OpenGL stipple pattern */ + for(n = 15; n >= 0; n--){ + tmp[n] = (char)(pattern & 0x01); + pattern >>= 1; + } + /* compute the on/off pixel sequence (since the PostScript + specification allows for at most 11 elements in the on/off array, + we limit ourselves to 5 couples of on/off states) */ + n = 0; + for(i = 0; i < 5; i++){ + while(n < 16 && !tmp[n]){ off[i]++; n++; } + while(n < 16 && tmp[n]){ on[i]++; n++; } + if(n >= 15) break; + } + /* store the on/off array from right to left, starting with off + pixels (the longest possible array is: [on4 off4 on3 off3 on2 + off2 on1 off1 on0 off0]) */ + *nb = 0; + for(n = i; n >= 0; n--){ + array[(*nb)++] = factor * on[n]; + array[(*nb)++] = factor * off[n]; + } +} + static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, char *str) { - int len = 0, i, n, on[5] = {0, 0, 0, 0, 0}, off[5] = {0, 0, 0, 0, 0}; - char tmp[16]; + int len = 0, i, n, array[10]; if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) return 0; @@ -2656,27 +2948,11 @@ static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, char *str) len += gl2psPrintf("[] 0 %s\n", str); } else{ - /* extract the 16 bits from the stipple pattern */ - for(n = 15; n >= 0; n--){ - tmp[n] = (char)(pattern & 0x01); - pattern >>= 1; - } - /* compute the on/off pixel sequence (since the PostScript - specification allows for at most 11 elements in the on/off - array, we limit ourselves to 5 couples of on/off states) */ - n = 0; - for(i = 0; i < 5; i++){ - while(n < 16 && !tmp[n]){ off[i]++; n++; } - while(n < 16 && tmp[n]){ on[i]++; n++; } - if(n >= 15) break; - } - /* print the on/off array from right to left, starting with off - pixels (the longest possible array is: [on4 off4 on3 off3 on2 - off2 on1 off1 on0 off0]) */ + gl2psParseStipplePattern(pattern, factor, &n, array); len += gl2psPrintf("["); - for(n = i; n >= 0; n--){ - len += gl2psPrintf("%d %d", factor * on[n], factor * off[n]); - if(n) len += gl2psPrintf(" "); + for(i = 0; i < n; i++){ + if(i) len += gl2psPrintf(" "); + len += gl2psPrintf("%d", array[i]); } len += gl2psPrintf("] 0 %s\n", str); } @@ -2704,7 +2980,7 @@ static void gl2psPrintPostScriptPrimitive(void *data) case GL2PS_POINT : gl2psPrintPostScriptColor(prim->verts[0].rgba); gl2psPrintf("%g %g %g P\n", - prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5*prim->width); + prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width); break; case GL2PS_LINE : if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || @@ -2811,20 +3087,20 @@ static void gl2psPrintPostScriptPrimitive(void *data) break; } break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if(prim->data.text->alignment == GL2PS_PS || + prim->data.text->alignment == GL2PS_EPS) + gl2psPrintf("%s\n", prim->data.text->str); + break; default : - gl2psMsg(GL2PS_ERROR, "Unknown type of primitive to print"); break; } } static void gl2psPrintPostScriptFooter(void) { -#ifdef GL2PS_HAVE_ZLIB - int n; - uLong crc, len; - char tmp[8]; -#endif - gl2psPrintf("grestore\n" "showpage\n" "cleartomark\n" @@ -2832,39 +3108,8 @@ static void gl2psPrintPostScriptFooter(void) "%%%%Trailer\n" "end\n" "%%%%EOF\n"); - -#ifdef GL2PS_HAVE_ZLIB - if(gl2ps->options & GL2PS_COMPRESS){ - if(Z_OK != gl2psDeflate()){ - gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); - } - else{ - /* determine the length of the header in the zlib stream */ - n = 2; /* CMF+FLG */ - if(gl2ps->compress->dest[1] & (1<<5)){ - n += 4; /* DICTID */ - } - /* write the data, without the zlib header and footer */ - fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), - 1, gl2ps->stream); - /* add the gzip file footer */ - crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen); - for(n = 0; n < 4; ++n){ - tmp[n] = (char)(crc & 0xff); - crc >>= 8; - } - len = gl2ps->compress->srcLen; - for(n = 4; n < 8; ++n){ - tmp[n] = (char)(len & 0xff); - len >>= 8; - } - fwrite(tmp, 8, 1, gl2ps->stream); - } - gl2psFreeCompress(); - gl2psFree(gl2ps->compress); - gl2ps->compress = NULL; - } -#endif + + gl2psPrintGzipFooter(); } static void gl2psPrintPostScriptBeginViewport(GLint viewport[4]) @@ -2892,7 +3137,7 @@ static void gl2psPrintPostScriptBeginViewport(GLint viewport[4]) rgba[0] = gl2ps->colormap[index][0]; rgba[1] = gl2ps->colormap[index][1]; rgba[2] = gl2ps->colormap[index][2]; - rgba[3] = 0.0F; + rgba[3] = 1.0F; } gl2psPrintf("%g %g %g C\n" "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" @@ -3031,6 +3276,12 @@ static void gl2psPrintTeXPrimitive(void *data) fprintf(gl2ps->stream, "}"); fprintf(gl2ps->stream, "}}\n"); break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if (prim->data.text->alignment == GL2PS_TEX) + fprintf(gl2ps->stream, "%s\n", prim->data.text->str); + break; default : break; } @@ -3044,11 +3295,17 @@ static void gl2psPrintTeXFooter(void) static void gl2psPrintTeXBeginViewport(GLint viewport[4]) { + glRenderMode(GL_FEEDBACK); + + if(gl2ps->header){ + gl2psPrintTeXHeader(); + gl2ps->header = GL_FALSE; + } } static GLint gl2psPrintTeXEndViewport(void) { - return 0; + return gl2psPrintPrimitives(); } static void gl2psPrintTeXFinalPrimitive(void) @@ -3076,7 +3333,7 @@ static GL2PSbackend gl2psTEX = { static int gl2psPrintPDFCompressorType(void) { -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n"); } @@ -3177,7 +3434,7 @@ static void gl2psPDFgroupListInit(void) int i; GL2PSprimitive *p = NULL; GL2PSpdfgroup gro; - int lasttype = GL2PS_NOTYPE; + int lasttype = GL2PS_NO_TYPE; GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F}; GLushort lastpattern = 0; GLint lastfactor = 0; @@ -3642,10 +3899,10 @@ static int gl2psPrintPDFInfo(void) "<<\n" "/Title (%s)\n" "/Creator (%s)\n" - "/Producer (GL2PS %d.%d.%d, " + "/Producer (GL2PS %d.%d.%d%s, " "(C) 1999-2006 Christophe Geuzaine <geuz@geuz.org>)\n", - gl2ps->title, gl2ps->producer, - GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION); + gl2ps->title, gl2ps->producer, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, + GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION); if(!newtime){ offs += fprintf(gl2ps->stream, @@ -3737,7 +3994,7 @@ static void gl2psPrintPDFHeader(void) gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psSetupCompress(); } @@ -3779,7 +4036,7 @@ static int gl2psClosePDFDataStream(void) { int offs = 0; -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ if(Z_OK != gl2psDeflate()) gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); @@ -3897,6 +4154,9 @@ static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, double dmax = ~1UL; char edgeflag = 0; + /* FIXME: temp bux fix for 64 bit archs: */ + if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; + offs += (*action)(edgeflag, 1); /* The Shader stream in PDF requires to be in a 'big-endian' @@ -3937,6 +4197,9 @@ static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex, unsigned long imap; double dmax = ~1UL; + /* FIXME: temp bux fix for 64 bit archs: */ + if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; + imap = (unsigned long)((vertex->rgba[0]) * dmax); offs += (*action)(imap, 1); @@ -3959,8 +4222,11 @@ static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, int offs = 0; unsigned long imap; double dmax = ~1UL; - - if(sigbyte!=8 && sigbyte!=16) + + /* FIXME: temp bux fix for 64 bit archs: */ + if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; + + if(sigbyte != 8 && sigbyte != 16) sigbyte = 8; sigbyte /= 8; @@ -4071,14 +4337,14 @@ static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, xmin, xmax, ymin, ymax, (gray) ? "" : "0 1 0 1"); -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress(vertexbytes * size * 3); for(i = 0; i < size; ++i) gl2psPrintPDFShaderStreamData(&triangles[i], xmax-xmin, ymax-ymin, xmin, ymin, - gl2psWriteBigEndianCompress,gray); + gl2psWriteBigEndianCompress, gray); if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ offs += gl2psPrintPDFCompressorType(); @@ -4107,7 +4373,7 @@ static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, for(i = 0; i < size; ++i) offs += gl2psPrintPDFShaderStreamData(&triangles[i], xmax-xmin, ymax-ymin, xmin, ymin, - gl2psWriteBigEndian,gray); + gl2psWriteBigEndian, gray); } offs += fprintf(gl2ps->stream, @@ -4261,7 +4527,7 @@ static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray) childobj); } -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress((int)(im->width * im->height * sigbytes)); @@ -4379,6 +4645,12 @@ static int gl2psPDFgroupListWriteObjects(int entryoffs) gl2ps->xreflist[gro->fontobjno] = offs; offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno); break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if(p->data.text->alignment == GL2PS_PDF) + offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str); + break; default: break; } @@ -4443,7 +4715,7 @@ static void gl2psPrintPDFFooter(void) gl2psListDelete(gl2ps->pdfprimlist); gl2psPDFgroupListDelete(); -#ifdef GL2PS_HAVE_ZLIB +#if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psFreeCompress(); gl2psFree(gl2ps->compress); @@ -4479,7 +4751,7 @@ static void gl2psPrintPDFBeginViewport(GLint viewport[4]) rgba[0] = gl2ps->colormap[index][0]; rgba[1] = gl2ps->colormap[index][1]; rgba[2] = gl2ps->colormap[index][2]; - rgba[3] = 0.0F; + rgba[3] = 1.0F; } offs += gl2psPrintPDFFillColor(rgba); offs += gl2psPrintf("%d %d %d %d re\n" @@ -4529,11 +4801,19 @@ static GL2PSbackend gl2psPDF = { * *********************************************************************/ -/* FIXME: this is just a canvas, still far from being usable in any - way. One big problem is that it seems like there is no easy way to - do Gouraud shading in SVG!? Another is horrible rendering - performance (that could be partially fixed by using 'path' instead - of 'polygon') */ +static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, + GL2PSxyz *xyz, GL2PSrgba *rgba) +{ + int i, j; + + for(i = 0; i < n; i++){ + xyz[i][0] = verts[i].xyz[0]; + xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1]; + xyz[i][2] = 0.0F; + for(j = 0; j < 4; j++) + rgba[i][j] = verts[i].rgba[j]; + } +} static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32]) { @@ -4546,119 +4826,332 @@ static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32]) sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc); } -static void gl2psSVGGetCoords(int n, GL2PSvertex *verts, GL2PSxyz *xyz) +static void gl2psPrintSVGHeader(void) +{ + char col[32]; + time_t now; + + /* Compressed SVG files (.svgz) are simply gzipped SVG files */ + gl2psPrintGzipHeader(); + + time(&now); + + gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); + gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n"); + gl2psPrintf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"); + gl2psPrintf(" viewBox=\"%d %d %d %d\">\n", + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : + (int)gl2ps->viewport[0], + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] : + (int)gl2ps->viewport[1], + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : + (int)gl2ps->viewport[2], + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : + (int)gl2ps->viewport[3]); + gl2psPrintf("<title>\n"); + gl2psPrintf("%s\n", gl2ps->title); + gl2psPrintf("</title>\n"); + gl2psPrintf("<desc>\n"); + gl2psPrintf("Creator: GL2PS %d.%d.%d%s\n" + "For: %s\n" + "CreationDate: %s", + GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, + GL2PS_EXTRA_VERSION, gl2ps->producer, ctime(&now)); + gl2psPrintf("</desc>\n"); + gl2psPrintf("<defs>\n"); + gl2psPrintf("</defs>\n"); + + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ + gl2psSVGGetColorString(gl2ps->bgcolor, col); + gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], + (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); + } +} + +static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3]) { int i; + GL2PSxyz xyz2[3]; + GL2PSrgba rgba2[3]; + char col[32]; + + /* Apparently there is no easy way to do Gouraud shading in SVG + without explicitly pre-defining gradients, so for now we just do + recursive subdivision */ + + if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){ + gl2psSVGGetColorString(rgba[0], col); + gl2psPrintf("<polygon fill=\"%s\" ", col); + if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]); + gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1], + xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]); + } + else{ + /* subdivide into 4 subtriangles */ + for(i = 0; i < 3; i++){ + xyz2[0][i] = xyz[0][i]; + xyz2[1][i] = 0.5 * (xyz[0][i] + xyz[1][i]); + xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]); + } + for(i = 0; i < 4; i++){ + rgba2[0][i] = rgba[0][i]; + rgba2[1][i] = 0.5 * (rgba[0][i] + rgba[1][i]); + rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]); + } + gl2psPrintSVGSmoothTriangle(xyz2, rgba2); + for(i = 0; i < 3; i++){ + xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]); + xyz2[1][i] = xyz[1][i]; + xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]); + } + for(i = 0; i < 4; i++){ + rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]); + rgba2[1][i] = rgba[1][i]; + rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]); + } + gl2psPrintSVGSmoothTriangle(xyz2, rgba2); + for(i = 0; i < 3; i++){ + xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[2][i]); + xyz2[1][i] = xyz[2][i]; + xyz2[2][i] = 0.5 * (xyz[1][i] + xyz[2][i]); + } + for(i = 0; i < 4; i++){ + rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[2][i]); + rgba2[1][i] = rgba[2][i]; + rgba2[2][i] = 0.5 * (rgba[1][i] + rgba[2][i]); + } + gl2psPrintSVGSmoothTriangle(xyz2, rgba2); + for(i = 0; i < 3; i++){ + xyz2[0][i] = 0.5 * (xyz[0][i] + xyz[1][i]); + xyz2[1][i] = 0.5 * (xyz[1][i] + xyz[2][i]); + xyz2[2][i] = 0.5 * (xyz[0][i] + xyz[2][i]); + } + for(i = 0; i < 4; i++){ + rgba2[0][i] = 0.5 * (rgba[0][i] + rgba[1][i]); + rgba2[1][i] = 0.5 * (rgba[1][i] + rgba[2][i]); + rgba2[2][i] = 0.5 * (rgba[0][i] + rgba[2][i]); + } + gl2psPrintSVGSmoothTriangle(xyz2, rgba2); + } +} +static void gl2psPrintSVGDash(GLushort pattern, GLint factor) +{ + int i, n, array[10]; + + if(!pattern || !factor) return; /* solid line */ + + gl2psParseStipplePattern(pattern, factor, &n, array); + gl2psPrintf("stroke-dasharray=\""); for(i = 0; i < n; i++){ - xyz[i][0] = verts[i].xyz[0]; - xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1]; + if(i) gl2psPrintf(","); + gl2psPrintf("%d", array[i]); } + gl2psPrintf("\" "); } -static void gl2psPrintSVGHeader(void) +static void gl2psEndSVGLine(void) { - time_t now; - time(&now); + int i; + if(gl2ps->lastvertex.rgba[0] >= 0.){ + gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], + gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]); + for(i = 0; i < 3; i++) + gl2ps->lastvertex.xyz[i] = -1.; + for(i = 0; i < 4; i++) + gl2ps->lastvertex.rgba[i] = -1.; + } +} - fprintf(gl2ps->stream, - "<svg viewBox=\"%d %d %d %d\" xmlns=\"http://www.w3.org/2000/svg\">\n", - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : - (int)gl2ps->viewport[0], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] : - (int)gl2ps->viewport[1], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : - (int)gl2ps->viewport[2], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : - (int)gl2ps->viewport[3]); - fprintf(gl2ps->stream, "<title>\n"); - fprintf(gl2ps->stream, "%s\n",gl2ps->title); - fprintf(gl2ps->stream, "</title>\n"); - fprintf(gl2ps->stream, "<desc>\n"); - fprintf(gl2ps->stream, - "Creator: GL2PS %d.%d.%d\n" - "For: %s\n" - "CreationDate: %s", - GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, - gl2ps->producer, ctime(&now)); - fprintf(gl2ps->stream, "</desc>\n"); - fprintf(gl2ps->stream, "<defs>\n"); - fprintf(gl2ps->stream, "</defs>\n"); +static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap) +{ +#if defined(GL2PS_HAVE_LIBPNG) + GL2PSlist *png; + unsigned char c; + int i; + + /* The only image types supported by the SVG standard are JPEG, PNG + and SVG. Here we choose PNG, and since we want to embed the image + directly in the SVG stream (and not link to an external image + file), we need to encode the pixmap into PNG in memory, then + encode it into base64. */ + + png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, + sizeof(unsigned char)); + gl2psConvertPixmapToPNG(pixmap, png); + c = '\0'; /* need to base64-encode a null-terminated string */ + gl2psListAdd(png, &c); + gl2psListEncodeBase64(png); + gl2psPrintf("<image x=\"%g\" y=\"%g\" width=\"%d\" height=\"%d\"\n", + x, y - pixmap->height, pixmap->width, pixmap->height); + gl2psPrintf("xlink:href=\"data:image/png;base64,"); + for(i = 0; i < gl2psListNbr(png); i++){ + gl2psListRead(png, i, &c); + gl2psPrintf("%c", c); + } + gl2psPrintf("\"/>\n"); + gl2psListDelete(png); +#else + gl2psMsg(GL2PS_WARNING, "GL2PS has to be compiled with PNG support in " + "order to embed images in SVG streams"); +#endif } static void gl2psPrintSVGPrimitive(void *data) { GL2PSprimitive *prim; GL2PSxyz xyz[4]; + GL2PSrgba rgba[4]; char col[32]; + int newline; prim = *(GL2PSprimitive**)data; if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; - gl2psSVGGetCoords(prim->numverts, prim->verts, xyz); + /* We try to draw connected lines as a single path to get nice line + joins and correct stippling. So if the primitive to print is not + a line we must first finish the current line (if any): */ + if(prim->type != GL2PS_LINE) gl2psEndSVGLine(); + + gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba); switch(prim->type){ case GL2PS_POINT : - /* FIXME */ + gl2psSVGGetColorString(rgba[0], col); + gl2psPrintf("<circle fill=\"%s\" ", col); + if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]); + gl2psPrintf("cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n", + xyz[0][0], xyz[0][1], 0.5 * prim->width); break; case GL2PS_LINE : - gl2psSVGGetColorString(prim->verts[0].rgba, col); - fprintf(gl2ps->stream, - "<line stroke=\"%s\" stroke-width=\"%d\" " - "x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n", - col, (int)(prim->width), - xyz[0][0], xyz[0][1], xyz[1][0], xyz[1][1]); + if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || + !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || + gl2ps->lastlinewidth != prim->width || + gl2ps->lastpattern != prim->pattern || + gl2ps->lastfactor != prim->factor){ + /* End the current line if the new segment does not start where + the last one ended, or if the color, the width or the + stippling have changed (we will need to use multi-point + gradients for smooth-shaded lines) */ + gl2psEndSVGLine(); + newline = 1; + } + else{ + newline = 0; + } + gl2ps->lastvertex = prim->verts[1]; + gl2psSetLastColor(prim->verts[0].rgba); + gl2ps->lastlinewidth = prim->width; + gl2ps->lastpattern = prim->pattern; + gl2ps->lastfactor = prim->factor; + if(newline){ + gl2psSVGGetColorString(rgba[0], col); + gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ", + col, prim->width); + if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]); + gl2psPrintSVGDash(prim->pattern, prim->factor); + gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]); + } + else{ + gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]); + } break; case GL2PS_TRIANGLE : - gl2psSVGGetColorString(prim->verts[0].rgba, col); - fprintf(gl2ps->stream, - "<polygon fill=\"%s\" points=\"%g,%g %g,%g %g,%g\"/>\n", - col, xyz[0][0], xyz[0][1], xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]); + gl2psPrintSVGSmoothTriangle(xyz, rgba); break; case GL2PS_QUADRANGLE : gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); break; case GL2PS_PIXMAP : - /* FIXME */ - break; - case GL2PS_IMAGEMAP : - /* FIXME */ + gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image); break; case GL2PS_TEXT : gl2psSVGGetColorString(prim->verts[0].rgba, col); - fprintf(gl2ps->stream, - "<text x=\"%g\" y=\"%g\" fill=\"%s\" " - "font-size=\"%d\" font-family=\"%s\">%s</text>\n", - xyz[0][0], xyz[0][1], col, - prim->data.text->fontsize, - prim->data.text->fontname, - prim->data.text->str); + gl2psPrintf("<text fill=\"%s\" x=\"%g\" y=\"%g\" " + "font-size=\"%d\" font-family=\"%s\">%s</text>\n", + col, xyz[0][0], xyz[0][1], + prim->data.text->fontsize, + prim->data.text->fontname, + prim->data.text->str); + break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if(prim->data.text->alignment == GL2PS_SVG) + gl2psPrintf("%s\n", prim->data.text->str); break; default : - gl2psMsg(GL2PS_ERROR, "Unknown type of primitive to print"); break; } } static void gl2psPrintSVGFooter(void) { - fprintf(gl2ps->stream, "</svg>\n"); + gl2psPrintf("</svg>\n"); + + gl2psPrintGzipFooter(); } static void gl2psPrintSVGBeginViewport(GLint viewport[4]) { - /* FIXME */ + GLint index; + char col[32]; + GLfloat rgba[4]; + int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; + + glRenderMode(GL_FEEDBACK); + + if(gl2ps->header){ + gl2psPrintSVGHeader(); + gl2ps->header = GL_FALSE; + } + + 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] = 1.0F; + } + gl2psSVGGetColorString(rgba, col); + gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, + x, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - (y + h), + x, gl2ps->viewport[3] - (y + h)); + } + + gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h); + gl2psPrintf(" <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", + x, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - (y + h), + x, gl2ps->viewport[3] - (y + h)); + gl2psPrintf("</clipPath>\n"); + gl2psPrintf("<g stroke=\"none\" clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h); } static GLint gl2psPrintSVGEndViewport(void) { - /* FIXME */ - return 0; + GLint res; + + res = gl2psPrintPrimitives(); + gl2psPrintf("</g>\n"); + return res; } static void gl2psPrintSVGFinalPrimitive(void) { + /* End any remaining line, if any */ + gl2psEndSVGLine(); } /* definition of the SVG backend */ @@ -4690,23 +5183,6 @@ static void gl2psPrintPGFColor(GL2PSrgba rgba) static void gl2psPrintPGFHeader(void) { - char name[256]; - int i; - - if(gl2ps->filename && strlen(gl2ps->filename) < 256){ - for(i = strlen(gl2ps->filename)-1; i >= 0; i--){ - if(gl2ps->filename[i] == '.'){ - strncpy(name, gl2ps->filename, i); - name[i] = '\0'; - break; - } - } - if(i <= 0) strcpy(name, gl2ps->filename); - } - else{ - strcpy(name, "untitled"); - } - fprintf(gl2ps->stream, "\\begin{pgfpicture}\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ gl2psPrintPGFColor(gl2ps->bgcolor); @@ -4721,8 +5197,7 @@ static void gl2psPrintPGFHeader(void) static void gl2psPrintPGFDash(GLushort pattern, GLint factor) { - int i, n, on[5] = {0, 0, 0, 0, 0}, off[5] = {0, 0, 0, 0, 0}; - char tmp[16]; + int i, n, array[10]; if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) return; @@ -4735,28 +5210,9 @@ static void gl2psPrintPGFDash(GLushort pattern, GLint factor) fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n"); } else{ - /* extract the 16 bits from the stipple pattern */ - for(n = 15; n >= 0; n--){ - tmp[n] = (char)(pattern & 0x01); - pattern >>= 1; - } - /* compute the on/off pixel sequence (since the PostScript - specification allows for at most 11 elements in the on/off - array, we limit ourselves to 5 couples of on/off states) */ - n = 0; - for(i = 0; i < 5; i++){ - while(n < 16 && !tmp[n]){ off[i]++; n++; } - while(n < 16 && tmp[n]){ on[i]++; n++; } - if(n >= 15) break; - } - /* print the on/off array from right to left, starting with off - pixels (the longest possible array is: [on4 off4 on3 off3 on2 - off2 on1 off1 on0 off0]) */ + gl2psParseStipplePattern(pattern, factor, &n, array); fprintf(gl2ps->stream, "\\pgfsetdash{"); - for(n = i; n >= 0; n--){ - fprintf(gl2ps->stream, "{%dpt}{%dpt}", - (int)(factor * on[n]), (int)(factor * off[n])); - } + for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]); fprintf(gl2ps->stream, "}{0pt}\n"); } } @@ -4841,6 +5297,12 @@ static void gl2psPrintPGFPrimitive(void *data) fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n"); break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if (prim->data.text->alignment == GL2PS_PGF) + fprintf(gl2ps->stream, "%s\n", prim->data.text->str); + break; default : break; } @@ -4874,7 +5336,7 @@ static void gl2psPrintPGFBeginViewport(GLint viewport[4]) rgba[0] = gl2ps->colormap[index][0]; rgba[1] = gl2ps->colormap[index][1]; rgba[2] = gl2ps->colormap[index][2]; - rgba[3] = 0.0F; + rgba[3] = 1.0F; } gl2psPrintPGFColor(rgba); fprintf(gl2ps->stream, @@ -4961,16 +5423,14 @@ static GLint gl2psPrintPrimitives(void) used = glRenderMode(GL_RENDER); - if(gl2ps->format != GL2PS_TEX){ - /* only report the overflow if we actually parse the buffer! */ - if(used < 0){ - gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow"); - return GL2PS_OVERFLOW; - } - if(used > 0) - gl2psParseFeedbackBuffer(used); + if(used < 0){ + gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow"); + return GL2PS_OVERFLOW; } + if(used > 0) + gl2psParseFeedbackBuffer(used); + gl2psRescaleAndOffset(); if(gl2ps->header){ @@ -5110,9 +5570,9 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, return GL2PS_ERROR; } - gl2ps->threshold[0] = nr ? 1.0F/(GLfloat)nr : 0.032F; - gl2ps->threshold[1] = ng ? 1.0F/(GLfloat)ng : 0.017F; - gl2ps->threshold[2] = nb ? 1.0F/(GLfloat)nb : 0.050F; + gl2ps->threshold[0] = nr ? 1.0F/(GLfloat)nr : 0.064F; + gl2ps->threshold[1] = ng ? 1.0F/(GLfloat)ng : 0.034F; + gl2ps->threshold[2] = nb ? 1.0F/(GLfloat)nb : 0.100F; gl2ps->colormode = colormode; gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048; for(i = 0; i < 3; i++){ @@ -5132,7 +5592,9 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, gl2ps->pdfgrouplist = NULL; gl2ps->xreflist = NULL; - gl2ps->blending = glIsEnabled(GL_BLEND); + /* get default blending mode from current OpenGL state (enabled by + default for SVG) */ + gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND); glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]); glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]); @@ -5155,7 +5617,7 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, gl2ps->bgcolor[0] = gl2ps->colormap[index][0]; gl2ps->bgcolor[1] = gl2ps->colormap[index][1]; gl2ps->bgcolor[2] = gl2ps->colormap[index][2]; - gl2ps->bgcolor[3] = 0.0F; + gl2ps->bgcolor[3] = 1.0F; } else{ gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage"); @@ -5192,6 +5654,7 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, } gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); + gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*)); gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat)); glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback); glRenderMode(GL_FEEDBACK); @@ -5213,6 +5676,7 @@ GL2PSDLL_API GLint gl2psEndPage(void) fflush(gl2ps->stream); gl2psListDelete(gl2ps->primitives); + gl2psListDelete(gl2ps->auxprimitives); gl2psFreeImagemap(gl2ps->imagemap_head); gl2psFree(gl2ps->colormap); gl2psFree(gl2ps->title); @@ -5248,51 +5712,17 @@ GL2PSDLL_API GLint gl2psEndViewport(void) GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle) { - GLfloat pos[4]; - GL2PSprimitive *prim; - GLboolean valid; - - if(!gl2ps || !str) return GL2PS_UNINITIALIZED; - - if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS; - - glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); - if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ - - glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); - - prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - prim->type = GL2PS_TEXT; - prim->boundary = 0; - prim->numverts = 1; - 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] = pos[2]; - prim->culled = 0; - prim->offset = 0; - prim->pattern = 0; - prim->factor = 0; - prim->width = 1; - glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); - prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); - prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char)); - strcpy(prim->data.text->str, str); - prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); - strcpy(prim->data.text->fontname, fontname); - prim->data.text->fontsize = fontsize; - prim->data.text->alignment = alignment; - prim->data.text->angle = angle; - - gl2psListAdd(gl2ps->primitives, &prim); + return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle); +} - return GL2PS_SUCCESS; +GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize) +{ + return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F); } -GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, - GLshort fontsize) +GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str) { - return gl2psTextOpt(str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F); + return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F); } GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, @@ -5370,7 +5800,8 @@ GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, break; } - gl2psListAdd(gl2ps->primitives, &prim); + gl2psListAdd(gl2ps->auxprimitives, &prim); + glPassThrough(GL2PS_DRAW_PIXELS_TOKEN); return GL2PS_SUCCESS; } @@ -5386,12 +5817,12 @@ GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, if((width <= 0) || (height <= 0)) return GL2PS_ERROR; size = height + height * ((width-1)/8); - glPassThrough(GL2PS_DRAW_IMAGEMAP_TOKEN); + glPassThrough(GL2PS_IMAGEMAP_TOKEN); glBegin(GL_POINTS); glVertex3f(position[0], position[1],position[2]); glEnd(); - glPassThrough(width); - glPassThrough(height); + glPassThrough((GLfloat)width); + glPassThrough((GLfloat)height); for(i = 0; i < size; i += sizeoffloat){ float *value = (float*)imagemap; glPassThrough(*value); @@ -5408,22 +5839,22 @@ GL2PSDLL_API GLint gl2psEnable(GLint mode) switch(mode){ case GL2PS_POLYGON_OFFSET_FILL : - glPassThrough(GL2PS_BEGIN_POLYGON_OFFSET_FILL); + glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN); glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]); glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]); break; case GL2PS_POLYGON_BOUNDARY : - glPassThrough(GL2PS_BEGIN_POLYGON_BOUNDARY); + glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN); break; case GL2PS_LINE_STIPPLE : - glPassThrough(GL2PS_BEGIN_LINE_STIPPLE); + glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN); glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp); glPassThrough((GLfloat)tmp); glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp); glPassThrough((GLfloat)tmp); break; case GL2PS_BLEND : - glPassThrough(GL2PS_BEGIN_BLEND); + glPassThrough(GL2PS_BEGIN_BLEND_TOKEN); break; default : gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode); @@ -5439,16 +5870,16 @@ GL2PSDLL_API GLint gl2psDisable(GLint mode) switch(mode){ case GL2PS_POLYGON_OFFSET_FILL : - glPassThrough(GL2PS_END_POLYGON_OFFSET_FILL); + glPassThrough(GL2PS_END_OFFSET_TOKEN); break; case GL2PS_POLYGON_BOUNDARY : - glPassThrough(GL2PS_END_POLYGON_BOUNDARY); + glPassThrough(GL2PS_END_BOUNDARY_TOKEN); break; case GL2PS_LINE_STIPPLE : - glPassThrough(GL2PS_END_LINE_STIPPLE); + glPassThrough(GL2PS_END_STIPPLE_TOKEN); break; case GL2PS_BLEND : - glPassThrough(GL2PS_END_BLEND); + glPassThrough(GL2PS_END_BLEND_TOKEN); break; default : gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode); @@ -5462,7 +5893,7 @@ GL2PSDLL_API GLint gl2psPointSize(GLfloat value) { if(!gl2ps) return GL2PS_UNINITIALIZED; - glPassThrough(GL2PS_SET_POINT_SIZE); + glPassThrough(GL2PS_POINT_SIZE_TOKEN); glPassThrough(value); return GL2PS_SUCCESS; @@ -5472,7 +5903,7 @@ GL2PSDLL_API GLint gl2psLineWidth(GLfloat value) { if(!gl2ps) return GL2PS_UNINITIALIZED; - glPassThrough(GL2PS_SET_LINE_WIDTH); + glPassThrough(GL2PS_LINE_WIDTH_TOKEN); glPassThrough(value); return GL2PS_SUCCESS; @@ -5485,9 +5916,9 @@ GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor) if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor)) return GL2PS_WARNING; - glPassThrough(GL2PS_SRC_BLEND); + glPassThrough(GL2PS_SRC_BLEND_TOKEN); glPassThrough((GLfloat)sfactor); - glPassThrough(GL2PS_DST_BLEND); + glPassThrough(GL2PS_DST_BLEND_TOKEN); glPassThrough((GLfloat)dfactor); return GL2PS_SUCCESS; diff --git a/Graphics/gl2ps.h b/Graphics/gl2ps.h index 9924e721fd6b35fc037aac513eac0bd1bbaa0c16..fd503a00820d22df2c3a08b0894a639b11a26608 100644 --- a/Graphics/gl2ps.h +++ b/Graphics/gl2ps.h @@ -1,4 +1,4 @@ -/* $Id: gl2ps.h,v 1.64 2006-02-27 18:38:13 geuzaine Exp $ */ +/* $Id: gl2ps.h,v 1.65 2006-07-24 14:05:50 geuzaine Exp $ */ /* * GL2PS, an OpenGL to PostScript Printing Library * Copyright (C) 1999-2006 Christophe Geuzaine <geuz@geuz.org> @@ -38,7 +38,7 @@ #include <stdio.h> #include <stdlib.h> -/* Define GL2PSDLL at compile time to build a Windows dll */ +/* Define GL2PSDLL at compile time to build a Windows DLL */ #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) # if defined(_MSC_VER) @@ -58,26 +58,27 @@ # define GL2PSDLL_API #endif -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(HAVE_OPENGL_GL_H) # include <OpenGL/gl.h> #else # include <GL/gl.h> #endif -/* Support for compressed PostScript/PDF */ +/* Support for compressed PostScript/PDF and for embedded PNG images in SVG */ -#if defined(HAVE_ZLIB) || defined(HAVE_LIBZ) || defined(GL2PS_HAVE_ZLIB) -# include <zlib.h> -# if !defined(GL2PS_HAVE_ZLIB) -# define GL2PS_HAVE_ZLIB +#if defined(HAVE_ZLIB) || defined(HAVE_LIBZ) +# define GL2PS_HAVE_ZLIB +# if defined(HAVE_LIBPNG) || defined(HAVE_PNG) +# define GL2PS_HAVE_LIBPNG # endif #endif /* Version number */ #define GL2PS_MAJOR_VERSION 1 -#define GL2PS_MINOR_VERSION 2 -#define GL2PS_PATCH_VERSION 8 +#define GL2PS_MINOR_VERSION 3 +#define GL2PS_PATCH_VERSION 0 +#define GL2PS_EXTRA_VERSION "-cvs" #define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \ 0.01 * GL2PS_MINOR_VERSION + \ @@ -168,6 +169,7 @@ GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize); GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint align, GLfloat angle); +GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str); GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, GLenum format, GLenum type, const void *pixels); diff --git a/Mesh/Read_Mesh.cpp b/Mesh/Read_Mesh.cpp index 7e4962da0dedfff4bf0d080a3003feebf4d990ab..8892e98254a60c4a49d93b4a435fc446baa26806 100644 --- a/Mesh/Read_Mesh.cpp +++ b/Mesh/Read_Mesh.cpp @@ -1,4 +1,4 @@ -// $Id: Read_Mesh.cpp,v 1.105 2006-04-16 19:02:37 geuzaine Exp $ +// $Id: Read_Mesh.cpp,v 1.106 2006-07-24 14:05:50 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -98,7 +98,7 @@ void addVerticesInCurve(void *a, void *b) } } - // find starting element (or use the first one for closed curve) + // find starting element (or use the first one for a closed curve) std::map<int, nodex*>::const_iterator beg = nodes.begin(); std::map<int, nodex*>::const_iterator end = nodes.end(); int start = 0; @@ -500,7 +500,7 @@ void Read_Mesh_MSH(Mesh * M, FILE * fp) Free_SimplexBase(&simp, 0); } // we don't insert the vertices in the list of vertices at - // this point, since we need the list to ordered (and + // this point, since we need the list to be ordered (and // consistent!), and simply doing a List_Insert and sorting // according to node numbers is not enough (in addition to // being slow): see addVerticesInCurve() below. diff --git a/Plugin/ExtractElements.cpp b/Plugin/ExtractElements.cpp index 8e4bc07bd690915fed7f7add539736b64a4794bb..47f2bf9ecbcd2bdcec03605edeaaa5b2b8cfb216 100644 --- a/Plugin/ExtractElements.cpp +++ b/Plugin/ExtractElements.cpp @@ -1,4 +1,4 @@ -// $Id: ExtractElements.cpp,v 1.5 2006-03-10 17:03:21 geuzaine Exp $ +// $Id: ExtractElements.cpp,v 1.6 2006-07-24 14:05:50 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -113,7 +113,7 @@ static void extract(List_T *inList, int inNb, } d /= (double)nbNod; // We use '>=' and '<' so that we can do segmentation without - // worrying about roudoff errors + // worrying about roundoff errors if(d >= MinVal && d < MaxVal){ for(int j = 0; j < nb; j++) List_Add(outList, List_Pointer_Fast(inList, i + j));