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