/opengl/tests/gl2_cameraeye/src/com/android/gl2cameraeye/GL2CameraEye.java

http://github.com/CyanogenMod/android_frameworks_base · Java · 508 lines · 373 code · 85 blank · 50 comment · 32 complexity · b3959b4784b84a793451983f552b5de1 MD5 · raw file

  1. /*
  2. * Copyright (C) 2011 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. package com.android.gl2cameraeye;
  17. import java.io.IOException;
  18. import java.nio.ByteBuffer;
  19. import java.nio.ByteOrder;
  20. import java.nio.FloatBuffer;
  21. import javax.microedition.khronos.egl.EGLConfig;
  22. import javax.microedition.khronos.opengles.GL10;
  23. import android.app.Activity;
  24. import android.content.pm.ActivityInfo;
  25. import android.os.Bundle;
  26. import android.view.MotionEvent;
  27. import android.content.Context;
  28. import android.util.Log;
  29. import android.opengl.GLES20;
  30. import android.opengl.GLSurfaceView;
  31. import android.opengl.GLUtils;
  32. import android.opengl.Matrix;
  33. import android.graphics.SurfaceTexture;
  34. import android.hardware.Camera;
  35. import android.hardware.SensorManager;
  36. import android.hardware.SensorEvent;
  37. import android.hardware.SensorEventListener;
  38. import android.hardware.Sensor;
  39. public class GL2CameraEye extends Activity {
  40. @Override
  41. protected void onCreate(Bundle savedInstanceState) {
  42. super.onCreate(savedInstanceState);
  43. mGLView = new CamGLSurfaceView(this);
  44. setContentView(mGLView);
  45. setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  46. }
  47. @Override
  48. protected void onPause() {
  49. super.onPause();
  50. mGLView.onPause();
  51. }
  52. @Override
  53. protected void onResume() {
  54. super.onResume();
  55. mGLView.onResume();
  56. }
  57. private GLSurfaceView mGLView;
  58. }
  59. class CamGLSurfaceView extends GLSurfaceView implements SensorEventListener {
  60. public CamGLSurfaceView(Context context) {
  61. super(context);
  62. setEGLContextClientVersion(2);
  63. mRenderer = new CamRenderer(context);
  64. setRenderer(mRenderer);
  65. mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
  66. mAcceleration = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
  67. }
  68. public boolean onTouchEvent(final MotionEvent event) {
  69. queueEvent(new Runnable(){
  70. public void run() {
  71. mRenderer.setPosition(event.getX() / getWidth(),
  72. event.getY() / getHeight());
  73. }});
  74. return true;
  75. }
  76. @Override
  77. public void onPause() {
  78. super.onPause();
  79. mCamera.stopPreview();
  80. mCamera.release();
  81. mSensorManager.unregisterListener(this);
  82. }
  83. @Override
  84. public void onResume() {
  85. mCamera = Camera.open();
  86. Camera.Parameters p = mCamera.getParameters();
  87. // No changes to default camera parameters
  88. mCamera.setParameters(p);
  89. queueEvent(new Runnable(){
  90. public void run() {
  91. mRenderer.setCamera(mCamera);
  92. }});
  93. mSensorManager.registerListener(this, mAcceleration, SensorManager.SENSOR_DELAY_GAME);
  94. super.onResume();
  95. }
  96. public void onSensorChanged(SensorEvent event) {
  97. if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
  98. final float[] accelerationVector = event.values;
  99. queueEvent(new Runnable(){
  100. public void run() {
  101. mRenderer.setAcceleration(accelerationVector);
  102. }});
  103. }
  104. }
  105. public void onAccuracyChanged(Sensor sensor, int accuracy) {
  106. // Ignoring sensor accuracy changes.
  107. }
  108. CamRenderer mRenderer;
  109. Camera mCamera;
  110. SensorManager mSensorManager;
  111. Sensor mAcceleration;
  112. }
  113. class CamRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
  114. public CamRenderer(Context context) {
  115. mContext = context;
  116. mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
  117. * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
  118. mTriangleVertices.put(mTriangleVerticesData).position(0);
  119. Matrix.setIdentityM(mSTMatrix, 0);
  120. Matrix.setIdentityM(mMMatrix, 0);
  121. float[] defaultAcceleration = {0.f,0.f,0.f};
  122. setAcceleration(defaultAcceleration);
  123. mPos[0] = 0.f;
  124. mPos[1] = 0.f;
  125. mPos[2] = 0.f;
  126. mVel[0] = 0.f;
  127. mVel[1] = 0.f;
  128. mVel[2] = 0.f;
  129. }
  130. /* The following set methods are not synchronized, so should only
  131. * be called within the rendering thread context. Use GLSurfaceView.queueEvent for safe access.
  132. */
  133. public void setPosition(float x, float y) {
  134. /* Map from screen (0,0)-(1,1) to scene coordinates */
  135. mPos[0] = (x*2-1)*mRatio;
  136. mPos[1] = (-y)*2+1;
  137. mPos[2] = 0.f;
  138. mVel[0] = 0;
  139. mVel[1] = 0;
  140. mVel[2] = 0;
  141. }
  142. public void setCamera(Camera camera) {
  143. mCamera = camera;
  144. Camera.Size previewSize = camera.getParameters().getPreviewSize();
  145. mCameraRatio = (float)previewSize.width/previewSize.height;
  146. }
  147. public void setAcceleration(float[] accelerationVector) {
  148. mGForce[0] = accelerationVector[0];
  149. mGForce[1] = accelerationVector[1];
  150. mGForce[2] = accelerationVector[2];
  151. }
  152. public void onDrawFrame(GL10 glUnused) {
  153. synchronized(this) {
  154. if (updateSurface) {
  155. mSurface.updateTexImage();
  156. mSurface.getTransformMatrix(mSTMatrix);
  157. long timestamp = mSurface.getTimestamp();
  158. doPhysics(timestamp);
  159. updateSurface = false;
  160. }
  161. }
  162. // Ignore the passed-in GL10 interface, and use the GLES20
  163. // class's static methods instead.
  164. GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
  165. GLES20.glUseProgram(mProgram);
  166. checkGlError("glUseProgram");
  167. GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
  168. GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
  169. mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
  170. GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
  171. TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
  172. checkGlError("glVertexAttribPointer maPosition");
  173. GLES20.glEnableVertexAttribArray(maPositionHandle);
  174. checkGlError("glEnableVertexAttribArray maPositionHandle");
  175. mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
  176. GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false,
  177. TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
  178. checkGlError("glVertexAttribPointer maTextureHandle");
  179. GLES20.glEnableVertexAttribArray(maTextureHandle);
  180. checkGlError("glEnableVertexAttribArray maTextureHandle");
  181. Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
  182. Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
  183. GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
  184. GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
  185. GLES20.glUniform1f(muCRatioHandle, mCameraRatio);
  186. GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
  187. checkGlError("glDrawArrays");
  188. }
  189. public void onSurfaceChanged(GL10 glUnused, int width, int height) {
  190. // Ignore the passed-in GL10 interface, and use the GLES20
  191. // class's static methods instead.
  192. GLES20.glViewport(0, 0, width, height);
  193. mRatio = (float) width / height;
  194. Matrix.frustumM(mProjMatrix, 0, -mRatio, mRatio, -1, 1, 3, 7);
  195. }
  196. public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
  197. // Ignore the passed-in GL10 interface, and use the GLES20
  198. // class's static methods instead.
  199. /* Set up alpha blending and an Android background color */
  200. GLES20.glEnable(GLES20.GL_BLEND);
  201. GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
  202. GLES20.glClearColor(0.643f, 0.776f, 0.223f, 1.0f);
  203. /* Set up shaders and handles to their variables */
  204. mProgram = createProgram(mVertexShader, mFragmentShader);
  205. if (mProgram == 0) {
  206. return;
  207. }
  208. maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
  209. checkGlError("glGetAttribLocation aPosition");
  210. if (maPositionHandle == -1) {
  211. throw new RuntimeException("Could not get attrib location for aPosition");
  212. }
  213. maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
  214. checkGlError("glGetAttribLocation aTextureCoord");
  215. if (maTextureHandle == -1) {
  216. throw new RuntimeException("Could not get attrib location for aTextureCoord");
  217. }
  218. muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
  219. checkGlError("glGetUniformLocation uMVPMatrix");
  220. if (muMVPMatrixHandle == -1) {
  221. throw new RuntimeException("Could not get attrib location for uMVPMatrix");
  222. }
  223. muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
  224. checkGlError("glGetUniformLocation uSTMatrix");
  225. if (muMVPMatrixHandle == -1) {
  226. throw new RuntimeException("Could not get attrib location for uSTMatrix");
  227. }
  228. muCRatioHandle = GLES20.glGetUniformLocation(mProgram, "uCRatio");
  229. checkGlError("glGetUniformLocation uCRatio");
  230. if (muMVPMatrixHandle == -1) {
  231. throw new RuntimeException("Could not get attrib location for uCRatio");
  232. }
  233. /*
  234. * Create our texture. This has to be done each time the
  235. * surface is created.
  236. */
  237. int[] textures = new int[1];
  238. GLES20.glGenTextures(1, textures, 0);
  239. mTextureID = textures[0];
  240. GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
  241. checkGlError("glBindTexture mTextureID");
  242. // Can't do mipmapping with camera source
  243. GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
  244. GLES20.GL_NEAREST);
  245. GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
  246. GLES20.GL_LINEAR);
  247. // Clamp to edge is the only option
  248. GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
  249. GLES20.GL_CLAMP_TO_EDGE);
  250. GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
  251. GLES20.GL_CLAMP_TO_EDGE);
  252. checkGlError("glTexParameteri mTextureID");
  253. /*
  254. * Create the SurfaceTexture that will feed this textureID, and pass it to the camera
  255. */
  256. mSurface = new SurfaceTexture(mTextureID);
  257. mSurface.setOnFrameAvailableListener(this);
  258. try {
  259. mCamera.setPreviewTexture(mSurface);
  260. } catch (IOException t) {
  261. Log.e(TAG, "Cannot set preview texture target!");
  262. }
  263. /* Start the camera */
  264. mCamera.startPreview();
  265. Matrix.setLookAtM(mVMatrix, 0, 0, 0, 5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
  266. mLastTime = 0;
  267. synchronized(this) {
  268. updateSurface = false;
  269. }
  270. }
  271. synchronized public void onFrameAvailable(SurfaceTexture surface) {
  272. /* For simplicity, SurfaceTexture calls here when it has new
  273. * data available. Call may come in from some random thread,
  274. * so let's be safe and use synchronize. No OpenGL calls can be done here.
  275. */
  276. updateSurface = true;
  277. }
  278. private void doPhysics(long timestamp) {
  279. /*
  280. * Move the camera surface around based on some simple spring physics with drag
  281. */
  282. if (mLastTime == 0)
  283. mLastTime = timestamp;
  284. float deltaT = (timestamp - mLastTime)/1000000000.f; // To seconds
  285. float springStrength = 20.f;
  286. float frictionCoeff = 10.f;
  287. float mass = 10.f;
  288. float gMultiplier = 4.f;
  289. /* Only update physics every 30 ms */
  290. if (deltaT > 0.030f) {
  291. mLastTime = timestamp;
  292. float[] totalForce = new float[3];
  293. totalForce[0] = -mPos[0] * springStrength - mVel[0]*frictionCoeff + gMultiplier*mGForce[0]*mass;
  294. totalForce[1] = -mPos[1] * springStrength - mVel[1]*frictionCoeff + gMultiplier*mGForce[1]*mass;
  295. totalForce[2] = -mPos[2] * springStrength - mVel[2]*frictionCoeff + gMultiplier*mGForce[2]*mass;
  296. float[] accel = new float[3];
  297. accel[0] = totalForce[0]/mass;
  298. accel[1] = totalForce[1]/mass;
  299. accel[2] = totalForce[2]/mass;
  300. /* Not a very accurate integrator */
  301. mVel[0] = mVel[0] + accel[0]*deltaT;
  302. mVel[1] = mVel[1] + accel[1]*deltaT;
  303. mVel[2] = mVel[2] + accel[2]*deltaT;
  304. mPos[0] = mPos[0] + mVel[0]*deltaT;
  305. mPos[1] = mPos[1] + mVel[1]*deltaT;
  306. mPos[2] = mPos[2] + mVel[2]*deltaT;
  307. Matrix.setIdentityM(mMMatrix, 0);
  308. Matrix.translateM(mMMatrix, 0, mPos[0], mPos[1], mPos[2]);
  309. }
  310. }
  311. private int loadShader(int shaderType, String source) {
  312. int shader = GLES20.glCreateShader(shaderType);
  313. if (shader != 0) {
  314. GLES20.glShaderSource(shader, source);
  315. GLES20.glCompileShader(shader);
  316. int[] compiled = new int[1];
  317. GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
  318. if (compiled[0] == 0) {
  319. Log.e(TAG, "Could not compile shader " + shaderType + ":");
  320. Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
  321. GLES20.glDeleteShader(shader);
  322. shader = 0;
  323. }
  324. }
  325. return shader;
  326. }
  327. private int createProgram(String vertexSource, String fragmentSource) {
  328. int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
  329. if (vertexShader == 0) {
  330. return 0;
  331. }
  332. int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
  333. if (pixelShader == 0) {
  334. return 0;
  335. }
  336. int program = GLES20.glCreateProgram();
  337. if (program != 0) {
  338. GLES20.glAttachShader(program, vertexShader);
  339. checkGlError("glAttachShader");
  340. GLES20.glAttachShader(program, pixelShader);
  341. checkGlError("glAttachShader");
  342. GLES20.glLinkProgram(program);
  343. int[] linkStatus = new int[1];
  344. GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
  345. if (linkStatus[0] != GLES20.GL_TRUE) {
  346. Log.e(TAG, "Could not link program: ");
  347. Log.e(TAG, GLES20.glGetProgramInfoLog(program));
  348. GLES20.glDeleteProgram(program);
  349. program = 0;
  350. }
  351. }
  352. return program;
  353. }
  354. private void checkGlError(String op) {
  355. int error;
  356. while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
  357. Log.e(TAG, op + ": glError " + error);
  358. throw new RuntimeException(op + ": glError " + error);
  359. }
  360. }
  361. private static final int FLOAT_SIZE_BYTES = 4;
  362. private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
  363. private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
  364. private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
  365. private final float[] mTriangleVerticesData = {
  366. // X, Y, Z, U, V
  367. -1.0f, -1.0f, 0, 0.f, 0.f,
  368. 1.0f, -1.0f, 0, 1.f, 0.f,
  369. -1.0f, 1.0f, 0, 0.f, 1.f,
  370. 1.0f, 1.0f, 0, 1.f, 1.f,
  371. };
  372. private FloatBuffer mTriangleVertices;
  373. private final String mVertexShader =
  374. "uniform mat4 uMVPMatrix;\n" +
  375. "uniform mat4 uSTMatrix;\n" +
  376. "uniform float uCRatio;\n" +
  377. "attribute vec4 aPosition;\n" +
  378. "attribute vec4 aTextureCoord;\n" +
  379. "varying vec2 vTextureCoord;\n" +
  380. "varying vec2 vTextureNormCoord;\n" +
  381. "void main() {\n" +
  382. " vec4 scaledPos = aPosition;\n" +
  383. " scaledPos.x = scaledPos.x * uCRatio;\n" +
  384. " gl_Position = uMVPMatrix * scaledPos;\n" +
  385. " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
  386. " vTextureNormCoord = aTextureCoord.xy;\n" +
  387. "}\n";
  388. private final String mFragmentShader =
  389. "#extension GL_OES_EGL_image_external : require\n" +
  390. "precision mediump float;\n" +
  391. "varying vec2 vTextureCoord;\n" +
  392. "varying vec2 vTextureNormCoord;\n" +
  393. "uniform samplerExternalOES sTexture;\n" +
  394. "void main() {\n" +
  395. " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
  396. " gl_FragColor.a = 1.0-min(length(vTextureNormCoord-0.5)*2.0,1.0);\n" +
  397. "}\n";
  398. private float[] mMVPMatrix = new float[16];
  399. private float[] mProjMatrix = new float[16];
  400. private float[] mMMatrix = new float[16];
  401. private float[] mVMatrix = new float[16];
  402. private float[] mSTMatrix = new float[16];
  403. private int mProgram;
  404. private int mTextureID;
  405. private int muMVPMatrixHandle;
  406. private int muSTMatrixHandle;
  407. private int muCRatioHandle;
  408. private int maPositionHandle;
  409. private int maTextureHandle;
  410. private float mRatio = 1.0f;
  411. private float mCameraRatio = 1.0f;
  412. private float[] mVel = new float[3];
  413. private float[] mPos = new float[3];
  414. private float[] mGForce = new float[3];
  415. private long mLastTime;
  416. private SurfaceTexture mSurface;
  417. private Camera mCamera;
  418. private boolean updateSurface = false;
  419. private Context mContext;
  420. private static String TAG = "CamRenderer";
  421. // Magic key
  422. private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
  423. }