1aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk/* 2dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk * Copyright (C) 2011 The Android Open Source Project 3aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * 4aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License"); 5aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * you may not use this file except in compliance with the License. 6aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * You may obtain a copy of the License at 7aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * 8aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * http://www.apache.org/licenses/LICENSE-2.0 9aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * 10aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software 11aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS, 12aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * See the License for the specific language governing permissions and 14aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk * limitations under the License. 15aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk */ 16aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 17aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchoukpackage com.android.modelviewer; 18aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 1935ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopianimport android.renderscript.Matrix4f; 20aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchoukimport android.renderscript.RSSurfaceView; 21aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchoukimport android.renderscript.RenderScriptGL; 22aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 23aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchoukimport android.content.Context; 2435ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopianimport android.hardware.Sensor; 2535ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopianimport android.hardware.SensorEvent; 2635ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopianimport android.hardware.SensorEventListener; 2735ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopianimport android.hardware.SensorManager; 28aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchoukimport android.view.MotionEvent; 29dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchoukimport android.view.SurfaceHolder; 30dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchoukimport android.view.ScaleGestureDetector; 31dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchoukimport android.util.Log; 32aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 3335ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopianpublic class SimpleModelView extends RSSurfaceView implements SensorEventListener { 34aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 35aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk private RenderScriptGL mRS; 3632e09b5891da0174f161d99e2d3ebe67d6efa39cAlex Sakhartchouk private SimpleModelRS mRender; 37aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 38dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk private ScaleGestureDetector mScaleDetector; 39aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 4035ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian private SensorManager mSensorManager; 4135ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian private Sensor mRotationVectorSensor; 4235ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian private final float[] mRotationMatrix = new float[16]; 4335ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian 44dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk private static final int INVALID_POINTER_ID = -1; 45dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk private int mActivePointerId = INVALID_POINTER_ID; 4635ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian private boolean mUseSensor = false; 4735ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian private Matrix4f mIdentityMatrix = new Matrix4f(); 48dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 49dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk public SimpleModelView(Context context) { 50dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk super(context); 51dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk ensureRenderScript(); 52dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 5335ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian // Get an instance of the SensorManager 5435ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mSensorManager = (SensorManager)getContext().getSystemService(Context.SENSOR_SERVICE); 5535ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian // find the rotation-vector sensor 5635ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mRotationVectorSensor = mSensorManager.getDefaultSensor( 5735ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian Sensor.TYPE_ROTATION_VECTOR); 5835ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mIdentityMatrix.loadIdentity(); 59dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 60dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 61dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk private void ensureRenderScript() { 62aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk if (mRS == null) { 632222aa90031604e9752ebc2909303a84139b8b18Jason Sams RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); 642222aa90031604e9752ebc2909303a84139b8b18Jason Sams sc.setDepth(16, 24); 65bf6ef8d78fffbce6c1849a4a28fb3f4401ad039eJason Sams mRS = createRenderScriptGL(sc); 6632e09b5891da0174f161d99e2d3ebe67d6efa39cAlex Sakhartchouk mRender = new SimpleModelRS(); 67dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.init(mRS, getResources()); 68aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk } 69aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk } 70aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 71aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk @Override 7235ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian public void resume() { 7335ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mSensorManager.registerListener(this, mRotationVectorSensor, 10000); 7435ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 7535ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian 7635ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian @Override 7735ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian public void pause() { 7835ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mSensorManager.unregisterListener(this); 7935ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 8035ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian 8135ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian @Override 82dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk protected void onAttachedToWindow() { 83dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk super.onAttachedToWindow(); 84dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk ensureRenderScript(); 85dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 86dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 87dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk @Override 88dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 89dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk super.surfaceChanged(holder, format, w, h); 90dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.surfaceChanged(); 91dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 92dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 93dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk @Override 94aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk protected void onDetachedFromWindow() { 95dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender = null; 96ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk if (mRS != null) { 97aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk mRS = null; 98bf6ef8d78fffbce6c1849a4a28fb3f4401ad039eJason Sams destroyRenderScriptGL(); 99aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk } 100aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk } 101aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 102dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk public void loadA3DFile(String path) { 103dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.loadA3DFile(path); 104aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk } 105aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 106aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk @Override 107dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk public boolean onTouchEvent(MotionEvent ev) { 108dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mScaleDetector.onTouchEvent(ev); 109dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 110dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk boolean ret = false; 111dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk float x = ev.getX(); 112dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk float y = ev.getY(); 113dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 114dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk final int action = ev.getAction(); 115dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 116dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk switch (action & MotionEvent.ACTION_MASK) { 117dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk case MotionEvent.ACTION_DOWN: { 118dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.onActionDown(x, y); 119dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mActivePointerId = ev.getPointerId(0); 120dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk ret = true; 121dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk break; 122dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 123dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk case MotionEvent.ACTION_MOVE: { 124dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk if (!mScaleDetector.isInProgress()) { 125dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.onActionMove(x, y); 126dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 127dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.onActionDown(x, y); 128dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk ret = true; 129dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk break; 130dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 131dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 132dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk case MotionEvent.ACTION_UP: { 133dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mActivePointerId = INVALID_POINTER_ID; 134dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk break; 135dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 136dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 137dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk case MotionEvent.ACTION_CANCEL: { 138dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mActivePointerId = INVALID_POINTER_ID; 139dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk break; 140dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 141dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 142dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk case MotionEvent.ACTION_POINTER_UP: { 143dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 144dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 145dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk final int pointerId = ev.getPointerId(pointerIndex); 146dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk if (pointerId == mActivePointerId) { 147dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk // This was our active pointer going up. Choose a new 148dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk // active pointer and adjust accordingly. 149dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 150dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk x = ev.getX(newPointerIndex); 151dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk y = ev.getY(newPointerIndex); 152dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.onActionDown(x, y); 153dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mActivePointerId = ev.getPointerId(newPointerIndex); 154dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 155dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk break; 156dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 157aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk } 158aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 159aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk return ret; 160aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk } 161dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk 162dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 163dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk @Override 164dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk public boolean onScale(ScaleGestureDetector detector) { 165dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk mRender.onActionScale(detector.getScaleFactor()); 166dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk return true; 167dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 168dc165b3365ca3e8fd7c4eb11b1154646977a6d0aAlex Sakhartchouk } 169aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 17035ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian public void onSensorChanged(SensorEvent event) { 17135ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian // we received a sensor event. it is a good practice to check 17235ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian // that we received the proper event 17335ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian if (mUseSensor) { 17435ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { 17535ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian // convert the rotation-vector to a 4x4 matrix. the matrix 17635ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian // is interpreted by Open GL as the inverse of the 17735ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian // rotation-vector, which is what we want. 17835ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian SensorManager.getRotationMatrixFromVector( 17935ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mRotationMatrix , event.values); 18035ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian 18135ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian if (mRender != null) { 18235ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mRender.onPostureChanged(new Matrix4f(mRotationMatrix)); 18335ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 18435ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 18535ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 18635ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 18735ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian 18835ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian public void onAccuracyChanged(Sensor sensor, int accuracy) { 18935ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 190aae74ad6144470c66e72b075ac3afeddb186fa98Alex Sakhartchouk 19135ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian public void toggleSensor() { 19235ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mUseSensor = !mUseSensor; 19335ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian if (mUseSensor == false) { 19435ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian mRender.onPostureChanged(mIdentityMatrix); 19535ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 19635ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian } 19735ccf46533c76cdc7c2f6c0ce8f33b34b29bc5e6Mathias Agopian} 198