/* * Test OSMesa interface at 8, 16 and 32 bits/channel. * * Usage: osdemo [options] * * Options: * -f generate image files * -g render gradient and print color values */ #include <assert.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "GL/osmesa.h" #include "GL/glu.h" #define WIDTH 600 #define HEIGHT 600 static GLboolean WriteFiles = GL_FALSE; static GLboolean Gradient = GL_FALSE; static void Sphere(float radius, int slices, int stacks) { GLUquadric *q = gluNewQuadric(); gluQuadricNormals(q, GLU_SMOOTH); gluSphere(q, radius, slices, stacks); gluDeleteQuadric(q); } static void Cone(float base, float height, int slices, int stacks) { GLUquadric *q = gluNewQuadric(); gluQuadricDrawStyle(q, GLU_FILL); gluQuadricNormals(q, GLU_SMOOTH); gluCylinder(q, base, 0.0, height, slices, stacks); gluDeleteQuadric(q); } static void Torus(float innerRadius, float outerRadius, int sides, int rings) { /* from GLUT... */ int i, j; GLfloat theta, phi, theta1; GLfloat cosTheta, sinTheta; GLfloat cosTheta1, sinTheta1; const GLfloat ringDelta = 2.0 * M_PI / rings; const GLfloat sideDelta = 2.0 * M_PI / sides; theta = 0.0; cosTheta = 1.0; sinTheta = 0.0; for (i = rings - 1; i >= 0; i--) { theta1 = theta + ringDelta; cosTheta1 = cos(theta1); sinTheta1 = sin(theta1); glBegin(GL_QUAD_STRIP); phi = 0.0; for (j = sides; j >= 0; j--) { GLfloat cosPhi, sinPhi, dist; phi += sideDelta; cosPhi = cos(phi); sinPhi = sin(phi); dist = outerRadius + innerRadius * cosPhi; glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, innerRadius * sinPhi); glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); glVertex3f(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi); } glEnd(); theta = theta1; cosTheta = cosTheta1; sinTheta = sinTheta1; } } static void Cube(float size) { size = 0.5 * size; glBegin(GL_QUADS); /* +X face */ glNormal3f(1, 0, 0); glVertex3f(size, -size, size); glVertex3f(size, -size, -size); glVertex3f(size, size, -size); glVertex3f(size, size, size); /* -X face */ glNormal3f(-1, 0, 0); glVertex3f(-size, size, size); glVertex3f(-size, size, -size); glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size); /* +Y face */ glNormal3f(0, 1, 0); glVertex3f(-size, size, size); glVertex3f( size, size, size); glVertex3f( size, size, -size); glVertex3f(-size, size, -size); /* -Y face */ glNormal3f(0, -1, 0); glVertex3f(-size, -size, -size); glVertex3f( size, -size, -size); glVertex3f( size, -size, size); glVertex3f(-size, -size, size); /* +Z face */ glNormal3f(0, 0, 1); glVertex3f(-size, -size, size); glVertex3f( size, -size, size); glVertex3f( size, size, size); glVertex3f(-size, size, size); /* -Z face */ glNormal3f(0, 0, -1); glVertex3f(-size, size, -size); glVertex3f( size, size, -size); glVertex3f( size, -size, -size); glVertex3f(-size, -size, -size); glEnd(); } /** * Draw red/green gradient across bottom of image. * Read pixels to check deltas. */ static void render_gradient(void) { GLfloat row[WIDTH][4]; int i; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1, 1, -1, 1, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBegin(GL_POLYGON); glColor3f(1, 0, 0); glVertex2f(-1, -1.0); glVertex2f(-1, -0.9); glColor3f(0, 1, 0); glVertex2f(1, -0.9); glVertex2f(1, -1.0); glEnd(); glFinish(); glReadPixels(0, 0, WIDTH, 1, GL_RGBA, GL_FLOAT, row); for (i = 0; i < 4; i++) { printf("row[i] = %f, %f, %f\n", row[i][0], row[i][1], row[i][2]); } } static void render_image(void) { static const GLfloat light_ambient[4] = { 0.0, 0.0, 0.0, 1.0 }; static const GLfloat light_diffuse[4] = { 1.0, 1.0, 1.0, 1.0 }; static const GLfloat light_specular[4] = { 1.0, 1.0, 1.0, 1.0 }; static const GLfloat light_position[4] = { 1.0, 1.0, 1.0, 0.0 }; static const GLfloat red_mat[4] = { 1.0, 0.2, 0.2, 1.0 }; static const GLfloat green_mat[4] = { 0.2, 1.0, 0.2, 1.0 }; static const GLfloat blue_mat[4] = { 0.2, 0.2, 1.0, 1.0 }; #if 0 static const GLfloat yellow_mat[4] = { 0.8, 0.8, 0.0, 1.0 }; #endif static const GLfloat purple_mat[4] = { 0.8, 0.4, 0.8, 0.6 }; glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHT0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 50.0); glMatrixMode(GL_MODELVIEW); glTranslatef(0, 0.5, -7); glClearColor(0.3, 0.3, 0.7, 0.0); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glPushMatrix(); glRotatef(20.0, 1.0, 0.0, 0.0); /* ground */ glEnable(GL_TEXTURE_2D); glBegin(GL_POLYGON); glNormal3f(0, 1, 0); glTexCoord2f(0, 0); glVertex3f(-5, -1, -5); glTexCoord2f(1, 0); glVertex3f( 5, -1, -5); glTexCoord2f(1, 1); glVertex3f( 5, -1, 5); glTexCoord2f(0, 1); glVertex3f(-5, -1, 5); glEnd(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); glPushMatrix(); glTranslatef(-1.5, 0.5, 0.0); glRotatef(90.0, 1.0, 0.0, 0.0); glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red_mat ); Torus(0.275, 0.85, 20, 20); glPopMatrix(); glPushMatrix(); glTranslatef(-1.5, -0.5, 0.0); glRotatef(270.0, 1.0, 0.0, 0.0); glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green_mat ); Cone(1.0, 2.0, 16, 1); glPopMatrix(); glPushMatrix(); glTranslatef(0.95, 0.0, -0.8); glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue_mat ); glLineWidth(2.0); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); Sphere(1.2, 20, 20); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPopMatrix(); #if 0 glPushMatrix(); glTranslatef(0.75, 0.0, 1.3); glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow_mat ); glutWireTeapot(1.0); glPopMatrix(); #endif glPushMatrix(); glTranslatef(-0.25, 0.0, 2.5); glRotatef(40, 0, 1, 0); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_CULL_FACE); glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, purple_mat ); Cube(1.0); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); glPopMatrix(); glDisable(GL_LIGHTING); glPopMatrix(); glDisable(GL_DEPTH_TEST); } static void init_context(void) { const GLint texWidth = 64, texHeight = 64; GLubyte *texImage; int i, j; /* checker image */ texImage = malloc(texWidth * texHeight * 4); for (i = 0; i < texHeight; i++) { for (j = 0; j < texWidth; j++) { int k = (i * texWidth + j) * 4; if ((i % 5) == 0 || (j % 5) == 0) { texImage[k+0] = 200; texImage[k+1] = 200; texImage[k+2] = 200; texImage[k+3] = 255; } else { if ((i % 5) == 1 || (j % 5) == 1) { texImage[k+0] = 50; texImage[k+1] = 50; texImage[k+2] = 50; texImage[k+3] = 255; } else { texImage[k+0] = 100; texImage[k+1] = 100; texImage[k+2] = 100; texImage[k+3] = 255; } } } } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); free(texImage); } static void write_ppm(const char *filename, const GLubyte *buffer, int width, int height) { const int binary = 0; FILE *f = fopen( filename, "w" ); if (f) { int i, x, y; const GLubyte *ptr = buffer; if (binary) { fprintf(f,"P6\n"); fprintf(f,"# ppm-file created by osdemo.c\n"); fprintf(f,"%i %i\n", width,height); fprintf(f,"255\n"); fclose(f); f = fopen( filename, "ab" ); /* reopen in binary append mode */ for (y=height-1; y>=0; y--) { for (x=0; x<width; x++) { i = (y*width + x) * 4; fputc(ptr[i], f); /* write red */ fputc(ptr[i+1], f); /* write green */ fputc(ptr[i+2], f); /* write blue */ } } } else { /*ASCII*/ int counter = 0; fprintf(f,"P3\n"); fprintf(f,"# ascii ppm file created by osdemo.c\n"); fprintf(f,"%i %i\n", width, height); fprintf(f,"255\n"); for (y=height-1; y>=0; y--) { for (x=0; x<width; x++) { i = (y*width + x) * 4; fprintf(f, " %3d %3d %3d", ptr[i], ptr[i+1], ptr[i+2]); counter++; if (counter % 5 == 0) fprintf(f, "\n"); } } } fclose(f); } } static GLboolean test(GLenum type, GLint bits, const char *filename) { const GLint z = 16, stencil = 0, accum = 0; OSMesaContext ctx; void *buffer; GLint cBits; assert(bits == 8 || bits == 16 || bits == 32); assert(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT || type == GL_FLOAT); ctx = OSMesaCreateContextExt(OSMESA_RGBA, z, stencil, accum, NULL ); if (!ctx) { printf("OSMesaCreateContextExt() failed!\n"); return 0; } /* Allocate the image buffer */ buffer = malloc(WIDTH * HEIGHT * 4 * bits / 8); if (!buffer) { printf("Alloc image buffer failed!\n"); return 0; } /* Bind the buffer to the context and make it current */ if (!OSMesaMakeCurrent( ctx, buffer, type, WIDTH, HEIGHT )) { printf("OSMesaMakeCurrent (%d bits/channel) failed!\n", bits); free(buffer); OSMesaDestroyContext(ctx); return 0; } /* sanity checks */ glGetIntegerv(GL_RED_BITS, &cBits); assert(cBits == bits); glGetIntegerv(GL_GREEN_BITS, &cBits); assert(cBits == bits); glGetIntegerv(GL_BLUE_BITS, &cBits); assert(cBits == bits); glGetIntegerv(GL_ALPHA_BITS, &cBits); assert(cBits == bits); printf("Rendering %d bit/channel image: %s\n", bits, filename); init_context(); render_image(); if (Gradient) render_gradient(); /* Make sure buffered commands are finished! */ glFinish(); if (WriteFiles && filename != NULL) { if (type == GL_UNSIGNED_SHORT) { GLushort *buffer16 = (GLushort *) buffer; GLubyte *buffer8 = malloc(WIDTH * HEIGHT * 4); int i; for (i = 0; i < WIDTH * HEIGHT * 4; i++) buffer8[i] = buffer16[i] >> 8; write_ppm(filename, buffer8, WIDTH, HEIGHT); free(buffer8); } else if (type == GL_FLOAT) { GLfloat *buffer32 = (GLfloat *) buffer; GLubyte *buffer8 = malloc(WIDTH * HEIGHT * 4); int i; for (i = 0; i < WIDTH * HEIGHT * 4; i++) buffer8[i] = (GLubyte) (buffer32[i] * 255.0); write_ppm(filename, buffer8, WIDTH, HEIGHT); free(buffer8); } else { write_ppm(filename, buffer, WIDTH, HEIGHT); } } OSMesaDestroyContext(ctx); free(buffer); return 1; } int main( int argc, char *argv[] ) { int i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-f") == 0) WriteFiles = GL_TRUE; else if (strcmp(argv[i], "-g") == 0) Gradient = GL_TRUE; } test(GL_UNSIGNED_BYTE, 8, "image8.ppm"); test(GL_UNSIGNED_SHORT, 16, "image16.ppm"); test(GL_FLOAT, 32, "image32.ppm"); return 0; }