• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &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 
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