793 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			793 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
/* San Angeles Observation OpenGL ES version example
 | 
						|
 * Copyright 2004-2005 Jetro Lauha
 | 
						|
 * All rights reserved.
 | 
						|
 * Web: http://iki.fi/jetro/
 | 
						|
 *
 | 
						|
 * This source is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of EITHER:
 | 
						|
 *   (1) The GNU Lesser General Public License as published by the Free
 | 
						|
 *       Software Foundation; either version 2.1 of the License, or (at
 | 
						|
 *       your option) any later version. The text of the GNU Lesser
 | 
						|
 *       General Public License is included with this source in the
 | 
						|
 *       file LICENSE-LGPL.txt.
 | 
						|
 *   (2) The BSD-style license that is included with this source in
 | 
						|
 *       the file LICENSE-BSD.txt.
 | 
						|
 *
 | 
						|
 * This source is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 | 
						|
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 | 
						|
 *
 | 
						|
 * $Id: demo.c,v 1.10 2005/02/08 20:54:39 tonic Exp $
 | 
						|
 * $Revision: 1.10 $
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <math.h>
 | 
						|
#include <float.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
#include <GLES/gl.h>
 | 
						|
 | 
						|
#include "app.h"
 | 
						|
#include "shapes.h"
 | 
						|
#include "cams.h"
 | 
						|
 | 
						|
 | 
						|
// Total run length is 20 * camera track base unit length (see cams.h).
 | 
						|
#define RUN_LENGTH  (20 * CAMTRACK_LEN)
 | 
						|
#undef PI
 | 
						|
#define PI 3.1415926535897932f
 | 
						|
#define RANDOM_UINT_MAX 65535
 | 
						|
 | 
						|
 | 
						|
static unsigned long sRandomSeed = 0;
 | 
						|
 | 
						|
static void seedRandom(unsigned long seed)
 | 
						|
{
 | 
						|
    sRandomSeed = seed;
 | 
						|
}
 | 
						|
 | 
						|
static unsigned long randomUInt()
 | 
						|
{
 | 
						|
    sRandomSeed = sRandomSeed * 0x343fd + 0x269ec3;
 | 
						|
    return sRandomSeed >> 16;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Capped conversion from float to fixed.
 | 
						|
static long floatToFixed(float value)
 | 
						|
{
 | 
						|
    if (value < -32768) value = -32768;
 | 
						|
    if (value > 32767) value = 32767;
 | 
						|
    return (long)(value * 65536);
 | 
						|
}
 | 
						|
 | 
						|
#define FIXED(value) floatToFixed(value)
 | 
						|
 | 
						|
 | 
						|
// Definition of one GL object in this demo.
 | 
						|
typedef struct {
 | 
						|
    /* Vertex array and color array are enabled for all objects, so their
 | 
						|
     * pointers must always be valid and non-NULL. Normal array is not
 | 
						|
     * used by the ground plane, so when its pointer is NULL then normal
 | 
						|
     * array usage is disabled.
 | 
						|
     *
 | 
						|
     * Vertex array is supposed to use GL_FIXED datatype and stride 0
 | 
						|
     * (i.e. tightly packed array). Color array is supposed to have 4
 | 
						|
     * components per color with GL_UNSIGNED_BYTE datatype and stride 0.
 | 
						|
     * Normal array is supposed to use GL_FIXED datatype and stride 0.
 | 
						|
     */
 | 
						|
    GLfixed *vertexArray;
 | 
						|
    GLubyte *colorArray;
 | 
						|
    GLfixed *normalArray;
 | 
						|
    GLint vertexComponents;
 | 
						|
    GLsizei count;
 | 
						|
} GLOBJECT;
 | 
						|
 | 
						|
 | 
						|
static long sStartTick = 0;
 | 
						|
static long sTick = 0;
 | 
						|
 | 
						|
static int sCurrentCamTrack = 0;
 | 
						|
static long sCurrentCamTrackStartTick = 0;
 | 
						|
static long sNextCamTrackStartTick = 0x7fffffff;
 | 
						|
 | 
						|
static GLOBJECT *sSuperShapeObjects[SUPERSHAPE_COUNT] = { NULL };
 | 
						|
static GLOBJECT *sGroundPlane = NULL;
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    float x, y, z;
 | 
						|
} VECTOR3;
 | 
						|
 | 
						|
 | 
						|
