OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chromoting; | 5 package org.chromium.chromoting; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.graphics.Bitmap; | 8 import android.graphics.Bitmap; |
9 import android.graphics.BitmapFactory; | 9 import android.graphics.BitmapFactory; |
10 import android.graphics.PointF; | 10 import android.graphics.PointF; |
(...skipping 29 matching lines...) Expand all Loading... |
40 private static final float DESKTOP_POSITION_Y = 0.0f; | 40 private static final float DESKTOP_POSITION_Y = 0.0f; |
41 private static final float DESKTOP_POSITION_Z = -2.0f; | 41 private static final float DESKTOP_POSITION_Z = -2.0f; |
42 private static final float HALF_SKYBOX_SIZE = 100.0f; | 42 private static final float HALF_SKYBOX_SIZE = 100.0f; |
43 private static final float VIEW_POSITION_MIN = -1.0f; | 43 private static final float VIEW_POSITION_MIN = -1.0f; |
44 private static final float VIEW_POSITION_MAX = 3.0f; | 44 private static final float VIEW_POSITION_MAX = 3.0f; |
45 | 45 |
46 // Allows user to click even when looking outside the desktop | 46 // Allows user to click even when looking outside the desktop |
47 // but within edge margin. | 47 // but within edge margin. |
48 private static final float EDGE_MARGIN = 0.1f; | 48 private static final float EDGE_MARGIN = 0.1f; |
49 | 49 |
50 // Fix the desktop height and adjust width accordingly. | |
51 private static final float HALF_DESKTOP_HEIGHT = 1.0f; | |
52 | |
53 // Distance to move camera each time. | 50 // Distance to move camera each time. |
54 private static final float CAMERA_MOTION_STEP = 0.5f; | 51 private static final float CAMERA_MOTION_STEP = 0.5f; |
55 | 52 |
56 private static final FloatBuffer DESKTOP_TEXTURE_COORDINATES = makeFloatBuff
er(new float[] { | |
57 // Texture coordinate data. | |
58 0.0f, 0.0f, | |
59 0.0f, 1.0f, | |
60 1.0f, 0.0f, | |
61 0.0f, 1.0f, | |
62 1.0f, 1.0f, | |
63 1.0f, 0.0f | |
64 }); | |
65 | |
66 private static final FloatBuffer SKYBOX_POSITION_COORDINATES = makeFloatBuff
er(new float[] { | 53 private static final FloatBuffer SKYBOX_POSITION_COORDINATES = makeFloatBuff
er(new float[] { |
67 -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (0) Top
-left near | 54 -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (0) Top
-left near |
68 HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (1) Top-
right near | 55 HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (1) Top-
right near |
69 -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (2) Bot
tom-left near | 56 -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (2) Bot
tom-left near |
70 HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (3) Bott
om-right near | 57 HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (3) Bott
om-right near |
71 -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (4) Top
-left far | 58 -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (4) Top
-left far |
72 HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (5) Top-
right far | 59 HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (5) Top-
right far |
73 -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (6) Bot
tom-left far | 60 -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (6) Bot
tom-left far |
74 HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE // (7) Botto
m-right far | 61 HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE // (7) Botto
m-right far |
75 }); | 62 }); |
(...skipping 17 matching lines...) Expand all Loading... |
93 | 80 |
94 // Top | 81 // Top |
95 5, 1, 4, | 82 5, 1, 4, |
96 4, 1, 0, | 83 4, 1, 0, |
97 | 84 |
98 // Bottom | 85 // Bottom |
99 6, 2, 7, | 86 6, 2, 7, |
100 7, 2, 3 | 87 7, 2, 3 |
101 }); | 88 }); |
102 | 89 |
103 private static final String DESKTOP_VERTEX_SHADER = | |
104 "uniform mat4 u_CombinedMatrix;" | |
105 + "attribute vec4 a_Position;" | |
106 + "attribute vec2 a_TexCoordinate;" | |
107 + "varying vec2 v_TexCoordinate;" | |
108 + "void main() {" | |
109 + " v_TexCoordinate = a_TexCoordinate;" | |
110 + " gl_Position = u_CombinedMatrix * a_Position;" | |
111 + "}"; | |
112 | |
113 private static final String DESKTOP_FRAGMENT_SHADER = | |
114 "precision highp float;" | |
115 + "uniform sampler2D u_Texture;" | |
116 + "varying vec2 v_TexCoordinate;" | |
117 + "const float borderWidth = 0.002;" | |
118 + "void main() {" | |
119 + " if (v_TexCoordinate.x > (1.0 - borderWidth) || v_TexCoordinate.
x < borderWidth" | |
120 + " || v_TexCoordinate.y > (1.0 - borderWidth)" | |
121 + " || v_TexCoordinate.y < borderWidth) {" | |
122 + " gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);" | |
123 + " } else {" | |
124 + " gl_FragColor = texture2D(u_Texture, v_TexCoordinate);" | |
125 + " }" | |
126 + "}"; | |
127 | |
128 private static final String SKYBOX_VERTEX_SHADER = | 90 private static final String SKYBOX_VERTEX_SHADER = |
129 "uniform mat4 u_CombinedMatrix;" | 91 "uniform mat4 u_CombinedMatrix;" |
130 + "attribute vec3 a_Position;" | 92 + "attribute vec3 a_Position;" |
131 + "varying vec3 v_Position;" | 93 + "varying vec3 v_Position;" |
132 + "void main() {" | 94 + "void main() {" |
133 + " v_Position = a_Position;" | 95 + " v_Position = a_Position;" |
134 // Make sure to convert from the right-handed coordinate system of t
he | 96 // Make sure to convert from the right-handed coordinate system of t
he |
135 // world to the left-handed coordinate system of the cube map, other
wise, | 97 // world to the left-handed coordinate system of the cube map, other
wise, |
136 // our cube map will still work but everything will be flipped. | 98 // our cube map will still work but everything will be flipped. |
137 + " v_Position.z = -v_Position.z;" | 99 + " v_Position.z = -v_Position.z;" |
(...skipping 20 matching lines...) Expand all Loading... |
158 "https://dl.google.com/chrome-remote-desktop/android-assets/room_back.pn
g", | 120 "https://dl.google.com/chrome-remote-desktop/android-assets/room_back.pn
g", |
159 "https://dl.google.com/chrome-remote-desktop/android-assets/room_front.p
ng" | 121 "https://dl.google.com/chrome-remote-desktop/android-assets/room_front.p
ng" |
160 }; | 122 }; |
161 | 123 |
162 private static final String[] SKYBOX_IMAGE_NAMES = new String[] { | 124 private static final String[] SKYBOX_IMAGE_NAMES = new String[] { |
163 "skybox_left", "skybox_right", "skybox_bottom", "skybox_top", "skybox_ba
ck", "skybox_front" | 125 "skybox_left", "skybox_right", "skybox_bottom", "skybox_top", "skybox_ba
ck", "skybox_front" |
164 }; | 126 }; |
165 | 127 |
166 private final Activity mActivity; | 128 private final Activity mActivity; |
167 | 129 |
168 private float mHalfDesktopWidth; | |
169 private float mCameraPosition; | 130 private float mCameraPosition; |
170 | 131 |
171 // Lock to allow multithreaded access to mCameraPosition. | 132 // Lock to allow multithreaded access to mCameraPosition. |
172 private Object mCameraPositionLock = new Object(); | 133 private Object mCameraPositionLock = new Object(); |
173 | 134 |
174 private float[] mCameraMatrix; | 135 private float[] mCameraMatrix; |
175 private float[] mViewMatrix; | 136 private float[] mViewMatrix; |
176 private float[] mProjectionMatrix; | 137 private float[] mProjectionMatrix; |
177 | 138 |
178 // Make matrix member variable to avoid unnecessary initialization. | 139 // Make matrix member variable to avoid unnecessary initialization. |
179 private float[] mDesktopModelMatrix; | 140 private float[] mDesktopModelMatrix; |
180 private float[] mDesktopCombinedMatrix; | 141 private float[] mDesktopCombinedMatrix; |
181 private float[] mEyePointModelMatrix; | 142 private float[] mEyePointModelMatrix; |
182 private float[] mEyePointCombinedMatrix; | 143 private float[] mEyePointCombinedMatrix; |
183 private float[] mSkyboxModelMatrix; | 144 private float[] mSkyboxModelMatrix; |
184 private float[] mSkyboxCombinedMatrix; | 145 private float[] mSkyboxCombinedMatrix; |
185 | 146 |
186 // Direction that user is looking towards. | 147 // Direction that user is looking towards. |
187 private float[] mForwardVector; | 148 private float[] mForwardVector; |
188 | 149 |
189 // Eye position in desktop. | 150 // Eye position in desktop. |
190 private float[] mEyePositionVector; | 151 private float[] mEyePositionVector; |
191 | 152 |
192 private int mDesktopCombinedMatrixHandle; | |
193 private int mPositionHandle; | |
194 private int mTextureDataHandle; | |
195 private int mTextureUniformHandle; | |
196 private int mTextureCoordinateHandle; | |
197 private int mProgramHandle; | |
198 private int mDesktopVertexShaderHandle; | |
199 private int mDesktopFragmentShaderHandle; | |
200 private int mSkyboxVertexShaderHandle; | 153 private int mSkyboxVertexShaderHandle; |
201 private int mSkyboxFragmentShaderHandle; | 154 private int mSkyboxFragmentShaderHandle; |
202 private int mSkyboxProgramHandle; | 155 private int mSkyboxProgramHandle; |
203 private int mSkyboxPositionHandle; | 156 private int mSkyboxPositionHandle; |
204 private int mSkyboxCombinedMatrixHandle; | 157 private int mSkyboxCombinedMatrixHandle; |
205 private int mSkyboxTextureUnitHandle; | 158 private int mSkyboxTextureUnitHandle; |
206 private int mSkyboxTextureDataHandle; | 159 private int mSkyboxTextureDataHandle; |
| 160 private CardboardActivityDesktop mDesktop; |
207 private CardboardActivityEyePoint mEyePoint; | 161 private CardboardActivityEyePoint mEyePoint; |
208 | 162 |
209 // Flag to indicate whether reload the desktop texture or not. | 163 // Flag to indicate whether reload the desktop texture or not. |
210 private boolean mReloadTexture; | 164 private boolean mReloadTexture; |
211 | 165 |
212 /** Lock to allow multithreaded access to mReloadTexture. */ | 166 /** Lock to allow multithreaded access to mReloadTexture. */ |
213 private Object mReloadTextureLock = new Object(); | 167 private Object mReloadTextureLock = new Object(); |
214 | 168 |
215 // Lock for eye position related operations. | 169 // Lock for eye position related operations. |
216 // This protects access to mEyePositionVector as well as mDesktop{Height/Wid
th}Pixels. | 170 // This protects access to mEyePositionVector as well as mImageFrame in mDes
ktop. |
217 private Object mEyePositionLock = new Object(); | 171 private Object mEyePositionLock = new Object(); |
218 | 172 |
219 private int mDesktopHeightPixels; | |
220 private int mDesktopWidthPixels; | |
221 | |
222 private FloatBuffer mDesktopCoordinates; | |
223 | |
224 // Flag to signal that the skybox images are fully decoded and should be loa
ded | 173 // Flag to signal that the skybox images are fully decoded and should be loa
ded |
225 // into the OpenGL textures. | 174 // into the OpenGL textures. |
226 private boolean mLoadSkyboxImagesTexture; | 175 private boolean mLoadSkyboxImagesTexture; |
227 | 176 |
228 // Lock to allow multithreaded access to mLoadSkyboxImagesTexture. | 177 // Lock to allow multithreaded access to mLoadSkyboxImagesTexture. |
229 private Object mLoadSkyboxImagesTextureLock = new Object(); | 178 private Object mLoadSkyboxImagesTextureLock = new Object(); |
230 | 179 |
231 private ChromotingDownloadManager mDownloadManager; | 180 private ChromotingDownloadManager mDownloadManager; |
232 | 181 |
233 public CardboardDesktopRenderer(Activity activity) { | 182 public CardboardDesktopRenderer(Activity activity) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 public void onSurfaceCreated(EGLConfig config) { | 227 public void onSurfaceCreated(EGLConfig config) { |
279 // Set the background clear color to black. | 228 // Set the background clear color to black. |
280 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | 229 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
281 | 230 |
282 // Use culling to remove back faces. | 231 // Use culling to remove back faces. |
283 GLES20.glEnable(GLES20.GL_CULL_FACE); | 232 GLES20.glEnable(GLES20.GL_CULL_FACE); |
284 | 233 |
285 // Enable depth testing. | 234 // Enable depth testing. |
286 GLES20.glEnable(GLES20.GL_DEPTH_TEST); | 235 GLES20.glEnable(GLES20.GL_DEPTH_TEST); |
287 | 236 |
288 // Set handles for desktop drawing. | |
289 mDesktopVertexShaderHandle = | |
290 ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, DESKTOP_VERT
EX_SHADER); | |
291 mDesktopFragmentShaderHandle = | |
292 ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, DESKTOP_FR
AGMENT_SHADER); | |
293 mProgramHandle = ShaderHelper.createAndLinkProgram(mDesktopVertexShaderH
andle, | |
294 mDesktopFragmentShaderHandle, new String[] {"a_Position", "a_Tex
Coordinate"}); | |
295 mDesktopCombinedMatrixHandle = | |
296 GLES20.glGetUniformLocation(mProgramHandle, "u_CombinedMatrix"); | |
297 mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_T
exture"); | |
298 mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position
"); | |
299 mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a
_TexCoordinate"); | |
300 mTextureDataHandle = TextureHelper.createTextureHandle(); | |
301 | |
302 // Set handlers for skybox drawing. | 237 // Set handlers for skybox drawing. |
303 GLES20.glEnable(GLES20.GL_TEXTURE_CUBE_MAP); | 238 GLES20.glEnable(GLES20.GL_TEXTURE_CUBE_MAP); |
304 mSkyboxVertexShaderHandle = | 239 mSkyboxVertexShaderHandle = |
305 ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, SKYBOX_VERTE
X_SHADER); | 240 ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, SKYBOX_VERTE
X_SHADER); |
306 mSkyboxFragmentShaderHandle = | 241 mSkyboxFragmentShaderHandle = |
307 ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, SKYBOX_FRA
GMENT_SHADER); | 242 ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, SKYBOX_FRA
GMENT_SHADER); |
308 mSkyboxProgramHandle = ShaderHelper.createAndLinkProgram(mSkyboxVertexSh
aderHandle, | 243 mSkyboxProgramHandle = ShaderHelper.createAndLinkProgram(mSkyboxVertexSh
aderHandle, |
309 mSkyboxFragmentShaderHandle, | 244 mSkyboxFragmentShaderHandle, |
310 new String[] {"a_Position", "u_CombinedMatrix", "u_TextureUnit"}
); | 245 new String[] {"a_Position", "u_CombinedMatrix", "u_TextureUnit"}
); |
311 mSkyboxPositionHandle = | 246 mSkyboxPositionHandle = |
312 GLES20.glGetAttribLocation(mSkyboxProgramHandle, "a_Position"); | 247 GLES20.glGetAttribLocation(mSkyboxProgramHandle, "a_Position"); |
313 mSkyboxCombinedMatrixHandle = | 248 mSkyboxCombinedMatrixHandle = |
314 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_CombinedMat
rix"); | 249 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_CombinedMat
rix"); |
315 mSkyboxTextureUnitHandle = | 250 mSkyboxTextureUnitHandle = |
316 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_TextureUnit
"); | 251 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_TextureUnit
"); |
317 mSkyboxTextureDataHandle = TextureHelper.createTextureHandle(); | 252 mSkyboxTextureDataHandle = TextureHelper.createTextureHandle(); |
318 | 253 |
| 254 mDesktop = new CardboardActivityDesktop(); |
319 mEyePoint = new CardboardActivityEyePoint(); | 255 mEyePoint = new CardboardActivityEyePoint(); |
320 } | 256 } |
321 | 257 |
322 @Override | 258 @Override |
323 public void onSurfaceChanged(int width, int height) { | 259 public void onSurfaceChanged(int width, int height) { |
324 } | 260 } |
325 | 261 |
326 @Override | 262 @Override |
327 public void onNewFrame(HeadTransform headTransform) { | 263 public void onNewFrame(HeadTransform headTransform) { |
328 // Position the eye at the origin. | 264 // Position the eye at the origin. |
(...skipping 11 matching lines...) Expand all Loading... |
340 | 276 |
341 // Set our up vector. This is where our head would be pointing were we h
olding the camera. | 277 // Set our up vector. This is where our head would be pointing were we h
olding the camera. |
342 float upX = 0.0f; | 278 float upX = 0.0f; |
343 float upY = 1.0f; | 279 float upY = 1.0f; |
344 float upZ = 0.0f; | 280 float upZ = 0.0f; |
345 | 281 |
346 Matrix.setLookAtM(mCameraMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, look
Z, upX, upY, upZ); | 282 Matrix.setLookAtM(mCameraMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, look
Z, upX, upY, upZ); |
347 | 283 |
348 headTransform.getForwardVector(mForwardVector, 0); | 284 headTransform.getForwardVector(mForwardVector, 0); |
349 getLookingPosition(); | 285 getLookingPosition(); |
350 maybeLoadTexture(mTextureDataHandle); | 286 maybeLoadDesktopTexture(); |
351 maybeLoadCubeMapAndCleanImages(mSkyboxTextureDataHandle); | 287 maybeLoadCubeMapAndCleanImages(mSkyboxTextureDataHandle); |
352 } | 288 } |
353 | 289 |
354 @Override | 290 @Override |
355 public void onDrawEye(Eye eye) { | 291 public void onDrawEye(Eye eye) { |
356 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); | 292 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); |
357 | 293 |
358 // Apply the eye transformation to the camera. | 294 // Apply the eye transformation to the camera. |
359 Matrix.multiplyMM(mViewMatrix, 0, eye.getEyeView(), 0, mCameraMatrix, 0)
; | 295 Matrix.multiplyMM(mViewMatrix, 0, eye.getEyeView(), 0, mCameraMatrix, 0)
; |
360 | 296 |
361 mProjectionMatrix = eye.getPerspective(Z_NEAR, Z_FAR); | 297 mProjectionMatrix = eye.getPerspective(Z_NEAR, Z_FAR); |
362 | 298 |
363 drawSkybox(); | 299 drawSkybox(); |
364 drawDesktop(); | 300 drawDesktop(); |
365 drawEyePoint(); | 301 drawEyePoint(); |
366 } | 302 } |
367 | 303 |
368 @Override | 304 @Override |
369 public void onRendererShutdown() { | 305 public void onRendererShutdown() { |
370 GLES20.glDeleteShader(mDesktopVertexShaderHandle); | 306 mDesktop.cleanup(); |
371 GLES20.glDeleteShader(mDesktopFragmentShaderHandle); | |
372 mEyePoint.cleanup(); | 307 mEyePoint.cleanup(); |
373 GLES20.glDeleteShader(mSkyboxVertexShaderHandle); | 308 GLES20.glDeleteShader(mSkyboxVertexShaderHandle); |
374 GLES20.glDeleteShader(mSkyboxFragmentShaderHandle); | 309 GLES20.glDeleteShader(mSkyboxFragmentShaderHandle); |
375 GLES20.glDeleteTextures(1, new int[] {mTextureDataHandle}, 0); | |
376 GLES20.glDeleteTextures(1, new int[] {mSkyboxTextureDataHandle}, 0); | 310 GLES20.glDeleteTextures(1, new int[] {mSkyboxTextureDataHandle}, 0); |
377 mActivity.runOnUiThread(new Runnable() { | 311 mActivity.runOnUiThread(new Runnable() { |
378 public void run() { | 312 public void run() { |
379 mDownloadManager.close(); | 313 mDownloadManager.close(); |
380 } | 314 } |
381 }); | 315 }); |
382 } | 316 } |
383 | 317 |
384 @Override | 318 @Override |
385 public void onFinishFrame(Viewport viewport) { | 319 public void onFinishFrame(Viewport viewport) { |
386 } | 320 } |
387 | 321 |
388 private void drawDesktop() { | 322 private void drawDesktop() { |
389 GLES20.glUseProgram(mProgramHandle); | 323 synchronized (mEyePositionLock) { |
| 324 if (!mDesktop.hasImageFrame()) { |
| 325 // This can happen if the client is connected, but a complete |
| 326 // video frame has not yet been decoded. |
| 327 return; |
| 328 } |
| 329 } |
390 | 330 |
391 // Translate the desktop model. | 331 |
392 Matrix.setIdentityM(mDesktopModelMatrix, 0); | 332 Matrix.setIdentityM(mDesktopModelMatrix, 0); |
393 Matrix.translateM(mDesktopModelMatrix, 0, DESKTOP_POSITION_X, | 333 Matrix.translateM(mDesktopModelMatrix, 0, DESKTOP_POSITION_X, |
394 DESKTOP_POSITION_Y, DESKTOP_POSITION_Z); | 334 DESKTOP_POSITION_Y, DESKTOP_POSITION_Z); |
395 | 335 |
396 // Pass in Model View Matrix and Model View Project Matrix. | 336 // Pass in Model View Matrix and Model View Project Matrix. |
397 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mViewMatrix, 0, mDesktopMod
elMatrix, 0); | 337 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mViewMatrix, 0, mDesktopMod
elMatrix, 0); |
398 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mProjectionMatrix, | 338 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mProjectionMatrix, |
399 0, mDesktopCombinedMatrix, 0); | 339 0, mDesktopCombinedMatrix, 0); |
| 340 mDesktop.setCombinedMatrix(mDesktopCombinedMatrix); |
400 | 341 |
401 // Pass in model view project matrix. | 342 mDesktop.draw(); |
402 GLES20.glUniformMatrix4fv(mDesktopCombinedMatrixHandle, 1, false, | |
403 mDesktopCombinedMatrix, 0); | |
404 | |
405 if (mDesktopCoordinates == null) { | |
406 // This can happen if the client is connected, but a complete video
frame has not yet | |
407 // been decoded. | |
408 return; | |
409 } | |
410 // Pass in the desktop position. | |
411 GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20
.GL_FLOAT, false, | |
412 0, mDesktopCoordinates); | |
413 GLES20.glEnableVertexAttribArray(mPositionHandle); | |
414 | |
415 // Pass in texture coordinate. | |
416 GLES20.glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINAT
E_DATA_SIZE, | |
417 GLES20.GL_FLOAT, false, 0, DESKTOP_TEXTURE_COORDINATES); | |
418 GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); | |
419 | |
420 // Pass in texture data. | |
421 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); | |
422 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle); | |
423 GLES20.glUniform1i(mTextureUniformHandle, 0); | |
424 | |
425 // Draw the desktop. | |
426 int totalPointNumber = 6; | |
427 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, totalPointNumber); | |
428 } | 343 } |
429 | 344 |
430 private void drawEyePoint() { | 345 private void drawEyePoint() { |
431 if (!isLookingAtDesktop()) { | 346 if (!isLookingAtDesktop()) { |
432 return; | 347 return; |
433 } | 348 } |
434 | 349 |
435 float eyePointX = clamp(mEyePositionVector[0], -mHalfDesktopWidth, | 350 float eyePointX = clamp(mEyePositionVector[0], -mDesktop.getHalfWidth(), |
436 mHalfDesktopWidth); | 351 mDesktop.getHalfWidth()); |
437 float eyePointY = clamp(mEyePositionVector[1], -HALF_DESKTOP_HEIGHT, | 352 float eyePointY = clamp(mEyePositionVector[1], -mDesktop.getHalfHeight()
, |
438 HALF_DESKTOP_HEIGHT); | 353 mDesktop.getHalfHeight()); |
439 Matrix.setIdentityM(mEyePointModelMatrix, 0); | 354 Matrix.setIdentityM(mEyePointModelMatrix, 0); |
440 Matrix.translateM(mEyePointModelMatrix, 0, -eyePointX, -eyePointY, | 355 Matrix.translateM(mEyePointModelMatrix, 0, -eyePointX, -eyePointY, |
441 DESKTOP_POSITION_Z); | 356 DESKTOP_POSITION_Z); |
442 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mViewMatrix, 0, mEyePointM
odelMatrix, 0); | 357 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mViewMatrix, 0, mEyePointM
odelMatrix, 0); |
443 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mProjectionMatrix, | 358 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mProjectionMatrix, |
444 0, mEyePointCombinedMatrix, 0); | 359 0, mEyePointCombinedMatrix, 0); |
445 | 360 |
446 mEyePoint.setCombinedMatrix(mEyePointCombinedMatrix); | 361 mEyePoint.setCombinedMatrix(mEyePointCombinedMatrix); |
447 mEyePoint.draw(); | 362 mEyePoint.draw(); |
448 } | 363 } |
(...skipping 21 matching lines...) Expand all Loading... |
470 } | 385 } |
471 | 386 |
472 /** | 387 /** |
473 * Returns coordinates in units of pixels in the desktop bitmap. | 388 * Returns coordinates in units of pixels in the desktop bitmap. |
474 * This can be called on any thread. | 389 * This can be called on any thread. |
475 */ | 390 */ |
476 public PointF getMouseCoordinates() { | 391 public PointF getMouseCoordinates() { |
477 PointF result = new PointF(); | 392 PointF result = new PointF(); |
478 synchronized (mEyePositionLock) { | 393 synchronized (mEyePositionLock) { |
479 // Due to the coordinate direction, we only have to inverse x. | 394 // Due to the coordinate direction, we only have to inverse x. |
480 result.x = (-mEyePositionVector[0] + mHalfDesktopWidth) | 395 result.x = (-mEyePositionVector[0] + mDesktop.getHalfWidth()) |
481 / (2 * mHalfDesktopWidth) * mDesktopWidthPixels; | 396 / (2 * mDesktop.getHalfWidth()) * mDesktop.getWidthPixels(); |
482 result.y = (mEyePositionVector[1] + HALF_DESKTOP_HEIGHT) | 397 result.y = (mEyePositionVector[1] + mDesktop.getHalfHeight()) |
483 / (2 * HALF_DESKTOP_HEIGHT) * mDesktopHeightPixels; | 398 / (2 * mDesktop.getHalfHeight()) * mDesktop.getHeightPixels(
); |
484 result.x = clamp(result.x, 0, mDesktopWidthPixels); | 399 result.x = clamp(result.x, 0, mDesktop.getWidthPixels()); |
485 result.y = clamp(result.y, 0, mDesktopHeightPixels); | 400 result.y = clamp(result.y, 0, mDesktop.getHeightPixels()); |
486 } | 401 } |
487 return result; | 402 return result; |
488 } | 403 } |
489 | 404 |
490 /** | 405 /** |
491 * Returns the passed in value if it resides within the specified range (inc
lusive). If not, | 406 * Returns the passed in value if it resides within the specified range (inc
lusive). If not, |
492 * it will return the closest boundary from the range. The ordering of the
boundary values | 407 * it will return the closest boundary from the range. The ordering of the
boundary values |
493 * does not matter. | 408 * does not matter. |
494 * | 409 * |
495 * @param value The value to be compared against the range. | 410 * @param value The value to be compared against the range. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 } | 448 } |
534 } | 449 } |
535 } | 450 } |
536 | 451 |
537 /** | 452 /** |
538 * Return true if user is looking at the desktop. | 453 * Return true if user is looking at the desktop. |
539 * This method can be called on any thread. | 454 * This method can be called on any thread. |
540 */ | 455 */ |
541 public boolean isLookingAtDesktop() { | 456 public boolean isLookingAtDesktop() { |
542 synchronized (mEyePositionLock) { | 457 synchronized (mEyePositionLock) { |
543 return Math.abs(mEyePositionVector[0]) <= (mHalfDesktopWidth + EDGE_
MARGIN) | 458 return Math.abs(mEyePositionVector[0]) <= (mDesktop.getHalfWidth() +
EDGE_MARGIN) |
544 && Math.abs(mEyePositionVector[1]) <= (HALF_DESKTOP_HEIGHT + EDG
E_MARGIN); | 459 && Math.abs(mEyePositionVector[1]) <= (mDesktop.getHalfHeight()
+ EDGE_MARGIN); |
545 } | 460 } |
546 } | 461 } |
547 | 462 |
548 /** | 463 /** |
549 * Return true if user is looking at the space to the left of the desktop. | 464 * Return true if user is looking at the space to the left of the desktop. |
550 * This method can be called on any thread. | 465 * This method can be called on any thread. |
551 */ | 466 */ |
552 public boolean isLookingLeftOfDesktop() { | 467 public boolean isLookingLeftOfDesktop() { |
553 synchronized (mEyePositionLock) { | 468 synchronized (mEyePositionLock) { |
554 return mEyePositionVector[0] >= (mHalfDesktopWidth + EDGE_MARGIN); | 469 return mEyePositionVector[0] >= (mDesktop.getHalfWidth() + EDGE_MARG
IN); |
555 } | 470 } |
556 } | 471 } |
557 | 472 |
558 /** | 473 /** |
559 * Return true if user is looking at the space to the right of the desktop. | 474 * Return true if user is looking at the space to the right of the desktop. |
560 * This method can be called on any thread. | 475 * This method can be called on any thread. |
561 */ | 476 */ |
562 public boolean isLookingRightOfDesktop() { | 477 public boolean isLookingRightOfDesktop() { |
563 synchronized (mEyePositionLock) { | 478 synchronized (mEyePositionLock) { |
564 return mEyePositionVector[0] <= -(mHalfDesktopWidth + EDGE_MARGIN); | 479 return mEyePositionVector[0] <= -(mDesktop.getHalfWidth() + EDGE_MAR
GIN); |
565 } | 480 } |
566 } | 481 } |
567 | 482 |
568 /** | 483 /** |
569 * Return true if user is looking at the space above the desktop. | 484 * Return true if user is looking at the space above the desktop. |
570 * This method can be called on any thread. | 485 * This method can be called on any thread. |
571 */ | 486 */ |
572 public boolean isLookingAboveDesktop() { | 487 public boolean isLookingAboveDesktop() { |
573 synchronized (mEyePositionLock) { | 488 synchronized (mEyePositionLock) { |
574 return mEyePositionVector[1] <= -(HALF_DESKTOP_HEIGHT + EDGE_MARGIN)
; | 489 return mEyePositionVector[1] <= -(mDesktop.getHalfHeight() + EDGE_MA
RGIN); |
575 } | 490 } |
576 } | 491 } |
577 | 492 |
578 /** | 493 /** |
579 * Return true if user is looking at the space below the desktop. | 494 * Return true if user is looking at the space below the desktop. |
580 * This method can be called on any thread. | 495 * This method can be called on any thread. |
581 */ | 496 */ |
582 public boolean isLookingBelowDesktop() { | 497 public boolean isLookingBelowDesktop() { |
583 synchronized (mEyePositionLock) { | 498 synchronized (mEyePositionLock) { |
584 return mEyePositionVector[1] >= (HALF_DESKTOP_HEIGHT + EDGE_MARGIN); | 499 return mEyePositionVector[1] >= (mDesktop.getHalfHeight() + EDGE_MAR
GIN); |
585 } | 500 } |
586 } | 501 } |
587 | 502 |
588 /** | 503 /** |
589 * Get position on desktop where user is looking at. | 504 * Get position on desktop where user is looking at. |
590 */ | 505 */ |
591 private void getLookingPosition() { | 506 private void getLookingPosition() { |
592 synchronized (mEyePositionLock) { | 507 synchronized (mEyePositionLock) { |
593 if (Math.abs(mForwardVector[2]) < 0.00001f) { | 508 if (Math.abs(mForwardVector[2]) < 0.00001f) { |
594 mEyePositionVector[0] = Math.signum(mForwardVector[0]) * Float.M
AX_VALUE; | 509 mEyePositionVector[0] = Math.signum(mForwardVector[0]) * Float.M
AX_VALUE; |
595 mEyePositionVector[1] = Math.signum(mForwardVector[1]) * Float.M
AX_VALUE; | 510 mEyePositionVector[1] = Math.signum(mForwardVector[1]) * Float.M
AX_VALUE; |
596 } else { | 511 } else { |
597 mEyePositionVector[0] = mForwardVector[0] * DESKTOP_POSITION_Z /
mForwardVector[2]; | 512 mEyePositionVector[0] = mForwardVector[0] * DESKTOP_POSITION_Z /
mForwardVector[2]; |
598 mEyePositionVector[1] = mForwardVector[1] * DESKTOP_POSITION_Z /
mForwardVector[2]; | 513 mEyePositionVector[1] = mForwardVector[1] * DESKTOP_POSITION_Z /
mForwardVector[2]; |
599 } | 514 } |
600 mEyePositionVector[2] = DESKTOP_POSITION_Z; | 515 mEyePositionVector[2] = DESKTOP_POSITION_Z; |
601 } | 516 } |
602 } | 517 } |
603 | 518 |
604 /** | 519 /** |
605 * Link desktop texture with textureDataHandle if {@link mReloadTexture} is
true. | 520 * Link desktop texture with {@link CardboardActivityDesktop} if {@link mRel
oadTexture} is true. |
606 * @param textureDataHandle the handle we want attach texture to | 521 * @param textureDataHandle the handle we want attach texture to |
607 */ | 522 */ |
608 private void maybeLoadTexture(int textureDataHandle) { | 523 private void maybeLoadDesktopTexture() { |
609 synchronized (mReloadTextureLock) { | 524 synchronized (mReloadTextureLock) { |
610 if (!mReloadTexture) { | 525 if (!mReloadTexture) { |
611 return; | 526 return; |
612 } | 527 } |
613 } | 528 } |
614 | 529 |
615 // TODO(shichengfeng): Record the time desktop drawing takes. | 530 // TODO(shichengfeng): Record the time desktop drawing takes. |
616 Bitmap bitmap = JniInterface.getVideoFrame(); | 531 Bitmap bitmap = JniInterface.getVideoFrame(); |
617 | 532 |
618 if (bitmap == null) { | 533 if (bitmap == null) { |
619 // This can happen if the client is connected, but a complete video
frame has not yet | 534 // This can happen if the client is connected, but a complete video
frame has not yet |
620 // been decoded. | 535 // been decoded. |
621 return; | 536 return; |
622 } | 537 } |
623 | 538 |
624 synchronized (mEyePositionLock) { | 539 synchronized (mEyePositionLock) { |
625 mDesktopHeightPixels = bitmap.getHeight(); | 540 mDesktop.setImageFrame(bitmap); |
626 mDesktopWidthPixels = bitmap.getWidth(); | 541 mDesktop.updateFrameData(); |
627 } | 542 } |
628 | 543 |
629 updateDesktopCoordinatesBuffer(bitmap); | |
630 TextureHelper.linkTexture(textureDataHandle, bitmap); | |
631 | |
632 synchronized (mReloadTextureLock) { | 544 synchronized (mReloadTextureLock) { |
633 mReloadTexture = false; | 545 mReloadTexture = false; |
634 } | 546 } |
635 } | 547 } |
636 | 548 |
637 /** | 549 /** |
638 * Convert float array to a FloatBuffer for use in OpenGL calls. | 550 * Convert float array to a FloatBuffer for use in OpenGL calls. |
639 */ | 551 */ |
640 private static FloatBuffer makeFloatBuffer(float[] data) { | 552 public static FloatBuffer makeFloatBuffer(float[] data) { |
641 FloatBuffer result = ByteBuffer | 553 FloatBuffer result = ByteBuffer |
642 .allocateDirect(data.length * BYTE_PER_FLOAT) | 554 .allocateDirect(data.length * BYTE_PER_FLOAT) |
643 .order(ByteOrder.nativeOrder()).asFloatBuffer(); | 555 .order(ByteOrder.nativeOrder()).asFloatBuffer(); |
644 result.put(data).position(0); | 556 result.put(data).position(0); |
645 return result; | 557 return result; |
646 } | 558 } |
647 | 559 |
648 /** | 560 /** |
649 * Update the desktop coordinates based on the new bitmap. Note here we fix
the | |
650 * height of the desktop and vary width accordingly. | |
651 */ | |
652 private void updateDesktopCoordinatesBuffer(Bitmap bitmap) { | |
653 int width = bitmap.getWidth(); | |
654 int height = bitmap.getHeight(); | |
655 float newHalfDesktopWidth = width * HALF_DESKTOP_HEIGHT / height; | |
656 if (Math.abs(mHalfDesktopWidth - newHalfDesktopWidth) > 0.0001) { | |
657 mHalfDesktopWidth = newHalfDesktopWidth; | |
658 mDesktopCoordinates = makeFloatBuffer(new float[] { | |
659 // Desktop model coordinates. | |
660 -mHalfDesktopWidth, HALF_DESKTOP_HEIGHT, 0.0f, | |
661 -mHalfDesktopWidth, -HALF_DESKTOP_HEIGHT, 0.0f, | |
662 mHalfDesktopWidth, HALF_DESKTOP_HEIGHT, 0.0f, | |
663 -mHalfDesktopWidth, -HALF_DESKTOP_HEIGHT, 0.0f, | |
664 mHalfDesktopWidth, -HALF_DESKTOP_HEIGHT, 0.0f, | |
665 mHalfDesktopWidth, HALF_DESKTOP_HEIGHT, 0.0f | |
666 }); | |
667 } | |
668 } | |
669 | |
670 /** | |
671 * Decode all skybox images to Bitmap files and return them. | 561 * Decode all skybox images to Bitmap files and return them. |
672 * Only call this method when we have complete skybox images. | 562 * Only call this method when we have complete skybox images. |
673 * @throws DecodeFileException if BitmapFactory fails to decode file. | 563 * @throws DecodeFileException if BitmapFactory fails to decode file. |
674 */ | 564 */ |
675 private Bitmap[] decodeSkyboxImages() throws DecodeFileException { | 565 private Bitmap[] decodeSkyboxImages() throws DecodeFileException { |
676 Bitmap[] result = new Bitmap[SKYBOX_IMAGE_NAMES.length]; | 566 Bitmap[] result = new Bitmap[SKYBOX_IMAGE_NAMES.length]; |
677 String fileDirectory = mDownloadManager.getDownloadDirectory(); | 567 String fileDirectory = mDownloadManager.getDownloadDirectory(); |
678 for (int i = 0; i < SKYBOX_IMAGE_NAMES.length; i++) { | 568 for (int i = 0; i < SKYBOX_IMAGE_NAMES.length; i++) { |
679 result[i] = BitmapFactory.decodeFile(fileDirectory + "/" + SKYBOX_IM
AGE_NAMES[i]); | 569 result[i] = BitmapFactory.decodeFile(fileDirectory + "/" + SKYBOX_IM
AGE_NAMES[i]); |
680 if (result[i] == null) { | 570 if (result[i] == null) { |
(...skipping 28 matching lines...) Expand all Loading... |
709 image.recycle(); | 599 image.recycle(); |
710 } | 600 } |
711 } | 601 } |
712 | 602 |
713 /** | 603 /** |
714 * Exception when BitmapFactory fails to decode file. | 604 * Exception when BitmapFactory fails to decode file. |
715 */ | 605 */ |
716 private static class DecodeFileException extends Exception { | 606 private static class DecodeFileException extends Exception { |
717 } | 607 } |
718 } | 608 } |
OLD | NEW |