1/*
2 * Copyright (C) 2008  Tunsgten Graphics,Inc.   All Rights Reserved.
3 */
4
5/*
6 * Draw a lit, textured torus with X/EGL and OpenGL ES 1.x
7 * Brian Paul
8 * July 2008
9 */
10
11
12#include <assert.h>
13#include <math.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <GLES/gl.h>
17
18#include "eglut.h"
19
20static const struct {
21   GLenum internalFormat;
22   const char *name;
23   GLuint num_entries;
24   GLuint size;
25} cpal_formats[] = {
26   { GL_PALETTE4_RGB8_OES,     "GL_PALETTE4_RGB8_OES",      16, 3 },
27   { GL_PALETTE4_RGBA8_OES,    "GL_PALETTE4_RGBA8_OES",     16, 4 },
28   { GL_PALETTE4_R5_G6_B5_OES, "GL_PALETTE4_R5_G6_B5_OES",  16, 2 },
29   { GL_PALETTE4_RGBA4_OES,    "GL_PALETTE4_RGBA4_OES",     16, 2 },
30   { GL_PALETTE4_RGB5_A1_OES,  "GL_PALETTE4_RGB5_A1_OES",   16, 2 },
31   { GL_PALETTE8_RGB8_OES,     "GL_PALETTE8_RGB8_OES",     256, 3 },
32   { GL_PALETTE8_RGBA8_OES,    "GL_PALETTE8_RGBA8_OES",    256, 4 },
33   { GL_PALETTE8_R5_G6_B5_OES, "GL_PALETTE8_R5_G6_B5_OES", 256, 2 },
34   { GL_PALETTE8_RGBA4_OES,    "GL_PALETTE8_RGBA4_OES",    256, 2 },
35   { GL_PALETTE8_RGB5_A1_OES,  "GL_PALETTE8_RGB5_A1_OES",  256, 2 }
36};
37#define NUM_CPAL_FORMATS (sizeof(cpal_formats) / sizeof(cpal_formats[0]))
38
39static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
40static GLint tex_format = NUM_CPAL_FORMATS;
41static GLboolean animate = GL_TRUE;
42static int win;
43
44
45static void
46Normal(GLfloat *n, GLfloat nx, GLfloat ny, GLfloat nz)
47{
48   n[0] = nx;
49   n[1] = ny;
50   n[2] = nz;
51}
52
53static void
54Vertex(GLfloat *v, GLfloat vx, GLfloat vy, GLfloat vz)
55{
56   v[0] = vx;
57   v[1] = vy;
58   v[2] = vz;
59}
60
61static void
62Texcoord(GLfloat *v, GLfloat s, GLfloat t)
63{
64   v[0] = s;
65   v[1] = t;
66}
67
68
69/* Borrowed from glut, adapted */
70static void
71draw_torus(GLfloat r, GLfloat R, GLint nsides, GLint rings)
72{
73   int i, j;
74   GLfloat theta, phi, theta1;
75   GLfloat cosTheta, sinTheta;
76   GLfloat cosTheta1, sinTheta1;
77   GLfloat ringDelta, sideDelta;
78   GLfloat varray[100][3], narray[100][3], tarray[100][2];
79   int vcount;
80
81   glVertexPointer(3, GL_FLOAT, 0, varray);
82   glNormalPointer(GL_FLOAT, 0, narray);
83   glTexCoordPointer(2, GL_FLOAT, 0, tarray);
84   glEnableClientState(GL_VERTEX_ARRAY);
85   glEnableClientState(GL_NORMAL_ARRAY);
86   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
87
88   ringDelta = 2.0 * M_PI / rings;
89   sideDelta = 2.0 * M_PI / nsides;
90
91   theta = 0.0;
92   cosTheta = 1.0;
93   sinTheta = 0.0;
94   for (i = rings - 1; i >= 0; i--) {
95      theta1 = theta + ringDelta;
96      cosTheta1 = cos(theta1);
97      sinTheta1 = sin(theta1);
98
99      vcount = 0; /* glBegin(GL_QUAD_STRIP); */
100
101      phi = 0.0;
102      for (j = nsides; j >= 0; j--) {
103         GLfloat s0, s1, t;
104         GLfloat cosPhi, sinPhi, dist;
105
106         phi += sideDelta;
107         cosPhi = cos(phi);
108         sinPhi = sin(phi);
109         dist = R + r * cosPhi;
110
111         s0 = 20.0 * theta / (2.0 * M_PI);
112         s1 = 20.0 * theta1 / (2.0 * M_PI);
113         t = 8.0 * phi / (2.0 * M_PI);
114
115         Normal(narray[vcount], cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
116         Texcoord(tarray[vcount], s1, t);
117         Vertex(varray[vcount], cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
118         vcount++;
119
120         Normal(narray[vcount], cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
121         Texcoord(tarray[vcount], s0, t);
122         Vertex(varray[vcount], cosTheta * dist, -sinTheta * dist,  r * sinPhi);
123         vcount++;
124      }
125
126      /*glEnd();*/
127      assert(vcount <= 100);
128      glDrawArrays(GL_TRIANGLE_STRIP, 0, vcount);
129
130      theta = theta1;
131      cosTheta = cosTheta1;
132      sinTheta = sinTheta1;
133   }
134
135   glDisableClientState(GL_VERTEX_ARRAY);
136   glDisableClientState(GL_NORMAL_ARRAY);
137   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
138}
139
140
141static void
142draw(void)
143{
144   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
145
146   glPushMatrix();
147   glRotatef(view_rotx, 1, 0, 0);
148   glRotatef(view_roty, 0, 1, 0);
149   glRotatef(view_rotz, 0, 0, 1);
150   glScalef(0.5, 0.5, 0.5);
151
152   draw_torus(1.0, 3.0, 30, 60);
153
154   glPopMatrix();
155}
156
157
158/* new window size or exposure */
159static void
160reshape(int width, int height)
161{
162   GLfloat ar = (GLfloat) width / (GLfloat) height;
163
164   glViewport(0, 0, (GLint) width, (GLint) height);
165
166   glMatrixMode(GL_PROJECTION);
167   glLoadIdentity();
168
169#ifdef GL_VERSION_ES_CM_1_0
170   glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
171#else
172   glFrustum(-ar, ar, -1, 1, 5.0, 60.0);
173#endif
174
175   glMatrixMode(GL_MODELVIEW);
176   glLoadIdentity();
177   glTranslatef(0.0, 0.0, -15.0);
178}
179
180
181static GLint
182make_cpal_texture(GLint idx)
183{
184#define SZ 64
185   GLenum internalFormat = GL_PALETTE4_RGB8_OES + idx;
186   GLenum Filter = GL_LINEAR;
187   GLubyte palette[256 * 4 + SZ * SZ];
188   GLubyte *indices;
189   GLsizei image_size;
190   GLuint i, j;
191   GLuint packed_indices = 0;
192
193   assert(cpal_formats[idx].internalFormat == internalFormat);
194
195   /* init palette */
196   switch (internalFormat) {
197   case GL_PALETTE4_RGB8_OES:
198   case GL_PALETTE8_RGB8_OES:
199      /* first entry */
200      palette[0] = 255;
201      palette[1] = 255;
202      palette[2] = 255;
203      /* second entry */
204      palette[3] = 127;
205      palette[4] = 127;
206      palette[5] = 127;
207      break;
208   case GL_PALETTE4_RGBA8_OES:
209   case GL_PALETTE8_RGBA8_OES:
210      /* first entry */
211      palette[0] = 255;
212      palette[1] = 255;
213      palette[2] = 255;
214      palette[3] = 255;
215      /* second entry */
216      palette[4] = 127;
217      palette[5] = 127;
218      palette[6] = 127;
219      palette[7] = 255;
220      break;
221   case GL_PALETTE4_R5_G6_B5_OES:
222   case GL_PALETTE8_R5_G6_B5_OES:
223      {
224         GLushort *pal = (GLushort *) palette;
225         /* first entry */
226         pal[0] = (31 << 11 | 63 << 5 | 31);
227         /* second entry */
228         pal[1] = (15 << 11 | 31 << 5 | 15);
229      }
230      break;
231   case GL_PALETTE4_RGBA4_OES:
232   case GL_PALETTE8_RGBA4_OES:
233      {
234         GLushort *pal = (GLushort *) palette;
235         /* first entry */
236         pal[0] = (15 << 12 | 15 << 8 | 15 << 4 | 15);
237         /* second entry */
238         pal[1] = (7 << 12 | 7 << 8 | 7 << 4 | 15);
239      }
240      break;
241   case GL_PALETTE4_RGB5_A1_OES:
242   case GL_PALETTE8_RGB5_A1_OES:
243      {
244         GLushort *pal = (GLushort *) palette;
245         /* first entry */
246         pal[0] = (31 << 11 | 31 << 6 | 31 << 1 | 1);
247         /* second entry */
248         pal[1] = (15 << 11 | 15 << 6 | 15 << 1 | 1);
249      }
250      break;
251   }
252
253   image_size = cpal_formats[idx].size * cpal_formats[idx].num_entries;
254   indices = palette + image_size;
255   for (i = 0; i < SZ; i++) {
256      for (j = 0; j < SZ; j++) {
257         GLfloat d;
258         GLint index;
259         d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
260         d = sqrt(d);
261         index = (d < SZ / 3) ? 0 : 1;
262
263         if (cpal_formats[idx].num_entries == 16) {
264            /* 4-bit indices packed in GLubyte */
265            packed_indices |= index << (4 * (1 - (j % 2)));
266            if (j % 2) {
267               *(indices + (i * SZ + j - 1) / 2) = packed_indices & 0xff;
268               packed_indices = 0;
269               image_size += 1;
270            }
271         }
272         else {
273            /* 8-bit indices */
274            *(indices + i * SZ + j) = index;
275            image_size += 1;
276         }
277      }
278   }
279
280   glActiveTexture(GL_TEXTURE0); /* unit 0 */
281   glBindTexture(GL_TEXTURE_2D, 42);
282   glCompressedTexImage2D(GL_TEXTURE_2D, 0, internalFormat, SZ, SZ, 0,
283                          image_size, palette);
284
285   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
286   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
287   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
288   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
289#undef SZ
290
291   return image_size;
292}
293
294
295static GLint
296make_texture(void)
297{
298#define SZ 64
299   GLenum Filter = GL_LINEAR;
300   GLubyte image[SZ][SZ][4];
301   GLuint i, j;
302
303   for (i = 0; i < SZ; i++) {
304      for (j = 0; j < SZ; j++) {
305         GLfloat d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
306         d = sqrt(d);
307         if (d < SZ/3) {
308            image[i][j][0] = 255;
309            image[i][j][1] = 255;
310            image[i][j][2] = 255;
311            image[i][j][3] = 255;
312         }
313         else {
314            image[i][j][0] = 127;
315            image[i][j][1] = 127;
316            image[i][j][2] = 127;
317            image[i][j][3] = 255;
318         }
319      }
320   }
321
322   glActiveTexture(GL_TEXTURE0); /* unit 0 */
323   glBindTexture(GL_TEXTURE_2D, 42);
324   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ, SZ, 0,
325                GL_RGBA, GL_UNSIGNED_BYTE, image);
326   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
327   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
328   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
329   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
330#undef SZ
331
332   return sizeof(image);
333}
334
335
336
337static void
338init(void)
339{
340   static const GLfloat red[4] = {1, 0, 0, 0};
341   static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
342   static const GLfloat diffuse[4] = {0.7, 0.7, 0.7, 1.0};
343   static const GLfloat specular[4] = {0.001, 0.001, 0.001, 1.0};
344   static const GLfloat pos[4] = {20, 20, 50, 1};
345
346   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
347   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
348   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 9.0);
349
350   glEnable(GL_LIGHTING);
351   glEnable(GL_LIGHT0);
352   glLightfv(GL_LIGHT0, GL_POSITION, pos);
353   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
354   glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
355
356   glClearColor(0.4, 0.4, 0.4, 0.0);
357   glEnable(GL_DEPTH_TEST);
358
359   make_texture();
360   glEnable(GL_TEXTURE_2D);
361
362   /* Enable automatic normalizing to get proper lighting when torus is
363    * scaled down via glScalef
364    */
365   glEnable(GL_NORMALIZE);
366}
367
368
369static void
370idle(void)
371{
372   if (animate) {
373      view_rotx += 1.0;
374      view_roty += 2.0;
375      eglutPostRedisplay();
376   }
377}
378
379static void
380key(unsigned char key)
381{
382   switch (key) {
383   case ' ':
384      animate = !animate;
385      break;
386   case 't':
387      {
388         GLint size;
389         tex_format = (tex_format + 1) % (NUM_CPAL_FORMATS + 1);
390         if (tex_format < NUM_CPAL_FORMATS) {
391            size = make_cpal_texture(tex_format);
392            printf("Using %s (%d bytes)\n",
393                  cpal_formats[tex_format].name, size);
394         }
395         else {
396            size = make_texture();
397            printf("Using uncompressed texture (%d bytes)\n", size);
398         }
399
400         eglutPostRedisplay();
401      }
402      break;
403   case 27:
404      eglutDestroyWindow(win);
405      exit(0);
406      break;
407   default:
408      break;
409   }
410}
411
412static void
413special_key(int key)
414{
415   switch (key) {
416   case EGLUT_KEY_LEFT:
417      view_roty += 5.0;
418      break;
419   case EGLUT_KEY_RIGHT:
420      view_roty -= 5.0;
421      break;
422   case EGLUT_KEY_UP:
423      view_rotx += 5.0;
424      break;
425   case EGLUT_KEY_DOWN:
426      view_rotx -= 5.0;
427      break;
428   default:
429      break;
430   }
431}
432
433int
434main(int argc, char *argv[])
435{
436   eglutInitWindowSize(300, 300);
437   eglutInitAPIMask(EGLUT_OPENGL_ES1_BIT);
438   eglutInit(argc, argv);
439
440   win = eglutCreateWindow("torus");
441
442   eglutIdleFunc(idle);
443   eglutReshapeFunc(reshape);
444   eglutDisplayFunc(draw);
445   eglutKeyboardFunc(key);
446   eglutSpecialFunc(special_key);
447
448   init();
449
450   eglutMainLoop();
451
452   return 0;
453}
454