1 /* 2 * Copyright (C) 2010 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.cts.verifier.sensors; 18 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.nio.ByteBuffer; 22 import java.nio.ByteOrder; 23 import java.nio.FloatBuffer; 24 import java.nio.ShortBuffer; 25 26 import javax.microedition.khronos.egl.EGLConfig; 27 import javax.microedition.khronos.opengles.GL10; 28 29 import android.content.Context; 30 import android.graphics.Bitmap; 31 import android.graphics.BitmapFactory; 32 import android.hardware.Sensor; 33 import android.hardware.SensorEvent; 34 import android.hardware.SensorEventListener; 35 import android.opengl.GLSurfaceView; 36 import android.opengl.GLU; 37 import android.opengl.GLUtils; 38 39 import com.android.cts.verifier.R; 40 41 public class AccelerometerTestRenderer implements GLSurfaceView.Renderer, SensorEventListener { 42 43 /** 44 * A representation of a 3D triangular wedge or arrowhead shape, suitable 45 * for pointing a direction. 46 */ 47 private static class Wedge { 48 private final static int VERTS = 6; 49 50 /** 51 * Storage for the vertices. 52 */ 53 private FloatBuffer mFVertexBuffer; 54 55 /** 56 * Storage for the drawing sequence of the vertices. This contains 57 * integer indices into the mFVertextBuffer structure. 58 */ 59 private ShortBuffer mIndexBuffer; 60 61 /** 62 * Storage for the texture used on the surface of the wedge. 63 */ 64 private FloatBuffer mTexBuffer; 65 Wedge()66 public Wedge() { 67 // Buffers to be passed to gl*Pointer() functions 68 // must be direct & use native ordering 69 70 ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 6 * 4); 71 vbb.order(ByteOrder.nativeOrder()); 72 mFVertexBuffer = vbb.asFloatBuffer(); 73 74 ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4); 75 tbb.order(ByteOrder.nativeOrder()); 76 mTexBuffer = tbb.asFloatBuffer(); 77 78 ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 8 * 2); 79 ibb.order(ByteOrder.nativeOrder()); 80 mIndexBuffer = ibb.asShortBuffer(); 81 82 /** 83 * Coordinates of the vertices making up a simple wedge. Six total 84 * vertices, representing two isosceles triangles, side by side, 85 * centered on the origin separated by 0.25 units, with elongated 86 * ends pointing down the negative Z axis. 87 */ 88 float[] coords = { 89 // X, Y, Z 90 -0.125f, -0.25f, -0.25f, 91 -0.125f, 0.25f, -0.25f, 92 -0.125f, 0.0f, 0.559016994f, 93 0.125f, -0.25f, -0.25f, 94 0.125f, 0.25f, -0.25f, 95 0.125f, 0.0f, 0.559016994f, 96 }; 97 98 for (int i = 0; i < VERTS; i++) { 99 for (int j = 0; j < 3; j++) { 100 mFVertexBuffer.put(coords[i * 3 + j] * 2.0f); 101 } 102 } 103 104 for (int i = 0; i < VERTS; i++) { 105 for (int j = 0; j < 2; j++) { 106 mTexBuffer.put(coords[i * 3 + j] * 2.0f + 0.5f); 107 } 108 } 109 110 // left face 111 mIndexBuffer.put((short) 0); 112 mIndexBuffer.put((short) 1); 113 mIndexBuffer.put((short) 2); 114 115 // right face 116 mIndexBuffer.put((short) 5); 117 mIndexBuffer.put((short) 4); 118 mIndexBuffer.put((short) 3); 119 120 // top side, 2 triangles to make rect 121 mIndexBuffer.put((short) 2); 122 mIndexBuffer.put((short) 5); 123 mIndexBuffer.put((short) 3); 124 mIndexBuffer.put((short) 3); 125 mIndexBuffer.put((short) 0); 126 mIndexBuffer.put((short) 2); 127 128 // bottom side, 2 triangles to make rect 129 mIndexBuffer.put((short) 5); 130 mIndexBuffer.put((short) 2); 131 mIndexBuffer.put((short) 1); 132 mIndexBuffer.put((short) 1); 133 mIndexBuffer.put((short) 4); 134 mIndexBuffer.put((short) 5); 135 136 // base, 2 triangles to make rect 137 mIndexBuffer.put((short) 0); 138 mIndexBuffer.put((short) 3); 139 mIndexBuffer.put((short) 4); 140 mIndexBuffer.put((short) 4); 141 mIndexBuffer.put((short) 1); 142 mIndexBuffer.put((short) 0); 143 144 mFVertexBuffer.position(0); 145 mTexBuffer.position(0); 146 mIndexBuffer.position(0); 147 } 148 draw(GL10 gl)149 public void draw(GL10 gl) { 150 gl.glFrontFace(GL10.GL_CCW); 151 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer); 152 gl.glEnable(GL10.GL_TEXTURE_2D); 153 gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer); 154 gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 24, GL10.GL_UNSIGNED_SHORT, mIndexBuffer); 155 } 156 } 157 158 /** 159 * A representation of the Z-axis in vector form. 160 */ 161 protected static final float[] Z_AXIS = new float[] { 162 0, 0, 1 163 }; 164 165 /** 166 * Computes the cross product of two vectors, storing the resulting 167 * pseudovector in out. All arrays must be length 3 or more, and out is 168 * overwritten. 169 * 170 * @param left the left operand of the cross product 171 * @param right the right operand of the cross product 172 * @param out the array into which to store the cross-product pseudovector's 173 * data 174 */ crossProduct(float[] left, float[] right, float[] out)175 public static void crossProduct(float[] left, float[] right, float[] out) { 176 out[0] = left[1] * right[2] - left[2] * right[1]; 177 out[1] = left[2] * right[0] - left[0] * right[2]; 178 out[2] = left[0] * right[1] - left[1] * right[0]; 179 } 180 181 /** 182 * Computes the dot product of two vectors. 183 * 184 * @param left the first dot product operand 185 * @param right the second dot product operand 186 * @return the dot product of left and right 187 */ dotProduct(float[] left, float[] right)188 public static float dotProduct(float[] left, float[] right) { 189 return left[0] * right[0] + left[1] * right[1] + left[2] * right[2]; 190 } 191 192 /** 193 * Normalizes the input vector into a unit vector. 194 * 195 * @param vector the vector to normalize. Contents are overwritten. 196 */ normalize(float[] vector)197 public static void normalize(float[] vector) { 198 double mag = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] 199 * vector[2]); 200 vector[0] /= mag; 201 vector[1] /= mag; 202 vector[2] /= mag; 203 } 204 205 /** 206 * The angle around mCrossProd to rotate to align Z-axis with gravity. 207 */ 208 protected float mAngle; 209 210 private Context mContext; 211 212 /** 213 * The (pseudo)vector around which to rotate to align Z-axis with gravity. 214 */ 215 protected float[] mCrossProd = new float[3]; 216 217 private int mTextureID; 218 219 private Wedge mWedge; 220 221 /** 222 * It's a constructor. Can you dig it? 223 * 224 * @param context the Android Context that owns this renderer 225 */ AccelerometerTestRenderer(Context context)226 public AccelerometerTestRenderer(Context context) { 227 mContext = context; 228 mWedge = new Wedge(); 229 } 230 onAccuracyChanged(Sensor arg0, int arg1)231 public void onAccuracyChanged(Sensor arg0, int arg1) { 232 // no-op 233 } 234 235 /** 236 * Actually draws the wedge. 237 */ onDrawFrame(GL10 gl)238 public void onDrawFrame(GL10 gl) { 239 // set up the texture for drawing 240 gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE); 241 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 242 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 243 gl.glActiveTexture(GL10.GL_TEXTURE0); 244 gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID); 245 gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT); 246 gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); 247 248 // clear the screen and draw 249 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 250 gl.glMatrixMode(GL10.GL_MODELVIEW); 251 gl.glLoadIdentity(); 252 gl.glRotatef(-mAngle * 180 / (float) Math.PI, mCrossProd[0], mCrossProd[1], mCrossProd[2]); 253 mWedge.draw(gl); 254 } 255 onSensorChanged(SensorEvent event)256 public void onSensorChanged(SensorEvent event) { 257 if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { 258 /* 259 * For this test we want *only* accelerometer data, so we can't use 260 * the convenience methods on SensorManager; so compute manually. 261 */ 262 normalize(event.values); 263 264 /* 265 * Because we need to invert gravity (because the accelerometer vector 266 * actually points up), that constitutes a 180-degree rotation around X, 267 * which means we need to invert Y. 268 */ 269 event.values[1] *= -1; 270 271 crossProduct(event.values, Z_AXIS, mCrossProd); 272 mAngle = (float) Math.acos(dotProduct(event.values, Z_AXIS)); 273 } 274 } 275 onSurfaceChanged(GL10 gl, int w, int h)276 public void onSurfaceChanged(GL10 gl, int w, int h) { 277 gl.glViewport(0, 0, w, h); 278 float ratio = (float) w / h; 279 gl.glMatrixMode(GL10.GL_PROJECTION); 280 gl.glLoadIdentity(); 281 gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); 282 GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 283 } 284 onSurfaceCreated(GL10 gl, EGLConfig config)285 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 286 // set up general OpenGL config 287 gl.glClearColor(0.6f, 0f, 0.4f, 1); // a nice purpley magenta 288 gl.glShadeModel(GL10.GL_SMOOTH); 289 gl.glEnable(GL10.GL_DEPTH_TEST); 290 gl.glEnable(GL10.GL_TEXTURE_2D); 291 292 // create the texture we use on the wedge 293 int[] textures = new int[1]; 294 gl.glGenTextures(1, textures, 0); 295 mTextureID = textures[0]; 296 297 gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID); 298 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); 299 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 300 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 301 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); 302 gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE); 303 304 InputStream is = mContext.getResources().openRawResource(R.raw.sns_texture); 305 Bitmap bitmap; 306 try { 307 bitmap = BitmapFactory.decodeStream(is); 308 } finally { 309 try { 310 is.close(); 311 } catch (IOException e) { 312 // Ignore. 313 } 314 } 315 316 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 317 bitmap.recycle(); 318 } 319 } 320