blob: f2f33c1e97dee6e7a70bfffce93d354afbb3fac7 [file] [log] [blame]
/*
* Copyright (C) 2010 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.cts.verifier.sensors.renderers;
import com.android.cts.verifier.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.GLUtils;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* Renders a wedge to indicate the direction of sensor data.
*/
public class GLArrowSensorTestRenderer implements GLSurfaceView.Renderer, SensorEventListener {
// A representation of the Z-axis in vector form.
private static final float[] Z_AXIS = new float[] {0, 0, 1};
// The (pseudo)vector around which to rotate to align Z-axis with gravity.
private final float[] mCrossProd = new float[3];
private final float[] mRotationMatrix = new float[16];
private final int mSensorType;
private final Context mContext;
private final Wedge mWedge;
// The angle around mCrossProd to rotate to align Z-axis with gravity.
private float mAngle;
private int mTextureID;
/**
* It's a constructor. Can you dig it?
*
* @param context the Android Context that owns this renderer
* @param type of arrow. Possible values: 0 = points towards gravity. 1 =
* points towards reference North
*/
public GLArrowSensorTestRenderer(Context context, int type) {
mContext = context;
mSensorType = type;
mWedge = new Wedge(mSensorType);
}
/**
* {@inheritDoc}
*/
@Override
public void onDrawFrame(GL10 gl) {
// set up the texture for drawing
gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
// clear the screen and draw
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
if (mSensorType == Sensor.TYPE_ACCELEROMETER) {
gl.glRotatef(
-mAngle * 180 / (float) Math.PI,
mCrossProd[0],
mCrossProd[1],
mCrossProd[2]);
} else {
gl.glMultMatrixf(mRotationMatrix, 0);
}
mWedge.draw(gl);
}
/**
* {@inheritDoc}
*/
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
float ratio = (float) w / h;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
/**
* {@inheritDoc}
*/
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// set up general OpenGL config
gl.glClearColor(0.6f, 0f, 0.4f, 1); // a nice purpley magenta
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_TEXTURE_2D);
// create the texture we use on the wedge
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
mTextureID = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);
InputStream is = mContext.getResources().openRawResource(R.raw.sns_texture);
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
// Ignore.
}
}
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
/**
* {@inheritDoc}
*/
@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// no-op
}
/**
* {@inheritDoc}
*/
@Override
public void onSensorChanged(SensorEvent event) {
int type = event.sensor.getType();
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
/*
* For this test we want *only* accelerometer data, so we can't use
* the convenience methods on SensorManager; so compute manually.
*/
normalize(event.values);
/*
* Because we need to invert gravity (because the accelerometer
* vector actually points up), that constitutes a 180-degree
* rotation around X, which means we need to invert Y.
*/
event.values[1] *= -1;
crossProduct(event.values, Z_AXIS, mCrossProd);
mAngle = (float) Math.acos(dotProduct(event.values, Z_AXIS));
} else if (type == Sensor.TYPE_ROTATION_VECTOR
|| type == Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR
|| type == Sensor.TYPE_GAME_ROTATION_VECTOR) {
float[] rotationMatrixTmp = new float[16];
SensorManager.getRotationMatrixFromVector(rotationMatrixTmp, event.values);
SensorManager.remapCoordinateSystem(rotationMatrixTmp,
SensorManager.AXIS_MINUS_X, SensorManager.AXIS_Y, mRotationMatrix);
}
}
/**
* Computes the cross product of two vectors, storing the resulting pseudo-vector in out. All
* arrays must be length 3 or more, and out is overwritten.
*
* @param left the left operand of the cross product
* @param right the right operand of the cross product
* @param out the array into which to store the cross-product pseudo-vector's data
*/
public static void crossProduct(float[] left, float[] right, float[] out) {
out[0] = left[1] * right[2] - left[2] * right[1];
out[1] = left[2] * right[0] - left[0] * right[2];
out[2] = left[0] * right[1] - left[1] * right[0];
}
/**
* Computes the dot product of two vectors.
*
* @param left the first dot product operand
* @param right the second dot product operand
* @return the dot product of left and right
*/
public static float dotProduct(float[] left, float[] right) {
return left[0] * right[0] + left[1] * right[1] + left[2] * right[2];
}
/**
* Normalizes the input vector into a unit vector.
*
* @param vector the vector to normalize. Contents are overwritten.
*/
public static void normalize(float[] vector) {
double mag = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2]
* vector[2]);
vector[0] /= mag;
vector[1] /= mag;
vector[2] /= mag;
}
}