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