• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
17 
18 import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.CameraStreamManager;
19 import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
20 import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.CameraPreviewRenderable;
21 import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
22 import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseProvider;
23 
24 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.MATRIX_4X4;
25 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.ORIENTATION_360_ANTI_CLOCKWISE;
26 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
27 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
28 import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
29 
30 import android.content.Context;
31 import android.content.res.Configuration;
32 import android.content.res.Resources;
33 import android.opengl.GLES20;
34 import android.opengl.GLSurfaceView;
35 import android.opengl.Matrix;
36 import android.util.Log;
37 import android.view.Display;
38 import android.view.Surface;
39 import android.view.WindowManager;
40 
41 import javax.microedition.khronos.egl.EGLConfig;
42 import javax.microedition.khronos.opengles.GL10;
43 
44 /**
45  * Abstract class that connects to Android Camera to use as an OpenGL texture.
46  */
47 public abstract class BaseRenderer implements GLSurfaceView.Renderer {
48     private static final String TAG = "BaseRenderer";
49     private static final int ORIENTATION_COUNT = 4;
50 
51     protected float[] mViewMatrix = new float[MATRIX_4X4];
52     protected float[] mOrthogonalViewMatrix = new float[MATRIX_4X4];
53     protected float[] mProjectionMatrix = new float[MATRIX_4X4];
54 
55     protected float[] mOrthogonalProjectionMatrix = new float[MATRIX_4X4];
56     protected float[] mFrustrumProjectionMatrix = new float[MATRIX_4X4];
57 
58     protected DrawParameters mDrawParameters;
59 
60     protected float[] mCameraCoordinates;
61 
62     protected PoseProvider mPoseProvider;
63     protected boolean mIsValid = false;
64 
65     protected CameraPreviewRenderable mCameraPreview;
66     protected double mLastRGBFrameTimestamp = -1;
67 
68     private int mCameraPreviewRotation = 0;
69 
70     protected int mOpenGlRotation = 0;
71     protected float[] mOpenGlUpVector;
72 
73     private Context mContext;
74 
BaseRenderer(Context context)75     public BaseRenderer(Context context) {
76         mContext = context;
77         mOpenGlRotation = getDeviceRotation(context);
78         mOpenGlUpVector = getUpVector(mOpenGlRotation);
79         mCameraPreviewRotation = CameraStreamManager.getRotation(context, mOpenGlRotation);
80     }
81 
82     @Override
onSurfaceCreated(GL10 glUnused, EGLConfig config)83     public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
84         // Set the background clear color to black.
85         GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
86 
87         // Enable depth testing
88         GLES20.glEnable(GLES20.GL_DEPTH_TEST);
89 
90         mCameraPreview = new CameraPreviewRenderable();
91 
92         resetViewMatrix();
93     }
94 
resetViewMatrix()95     protected void resetViewMatrix() {
96         // Position the eye in front of the origin.
97         final float eyeX = 0.0f;
98         final float eyeY = 0.0f;
99         final float eyeZ = 0.0f;
100 
101         // We are looking toward the distance
102         final float lookX = 0.0f;
103         final float lookY = 0.0f;
104         final float lookZ = -5.0f;
105 
106         // Set our up vector. This is where our head would be pointing were we holding the camera.
107         float[] upVector = getUpVector(mCameraPreviewRotation);
108 
109         // Set the view matrix.
110         Matrix.setLookAtM(mViewMatrix, 0,
111                 eyeX, eyeY, eyeZ,
112                 lookX, lookY, lookZ,
113                 upVector[X], upVector[Y], upVector[Z]);
114         Matrix.setLookAtM(mOrthogonalViewMatrix, 0,
115                 eyeX, eyeY, eyeZ,
116                 lookX, lookY, lookZ,
117                 upVector[X], upVector[Y], upVector[Z]);
118     }
119 
120     @Override
onSurfaceChanged(GL10 glUnused, int width, int height)121     public void onSurfaceChanged(GL10 glUnused, int width, int height) {
122         // Set the OpenGL viewport to the same size as the surface.
123         GLES20.glViewport(0, 0, width, height);
124 
125         // Create a new perspective projection matrix. The height will stay the same
126         // while the width will vary as per aspect ratio.
127         // This project matrix does not take into account the camera intrinsics and should not be
128         // used for AR purposes.
129         final float ratio = (float) width / height;
130         float left = -ratio;
131         float right = ratio;
132         float bottom = -1.0f;
133         float top = 1.0f;
134         final float near = 1.0f;
135         final float far = 10.0f;
136 
137         boolean invertAxis = false;
138 
139         switch (mCameraPreviewRotation) {
140             case MathsUtils.ORIENTATION_0:
141             case MathsUtils.ORIENTATION_180_ANTI_CLOCKWISE:
142             case MathsUtils.ORIENTATION_360_ANTI_CLOCKWISE:
143                 break;
144             case MathsUtils.ORIENTATION_90_ANTI_CLOCKWISE:
145             case MathsUtils.ORIENTATION_270_ANTI_CLOCKWISE:
146                 // Invert aspect ratio.
147                 invertAxis = true;
148                 bottom = -ratio;
149                 top = ratio;
150                 left = -1.0f;
151                 right = 1.0f;
152                 break;
153             default:
154                 // Unexpected orientation, error out.
155                 throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
156         }
157 
158         mCameraCoordinates = getCameraCoordinates(left, right, bottom, top);
159 
160         // Give camera preview reference to the context so that it can connect to the camera.
161         mCameraPreview.initialiseCameraPreview(mCameraCoordinates, invertAxis, mContext);
162 
163         Matrix.orthoM(mOrthogonalProjectionMatrix, 0, left, right, bottom, top, near, far);
164         Matrix.frustumM(mFrustrumProjectionMatrix, 0, left, right, bottom, top, near, far);
165 
166         mProjectionMatrix = mOrthogonalProjectionMatrix;
167 
168         mDrawParameters = new DrawParameters();
169 
170         mIsValid = true;
171     }
172 
173     @Override
onDrawFrame(GL10 glUnused)174     public void onDrawFrame(GL10 glUnused) {
175         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
176         doPreRenderingSetup();
177         doCoreRendering();
178         doTestSpecificRendering();
179     }
180 
doCoreRendering()181     private void doCoreRendering() {
182         mDrawParameters.update(mViewMatrix, mProjectionMatrix);
183         mCameraPreview.draw(mDrawParameters);
184     }
185 
updateCameraTexture()186     protected synchronized void updateCameraTexture() {
187         mLastRGBFrameTimestamp = mCameraPreview.updateTexture();
188     }
189 
190     /**
191      * Setup up view and projecttion matrices to be the ones you want for this draw call.
192      */
doPreRenderingSetup()193     protected abstract void doPreRenderingSetup();
194 
195     /**
196      * Do rendering that is unique to each test.
197      */
doTestSpecificRendering()198     protected abstract void doTestSpecificRendering();
199 
200     /**
201      * Where to position the camera preview on the screen. Can be overridden by sub classes.
202      */
getCameraCoordinates(float left, float right, float bottom, float top)203     protected float[] getCameraCoordinates(float left, float right, float bottom, float top) {
204         switch (mCameraPreviewRotation) {
205             case MathsUtils.ORIENTATION_0:
206             case MathsUtils.ORIENTATION_180_ANTI_CLOCKWISE:
207             case MathsUtils.ORIENTATION_360_ANTI_CLOCKWISE:
208                 // Normal aspect ratio.
209                 return new float[]{
210                         left, top, 0.0f,
211                         left, bottom, 0.0f,
212                         right, top, 0.0f,
213                         left, bottom, 0.0f,
214                         right, bottom, 0.0f,
215                         right, top, 0.0f,
216                 };
217             case MathsUtils.ORIENTATION_90_ANTI_CLOCKWISE:
218             case MathsUtils.ORIENTATION_270_ANTI_CLOCKWISE:
219                 // Inverted aspect ratio.
220                 return new float[]{
221                         bottom, right, 0.0f,
222                         bottom, left, 0.0f,
223                         top, right, 0.0f,
224                         bottom, left, 0.0f,
225                         top, left, 0.0f,
226                         top, right, 0.0f,
227                 };
228             default:
229                 // Unexpected orientation, error out.
230                 throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
231         }
232     }
233 
234 
235     /**
236      * Saves PoseProvider object for later so we can connect to camera at appropriate time.
237      */
connectCamera(PoseProvider poseProvider, Context context)238     public void connectCamera(PoseProvider poseProvider, Context context) {
239         // Save these for later so we can connect to camera after mCameraPreview has been
240         // initialised. Also used to setup extrinsics in ComplexMovementRenderer.
241         mPoseProvider = poseProvider;
242         mContext = context;
243     }
244 
disconnectCamera()245     public void disconnectCamera() {
246         mCameraPreview.disconnectCamera();
247     }
248 
onDestroy()249     public void onDestroy() {
250         mPoseProvider = null;
251         mContext = null;
252 
253         if (mCameraPreview != null) {
254             mCameraPreview.destroy();
255             mCameraPreview = null;
256         }
257     }
258 
getUpVector(int rotation)259     private static float[] getUpVector(int rotation) {
260         float [] upVector = new float[MathsUtils.VECTOR_3D];
261 
262         switch (rotation) {
263             case MathsUtils.ORIENTATION_0:
264             case ORIENTATION_360_ANTI_CLOCKWISE:
265                 upVector[X] = 0.0f;
266                 upVector[Y] = 1.0f;
267                 upVector[Z] = 0.0f;
268                 break;
269             case MathsUtils.ORIENTATION_90_ANTI_CLOCKWISE:
270                 upVector[X] = -1.0f;
271                 upVector[Y] = 0.0f;
272                 upVector[Z] = 0.0f;
273                 break;
274             case MathsUtils.ORIENTATION_180_ANTI_CLOCKWISE:
275                 upVector[X] = 0.0f;
276                 upVector[Y] = -1.0f;
277                 upVector[Z] = 0.0f;
278                 break;
279             case MathsUtils.ORIENTATION_270_ANTI_CLOCKWISE:
280                 upVector[X] = 1.0f;
281                 upVector[Y] = 0.0f;
282                 upVector[Z] = 0.0f;
283                 break;
284             default:
285                 // Unexpected orientation, error out.
286                 throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
287         }
288 
289         return upVector;
290     }
291 
getDeviceRotation(Context context)292     public static int getDeviceRotation(Context context) {
293         WindowManager windowManager = (WindowManager)
294                 context.getSystemService(Context.WINDOW_SERVICE);
295         final Display display = windowManager.getDefaultDisplay();
296         int naturalOrientation = Configuration.ORIENTATION_LANDSCAPE;
297         int configOrientation = context.getResources().getConfiguration().orientation;
298         switch (display.getRotation()) {
299             case Surface.ROTATION_0:
300             case Surface.ROTATION_180:
301                 // We are currently in the same basic orientation as the natural orientation.
302                 naturalOrientation = configOrientation;
303                 break;
304             case Surface.ROTATION_90:
305             case Surface.ROTATION_270:
306                 // We are currently in the other basic orientation to the natural orientation.
307                 naturalOrientation = (configOrientation == Configuration.ORIENTATION_LANDSCAPE) ?
308                         Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
309                 break;
310             default:
311                 // Unexpected orientation, error out.
312                 throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
313         }
314 
315         // Since the map starts at portrait, we need to offset if this device's natural orientation
316         // is landscape.
317         int indexOffset = 0;
318         if (naturalOrientation == Configuration.ORIENTATION_LANDSCAPE) {
319             indexOffset = 1;
320         }
321 
322         // Get rotation as a clockwise rotation.
323         int currentRotation = ORIENTATION_COUNT - display.getRotation();
324 
325         // Check for reverse rotation direction and currentRotation if required.
326         try {
327             if (context.getResources().getBoolean(context.getResources().getSystem().getIdentifier(
328                     "config_reverseDefaultRotation", "bool", "android"))) {
329                 currentRotation = display.getRotation();
330             }
331         } catch (Resources.NotFoundException e) {
332             // If resource is not found, assume default rotation and continue.
333             Log.d(TAG, "Cannot determine device rotation direction, assuming default");
334         }
335 
336         int currentOrientation = (currentRotation + indexOffset);
337         int defaultOrientation = indexOffset;
338 
339         int difference = (currentOrientation - defaultOrientation) % ORIENTATION_COUNT;
340         difference = difference * 90;
341 
342         return difference;
343     }
344 }
345