1/* 2 * Demo of off-screen Mesa rendering 3 * 4 * See Mesa/include/GL/osmesa.h for documentation of the OSMesa functions. 5 * 6 * If you want to render BIG images you'll probably have to increase 7 * MAX_WIDTH and MAX_Height in src/config.h. 8 * 9 * This program is in the public domain. 10 * 11 * Brian Paul 12 * 13 * PPM output provided by Joerg Schmalzl. 14 * ASCII PPM output added by Brian Paul. 15 * 16 * Usage: osdemo [filename] 17 */ 18 19 20#include <math.h> 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include "GL/osmesa.h" 25#include "gl_wrap.h" 26 27 28#define SAVE_TARGA 29 30static int Width = 400; 31static int Height = 400; 32 33 34static void 35Sphere(float radius, int slices, int stacks) 36{ 37 GLUquadric *q = gluNewQuadric(); 38 gluQuadricNormals(q, GLU_SMOOTH); 39 gluSphere(q, radius, slices, stacks); 40 gluDeleteQuadric(q); 41} 42 43 44static void 45Cone(float base, float height, int slices, int stacks) 46{ 47 GLUquadric *q = gluNewQuadric(); 48 gluQuadricDrawStyle(q, GLU_FILL); 49 gluQuadricNormals(q, GLU_SMOOTH); 50 gluCylinder(q, base, 0.0, height, slices, stacks); 51 gluDeleteQuadric(q); 52} 53 54 55static void 56Torus(float innerRadius, float outerRadius, int sides, int rings) 57{ 58 /* from GLUT... */ 59 int i, j; 60 GLfloat theta, phi, theta1; 61 GLfloat cosTheta, sinTheta; 62 GLfloat cosTheta1, sinTheta1; 63 const GLfloat ringDelta = 2.0 * M_PI / rings; 64 const GLfloat sideDelta = 2.0 * M_PI / sides; 65 66 theta = 0.0; 67 cosTheta = 1.0; 68 sinTheta = 0.0; 69 for (i = rings - 1; i >= 0; i--) { 70 theta1 = theta + ringDelta; 71 cosTheta1 = cos(theta1); 72 sinTheta1 = sin(theta1); 73 glBegin(GL_QUAD_STRIP); 74 phi = 0.0; 75 for (j = sides; j >= 0; j--) { 76 GLfloat cosPhi, sinPhi, dist; 77 78 phi += sideDelta; 79 cosPhi = cos(phi); 80 sinPhi = sin(phi); 81 dist = outerRadius + innerRadius * cosPhi; 82 83 glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); 84 glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, innerRadius * sinPhi); 85 glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); 86 glVertex3f(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi); 87 } 88 glEnd(); 89 theta = theta1; 90 cosTheta = cosTheta1; 91 sinTheta = sinTheta1; 92 } 93} 94 95 96static void 97render_image(void) 98{ 99 GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; 100 GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; 101 GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; 102 GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; 103 GLfloat red_mat[] = { 1.0, 0.2, 0.2, 1.0 }; 104 GLfloat green_mat[] = { 0.2, 1.0, 0.2, 1.0 }; 105 GLfloat blue_mat[] = { 0.2, 0.2, 1.0, 1.0 }; 106 107 108 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); 109 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); 110 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); 111 glLightfv(GL_LIGHT0, GL_POSITION, light_position); 112 113 glEnable(GL_LIGHTING); 114 glEnable(GL_LIGHT0); 115 glEnable(GL_DEPTH_TEST); 116 117 glMatrixMode(GL_PROJECTION); 118 glLoadIdentity(); 119 glOrtho(-2.5, 2.5, -2.5, 2.5, -10.0, 10.0); 120 glMatrixMode(GL_MODELVIEW); 121 122 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 123 124 glPushMatrix(); 125 glRotatef(20.0, 1.0, 0.0, 0.0); 126 127 glPushMatrix(); 128 glTranslatef(-0.75, 0.5, 0.0); 129 glRotatef(90.0, 1.0, 0.0, 0.0); 130 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red_mat ); 131 Torus(0.275, 0.85, 20, 20); 132 glPopMatrix(); 133 134 glPushMatrix(); 135 glTranslatef(-0.75, -0.5, 0.0); 136 glRotatef(270.0, 1.0, 0.0, 0.0); 137 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green_mat ); 138 Cone(1.0, 2.0, 16, 1); 139 glPopMatrix(); 140 141 glPushMatrix(); 142 glTranslatef(0.75, 0.0, -1.0); 143 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue_mat ); 144 Sphere(1.0, 20, 20); 145 glPopMatrix(); 146 147 glPopMatrix(); 148 149 /* This is very important!!! 150 * Make sure buffered commands are finished!!! 151 */ 152 glFinish(); 153} 154 155 156#ifdef SAVE_TARGA 157 158static void 159write_targa(const char *filename, const GLubyte *buffer, int width, int height) 160{ 161 FILE *f = fopen( filename, "w" ); 162 if (f) { 163 int i, x, y; 164 const GLubyte *ptr = buffer; 165 printf ("osdemo, writing tga file \n"); 166 fputc (0x00, f); /* ID Length, 0 => No ID */ 167 fputc (0x00, f); /* Color Map Type, 0 => No color map included */ 168 fputc (0x02, f); /* Image Type, 2 => Uncompressed, True-color Image */ 169 fputc (0x00, f); /* Next five bytes are about the color map entries */ 170 fputc (0x00, f); /* 2 bytes Index, 2 bytes length, 1 byte size */ 171 fputc (0x00, f); 172 fputc (0x00, f); 173 fputc (0x00, f); 174 fputc (0x00, f); /* X-origin of Image */ 175 fputc (0x00, f); 176 fputc (0x00, f); /* Y-origin of Image */ 177 fputc (0x00, f); 178 fputc (Width & 0xff, f); /* Image Width */ 179 fputc ((Width>>8) & 0xff, f); 180 fputc (Height & 0xff, f); /* Image Height */ 181 fputc ((Height>>8) & 0xff, f); 182 fputc (0x18, f); /* Pixel Depth, 0x18 => 24 Bits */ 183 fputc (0x20, f); /* Image Descriptor */ 184 fclose(f); 185 f = fopen( filename, "ab" ); /* reopen in binary append mode */ 186 for (y=height-1; y>=0; y--) { 187 for (x=0; x<width; x++) { 188 i = (y*width + x) * 4; 189 fputc(ptr[i+2], f); /* write blue */ 190 fputc(ptr[i+1], f); /* write green */ 191 fputc(ptr[i], f); /* write red */ 192 } 193 } 194 } 195} 196 197#else 198 199static void 200write_ppm(const char *filename, const GLubyte *buffer, int width, int height) 201{ 202 const int binary = 0; 203 FILE *f = fopen( filename, "w" ); 204 if (f) { 205 int i, x, y; 206 const GLubyte *ptr = buffer; 207 if (binary) { 208 fprintf(f,"P6\n"); 209 fprintf(f,"# ppm-file created by osdemo.c\n"); 210 fprintf(f,"%i %i\n", width,height); 211 fprintf(f,"255\n"); 212 fclose(f); 213 f = fopen( filename, "ab" ); /* reopen in binary append mode */ 214 for (y=height-1; y>=0; y--) { 215 for (x=0; x<width; x++) { 216 i = (y*width + x) * 4; 217 fputc(ptr[i], f); /* write red */ 218 fputc(ptr[i+1], f); /* write green */ 219 fputc(ptr[i+2], f); /* write blue */ 220 } 221 } 222 } 223 else { 224 /*ASCII*/ 225 int counter = 0; 226 fprintf(f,"P3\n"); 227 fprintf(f,"# ascii ppm file created by osdemo.c\n"); 228 fprintf(f,"%i %i\n", width, height); 229 fprintf(f,"255\n"); 230 for (y=height-1; y>=0; y--) { 231 for (x=0; x<width; x++) { 232 i = (y*width + x) * 4; 233 fprintf(f, " %3d %3d %3d", ptr[i], ptr[i+1], ptr[i+2]); 234 counter++; 235 if (counter % 5 == 0) 236 fprintf(f, "\n"); 237 } 238 } 239 } 240 fclose(f); 241 } 242} 243 244#endif 245 246 247 248int 249main(int argc, char *argv[]) 250{ 251 OSMesaContext ctx; 252 void *buffer; 253 char *filename = NULL; 254 255 if (argc < 2) { 256 fprintf(stderr, "Usage:\n"); 257 fprintf(stderr, " osdemo filename [width height]\n"); 258 return 0; 259 } 260 261 filename = argv[1]; 262 if (argc == 4) { 263 Width = atoi(argv[2]); 264 Height = atoi(argv[3]); 265 } 266 267 /* Create an RGBA-mode context */ 268#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305 269 /* specify Z, stencil, accum sizes */ 270 ctx = OSMesaCreateContextExt( OSMESA_RGBA, 16, 0, 0, NULL ); 271#else 272 ctx = OSMesaCreateContext( OSMESA_RGBA, NULL ); 273#endif 274 if (!ctx) { 275 printf("OSMesaCreateContext failed!\n"); 276 return 0; 277 } 278 279 /* Allocate the image buffer */ 280 buffer = malloc( Width * Height * 4 * sizeof(GLubyte) ); 281 if (!buffer) { 282 printf("Alloc image buffer failed!\n"); 283 return 0; 284 } 285 286 /* Bind the buffer to the context and make it current */ 287 if (!OSMesaMakeCurrent( ctx, buffer, GL_UNSIGNED_BYTE, Width, Height )) { 288 printf("OSMesaMakeCurrent failed!\n"); 289 return 0; 290 } 291 292 293 { 294 int z, s, a; 295 glGetIntegerv(GL_DEPTH_BITS, &z); 296 glGetIntegerv(GL_STENCIL_BITS, &s); 297 glGetIntegerv(GL_ACCUM_RED_BITS, &a); 298 printf("Depth=%d Stencil=%d Accum=%d\n", z, s, a); 299 } 300 301 render_image(); 302 303 if (filename != NULL) { 304#ifdef SAVE_TARGA 305 write_targa(filename, buffer, Width, Height); 306#else 307 write_ppm(filename, buffer, Width, Height); 308#endif 309 } 310 else { 311 printf("Specify a filename if you want to make an image file\n"); 312 } 313 314 printf("all done\n"); 315 316 /* free the image buffer */ 317 free( buffer ); 318 319 /* destroy the context */ 320 OSMesaDestroyContext( ctx ); 321 322 return 0; 323} 324