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, &params[6]);
374             r2 = ssFunc(t2, params);
375             r3 = ssFunc(p2, &params[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