From 83b7bd78837f2022f83f4f1bd814c072dd8ac1c5 Mon Sep 17 00:00:00 2001 From: Alexander Pacha Date: Sun, 15 Dec 2013 15:45:33 +0100 Subject: [PATCH] Cleaned up RotationVector example code to prepare for different fusion-providers. --- AndroidManifest.xml | 2 +- src/org/hitlabnz/sensor_fusion_demo/Cube.java | 10 +- .../sensor_fusion_demo/CubeRenderer.java | 96 +++++++++++++++++++ ...{RotationVector.java => MainActivity.java} | 26 ++++- .../sensor_fusion_demo/SensorFuser.java | 91 ------------------ .../OrientationProvider.java | 33 +++++++ .../RotationVectorProvider.java | 83 ++++++++++++++++ 7 files changed, 243 insertions(+), 98 deletions(-) create mode 100644 src/org/hitlabnz/sensor_fusion_demo/CubeRenderer.java rename src/org/hitlabnz/sensor_fusion_demo/{RotationVector.java => MainActivity.java} (69%) delete mode 100644 src/org/hitlabnz/sensor_fusion_demo/SensorFuser.java create mode 100644 src/org/hitlabnz/sensor_fusion_demo/orientationProvider/OrientationProvider.java create mode 100644 src/org/hitlabnz/sensor_fusion_demo/orientationProvider/RotationVectorProvider.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 1d560f7..40b5221 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -14,7 +14,7 @@ android:label="@string/app_name" android:theme="@style/AppTheme" > diff --git a/src/org/hitlabnz/sensor_fusion_demo/Cube.java b/src/org/hitlabnz/sensor_fusion_demo/Cube.java index dd620be..e3266b5 100644 --- a/src/org/hitlabnz/sensor_fusion_demo/Cube.java +++ b/src/org/hitlabnz/sensor_fusion_demo/Cube.java @@ -7,7 +7,7 @@ import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** - * A simple cube that is used for drawing the current rotation of the device + * A simple colour-cube that is used for drawing the current rotation of the device * */ public class Cube { @@ -24,6 +24,9 @@ public class Cube { */ private ByteBuffer mIndexBuffer; + /** + * Initialises a new instance of the cube + */ public Cube() { final float vertices[] = { -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, }; @@ -50,6 +53,11 @@ public class Cube { mIndexBuffer.position(0); } + /** + * Draws this cube of the given GL-Surface + * + * @param gl The GL-Surface this cube should be drawn upon. + */ public void draw(GL10 gl) { gl.glEnable(GL10.GL_CULL_FACE); gl.glFrontFace(GL10.GL_CW); diff --git a/src/org/hitlabnz/sensor_fusion_demo/CubeRenderer.java b/src/org/hitlabnz/sensor_fusion_demo/CubeRenderer.java new file mode 100644 index 0000000..c1ae2b1 --- /dev/null +++ b/src/org/hitlabnz/sensor_fusion_demo/CubeRenderer.java @@ -0,0 +1,96 @@ +package org.hitlabnz.sensor_fusion_demo; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +import org.hitlabnz.sensor_fusion_demo.orientationProvider.OrientationProvider; + +import android.opengl.GLSurfaceView; + +/** + * Class that implements the rendering of a cube with the current rotation of the device that is provided by a + * OrientationProvider + * + * @author Alexander Pacha + * + */ +public class CubeRenderer implements GLSurfaceView.Renderer { + /** + * The colour-cube that is drawn repeatedly + */ + private Cube mCube; + + /** + * The current provider of the device orientation. + */ + private OrientationProvider orientationProvider = null; + + /** + * Initialises a new CubeRenderer + */ + public CubeRenderer() { + mCube = new Cube(); + } + + /** + * Sets the orientationProvider of this renderer. Use this method to change which sensor fusion should be currently + * used for rendering the cube. Simply exchange it with another orientationProvider and the cube will be rendered + * with another approach. + * + * @param orientationProvider The new orientation provider that delivers the current orientation of the device + */ + public void setOrientationProvider(OrientationProvider orientationProvider) { + this.orientationProvider = orientationProvider; + } + + /** + * Perform the actual rendering of the cube for each frame + * + * @param gl The surface on which the cube should be rendered + */ + public void onDrawFrame(GL10 gl) { + // clear screen + gl.glClear(GL10.GL_COLOR_BUFFER_BIT); + + // set-up modelview matrix + gl.glMatrixMode(GL10.GL_MODELVIEW); + gl.glLoadIdentity(); + gl.glTranslatef(0, 0, -3.0f); + + if (orientationProvider != null) { + // Get the rotation from the current orientationProvider + gl.glMultMatrixf(orientationProvider.getRotationMatrix(), 0); + } + + // draw our object + gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); + gl.glEnableClientState(GL10.GL_COLOR_ARRAY); + + mCube.draw(gl); + } + + /** + * Update view-port with the new surface + * + * @param gl the surface + * @param width new width + * @param height new height + */ + public void onSurfaceChanged(GL10 gl, int width, int height) { + // set view-port + gl.glViewport(0, 0, width, height); + // set projection matrix + float ratio = (float) width / height; + gl.glMatrixMode(GL10.GL_PROJECTION); + gl.glLoadIdentity(); + gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + // dither is enabled by default, we don't need it + gl.glDisable(GL10.GL_DITHER); + // clear screen in black + gl.glClearColor(0, 0, 0, 1); + } +} diff --git a/src/org/hitlabnz/sensor_fusion_demo/RotationVector.java b/src/org/hitlabnz/sensor_fusion_demo/MainActivity.java similarity index 69% rename from src/org/hitlabnz/sensor_fusion_demo/RotationVector.java rename to src/org/hitlabnz/sensor_fusion_demo/MainActivity.java index 7d13071..2cbeb6b 100644 --- a/src/org/hitlabnz/sensor_fusion_demo/RotationVector.java +++ b/src/org/hitlabnz/sensor_fusion_demo/MainActivity.java @@ -11,6 +11,9 @@ package org.hitlabnz.sensor_fusion_demo; +import org.hitlabnz.sensor_fusion_demo.orientationProvider.OrientationProvider; +import org.hitlabnz.sensor_fusion_demo.orientationProvider.RotationVectorProvider; + import android.app.Activity; import android.hardware.Sensor; import android.hardware.SensorEvent; @@ -27,16 +30,29 @@ import android.os.Bundle; * @see SensorManager * */ -public class RotationVector extends Activity { +public class MainActivity extends Activity { + /** + * The surface that will be drawn upon + */ private GLSurfaceView mGLSurfaceView; - private SensorFuser mRenderer; + /** + * The class that renders the cube + */ + private CubeRenderer mRenderer; + /** + * The current orientation provider that delivers device orientation. + */ + private OrientationProvider currentOrientationProvider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + // Initialise the orientationProvider + currentOrientationProvider = new RotationVectorProvider((SensorManager) getSystemService(SENSOR_SERVICE)); // Create our Preview view and set it as the content of our Activity - mRenderer = new SensorFuser((SensorManager) getSystemService(SENSOR_SERVICE)); + mRenderer = new CubeRenderer(); + mRenderer.setOrientationProvider(currentOrientationProvider); mGLSurfaceView = new GLSurfaceView(this); mGLSurfaceView.setRenderer(mRenderer); setContentView(mGLSurfaceView); @@ -47,7 +63,7 @@ public class RotationVector extends Activity { // Ideally a game should implement onResume() and onPause() // to take appropriate action when the activity looses focus super.onResume(); - mRenderer.start(); + currentOrientationProvider.start(); mGLSurfaceView.onResume(); } @@ -56,7 +72,7 @@ public class RotationVector extends Activity { // Ideally a game should implement onResume() and onPause() // to take appropriate action when the activity looses focus super.onPause(); - mRenderer.stop(); + currentOrientationProvider.stop(); mGLSurfaceView.onPause(); } } \ No newline at end of file diff --git a/src/org/hitlabnz/sensor_fusion_demo/SensorFuser.java b/src/org/hitlabnz/sensor_fusion_demo/SensorFuser.java deleted file mode 100644 index e338248..0000000 --- a/src/org/hitlabnz/sensor_fusion_demo/SensorFuser.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.hitlabnz.sensor_fusion_demo; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.opengl.GLSurfaceView; - -public class SensorFuser implements GLSurfaceView.Renderer, SensorEventListener { - private Cube mCube; - private Sensor mRotationVectorSensor; - private final float[] mRotationMatrix = new float[16]; - private SensorManager mSensorManager; - - public SensorFuser(SensorManager sensorManager) { - mSensorManager = sensorManager; - - // find the rotation-vector sensor - mRotationVectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); - - mCube = new Cube(); - // initialize the rotation matrix to identity - mRotationMatrix[0] = 1; - mRotationMatrix[4] = 1; - mRotationMatrix[8] = 1; - mRotationMatrix[12] = 1; - } - - public void start() { - // enable our sensor when the activity is resumed, ask for - // 10 ms updates. - mSensorManager.registerListener(this, mRotationVectorSensor, 10000); - } - - public void stop() { - // make sure to turn our sensor off when the activity is paused - mSensorManager.unregisterListener(this); - } - - public void onSensorChanged(SensorEvent event) { - // we received a sensor event. it is a good practice to check - // that we received the proper event - if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { - // convert the rotation-vector to a 4x4 matrix. the matrix - // is interpreted by Open GL as the inverse of the - // rotation-vector, which is what we want. - SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values); - } - } - - public void onDrawFrame(GL10 gl) { - // clear screen - gl.glClear(GL10.GL_COLOR_BUFFER_BIT); - - // set-up modelview matrix - gl.glMatrixMode(GL10.GL_MODELVIEW); - gl.glLoadIdentity(); - gl.glTranslatef(0, 0, -3.0f); - gl.glMultMatrixf(mRotationMatrix, 0); - - // draw our object - gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); - gl.glEnableClientState(GL10.GL_COLOR_ARRAY); - - mCube.draw(gl); - } - - public void onSurfaceChanged(GL10 gl, int width, int height) { - // set view-port - gl.glViewport(0, 0, width, height); - // set projection matrix - float ratio = (float) width / height; - gl.glMatrixMode(GL10.GL_PROJECTION); - gl.glLoadIdentity(); - gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); - } - - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - // dither is enabled by default, we don't need it - gl.glDisable(GL10.GL_DITHER); - // clear screen in black - gl.glClearColor(0, 0, 0, 1); - } - - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } -} diff --git a/src/org/hitlabnz/sensor_fusion_demo/orientationProvider/OrientationProvider.java b/src/org/hitlabnz/sensor_fusion_demo/orientationProvider/OrientationProvider.java new file mode 100644 index 0000000..d1b3d72 --- /dev/null +++ b/src/org/hitlabnz/sensor_fusion_demo/orientationProvider/OrientationProvider.java @@ -0,0 +1,33 @@ +/** + * + */ +package org.hitlabnz.sensor_fusion_demo.orientationProvider; + +/** + * Classes implementing this interface provide an orientation of the device either by directly accessing hardware, using + * Android sensor fusion or fusing sensors itself. + * + * The orientation can be provided as rotation matrix or quaternion. + * + * @author Alexander Pacha + * + */ +public interface OrientationProvider { + + /** + * + * @return Returns the current rotation of the device in the rotation matrix format + */ + public float[] getRotationMatrix(); + + /** + * Starts the sensor fusion (e.g. when resuming the activity) + */ + public void start(); + + /** + * Stops the sensor fusion (e.g. when pausing/suspending the activity) + */ + public void stop(); + +} diff --git a/src/org/hitlabnz/sensor_fusion_demo/orientationProvider/RotationVectorProvider.java b/src/org/hitlabnz/sensor_fusion_demo/orientationProvider/RotationVectorProvider.java new file mode 100644 index 0000000..6a64bc2 --- /dev/null +++ b/src/org/hitlabnz/sensor_fusion_demo/orientationProvider/RotationVectorProvider.java @@ -0,0 +1,83 @@ +package org.hitlabnz.sensor_fusion_demo.orientationProvider; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +/** + * The orientation provider that delivers the current orientation from the {@link Sensor#TYPE_ROTATION_VECTOR Android + * Rotation Vector sensor}. + * + * @author Alexander Pacha + * + */ +public class RotationVectorProvider implements SensorEventListener, OrientationProvider { + + /** + * The rotation vector sensor that is being used for this provider to get device orientation + */ + private Sensor rotationVectorSensor; + + /** + * The matrix that holds the current rotation + */ + private final float[] currentOrientationRotationMatrix = new float[16]; + + /** + * The sensor manager for accessing android sensors + */ + private SensorManager sensorManager; + + /** + * Initialises a new RotationVectorProvider + * + * @param sensorManager The android sensor manager + */ + public RotationVectorProvider(SensorManager sensorManager) { + this.sensorManager = sensorManager; + + // find the rotation-vector sensor + rotationVectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); + + // initialize the rotation matrix to identity + currentOrientationRotationMatrix[0] = 1; + currentOrientationRotationMatrix[4] = 1; + currentOrientationRotationMatrix[8] = 1; + currentOrientationRotationMatrix[12] = 1; + } + + @Override + public void start() { + // enable our sensor when the activity is resumed, ask for + // 10 ms updates. + sensorManager.registerListener(this, rotationVectorSensor, 10000); + } + + @Override + public void stop() { + // make sure to turn our sensor off when the activity is paused + sensorManager.unregisterListener(this); + } + + @Override + public void onSensorChanged(SensorEvent event) { + // we received a sensor event. it is a good practice to check + // that we received the proper event + if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { + // convert the rotation-vector to a 4x4 matrix. the matrix + // is interpreted by Open GL as the inverse of the + // rotation-vector, which is what we want. + SensorManager.getRotationMatrixFromVector(currentOrientationRotationMatrix, event.values); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + + @Override + public float[] getRotationMatrix() { + return currentOrientationRotationMatrix; + } +}