• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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