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.Point; |
10 import android.graphics.PointF; | 11 import android.graphics.PointF; |
11 import android.opengl.GLES20; | 12 import android.opengl.GLES20; |
12 import android.opengl.Matrix; | 13 import android.opengl.Matrix; |
13 | 14 |
14 import com.google.vrtoolkit.cardboard.CardboardView; | 15 import com.google.vrtoolkit.cardboard.CardboardView; |
15 import com.google.vrtoolkit.cardboard.Eye; | 16 import com.google.vrtoolkit.cardboard.Eye; |
16 import com.google.vrtoolkit.cardboard.HeadTransform; | 17 import com.google.vrtoolkit.cardboard.HeadTransform; |
17 import com.google.vrtoolkit.cardboard.Viewport; | 18 import com.google.vrtoolkit.cardboard.Viewport; |
18 | 19 |
19 import org.chromium.base.Log; | 20 import org.chromium.base.Log; |
(...skipping 20 matching lines...) Expand all Loading... |
40 private static final float DESKTOP_POSITION_Y = 0.0f; | 41 private static final float DESKTOP_POSITION_Y = 0.0f; |
41 private static final float DESKTOP_POSITION_Z = -2.0f; | 42 private static final float DESKTOP_POSITION_Z = -2.0f; |
42 private static final float HALF_SKYBOX_SIZE = 100.0f; | 43 private static final float HALF_SKYBOX_SIZE = 100.0f; |
43 private static final float VIEW_POSITION_MIN = -1.0f; | 44 private static final float VIEW_POSITION_MIN = -1.0f; |
44 private static final float VIEW_POSITION_MAX = 3.0f; | 45 private static final float VIEW_POSITION_MAX = 3.0f; |
45 | 46 |
46 // Allows user to click even when looking outside the desktop | 47 // Allows user to click even when looking outside the desktop |
47 // but within edge margin. | 48 // but within edge margin. |
48 private static final float EDGE_MARGIN = 0.1f; | 49 private static final float EDGE_MARGIN = 0.1f; |
49 | 50 |
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. | 51 // Distance to move camera each time. |
54 private static final float CAMERA_MOTION_STEP = 0.5f; | 52 private static final float CAMERA_MOTION_STEP = 0.5f; |
55 | 53 |
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[] { | 54 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 | 55 -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 | 56 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 | 57 -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 | 58 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 | 59 -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 | 60 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 | 61 -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 | 62 HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE // (7) Botto
m-right far |
75 }); | 63 }); |
(...skipping 17 matching lines...) Expand all Loading... |
93 | 81 |
94 // Top | 82 // Top |
95 5, 1, 4, | 83 5, 1, 4, |
96 4, 1, 0, | 84 4, 1, 0, |
97 | 85 |
98 // Bottom | 86 // Bottom |
99 6, 2, 7, | 87 6, 2, 7, |
100 7, 2, 3 | 88 7, 2, 3 |
101 }); | 89 }); |
102 | 90 |
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 = | 91 private static final String SKYBOX_VERTEX_SHADER = |
129 "uniform mat4 u_CombinedMatrix;" | 92 "uniform mat4 u_CombinedMatrix;" |
130 + "attribute vec3 a_Position;" | 93 + "attribute vec3 a_Position;" |
131 + "varying vec3 v_Position;" | 94 + "varying vec3 v_Position;" |
132 + "void main() {" | 95 + "void main() {" |
133 + " v_Position = a_Position;" | 96 + " v_Position = a_Position;" |
134 // Make sure to convert from the right-handed coordinate system of t
he | 97 // 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, | 98 // 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. | 99 // our cube map will still work but everything will be flipped. |
137 + " v_Position.z = -v_Position.z;" | 100 + " 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", | 121 "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" | 122 "https://dl.google.com/chrome-remote-desktop/android-assets/room_front.p
ng" |
160 }; | 123 }; |
161 | 124 |
162 private static final String[] SKYBOX_IMAGE_NAMES = new String[] { | 125 private static final String[] SKYBOX_IMAGE_NAMES = new String[] { |
163 "skybox_left", "skybox_right", "skybox_bottom", "skybox_top", "skybox_ba
ck", "skybox_front" | 126 "skybox_left", "skybox_right", "skybox_bottom", "skybox_top", "skybox_ba
ck", "skybox_front" |
164 }; | 127 }; |
165 | 128 |
166 private final Activity mActivity; | 129 private final Activity mActivity; |
167 | 130 |
168 private float mHalfDesktopWidth; | |
169 private float mCameraPosition; | 131 private float mCameraPosition; |
170 | 132 |
171 // Lock to allow multithreaded access to mCameraPosition. | 133 // Lock to allow multithreaded access to mCameraPosition. |
172 private Object mCameraPositionLock = new Object(); | 134 private Object mCameraPositionLock = new Object(); |
173 | 135 |
174 private float[] mCameraMatrix; | 136 private float[] mCameraMatrix; |
175 private float[] mViewMatrix; | 137 private float[] mViewMatrix; |
176 private float[] mProjectionMatrix; | 138 private float[] mProjectionMatrix; |
177 | 139 |
178 // Make matrix member variable to avoid unnecessary initialization. | 140 // Make matrix member variable to avoid unnecessary initialization. |
179 private float[] mDesktopModelMatrix; | 141 private float[] mDesktopModelMatrix; |
180 private float[] mDesktopCombinedMatrix; | 142 private float[] mDesktopCombinedMatrix; |
181 private float[] mEyePointModelMatrix; | 143 private float[] mEyePointModelMatrix; |
182 private float[] mEyePointCombinedMatrix; | 144 private float[] mEyePointCombinedMatrix; |
183 private float[] mSkyboxModelMatrix; | 145 private float[] mSkyboxModelMatrix; |
184 private float[] mSkyboxCombinedMatrix; | 146 private float[] mSkyboxCombinedMatrix; |
185 | 147 |
186 // Direction that user is looking towards. | 148 // Direction that user is looking towards. |
187 private float[] mForwardVector; | 149 private float[] mForwardVector; |
188 | 150 |
189 // Eye position in desktop. | 151 // Eye position in desktop. |
190 private float[] mEyePositionVector; | 152 private float[] mEyePositionVector; |
191 | 153 |
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; | 154 private int mSkyboxVertexShaderHandle; |
201 private int mSkyboxFragmentShaderHandle; | 155 private int mSkyboxFragmentShaderHandle; |
202 private int mSkyboxProgramHandle; | 156 private int mSkyboxProgramHandle; |
203 private int mSkyboxPositionHandle; | 157 private int mSkyboxPositionHandle; |
204 private int mSkyboxCombinedMatrixHandle; | 158 private int mSkyboxCombinedMatrixHandle; |
205 private int mSkyboxTextureUnitHandle; | 159 private int mSkyboxTextureUnitHandle; |
206 private int mSkyboxTextureDataHandle; | 160 private int mSkyboxTextureDataHandle; |
| 161 private CardboardActivityDesktop mDesktop; |
207 private CardboardActivityEyePoint mEyePoint; | 162 private CardboardActivityEyePoint mEyePoint; |
208 | 163 |
209 // Flag to indicate whether reload the desktop texture or not. | 164 // Flag to indicate whether reload the desktop texture or not. |
210 private boolean mReloadTexture; | 165 private boolean mReloadTexture; |
211 | 166 |
212 /** Lock to allow multithreaded access to mReloadTexture. */ | 167 /** Lock to allow multithreaded access to mReloadTexture. */ |
213 private Object mReloadTextureLock = new Object(); | 168 private Object mReloadTextureLock = new Object(); |
214 | 169 |
215 // Lock for eye position related operations. | 170 // Lock for eye position related operations. |
216 // This protects access to mEyePositionVector as well as mDesktop{Height/Wid
th}Pixels. | 171 // This protects access to mEyePositionVector. |
217 private Object mEyePositionLock = new Object(); | 172 private Object mEyePositionLock = new Object(); |
218 | 173 |
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 | 174 // Flag to signal that the skybox images are fully decoded and should be loa
ded |
225 // into the OpenGL textures. | 175 // into the OpenGL textures. |
226 private boolean mLoadSkyboxImagesTexture; | 176 private boolean mLoadSkyboxImagesTexture; |
227 | 177 |
228 // Lock to allow multithreaded access to mLoadSkyboxImagesTexture. | 178 // Lock to allow multithreaded access to mLoadSkyboxImagesTexture. |
229 private Object mLoadSkyboxImagesTextureLock = new Object(); | 179 private Object mLoadSkyboxImagesTextureLock = new Object(); |
230 | 180 |
231 private ChromotingDownloadManager mDownloadManager; | 181 private ChromotingDownloadManager mDownloadManager; |
232 | 182 |
233 public CardboardDesktopRenderer(Activity activity) { | 183 public CardboardDesktopRenderer(Activity activity) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 public void onSurfaceCreated(EGLConfig config) { | 228 public void onSurfaceCreated(EGLConfig config) { |
279 // Set the background clear color to black. | 229 // Set the background clear color to black. |
280 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | 230 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
281 | 231 |
282 // Use culling to remove back faces. | 232 // Use culling to remove back faces. |
283 GLES20.glEnable(GLES20.GL_CULL_FACE); | 233 GLES20.glEnable(GLES20.GL_CULL_FACE); |
284 | 234 |
285 // Enable depth testing. | 235 // Enable depth testing. |
286 GLES20.glEnable(GLES20.GL_DEPTH_TEST); | 236 GLES20.glEnable(GLES20.GL_DEPTH_TEST); |
287 | 237 |
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. | 238 // Set handlers for skybox drawing. |
303 GLES20.glEnable(GLES20.GL_TEXTURE_CUBE_MAP); | 239 GLES20.glEnable(GLES20.GL_TEXTURE_CUBE_MAP); |
304 mSkyboxVertexShaderHandle = | 240 mSkyboxVertexShaderHandle = |
305 ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, SKYBOX_VERTE
X_SHADER); | 241 ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, SKYBOX_VERTE
X_SHADER); |
306 mSkyboxFragmentShaderHandle = | 242 mSkyboxFragmentShaderHandle = |
307 ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, SKYBOX_FRA
GMENT_SHADER); | 243 ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, SKYBOX_FRA
GMENT_SHADER); |
308 mSkyboxProgramHandle = ShaderHelper.createAndLinkProgram(mSkyboxVertexSh
aderHandle, | 244 mSkyboxProgramHandle = ShaderHelper.createAndLinkProgram(mSkyboxVertexSh
aderHandle, |
309 mSkyboxFragmentShaderHandle, | 245 mSkyboxFragmentShaderHandle, |
310 new String[] {"a_Position", "u_CombinedMatrix", "u_TextureUnit"}
); | 246 new String[] {"a_Position", "u_CombinedMatrix", "u_TextureUnit"}
); |
311 mSkyboxPositionHandle = | 247 mSkyboxPositionHandle = |
312 GLES20.glGetAttribLocation(mSkyboxProgramHandle, "a_Position"); | 248 GLES20.glGetAttribLocation(mSkyboxProgramHandle, "a_Position"); |
313 mSkyboxCombinedMatrixHandle = | 249 mSkyboxCombinedMatrixHandle = |
314 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_CombinedMat
rix"); | 250 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_CombinedMat
rix"); |
315 mSkyboxTextureUnitHandle = | 251 mSkyboxTextureUnitHandle = |
316 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_TextureUnit
"); | 252 GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_TextureUnit
"); |
317 mSkyboxTextureDataHandle = TextureHelper.createTextureHandle(); | 253 mSkyboxTextureDataHandle = TextureHelper.createTextureHandle(); |
318 | 254 |
| 255 mDesktop = new CardboardActivityDesktop(); |
319 mEyePoint = new CardboardActivityEyePoint(); | 256 mEyePoint = new CardboardActivityEyePoint(); |
320 } | 257 } |
321 | 258 |
322 @Override | 259 @Override |
323 public void onSurfaceChanged(int width, int height) { | 260 public void onSurfaceChanged(int width, int height) { |
324 } | 261 } |
325 | 262 |
326 @Override | 263 @Override |
327 public void onNewFrame(HeadTransform headTransform) { | 264 public void onNewFrame(HeadTransform headTransform) { |
328 // Position the eye at the origin. | 265 // Position the eye at the origin. |
(...skipping 11 matching lines...) Expand all Loading... |
340 | 277 |
341 // Set our up vector. This is where our head would be pointing were we h
olding the camera. | 278 // Set our up vector. This is where our head would be pointing were we h
olding the camera. |
342 float upX = 0.0f; | 279 float upX = 0.0f; |
343 float upY = 1.0f; | 280 float upY = 1.0f; |
344 float upZ = 0.0f; | 281 float upZ = 0.0f; |
345 | 282 |
346 Matrix.setLookAtM(mCameraMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, look
Z, upX, upY, upZ); | 283 Matrix.setLookAtM(mCameraMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, look
Z, upX, upY, upZ); |
347 | 284 |
348 headTransform.getForwardVector(mForwardVector, 0); | 285 headTransform.getForwardVector(mForwardVector, 0); |
349 getLookingPosition(); | 286 getLookingPosition(); |
350 maybeLoadTexture(mTextureDataHandle); | 287 maybeLoadDesktopTexture(); |
351 maybeLoadCubeMapAndCleanImages(mSkyboxTextureDataHandle); | 288 maybeLoadCubeMapAndCleanImages(mSkyboxTextureDataHandle); |
352 } | 289 } |
353 | 290 |
354 @Override | 291 @Override |
355 public void onDrawEye(Eye eye) { | 292 public void onDrawEye(Eye eye) { |
356 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); | 293 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); |
357 | 294 |
358 // Apply the eye transformation to the camera. | 295 // Apply the eye transformation to the camera. |
359 Matrix.multiplyMM(mViewMatrix, 0, eye.getEyeView(), 0, mCameraMatrix, 0)
; | 296 Matrix.multiplyMM(mViewMatrix, 0, eye.getEyeView(), 0, mCameraMatrix, 0)
; |
360 | 297 |
361 mProjectionMatrix = eye.getPerspective(Z_NEAR, Z_FAR); | 298 mProjectionMatrix = eye.getPerspective(Z_NEAR, Z_FAR); |
362 | 299 |
363 drawSkybox(); | 300 drawSkybox(); |
364 drawDesktop(); | 301 drawDesktop(); |
365 drawEyePoint(); | 302 drawEyePoint(); |
366 } | 303 } |
367 | 304 |
368 @Override | 305 @Override |
369 public void onRendererShutdown() { | 306 public void onRendererShutdown() { |
370 GLES20.glDeleteShader(mDesktopVertexShaderHandle); | 307 mDesktop.cleanup(); |
371 GLES20.glDeleteShader(mDesktopFragmentShaderHandle); | |
372 mEyePoint.cleanup(); | 308 mEyePoint.cleanup(); |
373 GLES20.glDeleteShader(mSkyboxVertexShaderHandle); | 309 GLES20.glDeleteShader(mSkyboxVertexShaderHandle); |
374 GLES20.glDeleteShader(mSkyboxFragmentShaderHandle); | 310 GLES20.glDeleteShader(mSkyboxFragmentShaderHandle); |
375 GLES20.glDeleteTextures(1, new int[] {mTextureDataHandle}, 0); | |
376 GLES20.glDeleteTextures(1, new int[] {mSkyboxTextureDataHandle}, 0); | 311 GLES20.glDeleteTextures(1, new int[] {mSkyboxTextureDataHandle}, 0); |
377 mActivity.runOnUiThread(new Runnable() { | 312 mActivity.runOnUiThread(new Runnable() { |
378 public void run() { | 313 public void run() { |
379 mDownloadManager.close(); | 314 mDownloadManager.close(); |
380 } | 315 } |
381 }); | 316 }); |
382 } | 317 } |
383 | 318 |
384 @Override | 319 @Override |
385 public void onFinishFrame(Viewport viewport) { | 320 public void onFinishFrame(Viewport viewport) { |
386 } | 321 } |
387 | 322 |
388 private void drawDesktop() { | 323 private void drawDesktop() { |
389 GLES20.glUseProgram(mProgramHandle); | 324 if (!mDesktop.hasVideoFrame()) { |
| 325 // This can happen if the client is connected, but a complete |
| 326 // video frame has not yet been decoded. |
| 327 return; |
| 328 } |
390 | 329 |
391 // Translate the desktop model. | 330 |
392 Matrix.setIdentityM(mDesktopModelMatrix, 0); | 331 Matrix.setIdentityM(mDesktopModelMatrix, 0); |
393 Matrix.translateM(mDesktopModelMatrix, 0, DESKTOP_POSITION_X, | 332 Matrix.translateM(mDesktopModelMatrix, 0, DESKTOP_POSITION_X, |
394 DESKTOP_POSITION_Y, DESKTOP_POSITION_Z); | 333 DESKTOP_POSITION_Y, DESKTOP_POSITION_Z); |
395 | 334 |
396 // Pass in Model View Matrix and Model View Project Matrix. | 335 // Pass in Model View Matrix and Model View Project Matrix. |
397 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mViewMatrix, 0, mDesktopMod
elMatrix, 0); | 336 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mViewMatrix, 0, mDesktopMod
elMatrix, 0); |
398 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mProjectionMatrix, | 337 Matrix.multiplyMM(mDesktopCombinedMatrix, 0, mProjectionMatrix, |
399 0, mDesktopCombinedMatrix, 0); | 338 0, mDesktopCombinedMatrix, 0); |
| 339 mDesktop.setCombinedMatrix(mDesktopCombinedMatrix); |
400 | 340 |
401 // Pass in model view project matrix. | 341 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 } | 342 } |
429 | 343 |
430 private void drawEyePoint() { | 344 private void drawEyePoint() { |
431 if (!isLookingAtDesktop()) { | 345 if (!isLookingAtDesktop()) { |
432 return; | 346 return; |
433 } | 347 } |
434 | 348 |
435 float eyePointX = clamp(mEyePositionVector[0], -mHalfDesktopWidth, | 349 float eyePointX = clamp(mEyePositionVector[0], -mDesktop.getHalfWidth(), |
436 mHalfDesktopWidth); | 350 mDesktop.getHalfWidth()); |
437 float eyePointY = clamp(mEyePositionVector[1], -HALF_DESKTOP_HEIGHT, | 351 float eyePointY = clamp(mEyePositionVector[1], -mDesktop.getHalfHeight()
, |
438 HALF_DESKTOP_HEIGHT); | 352 mDesktop.getHalfHeight()); |
439 Matrix.setIdentityM(mEyePointModelMatrix, 0); | 353 Matrix.setIdentityM(mEyePointModelMatrix, 0); |
440 Matrix.translateM(mEyePointModelMatrix, 0, -eyePointX, -eyePointY, | 354 Matrix.translateM(mEyePointModelMatrix, 0, -eyePointX, -eyePointY, |
441 DESKTOP_POSITION_Z); | 355 DESKTOP_POSITION_Z); |
442 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mViewMatrix, 0, mEyePointM
odelMatrix, 0); | 356 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mViewMatrix, 0, mEyePointM
odelMatrix, 0); |
443 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mProjectionMatrix, | 357 Matrix.multiplyMM(mEyePointCombinedMatrix, 0, mProjectionMatrix, |
444 0, mEyePointCombinedMatrix, 0); | 358 0, mEyePointCombinedMatrix, 0); |
445 | 359 |
446 mEyePoint.setCombinedMatrix(mEyePointCombinedMatrix); | 360 mEyePoint.setCombinedMatrix(mEyePointCombinedMatrix); |
447 mEyePoint.draw(); | 361 mEyePoint.draw(); |
448 } | 362 } |
(...skipping 19 matching lines...) Expand all Loading... |
468 GLES20.glDrawElements(GLES20.GL_TRIANGLES, 36, GLES20.GL_UNSIGNED_BYTE, | 382 GLES20.glDrawElements(GLES20.GL_TRIANGLES, 36, GLES20.GL_UNSIGNED_BYTE, |
469 SKYBOX_INDICES_BYTE_BUFFER); | 383 SKYBOX_INDICES_BYTE_BUFFER); |
470 } | 384 } |
471 | 385 |
472 /** | 386 /** |
473 * Returns coordinates in units of pixels in the desktop bitmap. | 387 * Returns coordinates in units of pixels in the desktop bitmap. |
474 * This can be called on any thread. | 388 * This can be called on any thread. |
475 */ | 389 */ |
476 public PointF getMouseCoordinates() { | 390 public PointF getMouseCoordinates() { |
477 PointF result = new PointF(); | 391 PointF result = new PointF(); |
| 392 Point shapePixels = mDesktop.getShapePixels(); |
| 393 int heightPixels = shapePixels.x; |
| 394 int widthPixels = shapePixels.y; |
| 395 |
478 synchronized (mEyePositionLock) { | 396 synchronized (mEyePositionLock) { |
479 // Due to the coordinate direction, we only have to inverse x. | 397 // Due to the coordinate direction, we only have to inverse x. |
480 result.x = (-mEyePositionVector[0] + mHalfDesktopWidth) | 398 result.x = (-mEyePositionVector[0] + mDesktop.getHalfWidth()) |
481 / (2 * mHalfDesktopWidth) * mDesktopWidthPixels; | 399 / (2 * mDesktop.getHalfWidth()) * widthPixels; |
482 result.y = (mEyePositionVector[1] + HALF_DESKTOP_HEIGHT) | 400 result.y = (mEyePositionVector[1] + mDesktop.getHalfHeight()) |
483 / (2 * HALF_DESKTOP_HEIGHT) * mDesktopHeightPixels; | 401 / (2 * mDesktop.getHalfHeight()) * heightPixels; |
484 result.x = clamp(result.x, 0, mDesktopWidthPixels); | 402 result.x = clamp(result.x, 0, widthPixels); |
485 result.y = clamp(result.y, 0, mDesktopHeightPixels); | 403 result.y = clamp(result.y, 0, heightPixels); |
486 } | 404 } |
487 return result; | 405 return result; |
488 } | 406 } |
489 | 407 |
490 /** | 408 /** |
491 * Returns the passed in value if it resides within the specified range (inc
lusive). If not, | 409 * 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 | 410 * it will return the closest boundary from the range. The ordering of the
boundary values |
493 * does not matter. | 411 * does not matter. |
494 * | 412 * |
495 * @param value The value to be compared against the range. | 413 * @param value The value to be compared against the range. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 } | 451 } |
534 } | 452 } |
535 } | 453 } |
536 | 454 |
537 /** | 455 /** |
538 * Return true if user is looking at the desktop. | 456 * Return true if user is looking at the desktop. |
539 * This method can be called on any thread. | 457 * This method can be called on any thread. |
540 */ | 458 */ |
541 public boolean isLookingAtDesktop() { | 459 public boolean isLookingAtDesktop() { |
542 synchronized (mEyePositionLock) { | 460 synchronized (mEyePositionLock) { |
543 return Math.abs(mEyePositionVector[0]) <= (mHalfDesktopWidth + EDGE_
MARGIN) | 461 return Math.abs(mEyePositionVector[0]) <= (mDesktop.getHalfWidth() +
EDGE_MARGIN) |
544 && Math.abs(mEyePositionVector[1]) <= (HALF_DESKTOP_HEIGHT + EDG
E_MARGIN); | 462 && Math.abs(mEyePositionVector[1]) <= (mDesktop.getHalfHeight()
+ EDGE_MARGIN); |
545 } | 463 } |
546 } | 464 } |
547 | 465 |
548 /** | 466 /** |
549 * Return true if user is looking at the space to the left of the desktop. | 467 * Return true if user is looking at the space to the left of the desktop. |
550 * This method can be called on any thread. | 468 * This method can be called on any thread. |
551 */ | 469 */ |
552 public boolean isLookingLeftOfDesktop() { | 470 public boolean isLookingLeftOfDesktop() { |
553 synchronized (mEyePositionLock) { | 471 synchronized (mEyePositionLock) { |
554 return mEyePositionVector[0] >= (mHalfDesktopWidth + EDGE_MARGIN); | 472 return mEyePositionVector[0] >= (mDesktop.getHalfWidth() + EDGE_MARG
IN); |
555 } | 473 } |
556 } | 474 } |
557 | 475 |
558 /** | 476 /** |
559 * Return true if user is looking at the space to the right of the desktop. | 477 * Return true if user is looking at the space to the right of the desktop. |
560 * This method can be called on any thread. | 478 * This method can be called on any thread. |
561 */ | 479 */ |
562 public boolean isLookingRightOfDesktop() { | 480 public boolean isLookingRightOfDesktop() { |
563 synchronized (mEyePositionLock) { | 481 synchronized (mEyePositionLock) { |
564 return mEyePositionVector[0] <= -(mHalfDesktopWidth + EDGE_MARGIN); | 482 return mEyePositionVector[0] <= -(mDesktop.getHalfWidth() + EDGE_MAR
GIN); |
565 } | 483 } |
566 } | 484 } |
567 | 485 |
568 /** | 486 /** |
569 * Return true if user is looking at the space above the desktop. | 487 * Return true if user is looking at the space above the desktop. |
570 * This method can be called on any thread. | 488 * This method can be called on any thread. |
571 */ | 489 */ |
572 public boolean isLookingAboveDesktop() { | 490 public boolean isLookingAboveDesktop() { |
573 synchronized (mEyePositionLock) { | 491 synchronized (mEyePositionLock) { |
574 return mEyePositionVector[1] <= -(HALF_DESKTOP_HEIGHT + EDGE_MARGIN)
; | 492 return mEyePositionVector[1] <= -(mDesktop.getHalfHeight() + EDGE_MA
RGIN); |
575 } | 493 } |
576 } | 494 } |
577 | 495 |
578 /** | 496 /** |
579 * Return true if user is looking at the space below the desktop. | 497 * Return true if user is looking at the space below the desktop. |
580 * This method can be called on any thread. | 498 * This method can be called on any thread. |
581 */ | 499 */ |
582 public boolean isLookingBelowDesktop() { | 500 public boolean isLookingBelowDesktop() { |
583 synchronized (mEyePositionLock) { | 501 synchronized (mEyePositionLock) { |
584 return mEyePositionVector[1] >= (HALF_DESKTOP_HEIGHT + EDGE_MARGIN); | 502 return mEyePositionVector[1] >= (mDesktop.getHalfHeight() + EDGE_MAR
GIN); |
585 } | 503 } |
586 } | 504 } |
587 | 505 |
588 /** | 506 /** |
589 * Get position on desktop where user is looking at. | 507 * Get position on desktop where user is looking at. |
590 */ | 508 */ |
591 private void getLookingPosition() { | 509 private void getLookingPosition() { |
592 synchronized (mEyePositionLock) { | 510 synchronized (mEyePositionLock) { |
593 if (Math.abs(mForwardVector[2]) < 0.00001f) { | 511 if (Math.abs(mForwardVector[2]) < 0.00001f) { |
594 mEyePositionVector[0] = Math.signum(mForwardVector[0]) * Float.M
AX_VALUE; | 512 mEyePositionVector[0] = Math.signum(mForwardVector[0]) * Float.M
AX_VALUE; |
595 mEyePositionVector[1] = Math.signum(mForwardVector[1]) * Float.M
AX_VALUE; | 513 mEyePositionVector[1] = Math.signum(mForwardVector[1]) * Float.M
AX_VALUE; |
596 } else { | 514 } else { |
597 mEyePositionVector[0] = mForwardVector[0] * DESKTOP_POSITION_Z /
mForwardVector[2]; | 515 mEyePositionVector[0] = mForwardVector[0] * DESKTOP_POSITION_Z /
mForwardVector[2]; |
598 mEyePositionVector[1] = mForwardVector[1] * DESKTOP_POSITION_Z /
mForwardVector[2]; | 516 mEyePositionVector[1] = mForwardVector[1] * DESKTOP_POSITION_Z /
mForwardVector[2]; |
599 } | 517 } |
600 mEyePositionVector[2] = DESKTOP_POSITION_Z; | 518 mEyePositionVector[2] = DESKTOP_POSITION_Z; |
601 } | 519 } |
602 } | 520 } |
603 | 521 |
604 /** | 522 /** |
605 * Link desktop texture with textureDataHandle if {@link mReloadTexture} is
true. | 523 * Link desktop texture with {@link CardboardActivityDesktop} if {@link mRel
oadTexture} is true. |
606 * @param textureDataHandle the handle we want attach texture to | 524 * @param textureDataHandle the handle we want attach texture to |
607 */ | 525 */ |
608 private void maybeLoadTexture(int textureDataHandle) { | 526 private void maybeLoadDesktopTexture() { |
609 synchronized (mReloadTextureLock) { | 527 synchronized (mReloadTextureLock) { |
610 if (!mReloadTexture) { | 528 if (!mReloadTexture) { |
611 return; | 529 return; |
612 } | 530 } |
613 } | 531 } |
614 | 532 |
615 // TODO(shichengfeng): Record the time desktop drawing takes. | 533 // TODO(shichengfeng): Record the time desktop drawing takes. |
616 Bitmap bitmap = JniInterface.getVideoFrame(); | 534 Bitmap bitmap = JniInterface.getVideoFrame(); |
617 | 535 |
618 if (bitmap == null) { | 536 if (bitmap == null) { |
619 // This can happen if the client is connected, but a complete video
frame has not yet | 537 // This can happen if the client is connected, but a complete video
frame has not yet |
620 // been decoded. | 538 // been decoded. |
621 return; | 539 return; |
622 } | 540 } |
623 | 541 |
624 synchronized (mEyePositionLock) { | 542 mDesktop.updateVideoFrameData(bitmap); |
625 mDesktopHeightPixels = bitmap.getHeight(); | |
626 mDesktopWidthPixels = bitmap.getWidth(); | |
627 } | |
628 | |
629 updateDesktopCoordinatesBuffer(bitmap); | |
630 TextureHelper.linkTexture(textureDataHandle, bitmap); | |
631 | 543 |
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 |