/* * GL2PS, an OpenGL to PostScript Printing Library * Copyright (C) 1999-2009 Christophe Geuzaine <geuz@geuz.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your * option) any later version; or * * b) the GL2PS License as published by Christophe Geuzaine, either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either * the GNU Library General Public License or the GL2PS License for * more details. * * You should have received a copy of the GNU Library General Public * License along with this library in the file named "COPYING.LGPL"; * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. * * You should have received a copy of the GL2PS License with this * library in the file named "COPYING.GL2PS"; if not, I will be glad * to provide one. * * For the latest info about gl2ps and a full list of contributors, * see http://www.geuz.org/gl2ps/. * * Please report all bugs and problems to <gl2ps@geuz.org>. */ /* To compile on Linux: gcc gl2psTest.c gl2ps.c -lglut -lGL -lGLU -lX11 -lm To compile on MacOSX: gcc gl2psTest.c gl2ps.c -framework OpenGL -framework GLUT -framework Cocoa (To enable file compression you must add "-DHAVE_ZLIB -lz" to the commands above. To enable embedded bitmaps in SVG files you must add "-DHAVE_LIBPNG -DHAVE_ZLIB -lpng -lz".) */ #ifdef _MSC_VER /* MSVC Compiler */ #pragma comment(linker, "/entry:\"mainCRTStartup\"") #endif #include "gl2ps.h" #include <string.h> #ifdef __APPLE__ # include <GLUT/glut.h> #else # include <GL/glut.h> #endif static float rotation = -58.; static GLsizei window_w = 0; static GLsizei window_h = 0; static GLboolean display_multi = GL_TRUE; static GLboolean blend = GL_FALSE; static GLboolean teapot = GL_FALSE; static char *pixmap[] = { "****************************************************************", "*..............................................................*", "*..................++++++++++++++++++++++++++..................*", "*.............+++++++++++++++++++++++++++++++++++++............*", "*.......++++++++++++aaaaaaaaaaaaaaaaaaaaaaaa++++++++++++.......*", "*.......++++++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa++++++.......*", "*.......++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa++.......*", "*.......++aaaa++++aa+aaaaaaaa++++aaa++++++aaa+++++aaaa++.......*", "*.......++aaa+aaaa+a+aaaaaaa+aaaa+aa+aaaaa+a+aaaaa+aaa++.......*", "*.......++aa+aaaaaaa+aaaaaaaaaaa+aaa+aaaaa+a+aaaaaaaaa++.......*", "*.......++aa+aaa+++a+aaaaaaaaaa+aaaa++++++aaa+++++aaaa++.......*", "*.......++aa+aaaaa+a+aaaaaaaaa+aaaaa+aaaaaaaaaaaaa+aaa++.......*", "*.......++aaa+aaaa+a+aaaaaaaa+aaaaaa+aaaaaaa+aaaaa+aaa++.......*", "*.......++aaaa+++++a++++++aa++++++aa+aaaaaaaa+++++aaaa++.......*", "*.......++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa++.......*", "*.......++aaaaaaaaa++++++++++++++++++++++++++aaaaaaaaa++.......*", "*.......++aaa+++++++@@@@@@@@@@@+++++++++++++++++++aaaa++.......*", "*.......++++++@@+@@@+@@@++@@@@@+++++++++++++++++++++++++.......*", "*.......++@@@@@+@@@+@@@+@@@@+@@+++++++++++++++++++++++++.......*", "*.......++@@@@+@@@+@@+++++++@@@+++++++++++++++++++++++++.......*", "*.......++@@@@+++++++@@@@@@++@@++#####################++.......*", "*.......++@+++++@@@@@@@@@@@@@@@++#####################++.......*", "*.......++@+++@@@@@@@@@@@@@@@@@++#####################++.......*", "*.......++@++@@@@@@@+@@+@@@@@@@++#####################++.......*", "*.......++@@@@@+@@@+@@+@@@@@@@@++#####################++.......*", "*.......++@@@@+@@@+@@+@@++++++++++++++++++++++++++++++++.......*", "*.......++@@@@+@+++++++++@++++@+@+@+++++++++++++++++++++.......*", "*.......++@@@@+++@@@@@@@+@++@+++@+@+@+@+++++++++++++++++.......*", "*.......++@++++@@@@@@@@@@+@+++@+@+@+++++++++++++++++++++.......*", "*.......++@+++@@@@@@@@@@+@@@@@@@@@@@@@@+++++++++++++++++.......*", "*.......++@++@@@@@@+@@+@+@@@+++@@@@@@@@+++++++++++++++++.......*", "*.......++@@@@@+@@+@@+@@+@@+++++@@@@@@@+##############++.......*", "*.......++@@@@+@@+@@+@@++@@+@+++@@@@@+@+##############++.......*", "*.......++@@@@+@+++++++@+@@@@+++@@@@++@+##############++.......*", "*.......++@++++++@@@@@@++@@@@+++@@@@++@+##############++.......*", "*.......++@+++@@@@@@@@@@+@@@+++++@@@+@@+##############++.......*", "*.......++@++@@@@@@@@@@@+@+++++++++++@@+##############++.......*", "*.......+++++++++++++++++@+@+++++++++@@+++++++++++++++++.......*", "*.......+++++++++++++++++@+@+@@@@++++@@+@@@@@@@@@@@@@@++.......*", "*.......+++++++++++++++++@@@+@@@@@+@+@@+@@@+@@+@@@@@@@++.......*", "*........++++++++++++++++@@@@+@@@++@++@+@@+@@+@@@+@@@++........*", "*........++++++++++++++++@@@@@@@@+@@+@@+@+@@+@@@+@@@@++........*", "*........+++++++++++++++++@@@@@@+@@+@@+@++++++++++@@@++........*", "*.........++##############+@@@@@@@@@@++++@@@@@@@@++@++.........*", "*.........++###############+@@@@@@@@++++@@@@@@@@@@@@++.........*", "*..........++###############++++++++@@@@@@@+@@+@@@@++..........*", "*..........++##################++@@@@@+@@@+@@+@@+@@++..........*", "*...........++#################++@@@@+@@@+@@+@@+@@++...........*", "*...........++#################++@@@+@@++++++++@@@++...........*", "*............++++++++++++++++++++@@@++++@@@@@@++@++............*", "*.............+++++++++++++++++++@@+++@@@@@@@@@@@+.............*", "*.............+++++++++++++++++++@+++@@@@@@@@@@@++.............*", "*..............++++++++++++++++++@++@@@@+@@@@@@++..............*", "*...............+++++++++++++++++@@@+@@+@@+@@@++...............*", "*................++++++++++++++++@@+@@+@@+@@@++................*", "*.................++###########++@@+++++++@@++.................*", "*..................++##########++@+++@@@@+@++..................*", "*...................++#########++@++@@@@@@++...................*", "*....................+++#######++@++@@@@+++....................*", "*.....................++++#####++@@@@@++++.....................*", "*.......................++++###++@@@++++.......................*", "*.........................++++#++@++++.........................*", "*...........................++++++++...........................*", "*.............................++++.............................*", "*..............................................................*", "****************************************************************"}; void triangles() { /* two intersecting triangles */ glBegin(GL_TRIANGLES); glColor3f(1., 0., 0.); glVertex3f(-1., 1., 0.); glColor4f(1., 1., 0., 0.1); glVertex3f(-1., 0., 0.); glColor4f(1., 0., 1., 1.0); glVertex3f(1., 0., 0.2); glColor3f(0., 1., 0.); glVertex3f(1., 0., 0.); glColor3f(0., 1., 1.); glVertex3f(1., 0.5, 0.); glColor3f(0., 1., 1.); glVertex3f(-1., 0.5, 0.1); glEnd(); } void extras() { glColor3f(1., 0., 0.); glPointSize(1.); gl2psPointSize(1.); glBegin(GL_POINTS); glVertex3f(-1., 1.1, 0.); glEnd(); glPointSize(3.); gl2psPointSize(3.); glBegin(GL_POINTS); glVertex3f(-0.8, 1.1, 0.); glEnd(); glPointSize(5.); gl2psPointSize(5.); glBegin(GL_POINTS); glVertex3f(-0.6, 1.1, 0.); glEnd(); glPointSize(7.); gl2psPointSize(7.); glBegin(GL_POINTS); glVertex3f(-0.4, 1.1, 0.); glEnd(); glLineWidth(1.); gl2psLineWidth(1.); glBegin(GL_LINES); glVertex3f(-0.2, 1.05, 0.); glVertex3f(0.2, 1.05, 0.); glEnd(); glEnable(GL_LINE_STIPPLE); glLineStipple(1, 0x087F); gl2psEnable(GL2PS_LINE_STIPPLE); glBegin(GL_LINES); glVertex3f(-0.2, 1.15, 0.); glVertex3f(0.2, 1.15, 0.); glEnd(); glDisable(GL_LINE_STIPPLE); gl2psDisable(GL2PS_LINE_STIPPLE); glLineWidth(3.); gl2psLineWidth(3.); glBegin(GL_LINES); glVertex3f(0.4, 1.05, 0.); glVertex3f(0.8, 1.05, 0.); glEnd(); glEnable(GL_LINE_STIPPLE); glLineStipple(2, 0x0F0F); /* glLineStipple(1, 0xAAAA); */ gl2psEnable(GL2PS_LINE_STIPPLE); glBegin(GL_LINES); glVertex3f(0.4, 1.15, 0.); glVertex3f(0.8, 1.15, 0.); glEnd(); glDisable(GL_LINE_STIPPLE); gl2psDisable(GL2PS_LINE_STIPPLE); glPointSize(1); gl2psPointSize(1); glLineWidth(1); gl2psLineWidth(1); } void objects() { glPushMatrix(); glEnable(GL_LIGHTING); glRotatef(rotation, 2., 0., 1.); glColor4d(0.2, 0.2, 0.9, 0.2); if(teapot == GL_TRUE){ glutSolidTeapot(0.7); } else{ glutSolidTorus(0.3, 0.6, 20, 20); } glDisable(GL_LIGHTING); glPopMatrix(); } void printstring(char *string, float angle) { unsigned int i; char *fonts[] = { "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", "Symbol", "ZapfDingbats" }; /* call gl2psText before the glut function since glutBitmapCharacter changes the raster position... */ gl2psTextOpt(string, fonts[4], 12, GL2PS_TEXT_BL, angle); for (i = 0; i < strlen(string); i++) glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, string[i]); } void text() { double x = -1.25, y = -0.33, dy = 0.13; glColor3f(1., 1., 0.); glRasterPos2d(x, y); printstring("Press:", 0.); y -= dy; glRasterPos2d(x, y); printstring(" p: to change the print format (PS, EPS, PDF, ...)", 0.); y -= dy; glRasterPos2d(x, y); printstring(" s: to save the images", 0.); y -= dy; glRasterPos2d(x, y); printstring(" t: to alternate between teapot and torus", 0.); y -= dy; glRasterPos2d(x, y); printstring(" v: to alternate between single and multiple viewport modes", 0.); y -= dy; glRasterPos2d(x, y); printstring(" b: to change the blending mode (transparency)", 0.); y -= dy; glRasterPos2d(x, y); printstring(" q: to quit", 0.), 0.; y -= dy; glRasterPos2d(x, y); printstring("Click and move the mouse to rotate the objects", 0.); glRasterPos2d(0, 0.75); printstring("rotated", 45.); gl2psSpecial(GL2PS_TEX, "% This should only be printed in LaTeX output!"); } void cube() { glColor3d (0.0,1.0,0.); glBegin(GL_POLYGON); glVertex3d( 0.5,-0.5,-0.5); glColor4d (0.0,1.0,0.,0.2); glVertex3d( 0.5, 0.5,-0.5); glVertex3d(-0.5, 0.5,-0.5); glColor4d (0.0,1.0,0.,1); glVertex3d(-0.5,-0.5,-0.5); glEnd(); glColor3d (1.0,0.0,0.); glBegin(GL_POLYGON); glColor4d (1.0,0.0,0.,0.1); glVertex3d( 0.5,-0.5,0.5); glColor4d (1.0,0.5,1.,0.9); glVertex3d( 0.5, 0.5,0.5); glVertex3d(-0.5, 0.5,0.5); glColor4d (1.0,0.5,1.,0.1); glVertex3d(-0.5,-0.5,0.5); glEnd(); glLineWidth(4.0); glColor3d (1.0,1.0,0.); glBegin(GL_LINES); glVertex3d( 0.5,-0.5, 0.5); glVertex3d( 0.5,-0.5,-0.5); glVertex3d( 0.5, 0.5, 0.5); glVertex3d( 0.5, 0.5,-0.5); glVertex3d(-0.5, 0.5, 0.5); glVertex3d(-0.5, 0.5,-0.5); glVertex3d(-0.5,-0.5, 0.5); glVertex3d(-0.5,-0.5,-0.5); glEnd(); } void image(float x, float y, GLboolean opaque) { int w = 64, h = 66, row, col, pos = 0; float *pixels, r = 0., g = 0., b = 0.; /* Fill a pixmap (each pixel contains three floats defining an RGB color) */ pixels = (opaque == GL_TRUE) ? (float*)malloc(3*w*h*sizeof(float)) : (float*)malloc(4*w*h*sizeof(float)); for(row = h-1; row >= 0; row--){ for(col = 0; col < w; col++){ switch(pixmap[row][col]){ case '.' : r = 255.; g = 255.; b = 255.; break; case '+' : r = 0. ; g = 0. ; b = 0. ; break; case '@' : r = 255.; g = 209.; b = 0. ; break; case '#' : r = 255.; g = 0. ; b = 0. ; break; case 'a' : r = 255.; g = 209.; b = 0. ; break; case '*' : r = 0.; g = 0. ; b = 20. ; break; } r /= 255.; g /= 255.; b /= 255.; pixels[pos] = r; pos++; pixels[pos] = g; pos++; pixels[pos] = b; pos++; if(opaque) continue; switch(pixmap[row][col]){ case '.' : pixels[pos] = col / (float)w ; break; case 'a' : pixels[pos] = 1 - col / ((float)w - 7) ; break; default : pixels[pos] = 1. ; break; } pos++; } } glRasterPos2f(x, y); /* call gl2psDrawPixels first since glDrawPixels can change the raster position */ if(opaque){ gl2psDrawPixels((GLsizei)w, (GLsizei)h, 0, 0, GL_RGB, GL_FLOAT, pixels); glDrawPixels((GLsizei)w, (GLsizei)h, GL_RGB, GL_FLOAT, pixels); } else{ gl2psDrawPixels((GLsizei)w, (GLsizei)h, 0, 0, GL_RGBA, GL_FLOAT, pixels); glDrawPixels((GLsizei)w, (GLsizei)h, GL_RGBA, GL_FLOAT, pixels); } free(pixels); } /* A simple drawing function, using the default viewport */ void draw_single() { glScissor(0, 0, window_w, window_h); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); triangles(); extras(); objects(); text(); glFlush(); } /* A more complex drawing function, using 2 separate viewports */ void draw_multi() { GLint viewport[4]; glScissor(0, 0, window_w, window_h); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* First viewport with triangles, teapot or torus, etc. */ glViewport((GLint)(window_w * 0.05), (GLint)(window_h * 0.525), (GLsizei)(window_w * 0.9), (GLsizei)(window_h * 0.45)); glScissor((GLint)(window_w * 0.05), (GLint)(window_h * 0.525), (GLsizei)(window_w * 0.9), (GLsizei)(window_h * 0.45)); glClearColor(0.2, 0.2, 0.2, 0.); glGetIntegerv(GL_VIEWPORT, viewport); gl2psBeginViewport(viewport); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.3,1.3, -1.3,1.3, -1.3,1.3); glMatrixMode(GL_MODELVIEW); objects(); triangles(); extras(); text(); gl2psEndViewport(); /* Second viewport with cube, image, etc. */ glViewport((GLint)(window_w * 0.05), (GLint)(window_h * 0.025), (GLsizei)(window_w * 0.9), (GLsizei)(window_h * 0.45)); glScissor((GLint)(window_w * 0.05), (GLint)(window_h * 0.025), (GLsizei)(window_w * 0.9), (GLsizei)(window_h * 0.45)); glClearColor(0.8, 0.8, 0.8, 0.); glGetIntegerv(GL_VIEWPORT, viewport); gl2psBeginViewport(viewport); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.3,1.3, -1.3,1.3, -1.3,1.3); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glRotatef(rotation, 1., 1., 1.); image(-0.8, -0.3, GL_TRUE); cube(); extras(); image(-0.8, 0.4, GL_FALSE); glPopMatrix(); gl2psEndViewport(); glClearColor(0.5, 0.5, 0.5, 0.); glFlush(); } void display() { GLfloat spec[4] = {0.6, 0.6, 0.6, 1.0}; glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glShadeModel(GL_SMOOTH); glEnable(GL_LIGHT0); glEnable(GL_SCISSOR_TEST); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 60); if(blend){ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else{ glDisable(GL_BLEND); } if(display_multi == GL_TRUE){ draw_multi(); } else{ draw_single(); } } void reshape(int w, int h) { window_w = w; window_h = h; glViewport(0, 0, (GLsizei)window_w, (GLsizei)window_h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.3,1.3, -1.3,1.3, -1.3,1.3); glMatrixMode(GL_MODELVIEW); glClearColor(0.5, 0.5, 0.5, 0.); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void writefile(int format, int sort, int options, int nbcol, char *filename, const char *extension) { FILE *fp; char file[256]; int state = GL2PS_OVERFLOW, buffsize = 0; GLint viewport[4]; strcpy(file, filename); strcat(file, "."); strcat(file, extension); viewport[0] = 0; viewport[1] = 0; viewport[2] = window_w; viewport[3] = window_h; fp = fopen(file, "wb"); if(!fp){ printf("Unable to open file %s for writing\n", file); exit(1); } printf("Saving image to file %s... ", file); fflush(stdout); while(state == GL2PS_OVERFLOW){ buffsize += 1024*1024; gl2psBeginPage(file, "gl2psTest", viewport, format, sort, options, GL_RGBA, 0, NULL, nbcol, nbcol, nbcol, buffsize, fp, file); display(); state = gl2psEndPage(); } fclose(fp); printf("Done!\n"); fflush(stdout); } void keyboard(unsigned char key, int x, int y) { int opt; char ext[32]; static int format = GL2PS_PS; switch(key){ case 27: case 'q': exit(0); break; case 't': teapot = (teapot) ? GL_FALSE : GL_TRUE; display(); break; case 'p': if (format == GL2PS_PS) format = GL2PS_EPS; else if(format == GL2PS_EPS) format = GL2PS_TEX; else if(format == GL2PS_TEX) format = GL2PS_PDF; else if(format == GL2PS_PDF) format = GL2PS_SVG; else if(format == GL2PS_SVG) format = GL2PS_PGF; else format = GL2PS_PS; printf("Print format changed to '%s'\n", gl2psGetFormatDescription(format)); break; case 'b': blend = !blend; display(); break; case 'v': display_multi = display_multi ? GL_FALSE : GL_TRUE; reshape(window_w, window_h); display(); break; case 's': strcpy(ext, gl2psGetFileExtension(format)); opt = GL2PS_DRAW_BACKGROUND; writefile(format, GL2PS_SIMPLE_SORT, opt, 0, "outSimple", ext); opt = GL2PS_DRAW_BACKGROUND | GL2PS_OCCLUSION_CULL; writefile(format, GL2PS_SIMPLE_SORT, opt, 0, "outSimpleCulled", ext); opt = GL2PS_DRAW_BACKGROUND | GL2PS_NO_PS3_SHADING | GL2PS_TIGHT_BOUNDING_BOX; writefile(format, GL2PS_SIMPLE_SORT, opt, 2, "outSimpleShading2", ext); writefile(format, GL2PS_SIMPLE_SORT, opt, 8, "outSimpleShading8", ext); writefile(format, GL2PS_SIMPLE_SORT, opt, 16, "outSimpleShading16", ext); opt = GL2PS_NO_TEXT; writefile(format, GL2PS_SIMPLE_SORT, opt, 0, "outSimpleNoText", ext); opt = GL2PS_DRAW_BACKGROUND | GL2PS_BEST_ROOT; writefile(format, GL2PS_BSP_SORT, opt, 0, "outBsp", ext); opt = GL2PS_DRAW_BACKGROUND | GL2PS_OCCLUSION_CULL | GL2PS_BEST_ROOT; writefile(format, GL2PS_BSP_SORT, opt, 0, "outBspCulled", ext); #ifdef GL2PS_HAVE_ZLIB opt = GL2PS_DRAW_BACKGROUND | GL2PS_OCCLUSION_CULL | GL2PS_BEST_ROOT | GL2PS_COMPRESS; if(format == GL2PS_PS || format == GL2PS_EPS) strcat(ext, ".gz"); else if(format == GL2PS_SVG) strcat(ext, "z"); writefile(format, GL2PS_BSP_SORT, opt, 0, "outBspCulledCompressed", ext); #endif printf("GL2PS %d.%d.%d%s done with all images\n", GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION); break; } } void motion(int x, int y) { rotation += 10.; display(); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_DEPTH); glutInitWindowSize(400, 600); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMotionFunc(motion); glutMainLoop(); return 0; }