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