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 // The GLES2 implementation is adapted from the javascript implementation 26 // upon WebGL by kwaters@. 27 28 // The OpenGL implementation uses VBO extensions instead. 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <math.h> 33 #include <float.h> 34 #include <assert.h> 35 36 #ifdef SAN_ANGELES_OBSERVATION_GLES 37 #undef IMPORTGL_API 38 #undef IMPORTGL_FNPTRINIT 39 #include "importgl.h" 40 #include "matrixop.h" 41 #include "shader.h" 42 #else // SAN_ANGELES_OBSERVATION_GLES 43 #undef IMPORTVBO_API 44 #undef IMPORTVBO_FNPTRINIT 45 #include "importvbo.h" 46 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 47 48 #include "app.h" 49 #include "shapes.h" 50 #include "cams.h" 51 52 53 // Total run length is 20 * camera track base unit length (see cams.h). 54 #define RUN_LENGTH (20 * CAMTRACK_LEN) 55 #undef PI 56 #define PI 3.1415926535897932f 57 #define RANDOM_UINT_MAX 65535 58 59 60 static unsigned long sRandomSeed = 0; 61 62 static void seedRandom(unsigned long seed) 63 { 64 sRandomSeed = seed; 65 } 66 67 static unsigned long randomUInt() 68 { 69 sRandomSeed = sRandomSeed * 0x343fd + 0x269ec3; 70 return sRandomSeed >> 16; 71 } 72 73 74 // Definition of one GL object in this demo. 75 typedef struct { 76 /* Vertex array and color array are enabled for all objects, so their 77 * pointers must always be valid and non-NULL. Normal array is not 78 * used by the ground plane, so when its pointer is NULL then normal 79 * array usage is disabled. 80 * 81 * Vertex array is supposed to use GL_FIXED datatype and stride 0 82 * (i.e. tightly packed array). Color array is supposed to have 4 83 * components per color with GL_UNSIGNED_BYTE datatype and stride 0. 84 * Normal array is supposed to use GL_FIXED datatype and stride 0. 85 */ 86 GLfloat *vertexArray; 87 GLint vertexArraySize; 88 GLintptr vertexArrayOffset; 89 GLubyte *colorArray; 90 GLint colorArraySize; 91 GLintptr colorArrayOffset; 92 GLfloat *normalArray; 93 GLint normalArraySize; 94 GLintptr normalArrayOffset; 95 GLint vertexComponents; 96 GLsizei count; 97 #ifdef SAN_ANGELES_OBSERVATION_GLES 98 GLuint shaderProgram; 99 #endif // SAN_ANGELES_OBSERVATION_GLES 100 } GLOBJECT; 101 102 103 static long sStartTick = 0; 104 static long sTick = 0; 105 106 static int sCurrentCamTrack = 0; 107 static long sCurrentCamTrackStartTick = 0; 108 static long sNextCamTrackStartTick = 0x7fffffff; 109 110 static GLOBJECT *sSuperShapeObjects[SUPERSHAPE_COUNT] = { NULL }; 111 static GLOBJECT *sGroundPlane = NULL; 112 static GLOBJECT *sFadeQuad = NULL; 113 114 static GLuint sVBO = 0; 115 116 typedef struct { 117 float x, y, z; 118 } VECTOR3; 119 120 121 static void freeGLObject(GLOBJECT *object) 122 { 123 if (object == NULL) 124 return; 125 126 free(object->normalArray); 127 free(object->colorArray); 128 free(object->vertexArray); 129 130 free(object); 131 } 132 133 134 static GLOBJECT * newGLObject(long vertices, int vertexComponents, 135 int useColorArray, int useNormalArray) 136 { 137 GLOBJECT *result; 138 result = malloc(sizeof(GLOBJECT)); 139 if (result == NULL) 140 return NULL; 141 result->count = vertices; 142 result->vertexComponents = vertexComponents; 143 result->vertexArraySize = vertices * vertexComponents * sizeof(GLfloat); 144 result->vertexArray = malloc(result->vertexArraySize); 145 result->vertexArrayOffset = 0; 146 if (useColorArray) 147 { 148 result->colorArraySize = vertices * 4 * sizeof(GLubyte); 149 result->colorArray = malloc(result->colorArraySize); 150 } 151 else 152 { 153 result->colorArraySize = 0; 154 result->colorArray = NULL; 155 } 156 result->colorArrayOffset = result->vertexArrayOffset + 157 result->vertexArraySize; 158 if (useNormalArray) 159 { 160 result->normalArraySize = vertices * 3 * sizeof(GLfloat); 161 result->normalArray = malloc(result->normalArraySize); 162 } 163 else 164 { 165 result->normalArraySize = 0; 166 result->normalArray = NULL; 167 } 168 result->normalArrayOffset = result->colorArrayOffset + 169 result->colorArraySize; 170 if (result->vertexArray == NULL || 171 (useColorArray && result->colorArray == NULL) || 172 (useNormalArray && result->normalArray == NULL)) 173 { 174 freeGLObject(result); 175 return NULL; 176 } 177 #ifdef SAN_ANGELES_OBSERVATION_GLES 178 result->shaderProgram = 0; 179 #endif // SAN_ANGELES_OBSERVATION_GLES 180 return result; 181 } 182 183 184 static void appendObjectVBO(GLOBJECT *object, GLint *offset) 185 { 186 assert(object != NULL); 187 188 object->vertexArrayOffset += *offset; 189 object->colorArrayOffset += *offset; 190 object->normalArrayOffset += *offset; 191 *offset += object->vertexArraySize + object->colorArraySize + 192 object->normalArraySize; 193 194 glBufferSubData(GL_ARRAY_BUFFER, object->vertexArrayOffset, 195 object->vertexArraySize, object->vertexArray); 196 if (object->colorArray) 197 glBufferSubData(GL_ARRAY_BUFFER, object->colorArrayOffset, 198 object->colorArraySize, object->colorArray); 199 if (object->normalArray) 200 glBufferSubData(GL_ARRAY_BUFFER, object->normalArrayOffset, 201 object->normalArraySize, object->normalArray); 202 203 free(object->normalArray); 204 object->normalArray = NULL; 205 free(object->colorArray); 206 object->colorArray = NULL; 207 free(object->vertexArray); 208 object->vertexArray = NULL; 209 } 210 211 212 static GLuint createVBO(GLOBJECT **superShapes, int superShapeCount, 213 GLOBJECT *groundPlane, GLOBJECT *fadeQuad) 214 { 215 GLuint vbo; 216 GLint totalSize = 0; 217 int a; 218 for (a = 0; a < superShapeCount; ++a) 219 { 220 assert(superShapes[a] != NULL); 221 totalSize += superShapes[a]->vertexArraySize + 222 superShapes[a]->colorArraySize + 223 superShapes[a]->normalArraySize; 224 } 225 totalSize += groundPlane->vertexArraySize + 226 groundPlane->colorArraySize + 227 groundPlane->normalArraySize; 228 totalSize += fadeQuad->vertexArraySize + 229 fadeQuad->colorArraySize + 230 fadeQuad->normalArraySize; 231 glGenBuffers(1, &vbo); 232 glBindBuffer(GL_ARRAY_BUFFER, vbo); 233 glBufferData(GL_ARRAY_BUFFER, totalSize, 0, GL_STATIC_DRAW); 234 GLint offset = 0; 235 for (a = 0; a < superShapeCount; ++a) 236 appendObjectVBO(superShapes[a], &offset); 237 appendObjectVBO(groundPlane, &offset); 238 appendObjectVBO(fadeQuad, &offset); 239 assert(offset == totalSize); 240 return vbo; 241 } 242 243 244 static void drawGLObject(GLOBJECT *object) 245 { 246 #ifdef SAN_ANGELES_OBSERVATION_GLES 247 int loc_pos = -1; 248 int loc_colorIn = -1; 249 int loc_normal = -1; 250 #endif // SAN_ANGELES_OBSERVATION_GLES 251 252 assert(object != NULL); 253 254 #ifdef SAN_ANGELES_OBSERVATION_GLES 255 bindShaderProgram(object->shaderProgram); 256 if (object->shaderProgram == sShaderLit.program) 257 { 258 loc_pos = sShaderLit.pos; 259 loc_colorIn = sShaderLit.colorIn; 260 loc_normal = sShaderLit.normal; 261 } 262 else if (object->shaderProgram == sShaderFlat.program) 263 { 264 loc_pos = sShaderFlat.pos; 265 loc_colorIn = sShaderFlat.colorIn; 266 } 267 else 268 { 269 assert(0); 270 } 271 glVertexAttribPointer(loc_pos, object->vertexComponents, GL_FLOAT, 272 GL_FALSE, 0, (GLvoid *)object->vertexArrayOffset); 273 glEnableVertexAttribArray(loc_pos); 274 glVertexAttribPointer(loc_colorIn, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 275 (GLvoid *)object->colorArrayOffset); 276 glEnableVertexAttribArray(loc_colorIn); 277 if (object->normalArraySize > 0) 278 { 279 glVertexAttribPointer(loc_normal, 3, GL_FLOAT, GL_FALSE, 0, 280 (GLvoid *)object->normalArrayOffset); 281 glEnableVertexAttribArray(loc_normal); 282 } 283 glDrawArrays(GL_TRIANGLES, 0, object->count); 284 285 if (object->normalArraySize > 0) 286 glDisableVertexAttribArray(loc_normal); 287 glDisableVertexAttribArray(loc_colorIn); 288 glDisableVertexAttribArray(loc_pos); 289 #else // !SAN_ANGELES_OBSERVATION_GLES 290 glVertexPointer(object->vertexComponents, GL_FLOAT, 0, 291 (GLvoid *)object->vertexArrayOffset); 292 glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid *)object->colorArrayOffset); 293 if (object->normalArraySize > 0) 294 { 295 glNormalPointer(GL_FLOAT, 0, (GLvoid *)object->normalArrayOffset); 296 glEnableClientState(GL_NORMAL_ARRAY); 297 } 298 else 299 glDisableClientState(GL_NORMAL_ARRAY); 300 glDrawArrays(GL_TRIANGLES, 0, object->count); 301 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 302 } 303 304 305 static void vector3Sub(VECTOR3 *dest, VECTOR3 *v1, VECTOR3 *v2) 306 { 307 dest->x = v1->x - v2->x; 308 dest->y = v1->y - v2->y; 309 dest->z = v1->z - v2->z; 310 } 311 312 313 static void superShapeMap(VECTOR3 *point, float r1, float r2, float t, float p) 314 { 315 // sphere-mapping of supershape parameters 316 point->x = (float)(cos(t) * cos(p) / r1 / r2); 317 point->y = (float)(sin(t) * cos(p) / r1 / r2); 318 point->z = (float)(sin(p) / r2); 319 } 320 321 322 static float ssFunc(const float t, const float *p) 323 { 324 return (float)(pow(pow(fabs(cos(p[0] * t / 4)) / p[1], p[4]) + 325 pow(fabs(sin(p[0] * t / 4)) / p[2], p[5]), 1 / p[3])); 326 } 327 328 329 // Creates and returns a supershape object. 330 // Based on Paul Bourke's POV-Ray implementation. 331 // http://astronomy.swin.edu.au/~pbourke/povray/supershape/ 332 static GLOBJECT * createSuperShape(const float *params) 333 { 334 const int resol1 = (int)params[SUPERSHAPE_PARAMS - 3]; 335 const int resol2 = (int)params[SUPERSHAPE_PARAMS - 2]; 336 // latitude 0 to pi/2 for no mirrored bottom 337 // (latitudeBegin==0 for -pi/2 to pi/2 originally) 338 const int latitudeBegin = resol2 / 4; 339 const int latitudeEnd = resol2 / 2; // non-inclusive 340 const int longitudeCount = resol1; 341 const int latitudeCount = latitudeEnd - latitudeBegin; 342 const long triangleCount = longitudeCount * latitudeCount * 2; 343 const long vertices = triangleCount * 3; 344 GLOBJECT *result; 345 float baseColor[3]; 346 int a, longitude, latitude; 347 long currentVertex, currentQuad; 348 349 result = newGLObject(vertices, 3, 1, 1); 350 if (result == NULL) 351 return NULL; 352 353 for (a = 0; a < 3; ++a) 354 baseColor[a] = ((randomUInt() % 155) + 100) / 255.f; 355 356 currentQuad = 0; 357 currentVertex = 0; 358 359 // longitude -pi to pi 360 for (longitude = 0; longitude < longitudeCount; ++longitude) 361 { 362 363 // latitude 0 to pi/2 364 for (latitude = latitudeBegin; latitude < latitudeEnd; ++latitude) 365 { 366 float t1 = -PI + longitude * 2 * PI / resol1; 367 float t2 = -PI + (longitude + 1) * 2 * PI / resol1; 368 float p1 = -PI / 2 + latitude * 2 * PI / resol2; 369 float p2 = -PI / 2 + (latitude + 1) * 2 * PI / resol2; 370 float r0, r1, r2, r3; 371 372 r0 = ssFunc(t1, params); 373 r1 = ssFunc(p1, ¶ms[6]); 374 r2 = ssFunc(t2, params); 375 r3 = ssFunc(p2, ¶ms[6]); 376 377 if (r0 != 0 && r1 != 0 && r2 != 0 && r3 != 0) 378 { 379 VECTOR3 pa, pb, pc, pd; 380 VECTOR3 v1, v2, n; 381 float ca; 382 int i; 383 //float lenSq, invLenSq; 384 385 superShapeMap(&pa, r0, r1, t1, p1); 386 superShapeMap(&pb, r2, r1, t2, p1); 387 superShapeMap(&pc, r2, r3, t2, p2); 388 superShapeMap(&pd, r0, r3, t1, p2); 389 390 // kludge to set lower edge of the object to fixed level 391 if (latitude == latitudeBegin + 1) 392 pa.z = pb.z = 0; 393 394 vector3Sub(&v1, &pb, &pa); 395 vector3Sub(&v2, &pd, &pa); 396 397 // Calculate normal with cross product. 398 /* i j k i j 399 * v1.x v1.y v1.z | v1.x v1.y 400 * v2.x v2.y v2.z | v2.x v2.y 401 */ 402 403 n.x = v1.y * v2.z - v1.z * v2.y; 404 n.y = v1.z * v2.x - v1.x * v2.z; 405 n.z = v1.x * v2.y - v1.y * v2.x; 406 407 /* Pre-normalization of the normals is disabled here because 408 * they will be normalized anyway later due to automatic 409 * normalization (GL_NORMALIZE). It is enabled because the 410 * objects are scaled with glScale. 411 */ 412 /* 413 lenSq = n.x * n.x + n.y * n.y + n.z * n.z; 414 invLenSq = (float)(1 / sqrt(lenSq)); 415 n.x *= invLenSq; 416 n.y *= invLenSq; 417 n.z *= invLenSq; 418 */ 419 420 ca = pa.z + 0.5f; 421 422 for (i = currentVertex * 3; 423 i < (currentVertex + 6) * 3; 424 i += 3) 425 { 426 result->normalArray[i] = n.x; 427 result->normalArray[i + 1] = n.y; 428 result->normalArray[i + 2] = n.z; 429 } 430 for (i = currentVertex * 4; 431 i < (currentVertex + 6) * 4; 432 i += 4) 433 { 434 int a, color[3]; 435 for (a = 0; a < 3; ++a) 436 { 437 color[a] = (int)(ca * baseColor[a] * 255); 438 if (color[a] > 255) color[a] = 255; 439 } 440 result->colorArray[i] = (GLubyte)color[0]; 441 result->colorArray[i + 1] = (GLubyte)color[1]; 442 result->colorArray[i + 2] = (GLubyte)color[2]; 443 result->colorArray[i + 3] = 0; 444 } 445 result->vertexArray[currentVertex * 3] = pa.x; 446 result->vertexArray[currentVertex * 3 + 1] = pa.y; 447 result->vertexArray[currentVertex * 3 + 2] = pa.z; 448 ++currentVertex; 449 result->vertexArray[currentVertex * 3] = pb.x; 450 result->vertexArray[currentVertex * 3 + 1] = pb.y; 451 result->vertexArray[currentVertex * 3 + 2] = pb.z; 452 ++currentVertex; 453 result->vertexArray[currentVertex * 3] = pd.x; 454 result->vertexArray[currentVertex * 3 + 1] = pd.y; 455 result->vertexArray[currentVertex * 3 + 2] = pd.z; 456 ++currentVertex; 457 result->vertexArray[currentVertex * 3] = pb.x; 458 result->vertexArray[currentVertex * 3 + 1] = pb.y; 459 result->vertexArray[currentVertex * 3 + 2] = pb.z; 460 ++currentVertex; 461 result->vertexArray[currentVertex * 3] = pc.x; 462 result->vertexArray[currentVertex * 3 + 1] = pc.y; 463 result->vertexArray[currentVertex * 3 + 2] = pc.z; 464 ++currentVertex; 465 result->vertexArray[currentVertex * 3] = pd.x; 466 result->vertexArray[currentVertex * 3 + 1] = pd.y; 467 result->vertexArray[currentVertex * 3 + 2] = pd.z; 468 ++currentVertex; 469 } // r0 && r1 && r2 && r3 470 ++currentQuad; 471 } // latitude 472 } // longitude 473 474 // Set number of vertices in object to the actual amount created. 475 result->count = currentVertex; 476 #ifdef SAN_ANGELES_OBSERVATION_GLES 477 result->shaderProgram = sShaderLit.program; 478 #endif // SAN_ANGELES_OBSERVATION_GLES 479 return result; 480 } 481 482 483 static GLOBJECT * createGroundPlane() 484 { 485 const int scale = 4; 486 const int yBegin = -15, yEnd = 15; // ends are non-inclusive 487 const int xBegin = -15, xEnd = 15; 488 const long triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2; 489 const long vertices = triangleCount * 3; 490 GLOBJECT *result; 491 int x, y; 492 long currentVertex, currentQuad; 493 494 result = newGLObject(vertices, 2, 1, 0); 495 if (result == NULL) 496 return NULL; 497 498 currentQuad = 0; 499 currentVertex = 0; 500 501 for (y = yBegin; y < yEnd; ++y) 502 { 503 for (x = xBegin; x < xEnd; ++x) 504 { 505 GLubyte color; 506 int i, a; 507 color = (GLubyte)((randomUInt() & 0x5f) + 81); // 101 1111 508 for (i = currentVertex * 4; i < (currentVertex + 6) * 4; i += 4) 509 { 510 result->colorArray[i] = color; 511 result->colorArray[i + 1] = color; 512 result->colorArray[i + 2] = color; 513 result->colorArray[i + 3] = 0; 514 } 515 516 // Axis bits for quad triangles: 517 // x: 011100 (0x1c), y: 110001 (0x31) (clockwise) 518 // x: 001110 (0x0e), y: 100011 (0x23) (counter-clockwise) 519 for (a = 0; a < 6; ++a) 520 { 521 const int xm = x + ((0x1c >> a) & 1); 522 const int ym = y + ((0x31 >> a) & 1); 523 const float m = (float)(cos(xm * 2) * sin(ym * 4) * 0.75f); 524 result->vertexArray[currentVertex * 2] = xm * scale + m; 525 result->vertexArray[currentVertex * 2 + 1] = ym * scale + m; 526 ++currentVertex; 527 } 528 ++currentQuad; 529 } 530 } 531 #ifdef SAN_ANGELES_OBSERVATION_GLES 532 result->shaderProgram = sShaderFlat.program; 533 #endif // SAN_ANGELES_OBSERVATION_GLES 534 return result; 535 } 536 537 538 static void drawGroundPlane() 539 { 540 glDisable(GL_CULL_FACE); 541 glDisable(GL_DEPTH_TEST); 542 glEnable(GL_BLEND); 543 glBlendFunc(GL_ZERO, GL_SRC_COLOR); 544 #ifndef SAN_ANGELES_OBSERVATION_GLES 545 glDisable(GL_LIGHTING); 546 #endif // !SAN_ANGELES_OBSERVATION_GLES 547 548 drawGLObject(sGroundPlane); 549 550 #ifndef SAN_ANGELES_OBSERVATION_GLES 551 glEnable(GL_LIGHTING); 552 #endif // !SAN_ANGELES_OBSERVATION_GLES 553 glDisable(GL_BLEND); 554 glEnable(GL_DEPTH_TEST); 555 } 556 557 558 static GLOBJECT * createFadeQuad() 559 { 560 static const GLfloat quadVertices[] = { 561 -1, -1, 562 1, -1, 563 -1, 1, 564 1, -1, 565 1, 1, 566 -1, 1 567 }; 568 569 GLOBJECT *result; 570 int i; 571 572 result = newGLObject(6, 2, 0, 0); 573 if (result == NULL) 574 return NULL; 575 576 for (i = 0; i < 12; ++i) 577 result->vertexArray[i] = quadVertices[i]; 578 579 #ifdef SAN_ANGELES_OBSERVATION_GLES 580 result->shaderProgram = sShaderFade.program; 581 #endif // SAN_ANGELES_OBSERVATION_GLES 582 return result; 583 } 584 585 586 static void drawFadeQuad() 587 { 588 const int beginFade = sTick - sCurrentCamTrackStartTick; 589 const int endFade = sNextCamTrackStartTick - sTick; 590 const int minFade = beginFade < endFade ? beginFade : endFade; 591 592 if (minFade < 1024) 593 { 594 const GLfloat fadeColor = minFade / 1024.f; 595 glDisable(GL_DEPTH_TEST); 596 glEnable(GL_BLEND); 597 glBlendFunc(GL_ZERO, GL_SRC_COLOR); 598 #ifdef SAN_ANGELES_OBSERVATION_GLES 599 bindShaderProgram(sShaderFade.program); 600 glUniform1f(sShaderFade.minFade, fadeColor); 601 glVertexAttribPointer(sShaderFade.pos, 2, GL_FLOAT, GL_FALSE, 0, 602 (GLvoid *)sFadeQuad->vertexArrayOffset); 603 glEnableVertexAttribArray(sShaderFade.pos); 604 glDrawArrays(GL_TRIANGLES, 0, 6); 605 glDisableVertexAttribArray(sShaderFade.pos); 606 #else // !SAN_ANGELES_OBSERVATION_GLES 607 glColor4f(fadeColor, fadeColor, fadeColor, 0); 608 609 glDisable(GL_LIGHTING); 610 611 glMatrixMode(GL_MODELVIEW); 612 glLoadIdentity(); 613 614 glMatrixMode(GL_PROJECTION); 615 glLoadIdentity(); 616 617 glDisableClientState(GL_COLOR_ARRAY); 618 glDisableClientState(GL_NORMAL_ARRAY); 619 glVertexPointer(2, GL_FLOAT, 0, (GLvoid *)sFadeQuad->vertexArrayOffset); 620 621 glDrawArrays(GL_TRIANGLES, 0, 6); 622 623 glEnableClientState(GL_COLOR_ARRAY); 624 625 glMatrixMode(GL_MODELVIEW); 626 627 glEnable(GL_LIGHTING); 628 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 629 glDisable(GL_BLEND); 630 glEnable(GL_DEPTH_TEST); 631 } 632 } 633 634 635 // Called from the app framework. 636 int appInit() 637 { 638 int a; 639 static GLfloat light0Diffuse[] = { 1.f, 0.4f, 0, 1.f }; 640 static GLfloat light1Diffuse[] = { 0.07f, 0.14f, 0.35f, 1.f }; 641 static GLfloat light2Diffuse[] = { 0.07f, 0.17f, 0.14f, 1.f }; 642 static GLfloat materialSpecular[] = { 1.f, 1.f, 1.f, 1.f }; 643 #ifdef SAN_ANGELES_OBSERVATION_GLES 644 static GLfloat lightAmbient[] = { 0.2f, 0.2f, 0.2f, 1.f }; 645 #endif // SAN_ANGELES_OBSERVATION_GLES 646 647 glDisable(GL_CULL_FACE); 648 glEnable(GL_DEPTH_TEST); 649 #ifdef SAN_ANGELES_OBSERVATION_GLES 650 if (initShaderPrograms() == 0) 651 { 652 fprintf(stderr, "Error: initShaderPrograms failed\n"); 653 return 0; 654 } 655 #else // !SAN_ANGELES_OBSERVATION_GLES 656 glShadeModel(GL_FLAT); 657 glEnable(GL_NORMALIZE); 658 659 glEnable(GL_LIGHTING); 660 glEnable(GL_LIGHT0); 661 glEnable(GL_LIGHT1); 662 glEnable(GL_LIGHT2); 663 664 glEnableClientState(GL_VERTEX_ARRAY); 665 glEnableClientState(GL_COLOR_ARRAY); 666 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 667 seedRandom(15); 668 669 for (a = 0; a < SUPERSHAPE_COUNT; ++a) 670 { 671 sSuperShapeObjects[a] = createSuperShape(sSuperShapeParams[a]); 672 assert(sSuperShapeObjects[a] != NULL); 673 } 674 sGroundPlane = createGroundPlane(); 675 assert(sGroundPlane != NULL); 676 sFadeQuad = createFadeQuad(); 677 assert(sFadeQuad != NULL); 678 sVBO = createVBO(sSuperShapeObjects, SUPERSHAPE_COUNT, 679 sGroundPlane, sFadeQuad); 680 681 // setup non-changing lighting parameters 682 #ifdef SAN_ANGELES_OBSERVATION_GLES 683 bindShaderProgram(sShaderLit.program); 684 glUniform4fv(sShaderLit.ambient, 1, lightAmbient); 685 glUniform4fv(sShaderLit.light_0_diffuse, 1, light0Diffuse); 686 glUniform4fv(sShaderLit.light_1_diffuse, 1, light1Diffuse); 687 glUniform4fv(sShaderLit.light_2_diffuse, 1, light2Diffuse); 688 glUniform4fv(sShaderLit.light_0_specular, 1, materialSpecular); 689 glUniform1f(sShaderLit.shininess, 60.f); 690 #else // !SAN_ANGELES_OBSERVATION_GLES 691 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse); 692 glLightfv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse); 693 glLightfv(GL_LIGHT2, GL_DIFFUSE, light2Diffuse); 694 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular); 695 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 60); 696 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 697 return 1; 698 } 699 700 701 // Called from the app framework. 702 void appDeinit() 703 { 704 int a; 705 for (a = 0; a < SUPERSHAPE_COUNT; ++a) 706 freeGLObject(sSuperShapeObjects[a]); 707 freeGLObject(sGroundPlane); 708 freeGLObject(sFadeQuad); 709 glDeleteBuffers(1, &sVBO); 710 #ifdef SAN_ANGELES_OBSERVATION_GLES 711 deInitShaderPrograms(); 712 #endif // SAN_ANGELES_OBSERVATION_GLES 713 } 714 715 #ifndef SAN_ANGELES_OBSERVATION_GLES 716 static void gluPerspective(GLfloat fovy, GLfloat aspect, 717 GLfloat zNear, GLfloat zFar) 718 { 719 GLfloat xmin, xmax, ymin, ymax; 720 721 ymax = zNear * (GLfloat)tan(fovy * PI / 360); 722 ymin = -ymax; 723 xmin = ymin * aspect; 724 xmax = ymax * aspect; 725 726 glFrustum(xmin, xmax, ymin, ymax, zNear, zFar); 727 } 728 #endif // !SAN_ANGELES_OBSERVATION_GLES 729 730 static void prepareFrame(int width, int height) 731 { 732 glViewport(0, 0, width, height); 733 734 glClearColor(0.1f, 0.2f, 0.3f, 1.f); 735 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 736 737 #ifdef SAN_ANGELES_OBSERVATION_GLES 738 Matrix4x4_LoadIdentity(sProjection); 739 Matrix4x4_Perspective(sProjection, 740 45.f, (float)width / height, 0.5f, 150); 741 742 Matrix4x4_LoadIdentity(sModelView); 743 #else // !SAN_ANGELES_OBSERVATION_GLES 744 glMatrixMode(GL_PROJECTION); 745 glLoadIdentity(); 746 gluPerspective(45, (float)width / height, 0.5f, 150); 747 748 glMatrixMode(GL_MODELVIEW); 749 glLoadIdentity(); 750 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 751 } 752 753 754 static void configureLightAndMaterial() 755 { 756 GLfloat light0Position[] = { -4.f, 1.f, 1.f, 0 }; 757 GLfloat light1Position[] = { 1.f, -2.f, -1.f, 0 }; 758 GLfloat light2Position[] = { -1.f, 0, -4.f, 0 }; 759 760 #ifdef SAN_ANGELES_OBSERVATION_GLES 761 Matrix4x4_Transform(sModelView, 762 light0Position, light0Position + 1, light0Position + 2); 763 Matrix4x4_Transform(sModelView, 764 light1Position, light1Position + 1, light1Position + 2); 765 Matrix4x4_Transform(sModelView, 766 light2Position, light2Position + 1, light2Position + 2); 767 768 bindShaderProgram(sShaderLit.program); 769 glUniform3fv(sShaderLit.light_0_direction, 1, light0Position); 770 glUniform3fv(sShaderLit.light_1_direction, 1, light1Position); 771 glUniform3fv(sShaderLit.light_2_direction, 1, light2Position); 772 #else // !SAN_ANGELES_OBSERVATION_GLES 773 glLightfv(GL_LIGHT0, GL_POSITION, light0Position); 774 glLightfv(GL_LIGHT1, GL_POSITION, light1Position); 775 glLightfv(GL_LIGHT2, GL_POSITION, light2Position); 776 777 glEnable(GL_COLOR_MATERIAL); 778 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 779 } 780 781 782 static void drawModels(float zScale) 783 { 784 const int translationScale = 9; 785 int x, y; 786 787 seedRandom(9); 788 789 #ifdef SAN_ANGELES_OBSERVATION_GLES 790 Matrix4x4_Scale(sModelView, 1.f, 1.f, zScale); 791 #else // !SAN_ANGELES_OBSERVATION_GLES 792 glScalef(1.f, 1.f, zScale); 793 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 794 795 for (y = -5; y <= 5; ++y) 796 { 797 for (x = -5; x <= 5; ++x) 798 { 799 float buildingScale; 800 #ifdef SAN_ANGELES_OBSERVATION_GLES 801 Matrix4x4 tmp; 802 #endif // SAN_ANGELES_OBSERVATION_GLES 803 804 int curShape = randomUInt() % SUPERSHAPE_COUNT; 805 buildingScale = sSuperShapeParams[curShape][SUPERSHAPE_PARAMS - 1]; 806 #ifdef SAN_ANGELES_OBSERVATION_GLES 807 Matrix4x4_Copy(tmp, sModelView); 808 Matrix4x4_Translate(sModelView, x * translationScale, 809 y * translationScale, 0); 810 Matrix4x4_Rotate(sModelView, randomUInt() % 360, 0, 0, 1.f); 811 Matrix4x4_Scale(sModelView, 812 buildingScale, buildingScale, buildingScale); 813 814 drawGLObject(sSuperShapeObjects[curShape]); 815 Matrix4x4_Copy(sModelView, tmp); 816 #else // !SAN_ANGELES_OBSERVATION_GLES 817 glPushMatrix(); 818 glTranslatef(x * translationScale, y * translationScale, 0); 819 glRotatef(randomUInt() % 360, 0, 0, 1.f); 820 glScalef(buildingScale, buildingScale, buildingScale); 821 822 drawGLObject(sSuperShapeObjects[curShape]); 823 glPopMatrix(); 824 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 825 } 826 } 827 828 for (x = -2; x <= 2; ++x) 829 { 830 const int shipScale100 = translationScale * 500; 831 const int offs100 = x * shipScale100 + (sTick % shipScale100); 832 float offs = offs100 * 0.01f; 833 #ifdef SAN_ANGELES_OBSERVATION_GLES 834 Matrix4x4 tmp; 835 Matrix4x4_Copy(tmp, sModelView); 836 Matrix4x4_Translate(sModelView, offs, -4.f, 2.f); 837 drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); 838 Matrix4x4_Copy(sModelView, tmp); 839 Matrix4x4_Translate(sModelView, -4.f, offs, 4.f); 840 Matrix4x4_Rotate(sModelView, 90.f, 0, 0, 1.f); 841 drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); 842 Matrix4x4_Copy(sModelView, tmp); 843 #else // !SAN_ANGELES_OBSERVATION_GLES 844 glPushMatrix(); 845 glTranslatef(offs, -4.f, 2.f); 846 drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); 847 glPopMatrix(); 848 glPushMatrix(); 849 glTranslatef(-4.f, offs, 4.f); 850 glRotatef(90.f, 0, 0, 1.f); 851 drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); 852 glPopMatrix(); 853 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 854 } 855 } 856 857 /* Following gluLookAt implementation is adapted from the 858 * Mesa 3D Graphics library. http://www.mesa3d.org 859 */ 860 static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, 861 GLfloat centerx, GLfloat centery, GLfloat centerz, 862 GLfloat upx, GLfloat upy, GLfloat upz) 863 { 864 #ifdef SAN_ANGELES_OBSERVATION_GLES 865 Matrix4x4 m; 866 #else // !SAN_ANGELES_OBSERVATION_GLES 867 GLfloat m[16]; 868 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 869 GLfloat x[3], y[3], z[3]; 870 GLfloat mag; 871 872 /* Make rotation matrix */ 873 874 /* Z vector */ 875 z[0] = eyex - centerx; 876 z[1] = eyey - centery; 877 z[2] = eyez - centerz; 878 mag = (float)sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); 879 if (mag) { /* mpichler, 19950515 */ 880 z[0] /= mag; 881 z[1] /= mag; 882 z[2] /= mag; 883 } 884 885 /* Y vector */ 886 y[0] = upx; 887 y[1] = upy; 888 y[2] = upz; 889 890 /* X vector = Y cross Z */ 891 x[0] = y[1] * z[2] - y[2] * z[1]; 892 x[1] = -y[0] * z[2] + y[2] * z[0]; 893 x[2] = y[0] * z[1] - y[1] * z[0]; 894 895 /* Recompute Y = Z cross X */ 896 y[0] = z[1] * x[2] - z[2] * x[1]; 897 y[1] = -z[0] * x[2] + z[2] * x[0]; 898 y[2] = z[0] * x[1] - z[1] * x[0]; 899 900 /* mpichler, 19950515 */ 901 /* cross product gives area of parallelogram, which is < 1.0 for 902 * non-perpendicular unit-length vectors; so normalize x, y here 903 */ 904 905 mag = (float)sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); 906 if (mag) { 907 x[0] /= mag; 908 x[1] /= mag; 909 x[2] /= mag; 910 } 911 912 mag = (float)sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); 913 if (mag) { 914 y[0] /= mag; 915 y[1] /= mag; 916 y[2] /= mag; 917 } 918 919 #ifdef SAN_ANGELES_OBSERVATION_GLES 920 #define M(row, col) m[col*4 + row] 921 M(0, 0) = x[0]; 922 M(0, 1) = x[1]; 923 M(0, 2) = x[2]; 924 M(0, 3) = 0.0; 925 M(1, 0) = y[0]; 926 M(1, 1) = y[1]; 927 M(1, 2) = y[2]; 928 M(1, 3) = 0.0; 929 M(2, 0) = z[0]; 930 M(2, 1) = z[1]; 931 M(2, 2) = z[2]; 932 M(2, 3) = 0.0; 933 M(3, 0) = 0.0; 934 M(3, 1) = 0.0; 935 M(3, 2) = 0.0; 936 M(3, 3) = 1.0; 937 #undef M 938 939 Matrix4x4_Multiply(sModelView, m, sModelView); 940 941 Matrix4x4_Translate(sModelView, -eyex, -eyey, -eyez); 942 #else // !SAN_ANGELES_OBSERVATION_GLES 943 #define M(row, col) m[col*4 + row] 944 M(0, 0) = x[0]; 945 M(0, 1) = x[1]; 946 M(0, 2) = x[2]; 947 M(0, 3) = 0.0; 948 M(1, 0) = y[0]; 949 M(1, 1) = y[1]; 950 M(1, 2) = y[2]; 951 M(1, 3) = 0.0; 952 M(2, 0) = z[0]; 953 M(2, 1) = z[1]; 954 M(2, 2) = z[2]; 955 M(2, 3) = 0.0; 956 M(3, 0) = 0.0; 957 M(3, 1) = 0.0; 958 M(3, 2) = 0.0; 959 M(3, 3) = 1.0; 960 #undef M 961 962 glMultMatrixf(m); 963 964 /* Translate Eye to Origin */ 965 glTranslatef(-eyex, -eyey, -eyez); 966 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 967 } 968 969 static void camTrack() 970 { 971 float lerp[5]; 972 float eX, eY, eZ, cX, cY, cZ; 973 float trackPos; 974 CAMTRACK *cam; 975 long currentCamTick; 976 int a; 977 978 if (sNextCamTrackStartTick <= sTick) 979 { 980 ++sCurrentCamTrack; 981 sCurrentCamTrackStartTick = sNextCamTrackStartTick; 982 } 983 sNextCamTrackStartTick = sCurrentCamTrackStartTick + 984 sCamTracks[sCurrentCamTrack].len * CAMTRACK_LEN; 985 986 cam = &sCamTracks[sCurrentCamTrack]; 987 currentCamTick = sTick - sCurrentCamTrackStartTick; 988 trackPos = (float)currentCamTick / (CAMTRACK_LEN * cam->len); 989 990 for (a = 0; a < 5; ++a) 991 lerp[a] = (cam->src[a] + cam->dest[a] * trackPos) * 0.01f; 992 993 if (cam->dist) 994 { 995 float dist = cam->dist * 0.1f; 996 cX = lerp[0]; 997 cY = lerp[1]; 998 cZ = lerp[2]; 999 eX = cX - (float)cos(lerp[3]) * dist; 1000 eY = cY - (float)sin(lerp[3]) * dist; 1001 eZ = cZ - lerp[4]; 1002 } 1003 else 1004 { 1005 eX = lerp[0]; 1006 eY = lerp[1]; 1007 eZ = lerp[2]; 1008 cX = eX + (float)cos(lerp[3]); 1009 cY = eY + (float)sin(lerp[3]); 1010 cZ = eZ + lerp[4]; 1011 } 1012 gluLookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1); 1013 } 1014 1015 1016 // Called from the app framework. 1017 /* The tick is current time in milliseconds, width and height 1018 * are the image dimensions to be rendered. 1019 */ 1020 void appRender(long tick, int width, int height) 1021 { 1022 #ifdef SAN_ANGELES_OBSERVATION_GLES 1023 Matrix4x4 tmp; 1024 #endif // SAN_ANGELES_OBSERVATION_GLES 1025 1026 if (sStartTick == 0) 1027 sStartTick = tick; 1028 if (!gAppAlive) 1029 return; 1030 1031 // Actual tick value is "blurred" a little bit. 1032 sTick = (sTick + tick - sStartTick) >> 1; 1033 1034 // Terminate application after running through the demonstration once. 1035 if (sTick >= RUN_LENGTH) 1036 { 1037 gAppAlive = 0; 1038 return; 1039 } 1040 1041 // Prepare OpenGL ES for rendering of the frame. 1042 prepareFrame(width, height); 1043 1044 // Update the camera position and set the lookat. 1045 camTrack(); 1046 1047 // Configure environment. 1048 configureLightAndMaterial(); 1049 1050 // Draw the reflection by drawing models with negated Z-axis. 1051 #ifdef SAN_ANGELES_OBSERVATION_GLES 1052 Matrix4x4_Copy(tmp, sModelView); 1053 drawModels(-1); 1054 Matrix4x4_Copy(sModelView, tmp); 1055 #else // !SAN_ANGELES_OBSERVATION_GLES 1056 glPushMatrix(); 1057 drawModels(-1); 1058 glPopMatrix(); 1059 #endif // SAN_ANGELES_OBSERVATION_GLES | !SAN_ANGELES_OBSERVATION_GLES 1060 1061 // Blend the ground plane to the window. 1062 drawGroundPlane(); 1063 1064 // Draw all the models normally. 1065 drawModels(1); 1066 1067 // Draw fade quad over whole window (when changing cameras). 1068 drawFadeQuad(); 1069 } 1070 1071