static void freeGLObject(GLOBJECT *object)
 | 
						|
{
 | 
						|
    if (object == NULL)
 | 
						|
        return;
 | 
						|
    free(object->normalArray);
 | 
						|
    free(object->colorArray);
 | 
						|
    free(object->vertexArray);
 | 
						|
    free(object);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static GLOBJECT * newGLObject(long vertices, int vertexComponents,
 | 
						|
                              int useNormalArray)
 | 
						|
{
 | 
						|
    GLOBJECT *result;
 | 
						|
    result = (GLOBJECT *)malloc(sizeof(GLOBJECT));
 | 
						|
    if (result == NULL)
 | 
						|
        return NULL;
 | 
						|
    result->count = vertices;
 | 
						|
    result->vertexComponents = vertexComponents;
 | 
						|
    result->vertexArray = (GLfixed *)malloc(vertices * vertexComponents *
 | 
						|
                                            sizeof(GLfixed));
 | 
						|
    result->colorArray = (GLubyte *)malloc(vertices * 4 * sizeof(GLubyte));
 | 
						|
    if (useNormalArray)
 | 
						|
    {
 | 
						|
        result->normalArray = (GLfixed *)malloc(vertices * 3 *
 | 
						|
                                                sizeof(GLfixed));
 | 
						|
    }
 | 
						|
    else
 | 
						|
        result->normalArray = NULL;
 | 
						|
    if (result->vertexArray == NULL ||
 | 
						|
        result->colorArray == NULL ||
 | 
						|
        (useNormalArray && result->normalArray == NULL))
 | 
						|
    {
 | 
						|
        freeGLObject(result);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void drawGLObject(GLOBJECT *object)
 | 
						|
{
 | 
						|
    assert(object != NULL);
 | 
						|
 | 
						|
    glVertexPointer(object->vertexComponents, GL_FIXED,
 | 
						|
                    0, object->vertexArray);
 | 
						|
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, object->colorArray);
 | 
						|
 | 
						|
    // Already done in initialization:
 | 
						|
    //glEnableClientState(GL_VERTEX_ARRAY);
 | 
						|
    //glEnableClientState(GL_COLOR_ARRAY);
 | 
						|
 | 
						|
    if (object->normalArray)
 | 
						|
    {
 | 
						|
        glNormalPointer(GL_FIXED, 0, object->normalArray);
 | 
						|
        glEnableClientState(GL_NORMAL_ARRAY);
 | 
						|
    }
 | 
						|
    else
 | 
						|
        glDisableClientState(GL_NORMAL_ARRAY);
 | 
						|
    glDrawArrays(GL_TRIANGLES, 0, object->count);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void vector3Sub(VECTOR3 *dest, VECTOR3 *v1, VECTOR3 *v2)
 | 
						|
{
 | 
						|
    dest->x = v1->x - v2->x;
 | 
						|
    dest->y = v1->y - v2->y;
 | 
						|
    dest->z = v1->z - v2->z;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void superShapeMap(VECTOR3 *point, float r1, float r2, float t, float p)
 | 
						|
{
 | 
						|
    // sphere-mapping of supershape parameters
 | 
						|
    point->x = (float)(cos(t) * cos(p) / r1 / r2);
 | 
						|
    point->y = (float)(sin(t) * cos(p) / r1 / r2);
 | 
						|
    point->z = (float)(sin(p) / r2);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static float ssFunc(const float t, const float *p)
 | 
						|
{
 | 
						|
    return (float)(pow(pow(fabs(cos(p[0] * t / 4)) / p[1], p[4]) +
 | 
						|
                       pow(fabs(sin(p[0] * t / 4)) / p[2], p[5]), 1 / p[3]));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Creates and returns a supershape object.
 | 
						|
// Based on Paul Bourke's POV-Ray implementation.
 | 
						|
// http://astronomy.swin.edu.au/~pbourke/povray/supershape/
 | 
						|
static GLOBJECT * createSuperShape(const float *params)
 | 
						|
{
 | 
						|
    const int resol1 = (int)params[SUPERSHAPE_PARAMS - 3];
 | 
						|
    const int resol2 = (int)params[SUPERSHAPE_PARAMS - 2];
 | 
						|
    // latitude 0 to pi/2 for no mirrored bottom
 | 
						|
    // (latitudeBegin==0 for -pi/2 to pi/2 originally)
 | 
						|
    const int latitudeBegin = resol2 / 4;
 | 
						|
    const int latitudeEnd = resol2 / 2;    // non-inclusive
 | 
						|
    const int longitudeCount = resol1;
 | 
						|
    const int latitudeCount = latitudeEnd - latitudeBegin;
 | 
						|
    const long triangleCount = longitudeCount * latitudeCount * 2;
 | 
						|
    const long vertices = triangleCount * 3;
 | 
						|
    GLOBJECT *result;
 | 
						|
    float baseColor[3];
 | 
						|
    int a, longitude, latitude;
 | 
						|
    long currentVertex, currentQuad;
 | 
						|
 | 
						|
    result = newGLObject(vertices, 3, 1);
 | 
						|
    if (result == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    for (a = 0; a < 3; ++a)
 | 
						|
        baseColor[a] = ((randomUInt() % 155) + 100) / 255.f;
 | 
						|
 | 
						|
    currentQuad = 0;
 | 
						|
    currentVertex = 0;
 | 
						|
 | 
						|
    // longitude -pi to pi
 | 
						|
    for (longitude = 0; longitude < longitudeCount; ++longitude)
 | 
						|
    {
 | 
						|
 | 
						|
        // latitude 0 to pi/2
 | 
						|
        for (latitude = latitudeBegin; latitude < latitudeEnd; ++latitude)
 | 
						|
        {
 | 
						|
            float t1 = -PI + longitude * 2 * PI / resol1;
 | 
						|
            float t2 = -PI + (longitude + 1) * 2 * PI / resol1;
 | 
						|
            float p1 = -PI / 2 + latitude * 2 * PI / resol2;
 | 
						|
            float p2 = -PI / 2 + (latitude + 1) * 2 * PI / resol2;
 | 
						|
            float r0, r1, r2, r3;
 | 
						|
 | 
						|
            r0 = ssFunc(t1, params);
 | 
						|
            r1 = ssFunc(p1, ¶ms[6]);
 | 
						|
            r2 = ssFunc(t2, params);
 | 
						|
            r3 = ssFunc(p2, ¶ms[6]);
 | 
						|
 | 
						|
            if (r0 != 0 && r1 != 0 && r2 != 0 && r3 != 0)
 | 
						|
            {
 | 
						|
                VECTOR3 pa, pb, pc, pd;
 | 
						|
                VECTOR3 v1, v2, n;
 | 
						|
                float ca;
 | 
						|
                int i;
 | 
						|
                //float lenSq, invLenSq;
 | 
						|
 | 
						|
                superShapeMap(&pa, r0, r1, t1, p1);
 | 
						|
                superShapeMap(&pb, r2, r1, t2, p1);
 | 
						|
                superShapeMap(&pc, r2, r3, t2, p2);
 | 
						|
                superShapeMap(&pd, r0, r3, t1, p2);
 | 
						|
 | 
						|
                // kludge to set lower edge of the object to fixed level
 | 
						|
                if (latitude == latitudeBegin + 1)
 | 
						|
                    pa.z = pb.z = 0;
 | 
						|
 | 
						|
                vector3Sub(&v1, &pb, &pa);
 | 
						|
                vector3Sub(&v2, &pd, &pa);
 | 
						|
 | 
						|
                // Calculate normal with cross product.
 | 
						|
                /*   i    j    k      i    j
 | 
						|
                 * v1.x v1.y v1.z | v1.x v1.y
 | 
						|
                 * v2.x v2.y v2.z | v2.x v2.y
 | 
						|
                 */
 | 
						|
 | 
						|
                n.x = v1.y * v2.z - v1.z * v2.y;
 | 
						|
                n.y = v1.z * v2.x - v1.x * v2.z;
 | 
						|
                n.z = v1.x * v2.y - v1.y * v2.x;
 | 
						|
 | 
						|
                /* Pre-normalization of the normals is disabled here because
 | 
						|
                 * they will be normalized anyway later due to automatic
 | 
						|
                 * normalization (GL_NORMALIZE). It is enabled because the
 | 
						|
                 * objects are scaled with glScale.
 | 
						|
                 */
 | 
						|
                /*
 | 
						|
                lenSq = n.x * n.x + n.y * n.y + n.z * n.z;
 | 
						|
                invLenSq = (float)(1 / sqrt(lenSq));
 | 
						|
                n.x *= invLenSq;
 | 
						|
                n.y *= invLenSq;
 | 
						|
                n.z *= invLenSq;
 | 
						|
                */
 | 
						|
 | 
						|
                ca = pa.z + 0.5f;
 | 
						|
 | 
						|
                for (i = currentVertex * 3;
 | 
						|
                     i < (currentVertex + 6) * 3;
 | 
						|
                     i += 3)
 | 
						|
                {
 | 
						|
                    result->normalArray[i] = FIXED(n.x);
 | 
						|
                    result->normalArray[i + 1] = FIXED(n.y);
 | 
						|
                    result->normalArray[i + 2] = FIXED(n.z);
 | 
						|
                }
 | 
						|
                for (i = currentVertex * 4;
 | 
						|
                     i < (currentVertex + 6) * 4;
 | 
						|
                     i += 4)
 | 
						|
                {
 | 
						|
                    int a, color[3];
 | 
						|
                    for (a = 0; a < 3; ++a)
 | 
						|
                    {
 | 
						|
                        color[a] = (int)(ca * baseColor[a] * 255);
 | 
						|
                        if (color[a] > 255) color[a] = 255;
 | 
						|
                    }
 | 
						|
                    result->colorArray[i] = (GLubyte)color[0];
 | 
						|
                    result->colorArray[i + 1] = (GLubyte)color[1];
 | 
						|
                    result->colorArray[i + 2] = (GLubyte)color[2];
 | 
						|
                    result->colorArray[i + 3] = 0;
 | 
						|
                }
 | 
						|
                result->vertexArray[currentVertex * 3] = FIXED(pa.x);
 | 
						|
                result->vertexArray[currentVertex * 3 + 1] = FIXED(pa.y);
 | 
						|
                result->vertexArray[currentVertex * 3 + 2] = FIXED(pa.z);
 | 
						|
                ++currentVertex;
 | 
						|
                result->vertexArray[currentVertex * 3] = FIXED(pb.x);
 | 
						|
                result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y);
 | 
						|
                result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z);
 | 
						|
                ++currentVertex;
 | 
						|
                result->vertexArray[currentVertex * 3] = FIXED(pd.x);
 | 
						|
                result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y);
 | 
						|
                result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z);
 | 
						|
                ++currentVertex;
 | 
						|
                result->vertexArray[currentVertex * 3] = FIXED(pb.x);
 | 
						|
                result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y);
 | 
						|
                result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z);
 | 
						|
                ++currentVertex;
 | 
						|
                result->vertexArray[currentVertex * 3] = FIXED(pc.x);
 | 
						|
                result->vertexArray[currentVertex * 3 + 1] = FIXED(pc.y);
 | 
						|
                result->vertexArray[currentVertex * 3 + 2] = FIXED(pc.z);
 | 
						|
                ++currentVertex;
 | 
						|
                result->vertexArray[currentVertex * 3] = FIXED(pd.x);
 | 
						|
                result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y);
 | 
						|
                result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z);
 | 
						|
                ++currentVertex;
 | 
						|
            } // r0 && r1 && r2 && r3
 | 
						|
            ++currentQuad;
 | 
						|
        } // latitude
 | 
						|
    } // longitude
 | 
						|
 | 
						|
    // Set number of vertices in object to the actual amount created.
 | 
						|
    result->count = currentVertex;
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static GLOBJECT * createGroundPlane()
 | 
						|
{
 | 
						|
    const int scale = 4;
 | 
						|
    const int yBegin = -15, yEnd = 15;    // ends are non-inclusive
 | 
						|
    const int xBegin = -15, xEnd = 15;
 | 
						|
    const long triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2;
 | 
						|
    const long vertices = triangleCount * 3;
 | 
						|
    GLOBJECT *result;
 | 
						|
    int x, y;
 | 
						|
    long currentVertex, currentQuad;
 | 
						|
 | 
						|
    result = newGLObject(vertices, 2, 0);
 | 
						|
    if (result == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    currentQuad = 0;
 | 
						|
    currentVertex = 0;
 | 
						|
 | 
						|
    for (y = yBegin; y < yEnd; ++y)
 | 
						|
    {
 | 
						|
        for (x = xBegin; x < xEnd; ++x)
 | 
						|
        {
 | 
						|
            GLubyte color;
 | 
						|
            int i, a;
 | 
						|
            color = (GLubyte)((randomUInt() & 0x5f) + 81);  // 101 1111
 | 
						|
            for (i = currentVertex * 4; i < (currentVertex + 6) * 4; i += 4)
 | 
						|
            {
 | 
						|
                result->colorArray[i] = color;
 | 
						|
                result->colorArray[i + 1] = color;
 | 
						|
                result->colorArray[i + 2] = color;
 | 
						|
                result->colorArray[i + 3] = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            // Axis bits for quad triangles:
 | 
						|
            // x: 011100 (0x1c), y: 110001 (0x31)  (clockwise)
 | 
						|
            // x: 001110 (0x0e), y: 100011 (0x23)  (counter-clockwise)
 | 
						|
            for (a = 0; a < 6; ++a)
 | 
						|
            {
 | 
						|
                const int xm = x + ((0x1c >> a) & 1);
 | 
						|
                const int ym = y + ((0x31 >> a) & 1);
 | 
						|
                const float m = (float)(cos(xm * 2) * sin(ym * 4) * 0.75f);
 | 
						|
                result->vertexArray[currentVertex * 2] =
 | 
						|
                    FIXED(xm * scale + m);
 | 
						|
                result->vertexArray[currentVertex * 2 + 1] =
 | 
						|
                    FIXED(ym * scale + m);
 | 
						|
                ++currentVertex;
 | 
						|
            }
 | 
						|
            ++currentQuad;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void drawGroundPlane()
 | 
						|
{
 | 
						|
    glDisable(GL_CULL_FACE);
 | 
						|
    glDisable(GL_DEPTH_TEST);
 | 
						|
    glEnable(GL_BLEND);
 | 
						|
    glBlendFunc(GL_ZERO, GL_SRC_COLOR);
 | 
						|
    glDisable(GL_LIGHTING);
 | 
						|
 | 
						|
    drawGLObject(sGroundPlane);
 | 
						|
 | 
						|
    glEnable(GL_LIGHTING);
 | 
						|
    glDisable(GL_BLEND);
 | 
						|
    glEnable(GL_DEPTH_TEST);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void drawFadeQuad()
 | 
						|
{
 | 
						|
    static const GLfixed quadVertices[] = {
 | 
						|
        -0x10000, -0x10000,
 | 
						|
         0x10000, -0x10000,
 | 
						|
        -0x10000,  0x10000,
 | 
						|
         0x10000, -0x10000,
 | 
						|
         0x10000,  0x10000,
 | 
						|
        -0x10000,  0x10000
 | 
						|
    };
 | 
						|
 | 
						|
    const int beginFade = sTick - sCurrentCamTrackStartTick;
 | 
						|
    const int endFade = sNextCamTrackStartTick - sTick;
 | 
						|
    const int minFade = beginFade < endFade ? beginFade : endFade;
 | 
						|
 | 
						|
    if (minFade < 1024)
 | 
						|
    {
 | 
						|
        const GLfixed fadeColor = minFade << 6;
 | 
						|
        glColor4x(fadeColor, fadeColor, fadeColor, 0);
 | 
						|
 | 
						|
        glDisable(GL_DEPTH_TEST);
 | 
						|
        glEnable(GL_BLEND);
 | 
						|
        glBlendFunc(GL_ZERO, GL_SRC_COLOR);
 | 
						|
        glDisable(GL_LIGHTING);
 | 
						|
 | 
						|
        glMatrixMode(GL_MODELVIEW);
 | 
						|
        glLoadIdentity();
 | 
						|
 | 
						|
        glMatrixMode(GL_PROJECTION);
 | 
						|
        glLoadIdentity();
 | 
						|
 | 
						|
        glDisableClientState(GL_COLOR_ARRAY);
 | 
						|
        glDisableClientState(GL_NORMAL_ARRAY);
 | 
						|
        glVertexPointer(2, GL_FIXED, 0, quadVertices);
 | 
						|
        glDrawArrays(GL_TRIANGLES, 0, 6);
 | 
						|
 | 
						|
        glEnableClientState(GL_COLOR_ARRAY);
 | 
						|
 | 
						|
        glMatrixMode(GL_MODELVIEW);
 | 
						|
 | 
						|
        glEnable(GL_LIGHTING);
 | 
						|
        glDisable(GL_BLEND);
 | 
						|
        glEnable(GL_DEPTH_TEST);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Called from the app framework.
 | 
						|
void appInit()
 | 
						|
{
 | 
						|
    unsigned int a;
 | 
						|
 | 
						|
    glEnable(GL_NORMALIZE);
 | 
						|
    glEnable(GL_DEPTH_TEST);
 | 
						|
    glDisable(GL_CULL_FACE);
 | 
						|
    glShadeModel(GL_FLAT);
 | 
						|
 | 
						|
    glEnable(GL_LIGHTING);
 | 
						|
    glEnable(GL_LIGHT0);
 | 
						|
    glEnable(GL_LIGHT1);
 | 
						|
    glEnable(GL_LIGHT2);
 | 
						|
 | 
						|
    glEnableClientState(GL_VERTEX_ARRAY);
 | 
						|
    glEnableClientState(GL_COLOR_ARRAY);
 | 
						|
 | 
						|
    seedRandom(15);
 | 
						|
 | 
						|
    for (a = 0; a < SUPERSHAPE_COUNT; ++a)
 | 
						|
    {
 | 
						|
        sSuperShapeObjects[a] = createSuperShape(sSuperShapeParams[a]);
 | 
						|
        assert(sSuperShapeObjects[a] != NULL);
 | 
						|
    }
 | 
						|
    sGroundPlane = createGroundPlane();
 | 
						|
    assert(sGroundPlane != NULL);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Called from the app framework.
 | 
						|
void appDeinit()
 | 
						|
{
 | 
						|
    unsigned int a;
 | 
						|
    for (a = 0; a < SUPERSHAPE_COUNT; ++a)
 | 
						|
        freeGLObject(sSuperShapeObjects[a]);
 | 
						|
    freeGLObject(sGroundPlane);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void gluPerspective(GLfloat fovy, GLfloat aspect,
 | 
						|
                           GLfloat zNear, GLfloat zFar)
 | 
						|
{
 | 
						|
    GLfloat xmin, xmax, ymin, ymax;
 | 
						|
 | 
						|
    ymax = zNear * (GLfloat)tan(fovy * PI / 360);
 | 
						|
    ymin = -ymax;
 | 
						|
    xmin = ymin * aspect;
 | 
						|
    xmax = ymax * aspect;
 | 
						|
 | 
						|
    glFrustumx((GLfixed)(xmin * 65536), (GLfixed)(xmax * 65536),
 | 
						|
               (GLfixed)(ymin * 65536), (GLfixed)(ymax * 65536),
 | 
						|
               (GLfixed)(zNear * 65536), (GLfixed)(zFar * 65536));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void prepareFrame(int width, int height)
 | 
						|
{
 | 
						|
    glViewport(0, 0, width, height);
 | 
						|
 | 
						|
    glClearColorx((GLfixed)(0.1f * 65536),
 | 
						|
                  (GLfixed)(0.2f * 65536),
 | 
						|
                  (GLfixed)(0.3f * 65536), 0x10000);
 | 
						|
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
 | 
						|
 | 
						|
    glMatrixMode(GL_PROJECTION);
 | 
						|
    glLoadIdentity();
 | 
						|
    gluPerspective(45, (float)width / height, 0.5f, 150);
 | 
						|
 | 
						|
    glMatrixMode(GL_MODELVIEW);
 | 
						|
 | 
						|
    glLoadIdentity();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void configureLightAndMaterial()
 | 
						|
{
 | 
						|
    static GLfixed light0Position[] = { -0x40000, 0x10000, 0x10000, 0 };
 | 
						|
    static GLfixed light0Diffuse[] = { 0x10000, 0x6666, 0, 0x10000 };
 | 
						|
    static GLfixed light1Position[] = { 0x10000, -0x20000, -0x10000, 0 };
 | 
						|
    static GLfixed light1Diffuse[] = { 0x11eb, 0x23d7, 0x5999, 0x10000 };
 | 
						|
    static GLfixed light2Position[] = { -0x10000, 0, -0x40000, 0 };
 | 
						|
    static GLfixed light2Diffuse[] = { 0x11eb, 0x2b85, 0x23d7, 0x10000 };
 | 
						|
    static GLfixed materialSpecular[] = { 0x10000, 0x10000, 0x10000, 0x10000 };
 | 
						|
 | 
						|
    glLightxv(GL_LIGHT0, GL_POSITION, light0Position);
 | 
						|
    glLightxv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse);
 | 
						|
    glLightxv(GL_LIGHT1, GL_POSITION, light1Position);
 | 
						|
    glLightxv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse);
 | 
						|
    glLightxv(GL_LIGHT2, GL_POSITION, light2Position);
 | 
						|
    glLightxv(GL_LIGHT2, GL_DIFFUSE, light2Diffuse);
 | 
						|
    glMaterialxv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular);
 | 
						|
 | 
						|
    glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, 60 << 16);
 | 
						|
    glEnable(GL_COLOR_MATERIAL);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void drawModels(float zScale)
 | 
						|
{
 | 
						|
    const int translationScale = 9;
 | 
						|
    int x, y;
 | 
						|
 | 
						|
    seedRandom(9);
 | 
						|
 | 
						|
    glScalex(1 << 16, 1 << 16, (GLfixed)(zScale * 65536));
 | 
						|
 | 
						|
    for (y = -5; y <= 5; ++y)
 | 
						|
    {
 | 
						|
        for (x = -5; x <= 5; ++x)
 | 
						|
        {
 | 
						|
            float buildingScale;
 | 
						|
            GLfixed fixedScale;
 | 
						|
 | 
						|
            int curShape = randomUInt() % SUPERSHAPE_COUNT;
 | 
						|
            buildingScale = sSuperShapeParams[curShape][SUPERSHAPE_PARAMS - 1];
 | 
						|
            fixedScale = (GLfixed)(buildingScale * 65536);
 | 
						|
 | 
						|
            glPushMatrix();
 | 
						|
            glTranslatex((x * translationScale) * 65536,
 | 
						|
                         (y * translationScale) * 65536,
 | 
						|
                         0);
 | 
						|
            glRotatex((GLfixed)((randomUInt() % 360) << 16), 0, 0, 1 << 16);
 | 
						|
            glScalex(fixedScale, fixedScale, fixedScale);
 | 
						|
 | 
						|
            drawGLObject(sSuperShapeObjects[curShape]);
 | 
						|
            glPopMatrix();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (x = -2; x <= 2; ++x)
 | 
						|
    {
 | 
						|
        const int shipScale100 = translationScale * 500;
 | 
						|
        const int offs100 = x * shipScale100 + (sTick % shipScale100);
 | 
						|
        float offs = offs100 * 0.01f;
 | 
						|
        GLfixed fixedOffs = (GLfixed)(offs * 65536);
 | 
						|
        glPushMatrix();
 | 
						|
        glTranslatex(fixedOffs, -4 * 65536, 2 << 16);
 | 
						|
        drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]);
 | 
						|
        glPopMatrix();
 | 
						|
        glPushMatrix();
 | 
						|
        glTranslatex(-4 * 65536, fixedOffs, 4 << 16);
 | 
						|
        glRotatex(90 << 16, 0, 0, 1 << 16);
 | 
						|
        drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]);
 | 
						|
        glPopMatrix();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Following gluLookAt implementation is adapted from the
 | 
						|
 * Mesa 3D Graphics library. http://www.mesa3d.org
 | 
						|
 */
 | 
						|
static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
 | 
						|
	              GLfloat centerx, GLfloat centery, GLfloat centerz,
 | 
						|
	              GLfloat upx, GLfloat upy, GLfloat upz)
 | 
						|
{
 | 
						|
    GLfloat m[16];
 | 
						|
    GLfloat x[3], y[3], z[3];
 | 
						|
    GLfloat mag;
 | 
						|
 | 
						|
    /* Make rotation matrix */
 | 
						|
 | 
						|
    /* Z vector */
 | 
						|
    z[0] = eyex - centerx;
 | 
						|
    z[1] = eyey - centery;
 | 
						|
    z[2] = eyez - centerz;
 | 
						|
    mag = (float)sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
 | 
						|
    if (mag) {			/* mpichler, 19950515 */
 | 
						|
        z[0] /= mag;
 | 
						|
        z[1] /= mag;
 | 
						|
        z[2] /= mag;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Y vector */
 | 
						|
    y[0] = upx;
 | 
						|
    y[1] = upy;
 | 
						|
    y[2] = upz;
 | 
						|
 | 
						|
    /* X vector = Y cross Z */
 | 
						|
    x[0] = y[1] * z[2] - y[2] * z[1];
 | 
						|
    x[1] = -y[0] * z[2] + y[2] * z[0];
 | 
						|
    x[2] = y[0] * z[1] - y[1] * z[0];
 | 
						|
 | 
						|
    /* Recompute Y = Z cross X */
 | 
						|
    y[0] = z[1] * x[2] - z[2] * x[1];
 | 
						|
    y[1] = -z[0] * x[2] + z[2] * x[0];
 | 
						|
    y[2] = z[0] * x[1] - z[1] * x[0];
 | 
						|
 | 
						|
    /* mpichler, 19950515 */
 | 
						|
    /* cross product gives area of parallelogram, which is < 1.0 for
 | 
						|
     * non-perpendicular unit-length vectors; so normalize x, y here
 | 
						|
     */
 | 
						|
 | 
						|
    mag = (float)sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
 | 
						|
    if (mag) {
 | 
						|
        x[0] /= mag;
 | 
						|
        x[1] /= mag;
 | 
						|
        x[2] /= mag;
 | 
						|
    }
 | 
						|
 | 
						|
    mag = (float)sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
 | 
						|
    if (mag) {
 | 
						|
        y[0] /= mag;
 | 
						|
        y[1] /= mag;
 | 
						|
        y[2] /= mag;
 | 
						|
    }
 | 
						|
 | 
						|
#define M(row,col)  m[(col)*4+(row)]
 | 
						|
    M(0, 0) = x[0];
 | 
						|
    M(0, 1) = x[1];
 | 
						|
    M(0, 2) = x[2];
 | 
						|
    M(0, 3) = 0.0;
 | 
						|
    M(1, 0) = y[0];
 | 
						|
    M(1, 1) = y[1];
 | 
						|
    M(1, 2) = y[2];
 | 
						|
    M(1, 3) = 0.0;
 | 
						|
    M(2, 0) = z[0];
 | 
						|
    M(2, 1) = z[1];
 | 
						|
    M(2, 2) = z[2];
 | 
						|
    M(2, 3) = 0.0;
 | 
						|
    M(3, 0) = 0.0;
 | 
						|
    M(3, 1) = 0.0;
 | 
						|
    M(3, 2) = 0.0;
 | 
						|
    M(3, 3) = 1.0;
 | 
						|
#undef M
 | 
						|
    {
 | 
						|
        int a;
 | 
						|
        GLfixed fixedM[16];
 | 
						|
        for (a = 0; a < 16; ++a)
 | 
						|
            fixedM[a] = (GLfixed)(m[a] * 65536);
 | 
						|
        glMultMatrixx(fixedM);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Translate Eye to Origin */
 | 
						|
    glTranslatex((GLfixed)(-eyex * 65536),
 | 
						|
                 (GLfixed)(-eyey * 65536),
 | 
						|
                 (GLfixed)(-eyez * 65536));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void camTrack()
 | 
						|
{
 | 
						|
    float lerp[5];
 | 
						|
    float eX, eY, eZ, cX, cY, cZ;
 | 
						|
    float trackPos;
 | 
						|
    CAMTRACK *cam;
 | 
						|
    long currentCamTick;
 | 
						|
    int a;
 | 
						|
 | 
						|
    if (sNextCamTrackStartTick <= sTick)
 | 
						|
    {
 | 
						|
        ++sCurrentCamTrack;
 | 
						|
        sCurrentCamTrackStartTick = sNextCamTrackStartTick;
 | 
						|
    }
 | 
						|
    sNextCamTrackStartTick = sCurrentCamTrackStartTick +
 | 
						|
                             sCamTracks[sCurrentCamTrack].len * CAMTRACK_LEN;
 | 
						|
 | 
						|
    cam = &sCamTracks[sCurrentCamTrack];
 | 
						|
    currentCamTick = sTick - sCurrentCamTrackStartTick;
 | 
						|
    trackPos = (float)currentCamTick / (CAMTRACK_LEN * cam->len);
 | 
						|
 | 
						|
    for (a = 0; a < 5; ++a)
 | 
						|
        lerp[a] = (cam->src[a] + cam->dest[a] * trackPos) * 0.01f;
 | 
						|
 | 
						|
    if (cam->dist)
 | 
						|
    {
 | 
						|
        float dist = cam->dist * 0.1f;
 | 
						|
        cX = lerp[0];
 | 
						|
        cY = lerp[1];
 | 
						|
        cZ = lerp[2];
 | 
						|
        eX = cX - (float)cos(lerp[3]) * dist;
 | 
						|
        eY = cY - (float)sin(lerp[3]) * dist;
 | 
						|
        eZ = cZ - lerp[4];
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        eX = lerp[0];
 | 
						|
        eY = lerp[1];
 | 
						|
        eZ = lerp[2];
 | 
						|
        cX = eX + (float)cos(lerp[3]);
 | 
						|
        cY = eY + (float)sin(lerp[3]);
 | 
						|
        cZ = eZ + lerp[4];
 | 
						|
    }
 | 
						|
    gluLookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Called from the app framework.
 | 
						|
/* The tick is current time in milliseconds, width and height
 | 
						|
 * are the image dimensions to be rendered.
 | 
						|
 */
 | 
						|
void appRender(long tick, int width, int height)
 | 
						|
{
 | 
						|
    if (sStartTick == 0)
 | 
						|
        sStartTick = tick;
 | 
						|
    if (!gAppAlive)
 | 
						|
        return;
 | 
						|
 | 
						|
    // Actual tick value is "blurred" a little bit.
 | 
						|
    sTick = (sTick + tick - sStartTick) >> 1;
 | 
						|
 | 
						|
    // Terminate application after running through the demonstration once.
 | 
						|
    if (sTick >= RUN_LENGTH)
 | 
						|
    {
 | 
						|
        gAppAlive = 0;
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Prepare OpenGL ES for rendering of the frame.
 | 
						|
    prepareFrame(width, height);
 | 
						|
 | 
						|
    // Update the camera position and set the lookat.
 | 
						|
    camTrack();
 | 
						|
 | 
						|
    // Configure environment.
 | 
						|
    configureLightAndMaterial();
 | 
						|
 | 
						|
    // Draw the reflection by drawing models with negated Z-axis.
 | 
						|
    glPushMatrix();
 | 
						|
    drawModels(-1);
 | 
						|
    glPopMatrix();
 | 
						|
 | 
						|
    // Blend the ground plane to the window.
 | 
						|
    drawGroundPlane();
 | 
						|
 | 
						|
    // Draw all the models normally.
 | 
						|
    drawModels(1);
 | 
						|
 | 
						|
    // Draw fade quad over whole window (when changing cameras).
 | 
						|
    drawFadeQuad();
 | 
						|
}
 |