Project: apps-for-android
/*
 * Copyright (C) 2007 Google Inc. 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
 
package com.android.globaltime; 
 
import java.nio.Buffer; 
import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.IntBuffer; 
import java.nio.ShortBuffer; 
 
import javax.microedition.khronos.opengles.GL10; 
 
/**
 * An abstract superclass for various three-dimensional objects to be drawn 
 * using OpenGL ES.  Each subclass is responsible for setting up NIO buffers 
 * containing vertices, texture coordinates, colors, normals, and indices. 
 * The {@link #draw(GL10)} method draws the object to the given OpenGL context. 
 */
 
public abstract class Shape { 
 
    public static final int INT_BYTES = 4
    public static final int SHORT_BYTES = 2
 
    public static final float DEGREES_TO_RADIANS = (float) Math.PI / 180.0f
    public static final float PI = (float) Math.PI; 
    public static final float TWO_PI = (float) (2.0 * Math.PI); 
    public static final float PI_OVER_TWO = (float) (Math.PI / 2.0); 
 
    protected int mPrimitive; 
    protected int mIndexDatatype; 
 
    protected boolean mEmitTextureCoordinates; 
    protected boolean mEmitNormals; 
    protected boolean mEmitColors; 
 
    protected IntBuffer mVertexBuffer; 
    protected IntBuffer mTexcoordBuffer; 
    protected IntBuffer mColorBuffer; 
    protected IntBuffer mNormalBuffer; 
    protected Buffer mIndexBuffer; 
    protected int mNumIndices = -1
 
    /**
     * Constructs a Shape. 
     *  
     * @param primitive a GL primitive type understood by glDrawElements, 
     * such as GL10.GL_TRIANGLES 
     * @param indexDatatype the GL datatype for the  index buffer, such as 
     * GL10.GL_UNSIGNED_SHORT 
     * @param emitTextureCoordinates true to enable use of the texture 
     * coordinate buffer 
     * @param emitNormals true to enable use of the normal buffer 
     * @param emitColors true to enable use of the color buffer 
     */
 
    protected Shape(int primitive, 
        int indexDatatype, 
        boolean emitTextureCoordinates, 
        boolean emitNormals, 
        boolean emitColors) { 
        mPrimitive = primitive; 
        mIndexDatatype = indexDatatype; 
        mEmitTextureCoordinates = emitTextureCoordinates; 
        mEmitNormals = emitNormals; 
        mEmitColors = emitColors; 
    } 
 
    /**
     * Converts the given floating-point value to fixed-point. 
     */
 
    public static int toFixed(float x) { 
        return (int) (x * 65536.0); 
    } 
 
    /**
     * Converts the given fixed-point value to floating-point. 
     */
 
    public static float toFloat(int x) { 
        return (float) (x / 65536.0); 
    } 
 
    /**
     * Computes the cross-product of two vectors p and q and places 
     * the result in out.  
     */
 
    public static void cross(float[] p, float[] q, float[] out) { 
        out[0] = p[1] * q[2] - p[2] * q[1]; 
        out[1] = p[2] * q[0] - p[0] * q[2]; 
        out[2] = p[0] * q[1] - p[1] * q[0]; 
    } 
 
    /**
     * Returns the length of a vector, given as three floats. 
     */
 
    public static float length(float vx, float vy, float vz) { 
        return (float) Math.sqrt(vx * vx + vy * vy + vz * vz); 
    } 
 
    /**
     * Returns the length of a vector, given as an array of three floats. 
     */
 
    public static float length(float[] v) {  
        return length(v[0], v[1], v[2]); 
    } 
 
    /**
     * Normalizes the given vector of three floats to have length == 1.0. 
     * Vectors with length zero are unaffected. 
     */
 
    public static void normalize(float[] v) { 
        float length = length(v); 
        if (length != 0.0f) { 
            float norm = 1.0f / length; 
            v[0] *= norm; 
            v[1] *= norm; 
            v[2] *= norm; 
        } 
    } 
 
    /**
     * Returns the number of triangles associated with this shape. 
     */
 
    public int getNumTriangles() { 
        if (mPrimitive == GL10.GL_TRIANGLES) { 
            return mIndexBuffer.capacity() / 3
        } else if (mPrimitive == GL10.GL_TRIANGLE_STRIP) { 
            return mIndexBuffer.capacity() - 2
        } 
        return 0
    } 
     
    /**
     * Copies the given data into the instance 
     * variables mVertexBuffer, mTexcoordBuffer, mNormalBuffer, mColorBuffer, 
     * and mIndexBuffer. 
     *  
     * @param vertices an array of fixed-point vertex coordinates 
     * @param texcoords an array of fixed-point texture coordinates 
     * @param normals an array of fixed-point normal vector coordinates 
     * @param colors an array of fixed-point color channel values 
     * @param indices an array of short indices 
     */
 
