From bbe072e547ef4a2d7f13675710509af9060b1f09 Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Tue, 16 Sep 2003 23:50:59 +0000 Subject: [PATCH] New native PDF support --- Fltk/Callbacks.cpp | 34 +- Graphics/CreateFile.cpp | 23 +- Graphics/gl2ps.cpp | 1113 ++++++++++++++++++++++++++++++++++++--- Graphics/gl2ps.h | 55 +- Mesh/Mesh.h | 2 + 5 files changed, 1148 insertions(+), 79 deletions(-) diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp index f7ca355a30..a0b8dd76b7 100644 --- a/Fltk/Callbacks.cpp +++ b/Fltk/Callbacks.cpp @@ -1,4 +1,4 @@ -// $Id: Callbacks.cpp,v 1.182 2003-07-21 23:31:16 geuzaine Exp $ +// $Id: Callbacks.cpp,v 1.183 2003-09-16 23:50:58 geuzaine Exp $ // // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle // @@ -469,6 +469,34 @@ void _save_epstex_accurate(char *name) CreateOutputFile(name, FORMAT_EPSTEX); CTX.print.eps_quality = old; } +void _save_pdf_simple(char *name) +{ + int old = CTX.print.eps_quality; + CTX.print.eps_quality = 1; + CreateOutputFile(name, FORMAT_PDF); + CTX.print.eps_quality = old; +} +void _save_pdf_accurate(char *name) +{ + int old = CTX.print.eps_quality; + CTX.print.eps_quality = 2; + CreateOutputFile(name, FORMAT_PDF); + CTX.print.eps_quality = old; +} +void _save_pdftex_simple(char *name) +{ + int old = CTX.print.eps_quality; + CTX.print.eps_quality = 1; + CreateOutputFile(name, FORMAT_PDFTEX); + CTX.print.eps_quality = old; +} +void _save_pdftex_accurate(char *name) +{ + int old = CTX.print.eps_quality; + CTX.print.eps_quality = 2; + CreateOutputFile(name, FORMAT_PDFTEX); + CTX.print.eps_quality = old; +} void _save_jpegtex(char *name) { CreateOutputFile(name, FORMAT_JPEGTEX); @@ -563,6 +591,8 @@ void file_save_as_cb(CALLBACK_ARGS) {"PostScript accurate (*.ps)", _save_ps_accurate}, {"Encapsulated PostScript fast (*.eps)", _save_eps_simple}, {"Encapsulated PostScript accurate (*.eps)", _save_eps_accurate}, + {"PDF fast (*.pdf)", _save_pdf_simple}, + {"PDF accurate (*.pdf)", _save_pdf_accurate}, {"PPM (*.ppm)", _save_ppm}, #if defined(HAVE_LIBJPEG) {"LaTeX JPEG part (*.jpg)", _save_jpegtex}, @@ -572,6 +602,8 @@ void file_save_as_cb(CALLBACK_ARGS) #endif {"LaTeX EPS part fast (*.eps)", _save_epstex_simple}, {"LaTeX EPS part accurate (*.eps)", _save_epstex_accurate}, + {"LaTeX PDF part fast (*.pdf)", _save_pdftex_simple}, + {"LaTeX PDF part accurate (*.pdf)", _save_pdftex_accurate}, {"LaTeX TeX part (*.tex)", _save_tex}, {"UCB YUV (*.yuv)", _save_yuv} }; diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp index ad846bdb37..a1069d4393 100644 --- a/Graphics/CreateFile.cpp +++ b/Graphics/CreateFile.cpp @@ -1,4 +1,4 @@ -// $Id: CreateFile.cpp,v 1.44 2003-09-01 23:53:00 geuzaine Exp $ +// $Id: CreateFile.cpp,v 1.45 2003-09-16 23:50:58 geuzaine Exp $ // // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle // @@ -92,12 +92,16 @@ void CreateOutputFile(char *name, int format) CreateOutputFile(name, FORMAT_PS); else if(!strcmp(ext, ".eps")) CreateOutputFile(name, FORMAT_EPS); + else if(!strcmp(ext, ".pdf")) + CreateOutputFile(name, FORMAT_PDF); else if(!strcmp(ext, ".tex")) CreateOutputFile(name, FORMAT_TEX); else if(!strcmp(ext, ".pstex")) CreateOutputFile(name, FORMAT_PSTEX); else if(!strcmp(ext, ".epstex")) CreateOutputFile(name, FORMAT_EPSTEX); + else if(!strcmp(ext, ".pdftex")) + CreateOutputFile(name, FORMAT_PDFTEX); else if(!strcmp(ext, ".jpegtex")) CreateOutputFile(name, FORMAT_JPEGTEX); else if(!strcmp(ext, ".ppm")) @@ -189,11 +193,18 @@ void CreateOutputFile(char *name, int format) case FORMAT_PSTEX: case FORMAT_EPS: case FORMAT_EPSTEX: + case FORMAT_PDF: + case FORMAT_PDFTEX: if(!(fp = fopen(name, "w"))) { Msg(GERROR, "Unable to open file '%s'", name); return; } - psformat = (format == FORMAT_PS || format == FORMAT_PSTEX) ? GL2PS_PS : GL2PS_EPS; + if(format == FORMAT_PDF || format == FORMAT_PDFTEX) + psformat = GL2PS_PDF; + else if(format == FORMAT_PS || format == FORMAT_PSTEX) + psformat = GL2PS_PS; + else + psformat = GL2PS_EPS; pssort = (CTX.print.eps_quality == 1) ? GL2PS_SIMPLE_SORT : GL2PS_BSP_SORT; psoptions = GL2PS_SIMPLE_LINE_OFFSET | GL2PS_SILENT | @@ -201,7 +212,8 @@ void CreateOutputFile(char *name, int format) (CTX.print.eps_best_root ? GL2PS_BEST_ROOT : 0) | (CTX.print.eps_background ? GL2PS_DRAW_BACKGROUND : 0) | (format == FORMAT_PSTEX ? GL2PS_NO_TEXT : 0) | - (format == FORMAT_EPSTEX ? GL2PS_NO_TEXT : 0); + (format == FORMAT_EPSTEX ? GL2PS_NO_TEXT : 0) | + (format == FORMAT_PDFTEX ? GL2PS_NO_TEXT : 0); size3d = 0; res = GL2PS_OVERFLOW; @@ -215,7 +227,10 @@ void CreateOutputFile(char *name, int format) CTX.print.gl_fonts = 1; res = gl2psEndPage(); } - Msg(INFO, "PS/EPS creation complete '%s'", name); + if(psformat == GL2PS_PDF) + Msg(INFO, "PDF creation complete '%s'", name); + else + Msg(INFO, "PS/EPS creation complete '%s'", name); Msg(STATUS2, "Wrote '%s'", name); fclose(fp); break; diff --git a/Graphics/gl2ps.cpp b/Graphics/gl2ps.cpp index 5247674324..57b05c6adc 100644 --- a/Graphics/gl2ps.cpp +++ b/Graphics/gl2ps.cpp @@ -2,7 +2,7 @@ * GL2PS, an OpenGL to PostScript Printing Library * Copyright (C) 1999-2003 Christophe Geuzaine * - * $Id: gl2ps.cpp,v 1.69 2003-07-04 15:11:55 geuzaine Exp $ + * $Id: gl2ps.cpp,v 1.70 2003-09-16 23:50:58 geuzaine Exp $ * * E-mail: geuz@geuz.org * URL: http://www.geuz.org/gl2ps/ @@ -35,12 +35,14 @@ * Shahzad Muzaffar <Shahzad.Muzaffar@cern.ch> * Lassi Tuura <lassi.tuura@cern.ch> * Guy Barrand <barrand@lal.in2p3.fr> + * Micha Bieber <bieber@traits.de> */ #include <string.h> #include <sys/types.h> #include <stdarg.h> #include <time.h> +#include <float.h> #include "gl2ps.h" /* The gl2ps context. gl2ps is not thread safe (we should create a @@ -48,7 +50,11 @@ GL2PScontext *gl2ps = NULL; -/* Some 'system' utility routines */ +/********************************************************************* + * + * Utility routines + * + *********************************************************************/ void gl2psMsg(GLint level, char *fmt, ...){ va_list args; @@ -94,6 +100,21 @@ void gl2psFree(void *ptr){ free(ptr); } +void gl2psWriteByte(FILE *stream, unsigned char byte){ + unsigned char h = byte / 16; + unsigned char l = byte % 16; + fprintf(stream, "%x%x", h, l); +} + +size_t gl2psWriteBigEndian(unsigned long data, size_t bytes, FILE* fp){ + size_t i; + size_t size = sizeof(unsigned long); + for(i = 1; i <= bytes; ++i){ + fputc(0xff & (data >> (size-i) * 8), fp); + } + return bytes; +} + /* The list handling routines */ void gl2psListRealloc(GL2PSlist *list, GLint n){ @@ -141,7 +162,7 @@ void gl2psListAdd(GL2PSlist *list, void *data){ memcpy(&list->array[(list->n - 1) * list->size], data, list->size); } -GLint gl2psListNbr(GL2PSlist *list){ +int gl2psListNbr(GL2PSlist *list){ return(list->n); } @@ -176,7 +197,96 @@ void gl2psListActionInverse(GL2PSlist *list, } } -/* The 3D sorting routines */ +/* Helper for pixmaps and strings */ + +GL2PSimage* gl2psCopyPixmap(GL2PSimage* im){ + int size; + 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); + + image->pixels = (GLfloat*)gl2psMalloc(size); + memcpy(image->pixels, im->pixels, size); + + return image; +} + +void gl2psFreePixmap(GL2PSimage* im){ + if(!im) + return; + if(im->pixels) + gl2psFree(im->pixels); + gl2psFree(im); +} + +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; + + return text; +} + +void gl2psFreeText(GL2PSstring* text){ + if(!text) + return; + if(text->str) + gl2psFree(text->str); + if(text->fontname) + gl2psFree(text->fontname); + gl2psFree(text); +} + +/* Helpers for rgba colors */ + +float gl2psColorDiff(GL2PSrgba rgba1, GL2PSrgba rgba2){ + int i; + float res = 0; + for(i = 0; i < 3; ++i){ + res += (rgba1[i] - rgba2[i]) * (rgba1[i] - rgba2[i]); + } + return res; +} + +GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2){ + return !(rgba1[0] != rgba2[0] || + rgba1[1] != rgba2[1] || + rgba1[2] != rgba2[2]); +} + +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 1; +} + +void gl2psSetLastColor(GL2PSrgba rgba){ + int i; + for(i = 0; i < 3; ++i){ + gl2ps->lastrgba[i] = rgba[i]; + } +} + +/********************************************************************* + * + * 3D sorting routines + * + *********************************************************************/ GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane){ return(plane[0] * point[0] + @@ -678,7 +788,11 @@ void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, } } -/* The 2D sorting routines (for occlusion culling) */ +/********************************************************************* + * + * 2D sorting routines (for occlusion culling) + * + *********************************************************************/ GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane){ GLfloat n; @@ -1087,7 +1201,11 @@ void gl2psBuildPolygonBoundary(GL2PSbsptree *tree){ gl2psBuildPolygonBoundary(tree->front); } -/* The feedback buffer parser */ +/********************************************************************* + * + * Feedback buffer parser + * + *********************************************************************/ void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, GL2PSvertex *verts, GLint offset, @@ -1298,34 +1416,11 @@ void gl2psParseFeedbackBuffer(GLint used){ } } -GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2){ - return !(rgba1[0] != rgba2[0] || - rgba1[1] != rgba2[1] || - rgba1[2] != rgba2[2]); -} - -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 1; -} - -/* The PostScript routines. Other (vector) image formats should be - easy to generate by creating the three corresponding routines - (gl2psPrintXXXHeader, gl2psPrintXXXPrimitive, gl2psPrintXXXFooter, - gl2psPrintXXXBeginViewport and gl2psPrintXXXEndViewport) for the - new format. */ - -void gl2psWriteByte(FILE *stream, unsigned char byte){ - unsigned char h = byte / 16; - unsigned char l = byte % 16; - fprintf(stream, "%x%x", h, l); -} +/********************************************************************* + * + * PostScript routines + * + *********************************************************************/ void gl2psGetRGB(GLfloat *pixels, GLsizei width, GLsizei height, GLuint x, GLuint y, GLfloat *red, GLfloat *green, GLfloat *blue){ @@ -1353,12 +1448,12 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei fprintf(stream, "gsave\n"); fprintf(stream, "%.2f %.2f translate\n", x, y); - fprintf(stream, "%d %d scale\n", width, height); + fprintf(stream, "%d %d scale\n", (int)width, (int)height); if(greyscale){ /* greyscale, 8 bits per pixel */ - fprintf(stream, "/picstr %d string def\n", width); - fprintf(stream, "%d %d %d\n", width, height, 8); - fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height); + fprintf(stream, "/picstr %d string def\n", (int)width); + fprintf(stream, "%d %d %d\n", (int)width, (int)height, 8); + fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)width, (int)height, (int)height); fprintf(stream, "{ currentfile picstr readhexstring pop }\n"); fprintf(stream, "image\n"); for(row = 0; row < height; row++){ @@ -1379,8 +1474,8 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei nbyte2 *=3; col_max = (nbyte2 * 4)/3; fprintf(stream, "/rgbstr %d string def\n", nbyte2); - fprintf(stream, "%d %d %d\n", col_max, height, 2); - fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", col_max, height, height); + fprintf(stream, "%d %d %d\n", (int)col_max, (int)height, 2); + fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)col_max, (int)height, (int)height); fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n" ); fprintf(stream, "false 3\n" ); fprintf(stream, "colorimage\n" ); @@ -1427,8 +1522,8 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei nbyte4 *=3; col_max = (nbyte4 * 2)/3; fprintf(stream, "/rgbstr %d string def\n", nbyte4); - fprintf(stream, "%d %d %d\n", col_max, height, 4); - fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", col_max, height, height); + fprintf(stream, "%d %d %d\n", (int)col_max, (int)height, 4); + fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)col_max, (int)height, (int)height); fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n"); fprintf(stream, "false 3\n"); fprintf(stream, "colorimage\n"); @@ -1452,8 +1547,8 @@ void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei hei else{ /* color, 8 bits for r and g and b; rgbs following each other */ nbyte8 = width * 3; fprintf(stream, "/rgbstr %d string def\n", nbyte8); - fprintf(stream, "%d %d %d\n", width, height, 8); - fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height); + fprintf(stream, "%d %d %d\n", (int)width, (int)height, 8); + fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", (int)width, (int)height, (int)height); fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n"); fprintf(stream, "false 3\n"); fprintf(stream, "colorimage\n"); @@ -1504,18 +1599,24 @@ void gl2psPrintPostScriptHeader(void){ "%%%%Orientation: %s\n" "%%%%DocumentMedia: Default %d %d 0 () ()\n", (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait", - (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[3] : gl2ps->viewport[2], - (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[2] : gl2ps->viewport[3]); + (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, "%%%%BoundingBox: %d %d %d %d\n" "%%%%Copyright: GNU LGPL (C) 1999-2003 Christophe Geuzaine <geuz@geuz.org>\n" "%%%%EndComments\n", - (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[1] : gl2ps->viewport[0], - (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[0] : gl2ps->viewport[1], - (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[3] : gl2ps->viewport[2], - (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[2] : gl2ps->viewport[3]); + (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]); /* RGB color: r g b C (replace C by G in output to change from rgb to gray) Grayscale: r g b G @@ -1661,7 +1762,7 @@ void gl2psPrintPostScriptHeader(void){ if(gl2ps->options & GL2PS_LANDSCAPE){ fprintf(gl2ps->stream, "%d 0 translate 90 rotate\n", - gl2ps->viewport[3]); + (int)gl2ps->viewport[3]); } fprintf(gl2ps->stream, @@ -1686,17 +1787,15 @@ void gl2psPrintPostScriptHeader(void){ "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath fill\n", rgba[0], rgba[1], rgba[2], - gl2ps->viewport[0], gl2ps->viewport[1], gl2ps->viewport[2], - gl2ps->viewport[1], gl2ps->viewport[2], gl2ps->viewport[3], - gl2ps->viewport[0], gl2ps->viewport[3]); + (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]); } } void gl2psPrintPostScriptColor(GL2PSrgba rgba){ if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ - gl2ps->lastrgba[0] = rgba[0]; - gl2ps->lastrgba[1] = rgba[1]; - gl2ps->lastrgba[2] = rgba[2]; + gl2psSetLastColor(rgba); fprintf(gl2ps->stream, "%g %g %g C\n", rgba[0], rgba[1], rgba[2]); } } @@ -1843,7 +1942,11 @@ GLint gl2psPrintPostScriptEndViewport(void){ return res; } -/* The LaTeX routines */ +/********************************************************************* + * + * LaTeX routines + * + *********************************************************************/ void gl2psPrintTeXHeader(void){ char name[256]; @@ -1870,7 +1973,7 @@ void gl2psPrintTeXHeader(void){ "\\end{picture}%%\n" "%s\\begin{picture}(%d,%d)(0,0)\n", name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "", - gl2ps->viewport[2], gl2ps->viewport[3]); + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); } void gl2psPrintTeXPrimitive(void *a, void *b){ @@ -1880,8 +1983,45 @@ void gl2psPrintTeXPrimitive(void *a, void *b){ switch(prim->type){ case GL2PS_TEXT : +#if 0 /* old code: */ fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)[lb]{%s}}\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->text->str); +#endif + fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", + prim->text->fontsize); + fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)", + prim->verts[0].xyz[0], prim->verts[0].xyz[1]); + switch (prim->text->alignment) { + case GL2PS_TEXT_CL: + fprintf(gl2ps->stream, "[l]"); + break; + case GL2PS_TEXT_CR: + fprintf(gl2ps->stream, "[r]"); + break; + case GL2PS_TEXT_B: + fprintf(gl2ps->stream, "[b]"); + break; + case GL2PS_TEXT_BL: + fprintf(gl2ps->stream, "[bl]"); + break; + case GL2PS_TEXT_BR: + fprintf(gl2ps->stream, "[br]"); + break; + case GL2PS_TEXT_T: + fprintf(gl2ps->stream, "[t]"); + break; + case GL2PS_TEXT_TL: + fprintf(gl2ps->stream, "[tl]"); + break; + case GL2PS_TEXT_TR: + fprintf(gl2ps->stream, "[tr]"); + break; + default: + break; + } + fprintf(gl2ps->stream, "{\\textcolor[rgb]{%f,%f,%f}{", + prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2]); + fprintf(gl2ps->stream, "{%s}}}}\n", prim->text->str); break; default : break; @@ -1900,7 +2040,807 @@ GLint gl2psPrintTeXEndViewport(void){ return GL2PS_SUCCESS; } -/* The general primitive printing routine */ +/********************************************************************* + * + * PDF routines + * + *********************************************************************/ + +int gl2psPrintPDFCompressorType(){ + if(gl2ps->options & GL2PS_DEFLATE){ + return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n"); + } + return 0; +} + +int gl2psPrintPDFStrokeColor(GL2PSrgba rgba){ + int offs = 0; + int i; + + gl2psSetLastColor(rgba); + for(i = 0; i < 3; ++i){ + if(GL2PS_ZERO(rgba[i])) + offs += fprintf(gl2ps->stream, "%.0f ", 0.); + else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting*/ + offs += fprintf(gl2ps->stream, "%f ", rgba[i]); + else + offs += fprintf(gl2ps->stream, "%g ", rgba[i]); + } + offs += fprintf(gl2ps->stream, "RG\n"); + return offs; +} + +int gl2psPrintPDFFillColor(GL2PSrgba rgba){ + int offs = 0; + int i; + + for(i = 0; i < 3; ++i){ + if(GL2PS_ZERO(rgba[i])) + offs += fprintf(gl2ps->stream, "%.0f ", 0.); + else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting*/ + offs += fprintf(gl2ps->stream, "%f ", rgba[i]); + else + offs += fprintf(gl2ps->stream, "%g ", rgba[i]); + } + offs += fprintf(gl2ps->stream, "rg\n"); + return offs; +} + +int gl2psPrintPDFLineWidth(float lw){ + if(GL2PS_ZERO(lw)) + return fprintf(gl2ps->stream, "%.0f w\n", 0.); + else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting*/ + return fprintf(gl2ps->stream, "%f w\n", lw); + else + return fprintf(gl2ps->stream, "%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, an OpenGL to PostScript Printing Library)\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 */ + +int gl2psPrintPDFCatalog(){ + return fprintf(gl2ps->stream, + "2 0 obj\n" + "<<\n" + "/Type /Catalog\n" + "/Pages 3 0 R\n" + ">>\n" + "endobj\n"); +} + +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"); +} + +/* Open stream for data - graphical objects, fonts etc. PDF object 4*/ + +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; +} + +/* Stream setup - Graphics state, fill background if allowed */ + +int gl2psOpenPDFDataStreamWritePreface(){ + int offs; + GLint index; + GLfloat rgba[4]; + + offs = fprintf(gl2ps->stream, "/GS1 gs\n"); + + 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.; + } + offs += gl2psPrintPDFFillColor(rgba); + offs += fprintf(gl2ps->stream, "%d %d %d %d re\n", + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); + offs += fprintf(gl2ps->stream, "f\n"); + } + return offs; +} + +/* Use the functions above to create the first part of the PDF*/ + +void gl2psPrintPDFHeader(){ + int offs; + + /* tlist, tidxlist, ilist and slist contain triangles, indexes for + consecutive triangles, images and strings */ + gl2ps->tlist = gl2psListCreate(0, 1, sizeof(GL2PStriangle)); + gl2ps->tidxlist = gl2psListCreate(0, 1, sizeof(int)); + gl2ps->ilist = gl2psListCreate(0, 1, sizeof(GL2PSimage)); + gl2ps->slist = gl2psListCreate(0, 1, 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(); +} + + +int gl2psFlushPDFTriangles(){ + int offs = 0; + if(gl2ps->lasttype == GL2PS_TRIANGLE){ + gl2psListAdd(gl2ps->tidxlist,&gl2ps->consec_inner_cnt); + offs = fprintf(gl2ps->stream, "/Sh%d sh\n", gl2ps->consec_cnt++); + gl2ps->consec_inner_cnt = 0; + gl2ps->streamlength += offs; + } + return offs; +} + +int gl2psFlushPDFLines(){ + int offs = 0; + if(gl2ps->lasttype == GL2PS_LINE && !gl2ps->line_stroked){ + offs = fprintf(gl2ps->stream, "S\n"); + gl2ps->streamlength += offs; + gl2ps->line_stroked = 1; + } + return offs; +} + +/* The central primitive drawing */ + +void gl2psPrintPDFPrimitive(void *a, void *b){ + GL2PSprimitive *prim; + GL2PStriangle t; + GL2PSimage* image; + GL2PSstring* str; + + prim = *(GL2PSprimitive**)a; + + if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; + + if(prim->type != GL2PS_TRIANGLE) + gl2psFlushPDFTriangles(); + if(prim->type != GL2PS_LINE) + gl2psFlushPDFLines(); + + switch(prim->type){ + case GL2PS_PIXMAP : + image = gl2psCopyPixmap(prim->image); + gl2psListAdd(gl2ps->ilist, &image); + gl2ps->streamlength += fprintf(gl2ps->stream, + "q\n" + "%d 0 0 %d %f %f cm\n" + "/Im%d Do\n" + "Q\n", + (int)prim->image->width, (int)prim->image->height, + prim->verts[0].xyz[0], prim->verts[0].xyz[1], + gl2psListNbr(gl2ps->ilist)-1); + break; + case GL2PS_TEXT : + str = gl2psCopyText(prim->text); + gl2psListAdd(gl2ps->slist, &str); + gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); + gl2ps->streamlength += fprintf(gl2ps->stream, + "BT\n" + "/F%d %d Tf\n" + "%f %f Td\n" + "(%s) Tj\n" + "ET\n", + gl2psListNbr(gl2ps->slist)-1, + prim->text->fontsize, prim->verts[0].xyz[0], + prim->verts[0].xyz[1], prim->text->str); + break; + case GL2PS_POINT : + if(gl2ps->lastlinewidth != prim->width){ + gl2ps->lastlinewidth = prim->width; + gl2ps->streamlength += gl2psPrintPDFLineWidth(gl2ps->lastlinewidth); + } + gl2ps->streamlength += fprintf(gl2ps->stream, "1 J\n"); + gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); + gl2ps->streamlength += fprintf(gl2ps->stream, "%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 += fprintf(gl2ps->stream, "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 += fprintf(gl2ps->stream, "[%d] 0 d\n", prim->dash); + } + gl2ps->streamlength += fprintf(gl2ps->stream, "%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->line_stroked = 0; + + if(prim->dash){ + /* FIXME: use prim->dash */ + gl2ps->streamlength += fprintf(gl2ps->stream, "S\n[] 0 d\n"); + gl2ps->line_stroked = 1; + } + 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; + 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; + } + gl2ps->lasttype = prim->type; +} + +/* close stream and ... */ + +int gl2psClosePDFDataStream(){ + int offs = 0; + + offs += gl2psFlushPDFTriangles(); + offs += gl2psFlushPDFLines(); + + offs += fprintf(gl2ps->stream, + "endstream\n" + "endobj\n"); + return offs; +} + +/* ... write the now known length object */ + +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(){ + int offs; + + offs = fprintf(gl2ps->stream, + "6 0 obj\n" + "<<\n" + "/Type /Page\n" + "/Parent 3 0 R\n" + "/MediaBox [%d %d %d %d]\n", + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); + + if(gl2ps->options & GL2PS_LANDSCAPE) + offs += fprintf(gl2ps->stream, "/Rotate -90\n"); + + offs += fprintf(gl2ps->stream, + "/Contents 4 0 R\n" + "/Resources\n" + "<<\n" + "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n" + "/Length 5 0 R\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, + ">>\n" + ">>\n" + "endobj\n"); + + return offs; +} + +/* Extended graphics state for shading */ + +int gl2psPrintPDFExtGState(){ + return fprintf(gl2ps->stream, + "7 0 obj\n" + "<<\n" + "/Type /ExtGState\n" + "/SA false\n" + "/SM 0.02\n" + "/OP false\n" + "/op false\n" + "/OPM 0\n" + "/BG2 /Default\n" + "/UCR2 /Default\n" + "/TR2 /Default\n" + ">>\n" + "endobj\n"); +} + +/* Put a triangles uncompressed raw data in shader stream */ + +int gl2psPrintPDFShaderStreamData(GL2PStriangle triangle){ + int offs = 0; + int i; + unsigned long imap; + GLfloat diff, dx, dy; + + char edgeflag = 0; + double dmax = ~1UL; + + dx = gl2ps->viewport[2]-gl2ps->viewport[0]; + dy = gl2ps->viewport[3]-gl2ps->viewport[1]; + + for(i = 0; i < 3; ++i){ + offs += fwrite (&edgeflag, sizeof(char), 1, gl2ps->stream); + + /* In unfiltered mode the Shader stream in PDF requires to be in a + 'big-endian' order */ + + if(fabs(dx*dy) < FLT_MIN){ + offs += gl2psWriteBigEndian(0, 4, gl2ps->stream); + offs += gl2psWriteBigEndian(0, 4, gl2ps->stream); + } + 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 += gl2psWriteBigEndian(imap, 4, gl2ps->stream); + + 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 += gl2psWriteBigEndian(imap, 4, gl2ps->stream); + } + + imap = (unsigned long)(triangle[i].rgba[0] * dmax); + offs += gl2psWriteBigEndian(imap, 1, gl2ps->stream); + + imap = (unsigned long)(triangle[i].rgba[1] * dmax); + offs += gl2psWriteBigEndian(imap, 1, gl2ps->stream); + + imap = (unsigned long)(triangle[i].rgba[2] * dmax); + offs += gl2psWriteBigEndian(imap, 1, gl2ps->stream); + } + return offs; +} + +/* Writes shaded triangle */ + +int gl2psPrintPDFShader(int obj, GL2PSlist* triangles, int idx, int cnt ){ + int offs = 0; + int vertexbytes = 1+4+4+1+1+1; + int i; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<< " + "/ShadingType 4 " + "/ColorSpace /DeviceRGB " + "/BitsPerCoordinate 32 " + "/BitsPerComponent 8 " + "/BitsPerFlag 8 " + "/Decode [%d %d %d %d 0 1 0 1 0 1] ", + obj, + (int)gl2ps->viewport[0], (int)gl2ps->viewport[2], + (int)gl2ps->viewport[1], (int)gl2ps->viewport[3]); + + offs += gl2psPrintPDFCompressorType(); + + offs += fprintf(gl2ps->stream, + "/Length %d " + ">>\n" + "stream\n", + vertexbytes * 3 * cnt); + for(i = 0; i < cnt; ++i) + offs += gl2psPrintPDFShaderStreamData((GL2PSvertex*)gl2psListPointer(triangles, idx+i)); + + offs += fprintf(gl2ps->stream, + "\nendstream\n" + "endobj\n"); + return offs; +} + +/* Writes all triangles and returns field of offsets for the PDF cross + reference table */ + +int* gl2psPrintPDFShaderObjects(int firstObjnumber, int firstOffs){ + int size; + int* offs; + int i; + int idx = 0; + int tmp; + + size = gl2psListNbr(gl2ps->tidxlist); + offs = (int*)gl2psMalloc(sizeof(int) * (size+1)); + + offs[0] = firstOffs; + + for(i = 0; i < size; ++i){ + tmp = *(int*)gl2psListPointer(gl2ps->tidxlist, i); + + firstOffs += gl2psPrintPDFShader(i+firstObjnumber, gl2ps->tlist, idx, tmp); + offs[i+1] = firstOffs; + idx += tmp; + } + return offs; +} + +/* Similar groups of functions for pixmaps and text */ + +int gl2psPrintPDFPixmapStreamData(GL2PSimage* im){ + int x,y; + GLfloat r,g,b; + + 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); + fputc((int)(r*255),gl2ps->stream); + fputc((int)(g*255),gl2ps->stream); + fputc((int)(b*255),gl2ps->stream); + } + return 3 * im->width * im->height; +} + +int gl2psPrintPDFPixmap(int obj, GL2PSimage* im ){ + int offs = 0; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n" + "/Type /XObject\n" + "/Subtype /Image\n" + "/Width %d\n" + "/Height %d\n" + "/ColorSpace /DeviceRGB\n" + "/BitsPerComponent 8\n" + "/Length %d\n" + ">>\n" + "stream\n", + obj, (int)im->width, (int)im->height, + (int)(im->width * im->height * 3)); + + offs += gl2psPrintPDFPixmapStreamData(im); + + 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 ){ + int offs = 0; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n" + "/Type /Font\n" + "/Subtype /Type1\n" + "/Name /F%d\n" + "/BaseFont /%s\n" + "/Encoding /MacRomanEncoding\n" + ">>\n" + "endobj\n", + obj, fontnumber, s->fontname); + 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; + + for(i = 0; i < size; ++i){ + firstOffs += gl2psPrintPDFText(i+firstObjnumber, + *(GL2PSstring**)gl2psListPointer(gl2ps->slist, i),i); + offs[i+1] = firstOffs; + } + 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 */ + +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; + offs += gl2psClosePDFDataStream(); + gl2ps->cref[4] = offs; + + offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength); + gl2ps->cref[5] = 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); + + 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; + + /* 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); + + 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]); + } + + fprintf(gl2ps->stream, + "trailer\n" + "<<\n" + "/Size %d\n" + "/Info 1 0 R\n" + "/Root 2 0 R\n" + ">>\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); +} + +/* PDF begin viewport */ + +void gl2psPrintPDFBeginViewport(GLint viewport[4]){ + int offs; + GLint index; + GLfloat rgba[4]; + int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; + + offs = 0; + + glRenderMode(GL_FEEDBACK); + + offs += fprintf(gl2ps->stream, "q\n"); + + 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.; + } + offs += fprintf(gl2ps->stream, + "%f %f %f rg\n" + "%d %d %d %d re\n" + /* "W\n" */ + "f\n", + rgba[0], rgba[1], rgba[2],x, y, w, h); + } + gl2ps->streamlength += offs; +} + +GLint gl2psPrintPDFEndViewport(){ + GLint res; + GLint gl2psPrintPrimitives(void); + + res = gl2psPrintPrimitives(); + gl2ps->streamlength += fprintf(gl2ps->stream, "Q\n"); + + return res; +} + +/********************************************************************* + * + * General primitive printing routine + * + *********************************************************************/ GLint gl2psPrintPrimitives(void){ GL2PSbsptree *root; @@ -1919,7 +2859,9 @@ GLint gl2psPrintPrimitives(void){ return GL2PS_NO_FEEDBACK; /* Empty feedback buffer */ } - if(gl2ps->format == GL2PS_PS || gl2ps->format == GL2PS_EPS){ + if(gl2ps->format == GL2PS_PS || + gl2ps->format == GL2PS_EPS || + gl2ps->format == GL2PS_PDF){ gl2psParseFeedbackBuffer(used); } @@ -1935,6 +2877,9 @@ GLint gl2psPrintPrimitives(void){ case GL2PS_EPS : pprim = gl2psPrintPostScriptPrimitive; break; + case GL2PS_PDF : + pprim = gl2psPrintPDFPrimitive; + break; } switch(gl2ps->sort){ @@ -1981,7 +2926,11 @@ GLint gl2psPrintPrimitives(void){ return GL2PS_SUCCESS; } -/* The public routines */ +/********************************************************************* + * + * Public routines + * + *********************************************************************/ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, @@ -2057,6 +3006,14 @@ 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->line_stroked = 0; + switch(gl2ps->format){ case GL2PS_TEX : gl2psPrintTeXHeader(); @@ -2065,6 +3022,9 @@ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, case GL2PS_EPS : gl2psPrintPostScriptHeader(); break; + case GL2PS_PDF : + gl2psPrintPDFHeader(); + break; default : gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", gl2ps->format); gl2psFree(gl2ps); @@ -2097,6 +3057,9 @@ GL2PSDLL_API GLint gl2psEndPage(void){ case GL2PS_EPS : gl2psPrintPostScriptFooter(); break; + case GL2PS_PDF : + gl2psPrintPDFFooter(); + break; } fflush(gl2ps->stream); @@ -2114,9 +3077,13 @@ GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]){ if(!gl2ps) return GL2PS_UNINITIALIZED; switch(gl2ps->format){ + case GL2PS_PS : case GL2PS_EPS : gl2psPrintPostScriptBeginViewport(viewport); break; + case GL2PS_PDF : + gl2psPrintPDFBeginViewport(viewport); + break; default : /* FIXME: handle other formats */ break; @@ -2131,9 +3098,13 @@ GL2PSDLL_API GLint gl2psEndViewport(void){ if(!gl2ps) return GL2PS_UNINITIALIZED; switch(gl2ps->format){ + case GL2PS_PS : case GL2PS_EPS : res = gl2psPrintPostScriptEndViewport(); break; + case GL2PS_PDF : + res = gl2psPrintPDFEndViewport(); + break; default : /* FIXME: handle other formats */ res = GL2PS_SUCCESS; @@ -2143,7 +3114,8 @@ GL2PSDLL_API GLint gl2psEndViewport(void){ return res; } -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 alignment, GL2PSrgba rgba){ GLfloat pos[4]; GL2PSprimitive *prim; GLboolean valid; @@ -2169,19 +3141,32 @@ GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort font prim->culled = 0; prim->dash = 0; prim->width = 1; - glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); + if(rgba){ + prim->verts[0].rgba[0] = rgba[0]; + prim->verts[0].rgba[1] = rgba[1]; + prim->verts[0].rgba[2] = rgba[2]; + prim->verts[0].rgba[3] = rgba[3]; + } + else{ + glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); + } prim->text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); prim->text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char)); strcpy(prim->text->str, str); prim->text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); strcpy(prim->text->fontname, fontname); prim->text->fontsize = fontsize; + prim->text->alignment = alignment; gl2psListAdd(gl2ps->primitives, &prim); return GL2PS_SUCCESS; } +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, diff --git a/Graphics/gl2ps.h b/Graphics/gl2ps.h index 74403c79c6..64eb67b348 100644 --- a/Graphics/gl2ps.h +++ b/Graphics/gl2ps.h @@ -2,7 +2,7 @@ * GL2PS, an OpenGL to PostScript Printing Library * Copyright (C) 1999-2003 Christophe Geuzaine * - * $Id: gl2ps.h,v 1.41 2003-07-03 18:59:52 geuzaine Exp $ + * $Id: gl2ps.h,v 1.42 2003-09-16 23:50:58 geuzaine Exp $ * * E-mail: geuz@geuz.org * URL: http://www.geuz.org/gl2ps/ @@ -55,9 +55,9 @@ /* Version number */ -#define GL2PS_MAJOR_VERSION 0 -#define GL2PS_MINOR_VERSION 9 -#define GL2PS_PATCH_VERSION 2 +#define GL2PS_MAJOR_VERSION 1 +#define GL2PS_MINOR_VERSION 0 +#define GL2PS_PATCH_VERSION 0 #define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \ 0.01 * GL2PS_MINOR_VERSION + \ @@ -65,9 +65,10 @@ /* Output file format */ -#define GL2PS_PS 1 -#define GL2PS_EPS 2 -#define GL2PS_TEX 3 +#define GL2PS_PS 1 +#define GL2PS_EPS 2 +#define GL2PS_TEX 3 +#define GL2PS_PDF 4 /* Sorting algorithms */ @@ -88,6 +89,7 @@ #define GL2PS_NO_PS3_SHADING (1<<7) #define GL2PS_NO_PIXMAP (1<<8) #define GL2PS_USE_CURRENT_VIEWPORT (1<<9) +#define GL2PS_DEFLATE (1<<10) /* Arguments for gl2psEnable/gl2psDisable */ @@ -102,6 +104,7 @@ #define GL2PS_SIMPLE_OFFSET 0.05 #define GL2PS_SIMPLE_OFFSET_LARGE 1.0 #define GL2PS_ZERO(arg) (fabs(arg)<1.e-20) +#define GL2PS_FIXED_XREF_ENTRIES 7 /* Message levels and error codes */ @@ -115,6 +118,7 @@ /* Primitive types */ +#define GL2PS_NOTYPE -1 #define GL2PS_TEXT 1 #define GL2PS_POINT 2 #define GL2PS_LINE 3 @@ -122,6 +126,18 @@ #define GL2PS_TRIANGLE 5 #define GL2PS_PIXMAP 6 +/* 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 @@ -175,9 +191,12 @@ typedef struct { GL2PSrgba rgba; } GL2PSvertex; +typedef GL2PSvertex GL2PStriangle[3]; + typedef struct { GLshort fontsize; char *str, *fontname; + GLint alignment; } GL2PSstring; typedef struct { @@ -196,17 +215,31 @@ typedef struct { } GL2PSprimitive; typedef struct { - GLint format, sort, options, colorsize, colormode, buffersize, maxbestroot; + /* general */ + GLint format, sort, options, colorsize, colormode, buffersize; const char *title, *producer, *filename; - GLboolean boundary, zerosurfacearea; + GLboolean boundary; GLfloat *feedback, offset[2]; GLint viewport[4]; GL2PSrgba *colormap, lastrgba, threshold; float lastlinewidth; GL2PSlist *primitives; - GL2PSbsptree2d *imagetree; FILE *stream; + + /* 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, line_stroked; } GL2PScontext; /* public functions */ @@ -225,6 +258,8 @@ 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 gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, + GLint align, GL2PSrgba color); GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, GLenum format, GLenum type, const void *pixels); diff --git a/Mesh/Mesh.h b/Mesh/Mesh.h index b2c4b24a34..5e29f74ef1 100644 --- a/Mesh/Mesh.h +++ b/Mesh/Mesh.h @@ -50,6 +50,8 @@ #define FORMAT_EPSTEX 21 #define FORMAT_PNG 22 #define FORMAT_PNGTEX 23 +#define FORMAT_PDF 24 +#define FORMAT_PDFTEX 25 #define CONV_VALUE 0.8 -- GitLab