1/*
2 * Demo of off-screen Mesa rendering with 32-bit float color channels.
3 * This requires the libOSMesa32.so library.
4 *
5 * Compile with something like this:
6 *
7 * gcc osdemo32.c -I../../include -L../../lib -lglut -lGLU -lOSMesa32 -lm -o osdemo32
8 */
9
10
11#include <stdio.h>
12#include <stdlib.h>
13#include "GL/osmesa.h"
14#include "glut_wrap.h"
15
16
17#define SAVE_TARGA
18
19
20#define WIDTH 400
21#define HEIGHT 400
22
23
24
25static void render_image( void )
26{
27   GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
28   GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
29   GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
30   GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
31   GLfloat red_mat[]   = { 1.0, 0.2, 0.2, 1.0 };
32   GLfloat green_mat[] = { 0.2, 1.0, 0.2, 0.5 };
33   GLfloat blue_mat[]  = { 0.2, 0.2, 1.0, 1.0 };
34   GLfloat white_mat[]  = { 1.0, 1.0, 1.0, 1.0 };
35   GLfloat purple_mat[] = { 1.0, 0.2, 1.0, 1.0 };
36   GLUquadricObj *qobj = gluNewQuadric();
37
38   glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
39   glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
40   glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
41   glLightfv(GL_LIGHT0, GL_POSITION, light_position);
42
43   glEnable(GL_LIGHTING);
44   glEnable(GL_LIGHT0);
45   glEnable(GL_DEPTH_TEST);
46
47   glMatrixMode(GL_PROJECTION);
48   glLoadIdentity();
49   glOrtho(-2.5, 2.5, -2.5, 2.5, -10.0, 10.0);
50   glMatrixMode(GL_MODELVIEW);
51
52   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
53
54   glPushMatrix();
55   glRotatef(20.0, 1.0, 0.0, 0.0);
56
57   /* red square */
58   glPushMatrix();
59   glTranslatef(0.0, -0.5, 0.0);
60   glRotatef(90, 1, 0.5, 0);
61   glScalef(3, 3, 3);
62   glDisable(GL_LIGHTING);
63   glColor4f(1, 0, 0, 0.5);
64   glBegin(GL_POLYGON);
65   glVertex2f(-1, -1);
66   glVertex2f( 1, -1);
67   glVertex2f( 1,  1);
68   glVertex2f(-1,  1);
69   glEnd();
70   glEnable(GL_LIGHTING);
71   glPopMatrix();
72
73#if 0
74   /* green square */
75   glPushMatrix();
76   glTranslatef(0.0, 0.5, 0.1);
77   glDisable(GL_LIGHTING);
78   glColor3f(0, 1, 0);
79   glBegin(GL_POLYGON);
80   glVertex2f(-1, -1);
81   glVertex2f( 1, -1);
82   glVertex2f( 1,  1);
83   glVertex2f(-1,  1);
84   glEnd();
85   glEnable(GL_LIGHTING);
86   glPopMatrix();
87
88   /* blue square */
89   glPushMatrix();
90   glTranslatef(0.75, 0.5, 0.3);
91   glDisable(GL_LIGHTING);
92   glColor3f(0, 0, 0.5);
93   glBegin(GL_POLYGON);
94   glVertex2f(-1, -1);
95   glVertex2f( 1, -1);
96   glVertex2f( 1,  1);
97   glVertex2f(-1,  1);
98   glEnd();
99   glEnable(GL_LIGHTING);
100   glPopMatrix();
101#endif
102
103   glPushMatrix();
104   glTranslatef(-0.75, -0.5, 0.0);
105   glRotatef(270.0, 1.0, 0.0, 0.0);
106   glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green_mat );
107   glEnable(GL_BLEND);
108   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
109   gluCylinder(qobj, 1.0, 0.0, 2.0, 16, 1);
110   glDisable(GL_BLEND);
111   glPopMatrix();
112
113   glPushMatrix();
114   glTranslatef(0.75, 1.0, 1.0);
115   glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue_mat );
116   gluSphere(qobj, 1.0, 20, 20);
117   glPopMatrix();
118
119   glPopMatrix();
120
121   /* This is very important!!!
122    * Make sure buffered commands are finished!!!
123    */
124   glFinish();
125
126   gluDeleteQuadric(qobj);
127
128   {
129      GLint r, g, b, a, d;
130      glGetIntegerv(GL_RED_BITS, &r);
131      glGetIntegerv(GL_GREEN_BITS, &g);
132      glGetIntegerv(GL_BLUE_BITS, &b);
133      glGetIntegerv(GL_ALPHA_BITS, &a);
134      glGetIntegerv(GL_DEPTH_BITS, &d);
135      printf("channel sizes: %d %d %d %d\n", r, g, b, a);
136      printf("depth bits %d\n", d);
137   }
138}
139
140
141
142static void
143write_targa(const char *filename, const GLfloat *buffer, int width, int height)
144{
145   FILE *f = fopen( filename, "w" );
146   if (f) {
147      int i, x, y;
148      const GLfloat *ptr = buffer;
149      printf ("osdemo, writing tga file \n");
150      fputc (0x00, f);	/* ID Length, 0 => No ID	*/
151      fputc (0x00, f);	/* Color Map Type, 0 => No color map included	*/
152      fputc (0x02, f);	/* Image Type, 2 => Uncompressed, True-color Image */
153      fputc (0x00, f);	/* Next five bytes are about the color map entries */
154      fputc (0x00, f);	/* 2 bytes Index, 2 bytes length, 1 byte size */
155      fputc (0x00, f);
156      fputc (0x00, f);
157      fputc (0x00, f);
158      fputc (0x00, f);	/* X-origin of Image	*/
159      fputc (0x00, f);
160      fputc (0x00, f);	/* Y-origin of Image	*/
161      fputc (0x00, f);
162      fputc (WIDTH & 0xff, f);      /* Image Width	*/
163      fputc ((WIDTH>>8) & 0xff, f);
164      fputc (HEIGHT & 0xff, f);     /* Image Height	*/
165      fputc ((HEIGHT>>8) & 0xff, f);
166      fputc (0x18, f);		/* Pixel Depth, 0x18 => 24 Bits	*/
167      fputc (0x20, f);		/* Image Descriptor	*/
168      fclose(f);
169      f = fopen( filename, "ab" );  /* reopen in binary append mode */
170      for (y=height-1; y>=0; y--) {
171         for (x=0; x<width; x++) {
172            int r, g, b;
173            i = (y*width + x) * 4;
174            r = (int) (ptr[i+0] * 255.0);
175            g = (int) (ptr[i+1] * 255.0);
176            b = (int) (ptr[i+2] * 255.0);
177            if (r > 255) r = 255;
178            if (g > 255) g = 255;
179            if (b > 255) b = 255;
180            fputc(b, f); /* write blue */
181            fputc(g, f); /* write green */
182            fputc(r, f); /* write red */
183         }
184      }
185   }
186}
187
188
189static void
190write_ppm(const char *filename, const GLfloat *buffer, int width, int height)
191{
192   const int binary = 0;
193   FILE *f = fopen( filename, "w" );
194   if (f) {
195      int i, x, y;
196      const GLfloat *ptr = buffer;
197      if (binary) {
198         fprintf(f,"P6\n");
199         fprintf(f,"# ppm-file created by osdemo.c\n");
200         fprintf(f,"%i %i\n", width,height);
201         fprintf(f,"255\n");
202         fclose(f);
203         f = fopen( filename, "ab" );  /* reopen in binary append mode */
204         for (y=height-1; y>=0; y--) {
205            for (x=0; x<width; x++) {
206               int r, g, b;
207               i = (y*width + x) * 4;
208               r = (int) (ptr[i+0] * 255.0);
209               g = (int) (ptr[i+1] * 255.0);
210               b = (int) (ptr[i+2] * 255.0);
211               if (r > 255) r = 255;
212               if (g > 255) g = 255;
213               if (b > 255) b = 255;
214               fputc(r, f);   /* write red */
215               fputc(g, f); /* write green */
216               fputc(b, f); /* write blue */
217            }
218         }
219      }
220      else {
221         /*ASCII*/
222         int counter = 0;
223         fprintf(f,"P3\n");
224         fprintf(f,"# ascii ppm file created by osdemo.c\n");
225         fprintf(f,"%i %i\n", width, height);
226         fprintf(f,"255\n");
227         for (y=height-1; y>=0; y--) {
228            for (x=0; x<width; x++) {
229               int r, g, b;
230               i = (y*width + x) * 4;
231               r = (int) (ptr[i+0] * 255.0);
232               g = (int) (ptr[i+1] * 255.0);
233               b = (int) (ptr[i+2] * 255.0);
234               if (r > 255) r = 255;
235               if (g > 255) g = 255;
236               if (b > 255) b = 255;
237               fprintf(f, " %3d %3d %3d", r, g, b);
238               counter++;
239               if (counter % 5 == 0)
240                  fprintf(f, "\n");
241            }
242         }
243      }
244      fclose(f);
245   }
246}
247
248
249
250int main( int argc, char *argv[] )
251{
252   GLfloat *buffer;
253
254   /* Create an RGBA-mode context */
255#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
256   /* specify Z, stencil, accum sizes */
257   OSMesaContext ctx = OSMesaCreateContextExt( GL_RGBA, 32, 0, 0, NULL );
258#else
259   OSMesaContext ctx = OSMesaCreateContext( GL_RGBA, NULL );
260#endif
261   if (!ctx) {
262      printf("OSMesaCreateContext failed!\n");
263      return 0;
264   }
265
266   /* Allocate the image buffer */
267   buffer = (GLfloat *) malloc( WIDTH * HEIGHT * 4 * sizeof(GLfloat));
268   if (!buffer) {
269      printf("Alloc image buffer failed!\n");
270      return 0;
271   }
272
273   /* Bind the buffer to the context and make it current */
274   if (!OSMesaMakeCurrent( ctx, buffer, GL_FLOAT, WIDTH, HEIGHT )) {
275      printf("OSMesaMakeCurrent failed!\n");
276      return 0;
277   }
278
279   render_image();
280
281   if (argc>1) {
282#ifdef SAVE_TARGA
283      write_targa(argv[1], buffer, WIDTH, HEIGHT);
284#else
285      write_ppm(argv[1], buffer, WIDTH, HEIGHT);
286#endif
287   }
288   else {
289      printf("Specify a filename if you want to make an image file\n");
290   }
291
292   printf("all done\n");
293
294   /* free the image buffer */
295   free( buffer );
296
297   /* destroy the context */
298   OSMesaDestroyContext( ctx );
299
300   return 0;
301}
302