    public void allocateBuffers(int[] vertices, int[] texcoords, int[] normals, 
        int[] colors, short[] indices) { 
        allocate(vertices, texcoords, normals, colors); 
         
        ByteBuffer ibb = 
            ByteBuffer.allocateDirect(indices.length * SHORT_BYTES); 
        ibb.order(ByteOrder.nativeOrder()); 
        ShortBuffer shortIndexBuffer = ibb.asShortBuffer(); 
        shortIndexBuffer.put(indices); 
        shortIndexBuffer.position(0); 
        this.mIndexBuffer = shortIndexBuffer; 
    } 
     
    /**
     * Copies the given data into the instance 
     * variables mVertexBuffer, mTexcoordBuffer, mNormalBuffer, mColorBuffer, 
     * and mIndexBuffer. 
     *  
     * @param vertices an array of fixed-point vertex coordinates 
     * @param texcoords an array of fixed-point texture coordinates 
     * @param normals an array of fixed-point normal vector coordinates 
     * @param colors an array of fixed-point color channel values 
     * @param indices an array of int indices 
     */
 
    public void allocateBuffers(int[] vertices, int[] texcoords, int[] normals, 
        int[] colors, int[] indices) { 
        allocate(vertices, texcoords, normals, colors); 
         
        ByteBuffer ibb = 
            ByteBuffer.allocateDirect(indices.length * INT_BYTES); 
        ibb.order(ByteOrder.nativeOrder()); 
        IntBuffer intIndexBuffer = ibb.asIntBuffer(); 
        intIndexBuffer.put(indices); 
        intIndexBuffer.position(0); 
        this.mIndexBuffer = intIndexBuffer; 
    } 
     
    /**
     * Allocate the vertex, texture coordinate, normal, and color buffer. 
     */
 
    private void allocate(int[] vertices, int[] texcoords, int[] normals, 
        int[] colors) { 
        ByteBuffer vbb = 
            ByteBuffer.allocateDirect(vertices.length * INT_BYTES); 
        vbb.order(ByteOrder.nativeOrder()); 
        mVertexBuffer = vbb.asIntBuffer(); 
        mVertexBuffer.put(vertices); 
        mVertexBuffer.position(0); 
 
        if ((texcoords != null) && mEmitTextureCoordinates) { 
            ByteBuffer tbb = 
                ByteBuffer.allocateDirect(texcoords.length * INT_BYTES); 
            tbb.order(ByteOrder.nativeOrder()); 
            mTexcoordBuffer = tbb.asIntBuffer(); 
            mTexcoordBuffer.put(texcoords); 
            mTexcoordBuffer.position(0); 
        } 
 
        if ((normals != null) && mEmitNormals) { 
            ByteBuffer nbb = 
                ByteBuffer.allocateDirect(normals.length * INT_BYTES); 
            nbb.order(ByteOrder.nativeOrder()); 
            mNormalBuffer = nbb.asIntBuffer(); 
            mNormalBuffer.put(normals); 
            mNormalBuffer.position(0); 
        } 
 
        if ((colors != null) && mEmitColors) { 
            ByteBuffer cbb = 
                ByteBuffer.allocateDirect(colors.length * INT_BYTES); 
            cbb.order(ByteOrder.nativeOrder()); 
            mColorBuffer = cbb.asIntBuffer(); 
            mColorBuffer.put(colors); 
            mColorBuffer.position(0); 
        } 
    } 
 
    /**
     * Draws the shape to the given OpenGL ES 1.0 context.  Texture coordinates, 
     * normals, and colors are emitted according the the preferences set for 
     * this shape. 
     */
 
    public void draw(GL10 gl) { 
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer); 
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
 
        if (mEmitTextureCoordinates) { 
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
            gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, mTexcoordBuffer); 
            gl.glEnable(GL10.GL_TEXTURE_2D); 
        } else { 
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
            gl.glDisable(GL10.GL_TEXTURE_2D); 
        } 
 
        if (mEmitNormals) { 
            gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); 
            gl.glNormalPointer(GL10.GL_FIXED, 0, mNormalBuffer); 
        } else { 
            gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); 
        } 
 
        if (mEmitColors) { 
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY); 
            gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer); 
        } else { 
            gl.glDisableClientState(GL10.GL_COLOR_ARRAY); 
        } 
 
        gl.glDrawElements(mPrimitive, 
                          mNumIndices > 0 ? mNumIndices : mIndexBuffer.capacity(), 
                          mIndexDatatype, 
                          mIndexBuffer); 
    } 
}