/* * Copyright (C) 2007 The Android Open Source Project * * 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); } }