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
seedRandom(unsigned long seed)62 static void seedRandom(unsigned long seed)
63 {
64 sRandomSeed = seed;
65 }
66
randomUInt()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
freeGLObject(GLOBJECT * object)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
newGLObject(long vertices,int vertexComponents,int useColorArray,int useNormalArray)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
appendObjectVBO(GLOBJECT * object,GLint * offset)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
createVBO(GLOBJECT ** superShapes,int superShapeCount,GLOBJECT * groundPlane,GLOBJECT * fadeQuad)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
drawGLObject(GLOBJECT * object)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
vector3Sub(VECTOR3 * dest,VECTOR3 * v1,VECTOR3 * v2)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
superShapeMap(VECTOR3 * point,float r1,float r2,float t,float p)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
ssFunc(const float t,const float * p)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/
createSuperShape(const float * params)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
createGroundPlane()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
drawGroundPlane()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
createFadeQuad()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
drawFadeQuad()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.
appInit()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.
appDeinit()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
gluPerspective(GLfloat fovy,GLfloat aspect,GLfloat zNear,GLfloat zFar)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
prepareFrame(int width,int height)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
configureLightAndMaterial()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
drawModels(float zScale)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 */
gluLookAt(GLfloat eyex,GLfloat eyey,GLfloat eyez,GLfloat centerx,GLfloat centery,GLfloat centerz,GLfloat upx,GLfloat upy,GLfloat upz)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
camTrack()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 */
appRender(long tick,int width,int height)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