1 /* 2 * Copyright (C) 2016 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.cts.verifier.sensors.sixdof.Renderer.Renderable; 17 18 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X; 19 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y; 20 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z; 21 22 import android.content.Context; 23 import android.graphics.SurfaceTexture; 24 import android.opengl.GLES11Ext; 25 import android.opengl.GLES20; 26 import android.opengl.Matrix; 27 import android.util.Log; 28 29 import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.CameraStreamManager; 30 import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters; 31 import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ShaderHelper; 32 33 import java.nio.ByteBuffer; 34 import java.nio.ByteOrder; 35 import java.nio.FloatBuffer; 36 37 /** 38 * Shows the camera preview as an opengl texture. 39 */ 40 public class CameraPreviewRenderable extends Renderable { 41 private static final String TAG = "CameraPreviewRenderable"; 42 private final int TEXTURE_COORDINATE_DATA_SIZE = 2; 43 private static final float[] CAMERA_TEXTURE_DATA = { 44 0.0f, 0.0f, 45 0.0f, 1.0f, 46 1.0f, 0.0f, 47 0.0f, 1.0f, 48 1.0f, 1.0f, 49 1.0f, 0.0f 50 }; 51 private static final float[] CAMERA_PREVIEW_POSITION = {0.0f, 0.0f, -3.0f}; 52 53 private FloatBuffer mPositionBuffer; 54 private FloatBuffer mTextureBuffer; 55 56 private int mTextureUniformHandle; 57 private int mTextureCoordinateHandle; 58 59 protected int mCameraTextureId = -1; 60 61 private SurfaceTexture mCameraSurfaceTexture; 62 private Context mContext; 63 private CameraStreamManager mCameraStreamManager; 64 private boolean mInvertAxis; 65 CameraPreviewRenderable()66 public CameraPreviewRenderable() { 67 // Reset the model matrix to the identity and move it so the OpenGL camera is looking at it. 68 Matrix.setIdentityM(getModelMatrix(), 0); 69 Matrix.translateM(getModelMatrix(), 0, 70 CAMERA_PREVIEW_POSITION[X], CAMERA_PREVIEW_POSITION[Y], CAMERA_PREVIEW_POSITION[Z]); 71 } 72 initialiseCameraPreview(float[] cameraPreviewPositionData, boolean invertAxis, Context context)73 public void initialiseCameraPreview(float[] cameraPreviewPositionData, boolean invertAxis, Context context) { 74 // float count / floats per vertex. 75 mVertexCount = cameraPreviewPositionData.length / POSITION_DATA_SIZE; 76 77 // Initialize the buffers. 78 mPositionBuffer = ByteBuffer.allocateDirect(cameraPreviewPositionData.length * BYTES_PER_FLOAT) 79 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 80 81 mTextureBuffer = ByteBuffer.allocateDirect(CAMERA_TEXTURE_DATA.length * BYTES_PER_FLOAT) 82 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 83 84 mPositionBuffer.put(cameraPreviewPositionData).position(0); 85 mTextureBuffer.put(CAMERA_TEXTURE_DATA).position(0); 86 87 final String vertexShader = ShaderHelper.getCameraPreviewVertexShader(); 88 final String fragmentShader = ShaderHelper.getCameraPreviewFragmentShader(); 89 90 final int vertexShaderHandle = 91 ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader); 92 final int fragmentShaderHandle = 93 ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader); 94 95 mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, 96 new String[]{"a_Position", "a_TexCoordinate"}); 97 98 mContext = context; 99 mInvertAxis = invertAxis; 100 connectCamera(); 101 } 102 103 @Override draw(DrawParameters drawParameters)104 public void draw(DrawParameters drawParameters) { 105 GLES20.glUseProgram(mProgramHandle); 106 107 // Set program handles for camera preview drawing. 108 mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix"); 109 mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix"); 110 mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture"); 111 mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position"); 112 mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate"); 113 114 // Set the active texture unit to texture unit 0. 115 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 116 117 // Bind the texture to this unit. 118 if (mCameraTextureId != -1) { 119 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mCameraTextureId); 120 } 121 122 // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0. 123 GLES20.glUniform1i(mTextureUniformHandle, 0); 124 125 // Compose the model, view, and projection matrices into a single m-v-p matrix 126 updateMvpMatrix(drawParameters.getViewMatrix(), drawParameters.getProjectionMatrix()); 127 128 drawCameraPreview(); 129 } 130 131 /** 132 * Draws a camera preview. 133 */ drawCameraPreview()134 private void drawCameraPreview() { 135 // Pass in the position information 136 mPositionBuffer.position(0); 137 GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 138 0, mPositionBuffer); 139 140 GLES20.glEnableVertexAttribArray(mPositionHandle); 141 142 // Pass in the texture coordinate information 143 mTextureBuffer.position(0); 144 GLES20.glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINATE_DATA_SIZE, GLES20.GL_FLOAT, false, 145 0, mTextureBuffer); 146 147 GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); 148 149 // Pass in the modelview matrix. 150 GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, getMvMatrix(), 0); 151 152 // Pass in the combined matrix. 153 GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, getMvpMatrix(), 0); 154 155 // Draw the camera preview. 156 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVertexCount); 157 } 158 159 /** 160 * Updates the texture with the latest camera data. 161 * 162 * @return the timestamp of the RGB image rendered into the texture. 163 */ updateTexture()164 public synchronized double updateTexture() { 165 double latestCameraFrameTimestamp = -1.0; 166 if (mCameraTextureId != -1) { 167 // Copy the camera frame from the camera to the OpenGL texture 168 mCameraSurfaceTexture.updateTexImage(); 169 latestCameraFrameTimestamp = mCameraSurfaceTexture.getTimestamp(); 170 } 171 return latestCameraFrameTimestamp; 172 } 173 174 /** 175 * Connects the camera to the OpenGl context 176 */ connectCamera()177 public void connectCamera() { 178 this.mCameraTextureId = connectCameraTexture(); 179 } 180 disconnectCamera()181 public void disconnectCamera() { 182 mCameraStreamManager.onStopCameraStream(); 183 } 184 185 /** 186 * Connects a texture to an Android camera 187 * 188 * @return textureId of texture with camera attached/ 189 */ connectCameraTexture()190 private int connectCameraTexture() { 191 if (mCameraTextureId == -1) { 192 mCameraTextureId = createEmptyTexture(); 193 mCameraSurfaceTexture = new SurfaceTexture(mCameraTextureId); 194 int width = mInvertAxis ? 1080 : 1920; 195 int height = mInvertAxis ? 1920 : 1080; 196 mCameraStreamManager = new CameraStreamManager(mContext, mCameraSurfaceTexture, width, height); 197 mCameraStreamManager.onStartCameraStream(); 198 } 199 return mCameraTextureId; 200 } 201 202 /** 203 * Creates an empty texture. 204 * 205 * @return textureId of empty texture. 206 */ createEmptyTexture()207 public static int createEmptyTexture() { 208 final int[] textureHandle = new int[1]; 209 210 GLES20.glGenTextures(1, textureHandle, 0); 211 212 if (textureHandle[0] != 0) { 213 return textureHandle[0]; 214 } 215 216 return -1; 217 } 218 219 @Override destroy()220 public void destroy() { 221 if (mCameraStreamManager != null) { 222 mCameraStreamManager.onStopCameraStream(); 223 mCameraStreamManager = null; 224 } 225 226 mPositionBuffer = null; 227 mTextureBuffer = null; 228 } 229 } 230