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 "importgl.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, ¶ms[6]);
238 r2 = ssFunc(t2, params);
239 r3 = ssFunc(p2, ¶ms[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 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 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