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