The Android Open Source Project | e09fd9e | 2008-12-17 18:05:43 -0800 | [diff] [blame^] | 1 | /* San Angeles Observation OpenGL ES version example |
| 2 | * Copyright 2004-2005 Jetro Lauha |
| 3 | * All rights reserved. |
| 4 | * Web: http://iki.fi/jetro/ |
| 5 | * |
| 6 | * This source is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of EITHER: |
| 8 | * (1) The GNU Lesser General Public License as published by the Free |
| 9 | * Software Foundation; either version 2.1 of the License, or (at |
| 10 | * your option) any later version. The text of the GNU Lesser |
| 11 | * General Public License is included with this source in the |
| 12 | * file LICENSE-LGPL.txt. |
| 13 | * (2) The BSD-style license that is included with this source in |
| 14 | * the file LICENSE-BSD.txt. |
| 15 | * |
| 16 | * This source is distributed in the hope that it will be useful, |
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files |
| 19 | * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. |
| 20 | * |
| 21 | * $Id: demo.c,v 1.10 2005/02/08 20:54:39 tonic Exp $ |
| 22 | * $Revision: 1.10 $ |
| 23 | */ |
| 24 | |
| 25 | #include <stdlib.h> |
| 26 | #include <math.h> |
| 27 | #include <float.h> |
| 28 | #include <assert.h> |
| 29 | |
| 30 | #include <GLES/gl.h> |
| 31 | |
| 32 | #include "app.h" |
| 33 | #include "shapes.h" |
| 34 | #include "cams.h" |
| 35 | |
| 36 | |
| 37 | // Total run length is 20 * camera track base unit length (see cams.h). |
| 38 | #define RUN_LENGTH (20 * CAMTRACK_LEN) |
| 39 | #undef PI |
| 40 | #define PI 3.1415926535897932f |
| 41 | #define RANDOM_UINT_MAX 65535 |
| 42 | |
| 43 | |
| 44 | static unsigned long sRandomSeed = 0; |
| 45 | |
| 46 | static void seedRandom(unsigned long seed) |
| 47 | { |
| 48 | sRandomSeed = seed; |
| 49 | } |
| 50 | |
| 51 | static unsigned long randomUInt() |
| 52 | { |
| 53 | sRandomSeed = sRandomSeed * 0x343fd + 0x269ec3; |
| 54 | return sRandomSeed >> 16; |
| 55 | } |
| 56 | |
| 57 | |
| 58 | // Capped conversion from float to fixed. |
| 59 | static long floatToFixed(float value) |
| 60 | { |
| 61 | if (value < -32768) value = -32768; |
| 62 | if (value > 32767) value = 32767; |
| 63 | return (long)(value * 65536); |
| 64 | } |
| 65 | |
| 66 | #define FIXED(value) floatToFixed(value) |
| 67 | |
| 68 | |
| 69 | // Definition of one GL object in this demo. |
| 70 | typedef struct { |
| 71 | /* Vertex array and color array are enabled for all objects, so their |
| 72 | * pointers must always be valid and non-NULL. Normal array is not |
| 73 | * used by the ground plane, so when its pointer is NULL then normal |
| 74 | * array usage is disabled. |
| 75 | * |
| 76 | * Vertex array is supposed to use GL_FIXED datatype and stride 0 |
| 77 | * (i.e. tightly packed array). Color array is supposed to have 4 |
| 78 | * components per color with GL_UNSIGNED_BYTE datatype and stride 0. |
| 79 | * Normal array is supposed to use GL_FIXED datatype and stride 0. |
| 80 | */ |
| 81 | GLfixed *vertexArray; |
| 82 | GLubyte *colorArray; |
| 83 | GLfixed *normalArray; |
| 84 | GLint vertexComponents; |
| 85 | GLsizei count; |
| 86 | } GLOBJECT; |
| 87 | |
| 88 | |
| 89 | static long sStartTick = 0; |
| 90 | static long sTick = 0; |
| 91 | |
| 92 | static int sCurrentCamTrack = 0; |
| 93 | static long sCurrentCamTrackStartTick = 0; |
| 94 | static long sNextCamTrackStartTick = 0x7fffffff; |
| 95 | |
| 96 | static GLOBJECT *sSuperShapeObjects[SUPERSHAPE_COUNT] = { NULL }; |
| 97 | static GLOBJECT *sGroundPlane = NULL; |
| 98 | |
| 99 | |
| 100 | typedef struct { |
| 101 | float x, y, z; |
| 102 | } VECTOR3; |
| 103 | |
| 104 | |
| 105 | static void freeGLObject(GLOBJECT *object) |
| 106 | { |
| 107 | if (object == NULL) |
| 108 | return; |
| 109 | free(object->normalArray); |
| 110 | free(object->colorArray); |
| 111 | free(object->vertexArray); |
| 112 | free(object); |
| 113 | } |
| 114 | |
| 115 | |
| 116 | static GLOBJECT * newGLObject(long vertices, int vertexComponents, |
| 117 | int useNormalArray) |
| 118 | { |
| 119 | GLOBJECT *result; |
| 120 | result = (GLOBJECT *)malloc(sizeof(GLOBJECT)); |
| 121 | if (result == NULL) |
| 122 | return NULL; |
| 123 | result->count = vertices; |
| 124 | result->vertexComponents = vertexComponents; |
| 125 | result->vertexArray = (GLfixed *)malloc(vertices * vertexComponents * |
| 126 | sizeof(GLfixed)); |
| 127 | result->colorArray = (GLubyte *)malloc(vertices * 4 * sizeof(GLubyte)); |
| 128 | if (useNormalArray) |
| 129 | { |
| 130 | result->normalArray = (GLfixed *)malloc(vertices * 3 * |
| 131 | sizeof(GLfixed)); |
| 132 | } |
| 133 | else |
| 134 | result->normalArray = NULL; |
| 135 | if (result->vertexArray == NULL || |
| 136 | result->colorArray == NULL || |
| 137 | (useNormalArray && result->normalArray == NULL)) |
| 138 | { |
| 139 | freeGLObject(result); |
| 140 | return NULL; |
| 141 | } |
| 142 | return result; |
| 143 | } |
| 144 | |
| 145 | |
| 146 | static void drawGLObject(GLOBJECT *object) |
| 147 | { |
| 148 | assert(object != NULL); |
| 149 | |
| 150 | glVertexPointer(object->vertexComponents, GL_FIXED, |
| 151 | 0, object->vertexArray); |
| 152 | glColorPointer(4, GL_UNSIGNED_BYTE, 0, object->colorArray); |
| 153 | |
| 154 | // Already done in initialization: |
| 155 | //glEnableClientState(GL_VERTEX_ARRAY); |
| 156 | //glEnableClientState(GL_COLOR_ARRAY); |
| 157 | |
| 158 | if (object->normalArray) |
| 159 | { |
| 160 | glNormalPointer(GL_FIXED, 0, object->normalArray); |
| 161 | glEnableClientState(GL_NORMAL_ARRAY); |
| 162 | } |
| 163 | else |
| 164 | glDisableClientState(GL_NORMAL_ARRAY); |
| 165 | glDrawArrays(GL_TRIANGLES, 0, object->count); |
| 166 | } |
| 167 | |
| 168 | |
| 169 | static void vector3Sub(VECTOR3 *dest, VECTOR3 *v1, VECTOR3 *v2) |
| 170 | { |
| 171 | dest->x = v1->x - v2->x; |
| 172 | dest->y = v1->y - v2->y; |
| 173 | dest->z = v1->z - v2->z; |
| 174 | } |
| 175 | |
| 176 | |
| 177 | static void superShapeMap(VECTOR3 *point, float r1, float r2, float t, float p) |
| 178 | { |
| 179 | // sphere-mapping of supershape parameters |
| 180 | point->x = (float)(cos(t) * cos(p) / r1 / r2); |
| 181 | point->y = (float)(sin(t) * cos(p) / r1 / r2); |
| 182 | point->z = (float)(sin(p) / r2); |
| 183 | } |
| 184 | |
| 185 | |
| 186 | static float ssFunc(const float t, const float *p) |
| 187 | { |
| 188 | return (float)(pow(pow(fabs(cos(p[0] * t / 4)) / p[1], p[4]) + |
| 189 | pow(fabs(sin(p[0] * t / 4)) / p[2], p[5]), 1 / p[3])); |
| 190 | } |
| 191 | |
| 192 | |
| 193 | // Creates and returns a supershape object. |
| 194 | // Based on Paul Bourke's POV-Ray implementation. |
| 195 | // http://astronomy.swin.edu.au/~pbourke/povray/supershape/ |
| 196 | static GLOBJECT * createSuperShape(const float *params) |
| 197 | { |
| 198 | const int resol1 = (int)params[SUPERSHAPE_PARAMS - 3]; |
| 199 | const int resol2 = (int)params[SUPERSHAPE_PARAMS - 2]; |
| 200 | // latitude 0 to pi/2 for no mirrored bottom |
| 201 | // (latitudeBegin==0 for -pi/2 to pi/2 originally) |
| 202 | const int latitudeBegin = resol2 / 4; |
| 203 | const int latitudeEnd = resol2 / 2; // non-inclusive |
| 204 | const int longitudeCount = resol1; |
| 205 | const int latitudeCount = latitudeEnd - latitudeBegin; |
| 206 | const long triangleCount = longitudeCount * latitudeCount * 2; |
| 207 | const long vertices = triangleCount * 3; |
| 208 | GLOBJECT *result; |
| 209 | float baseColor[3]; |
| 210 | int a, longitude, latitude; |
| 211 | long currentVertex, currentQuad; |
| 212 | |
| 213 | result = newGLObject(vertices, 3, 1); |
| 214 | if (result == NULL) |
| 215 | return NULL; |
| 216 | |
| 217 | for (a = 0; a < 3; ++a) |
| 218 | baseColor[a] = ((randomUInt() % 155) + 100) / 255.f; |
| 219 | |
| 220 | currentQuad = 0; |
| 221 | currentVertex = 0; |
| 222 | |
| 223 | // longitude -pi to pi |
| 224 | for (longitude = 0; longitude < longitudeCount; ++longitude) |
| 225 | { |
| 226 | |
| 227 | // latitude 0 to pi/2 |
| 228 | for (latitude = latitudeBegin; latitude < latitudeEnd; ++latitude) |
| 229 | { |
| 230 | float t1 = -PI + longitude * 2 * PI / resol1; |
| 231 | float t2 = -PI + (longitude + 1) * 2 * PI / resol1; |
| 232 | float p1 = -PI / 2 + latitude * 2 * PI / resol2; |
| 233 | float p2 = -PI / 2 + (latitude + 1) * 2 * PI / resol2; |
| 234 | float r0, r1, r2, r3; |
| 235 | |
| 236 | r0 = ssFunc(t1, params); |
| 237 | r1 = ssFunc(p1, ¶ms[6]); |
| 238 | r2 = ssFunc(t2, params); |
| 239 | r3 = ssFunc(p2, ¶ms[6]); |
| 240 | |
| 241 | if (r0 != 0 && r1 != 0 && r2 != 0 && r3 != 0) |
| 242 | { |
| 243 | VECTOR3 pa, pb, pc, pd; |
| 244 | VECTOR3 v1, v2, n; |
| 245 | float ca; |
| 246 | int i; |
| 247 | //float lenSq, invLenSq; |
| 248 | |
| 249 | superShapeMap(&pa, r0, r1, t1, p1); |
| 250 | superShapeMap(&pb, r2, r1, t2, p1); |
| 251 | superShapeMap(&pc, r2, r3, t2, p2); |
| 252 | superShapeMap(&pd, r0, r3, t1, p2); |
| 253 | |
| 254 | // kludge to set lower edge of the object to fixed level |
| 255 | if (latitude == latitudeBegin + 1) |
| 256 | pa.z = pb.z = 0; |
| 257 | |
| 258 | vector3Sub(&v1, &pb, &pa); |
| 259 | vector3Sub(&v2, &pd, &pa); |
| 260 | |
| 261 | // Calculate normal with cross product. |
| 262 | /* i j k i j |
| 263 | * v1.x v1.y v1.z | v1.x v1.y |
| 264 | * v2.x v2.y v2.z | v2.x v2.y |
| 265 | */ |
| 266 | |
| 267 | n.x = v1.y * v2.z - v1.z * v2.y; |
| 268 | n.y = v1.z * v2.x - v1.x * v2.z; |
| 269 | n.z = v1.x * v2.y - v1.y * v2.x; |
| 270 | |
| 271 | /* Pre-normalization of the normals is disabled here because |
| 272 | * they will be normalized anyway later due to automatic |
| 273 | * normalization (GL_NORMALIZE). It is enabled because the |
| 274 | * objects are scaled with glScale. |
| 275 | */ |
| 276 | /* |
| 277 | lenSq = n.x * n.x + n.y * n.y + n.z * n.z; |
| 278 | invLenSq = (float)(1 / sqrt(lenSq)); |
| 279 | n.x *= invLenSq; |
| 280 | n.y *= invLenSq; |
| 281 | n.z *= invLenSq; |
| 282 | */ |
| 283 | |
| 284 | ca = pa.z + 0.5f; |
| 285 | |
| 286 | for (i = currentVertex * 3; |
| 287 | i < (currentVertex + 6) * 3; |
| 288 | i += 3) |
| 289 | { |
| 290 | result->normalArray[i] = FIXED(n.x); |
| 291 | result->normalArray[i + 1] = FIXED(n.y); |
| 292 | result->normalArray[i + 2] = FIXED(n.z); |
| 293 | } |
| 294 | for (i = currentVertex * 4; |
| 295 | i < (currentVertex + 6) * 4; |
| 296 | i += 4) |
| 297 | { |
| 298 | int a, color[3]; |
| 299 | for (a = 0; a < 3; ++a) |
| 300 | { |
| 301 | color[a] = (int)(ca * baseColor[a] * 255); |
| 302 | if (color[a] > 255) color[a] = 255; |
| 303 | } |
| 304 | result->colorArray[i] = (GLubyte)color[0]; |
| 305 | result->colorArray[i + 1] = (GLubyte)color[1]; |
| 306 | result->colorArray[i + 2] = (GLubyte)color[2]; |
| 307 | result->colorArray[i + 3] = 0; |
| 308 | } |
| 309 | result->vertexArray[currentVertex * 3] = FIXED(pa.x); |
| 310 | result->vertexArray[currentVertex * 3 + 1] = FIXED(pa.y); |
| 311 | result->vertexArray[currentVertex * 3 + 2] = FIXED(pa.z); |
| 312 | ++currentVertex; |
| 313 | result->vertexArray[currentVertex * 3] = FIXED(pb.x); |
| 314 | result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y); |
| 315 | result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z); |
| 316 | ++currentVertex; |
| 317 | result->vertexArray[currentVertex * 3] = FIXED(pd.x); |
| 318 | result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y); |
| 319 | result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z); |
| 320 | ++currentVertex; |
| 321 | result->vertexArray[currentVertex * 3] = FIXED(pb.x); |
| 322 | result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y); |
| 323 | result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z); |
| 324 | ++currentVertex; |
| 325 | result->vertexArray[currentVertex * 3] = FIXED(pc.x); |
| 326 | result->vertexArray[currentVertex * 3 + 1] = FIXED(pc.y); |
| 327 | result->vertexArray[currentVertex * 3 + 2] = FIXED(pc.z); |
| 328 | ++currentVertex; |
| 329 | result->vertexArray[currentVertex * 3] = FIXED(pd.x); |
| 330 | result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y); |
| 331 | result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z); |
| 332 | ++currentVertex; |
| 333 | } // r0 && r1 && r2 && r3 |
| 334 | ++currentQuad; |
| 335 | } // latitude |
| 336 | } // longitude |
| 337 | |
| 338 | // Set number of vertices in object to the actual amount created. |
| 339 | result->count = currentVertex; |
| 340 | |
| 341 | return result; |
| 342 | } |
| 343 | |
| 344 | |
| 345 | static GLOBJECT * createGroundPlane() |
| 346 | { |
| 347 | const int scale = 4; |
| 348 | const int yBegin = -15, yEnd = 15; // ends are non-inclusive |
| 349 | const int xBegin = -15, xEnd = 15; |
| 350 | const long triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2; |
| 351 | const long vertices = triangleCount * 3; |
| 352 | GLOBJECT *result; |
| 353 | int x, y; |
| 354 | long currentVertex, currentQuad; |
| 355 | |
| 356 | result = newGLObject(vertices, 2, 0); |
| 357 | if (result == NULL) |
| 358 | return NULL; |
| 359 | |
| 360 | currentQuad = 0; |
| 361 | currentVertex = 0; |
| 362 | |
| 363 | for (y = yBegin; y < yEnd; ++y) |
| 364 | { |
| 365 | for (x = xBegin; x < xEnd; ++x) |
| 366 | { |
| 367 | GLubyte color; |
| 368 | int i, a; |
| 369 | color = (GLubyte)((randomUInt() & 0x5f) + 81); // 101 1111 |
| 370 | for (i = currentVertex * 4; i < (currentVertex + 6) * 4; i += 4) |
| 371 | { |
| 372 | result->colorArray[i] = color; |
| 373 | result->colorArray[i + 1] = color; |
| 374 | result->colorArray[i + 2] = color; |
| 375 | result->colorArray[i + 3] = 0; |
| 376 | } |
| 377 | |
| 378 | // Axis bits for quad triangles: |
| 379 | // x: 011100 (0x1c), y: 110001 (0x31) (clockwise) |
| 380 | // x: 001110 (0x0e), y: 100011 (0x23) (counter-clockwise) |
| 381 | for (a = 0; a < 6; ++a) |
| 382 | { |
| 383 | const int xm = x + ((0x1c >> a) & 1); |
| 384 | const int ym = y + ((0x31 >> a) & 1); |
| 385 | const float m = (float)(cos(xm * 2) * sin(ym * 4) * 0.75f); |
| 386 | result->vertexArray[currentVertex * 2] = |
| 387 | FIXED(xm * scale + m); |
| 388 | result->vertexArray[currentVertex * 2 + 1] = |
| 389 | FIXED(ym * scale + m); |
| 390 | ++currentVertex; |
| 391 | } |
| 392 | ++currentQuad; |
| 393 | } |
| 394 | } |
| 395 | return result; |
| 396 | } |
| 397 | |
| 398 | |
| 399 | static void drawGroundPlane() |
| 400 | { |
| 401 | glDisable(GL_CULL_FACE); |
| 402 | glDisable(GL_DEPTH_TEST); |
| 403 | glEnable(GL_BLEND); |
| 404 | glBlendFunc(GL_ZERO, GL_SRC_COLOR); |
| 405 | glDisable(GL_LIGHTING); |
| 406 | |
| 407 | drawGLObject(sGroundPlane); |
| 408 | |
| 409 | glEnable(GL_LIGHTING); |
| 410 | glDisable(GL_BLEND); |
| 411 | glEnable(GL_DEPTH_TEST); |
| 412 | } |
| 413 | |
| 414 | |
| 415 | static void drawFadeQuad() |
| 416 | { |
| 417 | static const GLfixed quadVertices[] = { |
| 418 | -0x10000, -0x10000, |
| 419 | 0x10000, -0x10000, |
| 420 | -0x10000, 0x10000, |
| 421 | 0x10000, -0x10000, |
| 422 | 0x10000, 0x10000, |
| 423 | -0x10000, 0x10000 |
| 424 | }; |
| 425 | |
| 426 | const int beginFade = sTick - sCurrentCamTrackStartTick; |
| 427 | const int endFade = sNextCamTrackStartTick - sTick; |
| 428 | const int minFade = beginFade < endFade ? beginFade : endFade; |
| 429 | |
| 430 | if (minFade < 1024) |
| 431 | { |
| 432 | const GLfixed fadeColor = minFade << 6; |
| 433 | glColor4x(fadeColor, fadeColor, fadeColor, 0); |
| 434 | |
| 435 | glDisable(GL_DEPTH_TEST); |
| 436 | glEnable(GL_BLEND); |
| 437 | glBlendFunc(GL_ZERO, GL_SRC_COLOR); |
| 438 | glDisable(GL_LIGHTING); |
| 439 | |
| 440 | glMatrixMode(GL_MODELVIEW); |
| 441 | glLoadIdentity(); |
| 442 | |
| 443 | glMatrixMode(GL_PROJECTION); |
| 444 | glLoadIdentity(); |
| 445 | |
| 446 | glDisableClientState(GL_COLOR_ARRAY); |
| 447 | glDisableClientState(GL_NORMAL_ARRAY); |
| 448 | glVertexPointer(2, GL_FIXED, 0, quadVertices); |
| 449 | glDrawArrays(GL_TRIANGLES, 0, 6); |
| 450 | |
| 451 | glEnableClientState(GL_COLOR_ARRAY); |
| 452 | |
| 453 | glMatrixMode(GL_MODELVIEW); |
| 454 | |
| 455 | glEnable(GL_LIGHTING); |
| 456 | glDisable(GL_BLEND); |
| 457 | glEnable(GL_DEPTH_TEST); |
| 458 | } |
| 459 | } |
| 460 | |
| 461 | |
| 462 | // Called from the app framework. |
| 463 | void appInit() |
| 464 | { |
| 465 | int a; |
| 466 | |
| 467 | glEnable(GL_NORMALIZE); |
| 468 | glEnable(GL_DEPTH_TEST); |
| 469 | glDisable(GL_CULL_FACE); |
| 470 | glShadeModel(GL_FLAT); |
| 471 | |
| 472 | glEnable(GL_LIGHTING); |
| 473 | glEnable(GL_LIGHT0); |
| 474 | glEnable(GL_LIGHT1); |
| 475 | glEnable(GL_LIGHT2); |
| 476 | |
| 477 | glEnableClientState(GL_VERTEX_ARRAY); |
| 478 | glEnableClientState(GL_COLOR_ARRAY); |
| 479 | |
| 480 | seedRandom(15); |
| 481 | |
| 482 | for (a = 0; a < SUPERSHAPE_COUNT; ++a) |
| 483 | { |
| 484 | sSuperShapeObjects[a] = createSuperShape(sSuperShapeParams[a]); |
| 485 | assert(sSuperShapeObjects[a] != NULL); |
| 486 | } |
| 487 | sGroundPlane = createGroundPlane(); |
| 488 | assert(sGroundPlane != NULL); |
| 489 | } |
| 490 | |
| 491 | |
| 492 | // Called from the app framework. |
| 493 | void appDeinit() |
| 494 | { |
| 495 | int a; |
| 496 | for (a = 0; a < SUPERSHAPE_COUNT; ++a) |
| 497 | freeGLObject(sSuperShapeObjects[a]); |
| 498 | freeGLObject(sGroundPlane); |
| 499 | } |
| 500 | |
| 501 | |
| 502 | static void gluPerspective(GLfloat fovy, GLfloat aspect, |
| 503 | GLfloat zNear, GLfloat zFar) |
| 504 | { |
| 505 | GLfloat xmin, xmax, ymin, ymax; |
| 506 | |
| 507 | ymax = zNear * (GLfloat)tan(fovy * PI / 360); |
| 508 | ymin = -ymax; |
| 509 | xmin = ymin * aspect; |
| 510 | xmax = ymax * aspect; |
| 511 | |
| 512 | glFrustumx((GLfixed)(xmin * 65536), (GLfixed)(xmax * 65536), |
| 513 | (GLfixed)(ymin * 65536), (GLfixed)(ymax * 65536), |
| 514 | (GLfixed)(zNear * 65536), (GLfixed)(zFar * 65536)); |
| 515 | } |
| 516 | |
| 517 | |
| 518 | static void prepareFrame(int width, int height) |
| 519 | { |
| 520 | glViewport(0, 0, width, height); |
| 521 | |
| 522 | glClearColorx((GLfixed)(0.1f * 65536), |
| 523 | (GLfixed)(0.2f * 65536), |
| 524 | (GLfixed)(0.3f * 65536), 0x10000); |
| 525 | glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
| 526 | |
| 527 | glMatrixMode(GL_PROJECTION); |
| 528 | glLoadIdentity(); |
| 529 | gluPerspective(45, (float)width / height, 0.5f, 150); |
| 530 | |
| 531 | glMatrixMode(GL_MODELVIEW); |
| 532 | |
| 533 | glLoadIdentity(); |
| 534 | } |
| 535 | |
| 536 | |
| 537 | static void configureLightAndMaterial() |
| 538 | { |
| 539 | static GLfixed light0Position[] = { -0x40000, 0x10000, 0x10000, 0 }; |
| 540 | static GLfixed light0Diffuse[] = { 0x10000, 0x6666, 0, 0x10000 }; |
| 541 | static GLfixed light1Position[] = { 0x10000, -0x20000, -0x10000, 0 }; |
| 542 | static GLfixed light1Diffuse[] = { 0x11eb, 0x23d7, 0x5999, 0x10000 }; |
| 543 | static GLfixed light2Position[] = { -0x10000, 0, -0x40000, 0 }; |
| 544 | static GLfixed light2Diffuse[] = { 0x11eb, 0x2b85, 0x23d7, 0x10000 }; |
| 545 | static GLfixed materialSpecular[] = { 0x10000, 0x10000, 0x10000, 0x10000 }; |
| 546 | |
| 547 | glLightxv(GL_LIGHT0, GL_POSITION, light0Position); |
| 548 | glLightxv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse); |
| 549 | glLightxv(GL_LIGHT1, GL_POSITION, light1Position); |
| 550 | glLightxv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse); |
| 551 | glLightxv(GL_LIGHT2, GL_POSITION, light2Position); |
| 552 | glLightxv(GL_LIGHT2, GL_DIFFUSE, light2Diffuse); |
| 553 | glMaterialxv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular); |
| 554 | |
| 555 | glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, 60 << 16); |
| 556 | glEnable(GL_COLOR_MATERIAL); |
| 557 | } |
| 558 | |
| 559 | |
| 560 | static void drawModels(float zScale) |
| 561 | { |
| 562 | const int translationScale = 9; |
| 563 | int x, y; |
| 564 | |
| 565 | seedRandom(9); |
| 566 | |
| 567 | glScalex(1 << 16, 1 << 16, (GLfixed)(zScale * 65536)); |
| 568 | |
| 569 | for (y = -5; y <= 5; ++y) |
| 570 | { |
| 571 | for (x = -5; x <= 5; ++x) |
| 572 | { |
| 573 | float buildingScale; |
| 574 | GLfixed fixedScale; |
| 575 | |
| 576 | int curShape = randomUInt() % SUPERSHAPE_COUNT; |
| 577 | buildingScale = sSuperShapeParams[curShape][SUPERSHAPE_PARAMS - 1]; |
| 578 | fixedScale = (GLfixed)(buildingScale * 65536); |
| 579 | |
| 580 | glPushMatrix(); |
| 581 | glTranslatex((x * translationScale) * 65536, |
| 582 | (y * translationScale) * 65536, |
| 583 | 0); |
| 584 | glRotatex((GLfixed)((randomUInt() % 360) << 16), 0, 0, 1 << 16); |
| 585 | glScalex(fixedScale, fixedScale, fixedScale); |
| 586 | |
| 587 | drawGLObject(sSuperShapeObjects[curShape]); |
| 588 | glPopMatrix(); |
| 589 | } |
| 590 | } |
| 591 | |
| 592 | for (x = -2; x <= 2; ++x) |
| 593 | { |
| 594 | const int shipScale100 = translationScale * 500; |
| 595 | const int offs100 = x * shipScale100 + (sTick % shipScale100); |
| 596 | float offs = offs100 * 0.01f; |
| 597 | GLfixed fixedOffs = (GLfixed)(offs * 65536); |
| 598 | glPushMatrix(); |
| 599 | glTranslatex(fixedOffs, -4 * 65536, 2 << 16); |
| 600 | drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); |
| 601 | glPopMatrix(); |
| 602 | glPushMatrix(); |
| 603 | glTranslatex(-4 * 65536, fixedOffs, 4 << 16); |
| 604 | glRotatex(90 << 16, 0, 0, 1 << 16); |
| 605 | drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); |
| 606 | glPopMatrix(); |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | |
| 611 | /* Following gluLookAt implementation is adapted from the |
| 612 | * Mesa 3D Graphics library. http://www.mesa3d.org |
| 613 | */ |
| 614 | static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, |
| 615 | GLfloat centerx, GLfloat centery, GLfloat centerz, |
| 616 | GLfloat upx, GLfloat upy, GLfloat upz) |
| 617 | { |
| 618 | GLfloat m[16]; |
| 619 | GLfloat x[3], y[3], z[3]; |
| 620 | GLfloat mag; |
| 621 | |
| 622 | /* Make rotation matrix */ |
| 623 | |
| 624 | /* Z vector */ |
| 625 | z[0] = eyex - centerx; |
| 626 | z[1] = eyey - centery; |
| 627 | z[2] = eyez - centerz; |
| 628 | mag = (float)sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); |
| 629 | if (mag) { /* mpichler, 19950515 */ |
| 630 | z[0] /= mag; |
| 631 | z[1] /= mag; |
| 632 | z[2] /= mag; |
| 633 | } |
| 634 | |
| 635 | /* Y vector */ |
| 636 | y[0] = upx; |
| 637 | y[1] = upy; |
| 638 | y[2] = upz; |
| 639 | |
| 640 | /* X vector = Y cross Z */ |
| 641 | x[0] = y[1] * z[2] - y[2] * z[1]; |
| 642 | x[1] = -y[0] * z[2] + y[2] * z[0]; |
| 643 | x[2] = y[0] * z[1] - y[1] * z[0]; |
| 644 | |
| 645 | /* Recompute Y = Z cross X */ |
| 646 | y[0] = z[1] * x[2] - z[2] * x[1]; |
| 647 | y[1] = -z[0] * x[2] + z[2] * x[0]; |
| 648 | y[2] = z[0] * x[1] - z[1] * x[0]; |
| 649 | |
| 650 | /* mpichler, 19950515 */ |
| 651 | /* cross product gives area of parallelogram, which is < 1.0 for |
| 652 | * non-perpendicular unit-length vectors; so normalize x, y here |
| 653 | */ |
| 654 | |
| 655 | mag = (float)sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); |
| 656 | if (mag) { |
| 657 | x[0] /= mag; |
| 658 | x[1] /= mag; |
| 659 | x[2] /= mag; |
| 660 | } |
| 661 | |
| 662 | mag = (float)sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); |
| 663 | if (mag) { |
| 664 | y[0] /= mag; |
| 665 | y[1] /= mag; |
| 666 | y[2] /= mag; |
| 667 | } |
| 668 | |
| 669 | #define M(row,col) m[col*4+row] |
| 670 | M(0, 0) = x[0]; |
| 671 | M(0, 1) = x[1]; |
| 672 | M(0, 2) = x[2]; |
| 673 | M(0, 3) = 0.0; |
| 674 | M(1, 0) = y[0]; |
| 675 | M(1, 1) = y[1]; |
| 676 | M(1, 2) = y[2]; |
| 677 | M(1, 3) = 0.0; |
| 678 | M(2, 0) = z[0]; |
| 679 | M(2, 1) = z[1]; |
| 680 | M(2, 2) = z[2]; |
| 681 | M(2, 3) = 0.0; |
| 682 | M(3, 0) = 0.0; |
| 683 | M(3, 1) = 0.0; |
| 684 | M(3, 2) = 0.0; |
| 685 | M(3, 3) = 1.0; |
| 686 | #undef M |
| 687 | { |
| 688 | int a; |
| 689 | GLfixed fixedM[16]; |
| 690 | for (a = 0; a < 16; ++a) |
| 691 | fixedM[a] = (GLfixed)(m[a] * 65536); |
| 692 | glMultMatrixx(fixedM); |
| 693 | } |
| 694 | |
| 695 | /* Translate Eye to Origin */ |
| 696 | glTranslatex((GLfixed)(-eyex * 65536), |
| 697 | (GLfixed)(-eyey * 65536), |
| 698 | (GLfixed)(-eyez * 65536)); |
| 699 | } |
| 700 | |
| 701 | |
| 702 | static void camTrack() |
| 703 | { |
| 704 | float lerp[5]; |
| 705 | float eX, eY, eZ, cX, cY, cZ; |
| 706 | float trackPos; |
| 707 | CAMTRACK *cam; |
| 708 | long currentCamTick; |
| 709 | int a; |
| 710 | |
| 711 | if (sNextCamTrackStartTick <= sTick) |
| 712 | { |
| 713 | ++sCurrentCamTrack; |
| 714 | sCurrentCamTrackStartTick = sNextCamTrackStartTick; |
| 715 | } |
| 716 | sNextCamTrackStartTick = sCurrentCamTrackStartTick + |
| 717 | sCamTracks[sCurrentCamTrack].len * CAMTRACK_LEN; |
| 718 | |
| 719 | cam = &sCamTracks[sCurrentCamTrack]; |
| 720 | currentCamTick = sTick - sCurrentCamTrackStartTick; |
| 721 | trackPos = (float)currentCamTick / (CAMTRACK_LEN * cam->len); |
| 722 | |
| 723 | for (a = 0; a < 5; ++a) |
| 724 | lerp[a] = (cam->src[a] + cam->dest[a] * trackPos) * 0.01f; |
| 725 | |
| 726 | if (cam->dist) |
| 727 | { |
| 728 | float dist = cam->dist * 0.1f; |
| 729 | cX = lerp[0]; |
| 730 | cY = lerp[1]; |
| 731 | cZ = lerp[2]; |
| 732 | eX = cX - (float)cos(lerp[3]) * dist; |
| 733 | eY = cY - (float)sin(lerp[3]) * dist; |
| 734 | eZ = cZ - lerp[4]; |
| 735 | } |
| 736 | else |
| 737 | { |
| 738 | eX = lerp[0]; |
| 739 | eY = lerp[1]; |
| 740 | eZ = lerp[2]; |
| 741 | cX = eX + (float)cos(lerp[3]); |
| 742 | cY = eY + (float)sin(lerp[3]); |
| 743 | cZ = eZ + lerp[4]; |
| 744 | } |
| 745 | gluLookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1); |
| 746 | } |
| 747 | |
| 748 | |
| 749 | // Called from the app framework. |
| 750 | /* The tick is current time in milliseconds, width and height |
| 751 | * are the image dimensions to be rendered. |
| 752 | */ |
| 753 | void appRender(long tick, int width, int height) |
| 754 | { |
| 755 | if (sStartTick == 0) |
| 756 | sStartTick = tick; |
| 757 | if (!gAppAlive) |
| 758 | return; |
| 759 | |
| 760 | // Actual tick value is "blurred" a little bit. |
| 761 | sTick = (sTick + tick - sStartTick) >> 1; |
| 762 | |
| 763 | // Terminate application after running through the demonstration once. |
| 764 | if (sTick >= RUN_LENGTH) |
| 765 | { |
| 766 | gAppAlive = 0; |
| 767 | return; |
| 768 | } |
| 769 | |
| 770 | // Prepare OpenGL ES for rendering of the frame. |
| 771 | prepareFrame(width, height); |
| 772 | |
| 773 | // Update the camera position and set the lookat. |
| 774 | camTrack(); |
| 775 | |
| 776 | // Configure environment. |
| 777 | configureLightAndMaterial(); |
| 778 | |
| 779 | // Draw the reflection by drawing models with negated Z-axis. |
| 780 | glPushMatrix(); |
| 781 | drawModels(-1); |
| 782 | glPopMatrix(); |
| 783 | |
| 784 | // Blend the ground plane to the window. |
| 785 | drawGroundPlane(); |
| 786 | |
| 787 | // Draw all the models normally. |
| 788 | drawModels(1); |
| 789 | |
| 790 | // Draw fade quad over whole window (when changing cameras). |
| 791 | drawFadeQuad(); |
| 792 | } |