1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.globaltime; 18 19 import java.nio.Buffer; 20 import java.nio.ByteBuffer; 21 import java.nio.ByteOrder; 22 import java.nio.IntBuffer; 23 import java.nio.ShortBuffer; 24 25 import javax.microedition.khronos.opengles.GL10; 26 27 /** 28 * An abstract superclass for various three-dimensional objects to be drawn 29 * using OpenGL ES. Each subclass is responsible for setting up NIO buffers 30 * containing vertices, texture coordinates, colors, normals, and indices. 31 * The {@link #draw(GL10)} method draws the object to the given OpenGL context. 32 */ 33 public abstract class Shape { 34 35 public static final int INT_BYTES = 4; 36 public static final int SHORT_BYTES = 2; 37 38 public static final float DEGREES_TO_RADIANS = (float) Math.PI / 180.0f; 39 public static final float PI = (float) Math.PI; 40 public static final float TWO_PI = (float) (2.0 * Math.PI); 41 public static final float PI_OVER_TWO = (float) (Math.PI / 2.0); 42 43 protected int mPrimitive; 44 protected int mIndexDatatype; 45 46 protected boolean mEmitTextureCoordinates; 47 protected boolean mEmitNormals; 48 protected boolean mEmitColors; 49 50 protected IntBuffer mVertexBuffer; 51 protected IntBuffer mTexcoordBuffer; 52 protected IntBuffer mColorBuffer; 53 protected IntBuffer mNormalBuffer; 54 protected Buffer mIndexBuffer; 55 protected int mNumIndices = -1; 56 57 /** 58 * Constructs a Shape. 59 * 60 * @param primitive a GL primitive type understood by glDrawElements, 61 * such as GL10.GL_TRIANGLES 62 * @param indexDatatype the GL datatype for the index buffer, such as 63 * GL10.GL_UNSIGNED_SHORT 64 * @param emitTextureCoordinates true to enable use of the texture 65 * coordinate buffer 66 * @param emitNormals true to enable use of the normal buffer 67 * @param emitColors true to enable use of the color buffer 68 */ 69 protected Shape(int primitive, 70 int indexDatatype, 71 boolean emitTextureCoordinates, 72 boolean emitNormals, 73 boolean emitColors) { 74 mPrimitive = primitive; 75 mIndexDatatype = indexDatatype; 76 mEmitTextureCoordinates = emitTextureCoordinates; 77 mEmitNormals = emitNormals; 78 mEmitColors = emitColors; 79 } 80 81 /** 82 * Converts the given floating-point value to fixed-point. 83 */ 84 public static int toFixed(float x) { 85 return (int) (x * 65536.0); 86 } 87 88 /** 89 * Converts the given fixed-point value to floating-point. 90 */ 91 public static float toFloat(int x) { 92 return (float) (x / 65536.0); 93 } 94 95 /** 96 * Computes the cross-product of two vectors p and q and places 97 * the result in out. 98 */ 99 public static void cross(float[] p, float[] q, float[] out) { 100 out[0] = p[1] * q[2] - p[2] * q[1]; 101 out[1] = p[2] * q[0] - p[0] * q[2]; 102 out[2] = p[0] * q[1] - p[1] * q[0]; 103 } 104 105 /** 106 * Returns the length of a vector, given as three floats. 107 */ 108 public static float length(float vx, float vy, float vz) { 109 return (float) Math.sqrt(vx * vx + vy * vy + vz * vz); 110 } 111 112 /** 113 * Returns the length of a vector, given as an array of three floats. 114 */ 115 public static float length(float[] v) { 116 return length(v[0], v[1], v[2]); 117 } 118 119 /** 120 * Normalizes the given vector of three floats to have length == 1.0. 121 * Vectors with length zero are unaffected. 122 */ 123 public static void normalize(float[] v) { 124 float length = length(v); 125 if (length != 0.0f) { 126 float norm = 1.0f / length; 127 v[0] *= norm; 128 v[1] *= norm; 129 v[2] *= norm; 130 } 131 } 132 133 /** 134 * Returns the number of triangles associated with this shape. 135 */ 136 public int getNumTriangles() { 137 if (mPrimitive == GL10.GL_TRIANGLES) { 138 return mIndexBuffer.capacity() / 3; 139 } else if (mPrimitive == GL10.GL_TRIANGLE_STRIP) { 140 return mIndexBuffer.capacity() - 2; 141 } 142 return 0; 143 } 144 145 /** 146 * Copies the given data into the instance 147 * variables mVertexBuffer, mTexcoordBuffer, mNormalBuffer, mColorBuffer, 148 * and mIndexBuffer. 149 * 150 * @param vertices an array of fixed-point vertex coordinates 151 * @param texcoords an array of fixed-point texture coordinates 152 * @param normals an array of fixed-point normal vector coordinates 153 * @param colors an array of fixed-point color channel values 154 * @param indices an array of short indices 155 */ 156 public void allocateBuffers(int[] vertices, int[] texcoords, int[] normals, 157 int[] colors, short[] indices) { 158 allocate(vertices, texcoords, normals, colors); 159 160 ByteBuffer ibb = 161 ByteBuffer.allocateDirect(indices.length * SHORT_BYTES); 162 ibb.order(ByteOrder.nativeOrder()); 163 ShortBuffer shortIndexBuffer = ibb.asShortBuffer(); 164 shortIndexBuffer.put(indices); 165 shortIndexBuffer.position(0); 166 this.mIndexBuffer = shortIndexBuffer; 167 } 168 169 /** 170 * Copies the given data into the instance 171 * variables mVertexBuffer, mTexcoordBuffer, mNormalBuffer, mColorBuffer, 172 * and mIndexBuffer. 173 * 174 * @param vertices an array of fixed-point vertex coordinates 175 * @param texcoords an array of fixed-point texture coordinates 176 * @param normals an array of fixed-point normal vector coordinates 177 * @param colors an array of fixed-point color channel values 178 * @param indices an array of int indices 179 */ 180 public void allocateBuffers(int[] vertices, int[] texcoords, int[] normals, 181 int[] colors, int[] indices) { 182 allocate(vertices, texcoords, normals, colors); 183 184 ByteBuffer ibb = 185 ByteBuffer.allocateDirect(indices.length * INT_BYTES); 186 ibb.order(ByteOrder.nativeOrder()); 187 IntBuffer intIndexBuffer = ibb.asIntBuffer(); 188 intIndexBuffer.put(indices); 189 intIndexBuffer.position(0); 190 this.mIndexBuffer = intIndexBuffer; 191 } 192 193 /** 194 * Allocate the vertex, texture coordinate, normal, and color buffer. 195 */ 196 private void allocate(int[] vertices, int[] texcoords, int[] normals, 197 int[] colors) { 198 ByteBuffer vbb = 199 ByteBuffer.allocateDirect(vertices.length * INT_BYTES); 200 vbb.order(ByteOrder.nativeOrder()); 201 mVertexBuffer = vbb.asIntBuffer(); 202 mVertexBuffer.put(vertices); 203 mVertexBuffer.position(0); 204 205 if ((texcoords != null) && mEmitTextureCoordinates) { 206 ByteBuffer tbb = 207 ByteBuffer.allocateDirect(texcoords.length * INT_BYTES); 208 tbb.order(ByteOrder.nativeOrder()); 209 mTexcoordBuffer = tbb.asIntBuffer(); 210 mTexcoordBuffer.put(texcoords); 211 mTexcoordBuffer.position(0); 212 } 213 214 if ((normals != null) && mEmitNormals) { 215 ByteBuffer nbb = 216 ByteBuffer.allocateDirect(normals.length * INT_BYTES); 217 nbb.order(ByteOrder.nativeOrder()); 218 mNormalBuffer = nbb.asIntBuffer(); 219 mNormalBuffer.put(normals); 220 mNormalBuffer.position(0); 221 } 222 223 if ((colors != null) && mEmitColors) { 224 ByteBuffer cbb = 225 ByteBuffer.allocateDirect(colors.length * INT_BYTES); 226 cbb.order(ByteOrder.nativeOrder()); 227 mColorBuffer = cbb.asIntBuffer(); 228 mColorBuffer.put(colors); 229 mColorBuffer.position(0); 230 } 231 } 232 233 /** 234 * Draws the shape to the given OpenGL ES 1.0 context. Texture coordinates, 235 * normals, and colors are emitted according the the preferences set for 236 * this shape. 237 */ 238 public void draw(GL10 gl) { 239 gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer); 240 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 241 242 if (mEmitTextureCoordinates) { 243 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 244 gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, mTexcoordBuffer); 245 gl.glEnable(GL10.GL_TEXTURE_2D); 246 } else { 247 gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 248 gl.glDisable(GL10.GL_TEXTURE_2D); 249 } 250 251 if (mEmitNormals) { 252 gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); 253 gl.glNormalPointer(GL10.GL_FIXED, 0, mNormalBuffer); 254 } else { 255 gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); 256 } 257 258 if (mEmitColors) { 259 gl.glEnableClientState(GL10.GL_COLOR_ARRAY); 260 gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer); 261 } else { 262 gl.glDisableClientState(GL10.GL_COLOR_ARRAY); 263 } 264 265 gl.glDrawElements(mPrimitive, 266 mNumIndices > 0 ? mNumIndices : mIndexBuffer.capacity(), 267 mIndexDatatype, 268 mIndexBuffer); 269 } 270 } 271