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