1 /*
2 * Test OSMesa interface at 8, 16 and 32 bits/channel.
3 *
4 * Usage: osdemo [options]
5 *
6 * Options:
7 * -f generate image files
8 * -g render gradient and print color values
9 */
10
11 #include <assert.h>
12 #include <math.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include "GL/osmesa.h"
17
18
19 #define WIDTH 600
20 #define HEIGHT 600
21
22 static GLboolean WriteFiles = GL_FALSE;
23 static GLboolean Gradient = GL_FALSE;
24
25
26 static void
Sphere(float radius,int slices,int stacks)27 Sphere(float radius, int slices, int stacks)
28 {
29 GLUquadric *q = gluNewQuadric();
30 gluQuadricNormals(q, GLU_SMOOTH);
31 gluSphere(q, radius, slices, stacks);
32 gluDeleteQuadric(q);
33 }
34
35
36 static void
Cone(float base,float height,int slices,int stacks)37 Cone(float base, float height, int slices, int stacks)
38 {
39 GLUquadric *q = gluNewQuadric();
40 gluQuadricDrawStyle(q, GLU_FILL);
41 gluQuadricNormals(q, GLU_SMOOTH);
42 gluCylinder(q, base, 0.0, height, slices, stacks);
43 gluDeleteQuadric(q);
44 }
45
46
47 static void
Torus(float innerRadius,float outerRadius,int sides,int rings)48 Torus(float innerRadius, float outerRadius, int sides, int rings)
49 {
50 /* from GLUT... */
51 int i, j;
52 GLfloat theta, phi, theta1;
53 GLfloat cosTheta, sinTheta;
54 GLfloat cosTheta1, sinTheta1;
55 const GLfloat ringDelta = 2.0 * M_PI / rings;
56 const GLfloat sideDelta = 2.0 * M_PI / sides;
57
58 theta = 0.0;
59 cosTheta = 1.0;
60 sinTheta = 0.0;
61 for (i = rings - 1; i >= 0; i--) {
62 theta1 = theta + ringDelta;
63 cosTheta1 = cos(theta1);
64 sinTheta1 = sin(theta1);
65 glBegin(GL_QUAD_STRIP);
66 phi = 0.0;
67 for (j = sides; j >= 0; j--) {
68 GLfloat cosPhi, sinPhi, dist;
69
70 phi += sideDelta;
71 cosPhi = cos(phi);
72 sinPhi = sin(phi);
73 dist = outerRadius + innerRadius * cosPhi;
74
75 glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
76 glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, innerRadius * sinPhi);
77 glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
78 glVertex3f(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi);
79 }
80 glEnd();
81 theta = theta1;
82 cosTheta = cosTheta1;
83 sinTheta = sinTheta1;
84 }
85 }
86
87
Cube(float size)88 static void Cube(float size)
89 {
90 size = 0.5 * size;
91
92 glBegin(GL_QUADS);
93 /* +X face */
94 glNormal3f(1, 0, 0);
95 glVertex3f(size, -size, size);
96 glVertex3f(size, -size, -size);
97 glVertex3f(size, size, -size);
98 glVertex3f(size, size, size);
99
100 /* -X face */
101 glNormal3f(-1, 0, 0);
102 glVertex3f(-size, size, size);
103 glVertex3f(-size, size, -size);
104 glVertex3f(-size, -size, -size);
105 glVertex3f(-size, -size, size);
106
107 /* +Y face */
108 glNormal3f(0, 1, 0);
109 glVertex3f(-size, size, size);
110 glVertex3f( size, size, size);
111 glVertex3f( size, size, -size);
112 glVertex3f(-size, size, -size);
113
114 /* -Y face */
115 glNormal3f(0, -1, 0);
116 glVertex3f(-size, -size, -size);
117 glVertex3f( size, -size, -size);
118 glVertex3f( size, -size, size);
119 glVertex3f(-size, -size, size);
120
121 /* +Z face */
122 glNormal3f(0, 0, 1);
123 glVertex3f(-size, -size, size);
124 glVertex3f( size, -size, size);
125 glVertex3f( size, size, size);
126 glVertex3f(-size, size, size);
127
128 /* -Z face */
129 glNormal3f(0, 0, -1);
130 glVertex3f(-size, size, -size);
131 glVertex3f( size, size, -size);
132 glVertex3f( size, -size, -size);
133 glVertex3f(-size, -size, -size);
134
135 glEnd();
136 }
137
138
139
140 /**
141 * Draw red/green gradient across bottom of image.
142 * Read pixels to check deltas.
143 */
144 static void
render_gradient(void)145 render_gradient(void)
146 {
147 GLfloat row[WIDTH][4];
148 int i;
149
150 glMatrixMode(GL_PROJECTION);
151 glLoadIdentity();
152 glOrtho(-1, 1, -1, 1, -1, 1);
153 glMatrixMode(GL_MODELVIEW);
154 glLoadIdentity();
155
156 glBegin(GL_POLYGON);
157 glColor3f(1, 0, 0);
158 glVertex2f(-1, -1.0);
159 glVertex2f(-1, -0.9);
160 glColor3f(0, 1, 0);
161 glVertex2f(1, -0.9);
162 glVertex2f(1, -1.0);
163 glEnd();
164 glFinish();
165
166 glReadPixels(0, 0, WIDTH, 1, GL_RGBA, GL_FLOAT, row);
167 for (i = 0; i < 4; i++) {
168 printf("row[i] = %f, %f, %f\n", row[i][0], row[i][1], row[i][2]);
169 }
170 }
171
172
173 static void
render_image(void)174 render_image(void)
175 {
176 static const GLfloat light_ambient[4] = { 0.0, 0.0, 0.0, 1.0 };
177 static const GLfloat light_diffuse[4] = { 1.0, 1.0, 1.0, 1.0 };
178 static const GLfloat light_specular[4] = { 1.0, 1.0, 1.0, 1.0 };
179 static const GLfloat light_position[4] = { 1.0, 1.0, 1.0, 0.0 };
180 static const GLfloat red_mat[4] = { 1.0, 0.2, 0.2, 1.0 };
181 static const GLfloat green_mat[4] = { 0.2, 1.0, 0.2, 1.0 };
182 static const GLfloat blue_mat[4] = { 0.2, 0.2, 1.0, 1.0 };
183 #if 0
184 static const GLfloat yellow_mat[4] = { 0.8, 0.8, 0.0, 1.0 };
185 #endif
186 static const GLfloat purple_mat[4] = { 0.8, 0.4, 0.8, 0.6 };
187
188 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
189 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
190 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
191 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
192
193 glEnable(GL_DEPTH_TEST);
194 glEnable(GL_LIGHT0);
195
196 glMatrixMode(GL_PROJECTION);
197 glLoadIdentity();
198 glFrustum(-1.0, 1.0, -1.0, 1.0, 2.0, 50.0);
199 glMatrixMode(GL_MODELVIEW);
200 glTranslatef(0, 0.5, -7);
201
202 glClearColor(0.3, 0.3, 0.7, 0.0);
203 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
204
205 glPushMatrix();
206 glRotatef(20.0, 1.0, 0.0, 0.0);
207
208 /* ground */
209 glEnable(GL_TEXTURE_2D);
210 glBegin(GL_POLYGON);
211 glNormal3f(0, 1, 0);
212 glTexCoord2f(0, 0); glVertex3f(-5, -1, -5);
213 glTexCoord2f(1, 0); glVertex3f( 5, -1, -5);
214 glTexCoord2f(1, 1); glVertex3f( 5, -1, 5);
215 glTexCoord2f(0, 1); glVertex3f(-5, -1, 5);
216 glEnd();
217 glDisable(GL_TEXTURE_2D);
218
219 glEnable(GL_LIGHTING);
220
221 glPushMatrix();
222 glTranslatef(-1.5, 0.5, 0.0);
223 glRotatef(90.0, 1.0, 0.0, 0.0);
224 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red_mat );
225 Torus(0.275, 0.85, 20, 20);
226 glPopMatrix();
227
228 glPushMatrix();
229 glTranslatef(-1.5, -0.5, 0.0);
230 glRotatef(270.0, 1.0, 0.0, 0.0);
231 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green_mat );
232 Cone(1.0, 2.0, 16, 1);
233 glPopMatrix();
234
235 glPushMatrix();
236 glTranslatef(0.95, 0.0, -0.8);
237 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue_mat );
238 glLineWidth(2.0);
239 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
240 Sphere(1.2, 20, 20);
241 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
242 glPopMatrix();
243
244 #if 0
245 glPushMatrix();
246 glTranslatef(0.75, 0.0, 1.3);
247 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow_mat );
248 glutWireTeapot(1.0);
249 glPopMatrix();
250 #endif
251
252 glPushMatrix();
253 glTranslatef(-0.25, 0.0, 2.5);
254 glRotatef(40, 0, 1, 0);
255 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
256 glEnable(GL_BLEND);
257 glEnable(GL_CULL_FACE);
258 glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, purple_mat );
259 Cube(1.0);
260 glDisable(GL_BLEND);
261 glDisable(GL_CULL_FACE);
262 glPopMatrix();
263
264 glDisable(GL_LIGHTING);
265
266 glPopMatrix();
267
268 glDisable(GL_DEPTH_TEST);
269 }
270
271
272 static void
init_context(void)273 init_context(void)
274 {
275 const GLint texWidth = 64, texHeight = 64;
276 GLubyte *texImage;
277 int i, j;
278
279 /* checker image */
280 texImage = malloc(texWidth * texHeight * 4);
281 for (i = 0; i < texHeight; i++) {
282 for (j = 0; j < texWidth; j++) {
283 int k = (i * texWidth + j) * 4;
284 if ((i % 5) == 0 || (j % 5) == 0) {
285 texImage[k+0] = 200;
286 texImage[k+1] = 200;
287 texImage[k+2] = 200;
288 texImage[k+3] = 255;
289 }
290 else {
291 if ((i % 5) == 1 || (j % 5) == 1) {
292 texImage[k+0] = 50;
293 texImage[k+1] = 50;
294 texImage[k+2] = 50;
295 texImage[k+3] = 255;
296 }
297 else {
298 texImage[k+0] = 100;
299 texImage[k+1] = 100;
300 texImage[k+2] = 100;
301 texImage[k+3] = 255;
302 }
303 }
304 }
305 }
306
307 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0,
308 GL_RGBA, GL_UNSIGNED_BYTE, texImage);
309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
311
312 free(texImage);
313 }
314
315
316 static void
write_ppm(const char * filename,const GLubyte * buffer,int width,int height)317 write_ppm(const char *filename, const GLubyte *buffer, int width, int height)
318 {
319 const int binary = 0;
320 FILE *f = fopen( filename, "w" );
321 if (f) {
322 int i, x, y;
323 const GLubyte *ptr = buffer;
324 if (binary) {
325 fprintf(f,"P6\n");
326 fprintf(f,"# ppm-file created by osdemo.c\n");
327 fprintf(f,"%i %i\n", width,height);
328 fprintf(f,"255\n");
329 fclose(f);
330 f = fopen( filename, "ab" ); /* reopen in binary append mode */
331 for (y=height-1; y>=0; y--) {
332 for (x=0; x<width; x++) {
333 i = (y*width + x) * 4;
334 fputc(ptr[i], f); /* write red */
335 fputc(ptr[i+1], f); /* write green */
336 fputc(ptr[i+2], f); /* write blue */
337 }
338 }
339 }
340 else {
341 /*ASCII*/
342 int counter = 0;
343 fprintf(f,"P3\n");
344 fprintf(f,"# ascii ppm file created by osdemo.c\n");
345 fprintf(f,"%i %i\n", width, height);
346 fprintf(f,"255\n");
347 for (y=height-1; y>=0; y--) {
348 for (x=0; x<width; x++) {
349 i = (y*width + x) * 4;
350 fprintf(f, " %3d %3d %3d", ptr[i], ptr[i+1], ptr[i+2]);
351 counter++;
352 if (counter % 5 == 0)
353 fprintf(f, "\n");
354 }
355 }
356 }
357 fclose(f);
358 }
359 }
360
361
362 static GLboolean
test(GLenum type,GLint bits,const char * filename)363 test(GLenum type, GLint bits, const char *filename)
364 {
365 const GLint z = 16, stencil = 0, accum = 0;
366 OSMesaContext ctx;
367 void *buffer;
368 GLint cBits;
369
370 assert(bits == 8 ||
371 bits == 16 ||
372 bits == 32);
373
374 assert(type == GL_UNSIGNED_BYTE ||
375 type == GL_UNSIGNED_SHORT ||
376 type == GL_FLOAT);
377
378 ctx = OSMesaCreateContextExt(OSMESA_RGBA, z, stencil, accum, NULL );
379 if (!ctx) {
380 printf("OSMesaCreateContextExt() failed!\n");
381 return 0;
382 }
383
384 /* Allocate the image buffer */
385 buffer = malloc(WIDTH * HEIGHT * 4 * bits / 8);
386 if (!buffer) {
387 printf("Alloc image buffer failed!\n");
388 return 0;
389 }
390
391 /* Bind the buffer to the context and make it current */
392 if (!OSMesaMakeCurrent( ctx, buffer, type, WIDTH, HEIGHT )) {
393 printf("OSMesaMakeCurrent (%d bits/channel) failed!\n", bits);
394 free(buffer);
395 OSMesaDestroyContext(ctx);
396 return 0;
397 }
398
399 /* sanity checks */
400 glGetIntegerv(GL_RED_BITS, &cBits);
401 if (cBits != bits) {
402 fprintf(stderr, "Unable to create %d-bit/channel renderbuffer.\n", bits);
403 fprintf(stderr, "May need to recompile Mesa with CHAN_BITS=16 or 32.\n");
404 return 0;
405 }
406 glGetIntegerv(GL_GREEN_BITS, &cBits);
407 assert(cBits == bits);
408 glGetIntegerv(GL_BLUE_BITS, &cBits);
409 assert(cBits == bits);
410 glGetIntegerv(GL_ALPHA_BITS, &cBits);
411 assert(cBits == bits);
412
413 if (WriteFiles)
414 printf("Rendering %d bit/channel image: %s\n", bits, filename);
415 else
416 printf("Rendering %d bit/channel image\n", bits);
417
418 OSMesaColorClamp(GL_TRUE);
419
420 init_context();
421 render_image();
422 if (Gradient)
423 render_gradient();
424
425 /* Make sure buffered commands are finished! */
426 glFinish();
427
428
429 if (WriteFiles && filename != NULL) {
430 if (type == GL_UNSIGNED_SHORT) {
431 GLushort *buffer16 = (GLushort *) buffer;
432 GLubyte *buffer8 = (GLubyte *) malloc(WIDTH * HEIGHT * 4);
433 int i;
434 for (i = 0; i < WIDTH * HEIGHT * 4; i++)
435 buffer8[i] = buffer16[i] >> 8;
436 write_ppm(filename, buffer8, WIDTH, HEIGHT);
437 free(buffer8);
438 }
439 else if (type == GL_FLOAT) {
440 GLfloat *buffer32 = (GLfloat *) buffer;
441 GLubyte *buffer8 = (GLubyte *) malloc(WIDTH * HEIGHT * 4);
442 int i;
443 /* colors may be outside [0,1] so we need to clamp */
444 for (i = 0; i < WIDTH * HEIGHT * 4; i++)
445 buffer8[i] = (GLubyte) (buffer32[i] * 255.0);
446 write_ppm(filename, buffer8, WIDTH, HEIGHT);
447 free(buffer8);
448 }
449 else {
450 write_ppm(filename, buffer, WIDTH, HEIGHT);
451 }
452 }
453
454 OSMesaDestroyContext(ctx);
455
456 free(buffer);
457
458 return 1;
459 }
460
461
462 int
main(int argc,char * argv[])463 main( int argc, char *argv[] )
464 {
465 int i;
466
467 printf("Use -f to write image files\n");
468
469 for (i = 1; i < argc; i++) {
470 if (strcmp(argv[i], "-f") == 0)
471 WriteFiles = GL_TRUE;
472 else if (strcmp(argv[i], "-g") == 0)
473 Gradient = GL_TRUE;
474 }
475
476 test(GL_UNSIGNED_BYTE, 8, "image8.ppm");
477 test(GL_UNSIGNED_SHORT, 16, "image16.ppm");
478 test(GL_FLOAT, 32, "image32.ppm");
479
480 return 0;
481 }
482