132001f49Smrg/* 232001f49Smrg * Demo of off-screen Mesa rendering 332001f49Smrg * 432001f49Smrg * See Mesa/include/GL/osmesa.h for documentation of the OSMesa functions. 532001f49Smrg * 632001f49Smrg * If you want to render BIG images you'll probably have to increase 732001f49Smrg * MAX_WIDTH and MAX_Height in src/config.h. 832001f49Smrg * 932001f49Smrg * This program is in the public domain. 1032001f49Smrg * 1132001f49Smrg * Brian Paul 1232001f49Smrg * 1332001f49Smrg * PPM output provided by Joerg Schmalzl. 1432001f49Smrg * ASCII PPM output added by Brian Paul. 1532001f49Smrg * 1632001f49Smrg * Usage: osdemo [filename] 1732001f49Smrg */ 1832001f49Smrg 1932001f49Smrg 2032001f49Smrg#include <math.h> 2132001f49Smrg#include <stdio.h> 2232001f49Smrg#include <stdlib.h> 2332001f49Smrg#include <string.h> 2432001f49Smrg#include "GL/osmesa.h" 2532001f49Smrg#include "gl_wrap.h" 2632001f49Smrg 2732001f49Smrg 2832001f49Smrg#define SAVE_TARGA 2932001f49Smrg 3032001f49Smrgstatic int Width = 400; 3132001f49Smrgstatic int Height = 400; 3232001f49Smrg 3332001f49Smrg 3432001f49Smrgstatic void 3532001f49SmrgSphere(float radius, int slices, int stacks) 3632001f49Smrg{ 3732001f49Smrg GLUquadric *q = gluNewQuadric(); 3832001f49Smrg gluQuadricNormals(q, GLU_SMOOTH); 3932001f49Smrg gluSphere(q, radius, slices, stacks); 4032001f49Smrg gluDeleteQuadric(q); 4132001f49Smrg} 4232001f49Smrg 4332001f49Smrg 4432001f49Smrgstatic void 4532001f49SmrgCone(float base, float height, int slices, int stacks) 4632001f49Smrg{ 4732001f49Smrg GLUquadric *q = gluNewQuadric(); 4832001f49Smrg gluQuadricDrawStyle(q, GLU_FILL); 4932001f49Smrg gluQuadricNormals(q, GLU_SMOOTH); 5032001f49Smrg gluCylinder(q, base, 0.0, height, slices, stacks); 5132001f49Smrg gluDeleteQuadric(q); 5232001f49Smrg} 5332001f49Smrg 5432001f49Smrg 5532001f49Smrgstatic void 5632001f49SmrgTorus(float innerRadius, float outerRadius, int sides, int rings) 5732001f49Smrg{ 5832001f49Smrg /* from GLUT... */ 5932001f49Smrg int i, j; 6032001f49Smrg GLfloat theta, phi, theta1; 6132001f49Smrg GLfloat cosTheta, sinTheta; 6232001f49Smrg GLfloat cosTheta1, sinTheta1; 6332001f49Smrg const GLfloat ringDelta = 2.0 * M_PI / rings; 6432001f49Smrg const GLfloat sideDelta = 2.0 * M_PI / sides; 6532001f49Smrg 6632001f49Smrg theta = 0.0; 6732001f49Smrg cosTheta = 1.0; 6832001f49Smrg sinTheta = 0.0; 6932001f49Smrg for (i = rings - 1; i >= 0; i--) { 7032001f49Smrg theta1 = theta + ringDelta; 7132001f49Smrg cosTheta1 = cos(theta1); 7232001f49Smrg sinTheta1 = sin(theta1); 7332001f49Smrg glBegin(GL_QUAD_STRIP); 7432001f49Smrg phi = 0.0; 7532001f49Smrg for (j = sides; j >= 0; j--) { 7632001f49Smrg GLfloat cosPhi, sinPhi, dist; 7732001f49Smrg 7832001f49Smrg phi += sideDelta; 7932001f49Smrg cosPhi = cos(phi); 8032001f49Smrg sinPhi = sin(phi); 8132001f49Smrg dist = outerRadius + innerRadius * cosPhi; 8232001f49Smrg 8332001f49Smrg glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); 8432001f49Smrg glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, innerRadius * sinPhi); 8532001f49Smrg glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); 8632001f49Smrg glVertex3f(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi); 8732001f49Smrg } 8832001f49Smrg glEnd(); 8932001f49Smrg theta = theta1; 9032001f49Smrg cosTheta = cosTheta1; 9132001f49Smrg sinTheta = sinTheta1; 9232001f49Smrg } 9332001f49Smrg} 9432001f49Smrg 9532001f49Smrg 9632001f49Smrgstatic void 9732001f49Smrgrender_image(void) 9832001f49Smrg{ 9932001f49Smrg GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; 10032001f49Smrg GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; 10132001f49Smrg GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; 10232001f49Smrg GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; 10332001f49Smrg GLfloat red_mat[] = { 1.0, 0.2, 0.2, 1.0 }; 10432001f49Smrg GLfloat green_mat[] = { 0.2, 1.0, 0.2, 1.0 }; 10532001f49Smrg GLfloat blue_mat[] = { 0.2, 0.2, 1.0, 1.0 }; 10632001f49Smrg 10732001f49Smrg 10832001f49Smrg glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); 10932001f49Smrg glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); 11032001f49Smrg glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); 11132001f49Smrg glLightfv(GL_LIGHT0, GL_POSITION, light_position); 11232001f49Smrg 11332001f49Smrg glEnable(GL_LIGHTING); 11432001f49Smrg glEnable(GL_LIGHT0); 11532001f49Smrg glEnable(GL_DEPTH_TEST); 11632001f49Smrg 11732001f49Smrg glMatrixMode(GL_PROJECTION); 11832001f49Smrg glLoadIdentity(); 11932001f49Smrg glOrtho(-2.5, 2.5, -2.5, 2.5, -10.0, 10.0); 12032001f49Smrg glMatrixMode(GL_MODELVIEW); 12132001f49Smrg 12232001f49Smrg glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 12332001f49Smrg 12432001f49Smrg glPushMatrix(); 12532001f49Smrg glRotatef(20.0, 1.0, 0.0, 0.0); 12632001f49Smrg 12732001f49Smrg glPushMatrix(); 12832001f49Smrg glTranslatef(-0.75, 0.5, 0.0); 12932001f49Smrg glRotatef(90.0, 1.0, 0.0, 0.0); 13032001f49Smrg glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red_mat ); 13132001f49Smrg Torus(0.275, 0.85, 20, 20); 13232001f49Smrg glPopMatrix(); 13332001f49Smrg 13432001f49Smrg glPushMatrix(); 13532001f49Smrg glTranslatef(-0.75, -0.5, 0.0); 13632001f49Smrg glRotatef(270.0, 1.0, 0.0, 0.0); 13732001f49Smrg glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green_mat ); 13832001f49Smrg Cone(1.0, 2.0, 16, 1); 13932001f49Smrg glPopMatrix(); 14032001f49Smrg 14132001f49Smrg glPushMatrix(); 14232001f49Smrg glTranslatef(0.75, 0.0, -1.0); 14332001f49Smrg glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue_mat ); 14432001f49Smrg Sphere(1.0, 20, 20); 14532001f49Smrg glPopMatrix(); 14632001f49Smrg 14732001f49Smrg glPopMatrix(); 14832001f49Smrg 14932001f49Smrg /* This is very important!!! 15032001f49Smrg * Make sure buffered commands are finished!!! 15132001f49Smrg */ 15232001f49Smrg glFinish(); 15332001f49Smrg} 15432001f49Smrg 15532001f49Smrg 15632001f49Smrg#ifdef SAVE_TARGA 15732001f49Smrg 15832001f49Smrgstatic void 15932001f49Smrgwrite_targa(const char *filename, const GLubyte *buffer, int width, int height) 16032001f49Smrg{ 16132001f49Smrg FILE *f = fopen( filename, "w" ); 16232001f49Smrg if (f) { 16332001f49Smrg int i, x, y; 16432001f49Smrg const GLubyte *ptr = buffer; 16532001f49Smrg printf ("osdemo, writing tga file \n"); 16632001f49Smrg fputc (0x00, f); /* ID Length, 0 => No ID */ 16732001f49Smrg fputc (0x00, f); /* Color Map Type, 0 => No color map included */ 16832001f49Smrg fputc (0x02, f); /* Image Type, 2 => Uncompressed, True-color Image */ 16932001f49Smrg fputc (0x00, f); /* Next five bytes are about the color map entries */ 17032001f49Smrg fputc (0x00, f); /* 2 bytes Index, 2 bytes length, 1 byte size */ 17132001f49Smrg fputc (0x00, f); 17232001f49Smrg fputc (0x00, f); 17332001f49Smrg fputc (0x00, f); 17432001f49Smrg fputc (0x00, f); /* X-origin of Image */ 17532001f49Smrg fputc (0x00, f); 17632001f49Smrg fputc (0x00, f); /* Y-origin of Image */ 17732001f49Smrg fputc (0x00, f); 17832001f49Smrg fputc (Width & 0xff, f); /* Image Width */ 17932001f49Smrg fputc ((Width>>8) & 0xff, f); 18032001f49Smrg fputc (Height & 0xff, f); /* Image Height */ 18132001f49Smrg fputc ((Height>>8) & 0xff, f); 18232001f49Smrg fputc (0x18, f); /* Pixel Depth, 0x18 => 24 Bits */ 18332001f49Smrg fputc (0x20, f); /* Image Descriptor */ 18432001f49Smrg fclose(f); 18532001f49Smrg f = fopen( filename, "ab" ); /* reopen in binary append mode */ 18632001f49Smrg for (y=height-1; y>=0; y--) { 18732001f49Smrg for (x=0; x<width; x++) { 18832001f49Smrg i = (y*width + x) * 4; 18932001f49Smrg fputc(ptr[i+2], f); /* write blue */ 19032001f49Smrg fputc(ptr[i+1], f); /* write green */ 19132001f49Smrg fputc(ptr[i], f); /* write red */ 19232001f49Smrg } 19332001f49Smrg } 19432001f49Smrg } 19532001f49Smrg} 19632001f49Smrg 19732001f49Smrg#else 19832001f49Smrg 19932001f49Smrgstatic void 20032001f49Smrgwrite_ppm(const char *filename, const GLubyte *buffer, int width, int height) 20132001f49Smrg{ 20232001f49Smrg const int binary = 0; 20332001f49Smrg FILE *f = fopen( filename, "w" ); 20432001f49Smrg if (f) { 20532001f49Smrg int i, x, y; 20632001f49Smrg const GLubyte *ptr = buffer; 20732001f49Smrg if (binary) { 20832001f49Smrg fprintf(f,"P6\n"); 20932001f49Smrg fprintf(f,"# ppm-file created by osdemo.c\n"); 21032001f49Smrg fprintf(f,"%i %i\n", width,height); 21132001f49Smrg fprintf(f,"255\n"); 21232001f49Smrg fclose(f); 21332001f49Smrg f = fopen( filename, "ab" ); /* reopen in binary append mode */ 21432001f49Smrg for (y=height-1; y>=0; y--) { 21532001f49Smrg for (x=0; x<width; x++) { 21632001f49Smrg i = (y*width + x) * 4; 21732001f49Smrg fputc(ptr[i], f); /* write red */ 21832001f49Smrg fputc(ptr[i+1], f); /* write green */ 21932001f49Smrg fputc(ptr[i+2], f); /* write blue */ 22032001f49Smrg } 22132001f49Smrg } 22232001f49Smrg } 22332001f49Smrg else { 22432001f49Smrg /*ASCII*/ 22532001f49Smrg int counter = 0; 22632001f49Smrg fprintf(f,"P3\n"); 22732001f49Smrg fprintf(f,"# ascii ppm file created by osdemo.c\n"); 22832001f49Smrg fprintf(f,"%i %i\n", width, height); 22932001f49Smrg fprintf(f,"255\n"); 23032001f49Smrg for (y=height-1; y>=0; y--) { 23132001f49Smrg for (x=0; x<width; x++) { 23232001f49Smrg i = (y*width + x) * 4; 23332001f49Smrg fprintf(f, " %3d %3d %3d", ptr[i], ptr[i+1], ptr[i+2]); 23432001f49Smrg counter++; 23532001f49Smrg if (counter % 5 == 0) 23632001f49Smrg fprintf(f, "\n"); 23732001f49Smrg } 23832001f49Smrg } 23932001f49Smrg } 24032001f49Smrg fclose(f); 24132001f49Smrg } 24232001f49Smrg} 24332001f49Smrg 24432001f49Smrg#endif 24532001f49Smrg 24632001f49Smrg 24732001f49Smrg 24832001f49Smrgint 24932001f49Smrgmain(int argc, char *argv[]) 25032001f49Smrg{ 25132001f49Smrg OSMesaContext ctx; 25232001f49Smrg void *buffer; 25332001f49Smrg char *filename = NULL; 25432001f49Smrg 25532001f49Smrg if (argc < 2) { 25632001f49Smrg fprintf(stderr, "Usage:\n"); 25732001f49Smrg fprintf(stderr, " osdemo filename [width height]\n"); 25832001f49Smrg return 0; 25932001f49Smrg } 26032001f49Smrg 26132001f49Smrg filename = argv[1]; 26232001f49Smrg if (argc == 4) { 26332001f49Smrg Width = atoi(argv[2]); 26432001f49Smrg Height = atoi(argv[3]); 26532001f49Smrg } 26632001f49Smrg 26732001f49Smrg /* Create an RGBA-mode context */ 26832001f49Smrg#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305 26932001f49Smrg /* specify Z, stencil, accum sizes */ 27032001f49Smrg ctx = OSMesaCreateContextExt( OSMESA_RGBA, 16, 0, 0, NULL ); 27132001f49Smrg#else 27232001f49Smrg ctx = OSMesaCreateContext( OSMESA_RGBA, NULL ); 27332001f49Smrg#endif 27432001f49Smrg if (!ctx) { 27532001f49Smrg printf("OSMesaCreateContext failed!\n"); 27632001f49Smrg return 0; 27732001f49Smrg } 27832001f49Smrg 27932001f49Smrg /* Allocate the image buffer */ 28032001f49Smrg buffer = malloc( Width * Height * 4 * sizeof(GLubyte) ); 28132001f49Smrg if (!buffer) { 28232001f49Smrg printf("Alloc image buffer failed!\n"); 28332001f49Smrg return 0; 28432001f49Smrg } 28532001f49Smrg 28632001f49Smrg /* Bind the buffer to the context and make it current */ 28732001f49Smrg if (!OSMesaMakeCurrent( ctx, buffer, GL_UNSIGNED_BYTE, Width, Height )) { 28832001f49Smrg printf("OSMesaMakeCurrent failed!\n"); 28932001f49Smrg return 0; 29032001f49Smrg } 29132001f49Smrg 29232001f49Smrg 29332001f49Smrg { 29432001f49Smrg int z, s, a; 29532001f49Smrg glGetIntegerv(GL_DEPTH_BITS, &z); 29632001f49Smrg glGetIntegerv(GL_STENCIL_BITS, &s); 29732001f49Smrg glGetIntegerv(GL_ACCUM_RED_BITS, &a); 29832001f49Smrg printf("Depth=%d Stencil=%d Accum=%d\n", z, s, a); 29932001f49Smrg } 30032001f49Smrg 30132001f49Smrg render_image(); 30232001f49Smrg 30332001f49Smrg if (filename != NULL) { 30432001f49Smrg#ifdef SAVE_TARGA 30532001f49Smrg write_targa(filename, buffer, Width, Height); 30632001f49Smrg#else 30732001f49Smrg write_ppm(filename, buffer, Width, Height); 30832001f49Smrg#endif 30932001f49Smrg } 31032001f49Smrg else { 31132001f49Smrg printf("Specify a filename if you want to make an image file\n"); 31232001f49Smrg } 31332001f49Smrg 31432001f49Smrg printf("all done\n"); 31532001f49Smrg 31632001f49Smrg /* free the image buffer */ 31732001f49Smrg free( buffer ); 31832001f49Smrg 31932001f49Smrg /* destroy the context */ 32032001f49Smrg OSMesaDestroyContext( ctx ); 32132001f49Smrg 32232001f49Smrg return 0; 32332001f49Smrg} 324