diff options
Diffstat (limited to 'remoting/android/java/src/org/chromium/chromoting/CardboardDesktopRenderer.java')
-rw-r--r-- | remoting/android/java/src/org/chromium/chromoting/CardboardDesktopRenderer.java | 227 |
1 files changed, 217 insertions, 10 deletions
diff --git a/remoting/android/java/src/org/chromium/chromoting/CardboardDesktopRenderer.java b/remoting/android/java/src/org/chromium/chromoting/CardboardDesktopRenderer.java index 33aa5e8..5d5aabb 100644 --- a/remoting/android/java/src/org/chromium/chromoting/CardboardDesktopRenderer.java +++ b/remoting/android/java/src/org/chromium/chromoting/CardboardDesktopRenderer.java @@ -4,8 +4,9 @@ package org.chromium.chromoting; -import android.content.Context; +import android.app.Activity; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.PointF; import android.opengl.GLES20; import android.opengl.Matrix; @@ -15,6 +16,7 @@ import com.google.vrtoolkit.cardboard.Eye; import com.google.vrtoolkit.cardboard.HeadTransform; import com.google.vrtoolkit.cardboard.Viewport; +import org.chromium.base.Log; import org.chromium.chromoting.jni.JniInterface; import java.nio.ByteBuffer; @@ -37,6 +39,7 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { private static final float DESKTOP_POSITION_X = 0.0f; private static final float DESKTOP_POSITION_Y = 0.0f; private static final float DESKTOP_POSITION_Z = -2.0f; + private static final float HALF_SKYBOX_SIZE = 100.0f; // Allows user to click even when looking outside the desktop // but within edge margin. @@ -55,6 +58,43 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { 1.0f, 0.0f }); + private static final FloatBuffer SKYBOX_POSITION_COORDINATES = makeFloatBuffer(new float[] { + -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (0) Top-left near + HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (1) Top-right near + -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (2) Bottom-left near + HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, // (3) Bottom-right near + -HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (4) Top-left far + HALF_SKYBOX_SIZE, HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (5) Top-right far + -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, // (6) Bottom-left far + HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE, -HALF_SKYBOX_SIZE // (7) Bottom-right far + }); + + private static final ByteBuffer SKYBOX_INDICES_BYTE_BUFFER = ByteBuffer.wrap(new byte[] { + // Front + 1, 3, 0, + 0, 3, 2, + + // Back + 4, 6, 5, + 5, 6, 7, + + // Left + 0, 2, 4, + 4, 2, 6, + + // Right + 5, 7, 1, + 1, 7, 3, + + // Top + 5, 1, 4, + 4, 1, 0, + + // Bottom + 6, 2, 7, + 7, 2, 3 + }); + private static final String DESKTOP_VERTEX_SHADER = "uniform mat4 u_CombinedMatrix;" + "attribute vec4 a_Position;" @@ -87,12 +127,47 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { + " gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);" + "}"; - private final Context mActivityContext; + private static final String SKYBOX_VERTEX_SHADER = + "uniform mat4 u_CombinedMatrix;" + + "attribute vec3 a_Position;" + + "varying vec3 v_Position;" + + "void main() {" + + " v_Position = a_Position;" + // Make sure to convert from the right-handed coordinate system of the + // world to the left-handed coordinate system of the cube map, otherwise, + // our cube map will still work but everything will be flipped. + + " v_Position.z = -v_Position.z;" + + " gl_Position = u_CombinedMatrix * vec4(a_Position, 1.0);" + + " gl_Position = gl_Position.xyww;" + + "}"; - private float mHalfDesktopWidth; + private static final String SKYBOX_FRAGMENT_SHADER = + "precision mediump float;" + + "uniform samplerCube u_TextureUnit;" + + "varying vec3 v_Position;" + + "void main() {" + + " gl_FragColor = textureCube(u_TextureUnit, v_Position);" + + "}"; - // Flag to indicate whether reload the desktop texture or not. - private boolean mReloadTexture; + private static final String ASSETS_URI_PREFIX = + "https://dl.google.com/chrome-remote-desktop/android-assets/";; + + private static final String[] SKYBOX_IMAGE_URIS = new String[] { + "https://dl.google.com/chrome-remote-desktop/android-assets/room_left.png", + "https://dl.google.com/chrome-remote-desktop/android-assets/room_right.png", + "https://dl.google.com/chrome-remote-desktop/android-assets/room_bottom.png", + "https://dl.google.com/chrome-remote-desktop/android-assets/room_top.png", + "https://dl.google.com/chrome-remote-desktop/android-assets/room_back.png", + "https://dl.google.com/chrome-remote-desktop/android-assets/room_front.png" + }; + + private static final String[] SKYBOX_IMAGE_NAMES = new String[] { + "skybox_left", "skybox_right", "skybox_bottom", "skybox_top", "skybox_back", "skybox_front" + }; + + private final Activity mActivity; + + private float mHalfDesktopWidth; private float[] mCameraMatrix; private float[] mViewMatrix; @@ -103,6 +178,8 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { private float[] mDesktopCombinedMatrix; private float[] mEyePointModelMatrix; private float[] mEyePointCombinedMatrix; + private float[] mSkyboxModelMatrix; + private float[] mSkyboxCombinedMatrix; // Direction that user is looking towards. private float[] mForwardVector; @@ -123,6 +200,16 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { private int mEyePointProgramHandle; private int mEyePointPositionHandle; private int mEyePointCombinedMatrixHandle; + private int mSkyboxVertexShaderHandle; + private int mSkyboxFragmentShaderHandle; + private int mSkyboxProgramHandle; + private int mSkyboxPositionHandle; + private int mSkyboxCombinedMatrixHandle; + private int mSkyboxTextureUnitHandle; + private int mSkyboxTextureDataHandle; + + // Flag to indicate whether reload the desktop texture or not. + private boolean mReloadTexture; /** Lock to allow multithreaded access to mReloadTexture. */ private Object mReloadTextureLock = new Object(); @@ -136,8 +223,17 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { private FloatBuffer mDesktopCoordinates; - public CardboardDesktopRenderer(Context context) { - mActivityContext = context; + // Flag to signal that the skybox images are fully decoded and should be loaded + // into the OpenGL textures. + private boolean mLoadSkyboxImagesTexture; + + // Lock to allow multithreaded access to mLoadSkyboxImagesTexture. + private Object mLoadSkyboxImagesTextureLock = new Object(); + + private ChromotingDownloadManager mDownloadManager; + + public CardboardDesktopRenderer(Activity activity) { + mActivity = activity; mReloadTexture = false; mCameraMatrix = new float[16]; @@ -147,11 +243,24 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { mDesktopCombinedMatrix = new float[16]; mEyePointModelMatrix = new float[16]; mEyePointCombinedMatrix = new float[16]; + mSkyboxModelMatrix = new float[16]; + mSkyboxCombinedMatrix = new float[16]; mForwardVector = new float[3]; mEyePositionVector = new float[3]; attachRedrawCallback(); + + mDownloadManager = new ChromotingDownloadManager(mActivity, SKYBOX_IMAGE_NAMES, + SKYBOX_IMAGE_URIS, new ChromotingDownloadManager.Callback() { + @Override + public void onBatchDownloadComplete() { + synchronized (mLoadSkyboxImagesTextureLock) { + mLoadSkyboxImagesTexture = true; + } + } + }); + mDownloadManager.download(); } // This can be called on any thread. @@ -203,6 +312,23 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { mEyePointCombinedMatrixHandle = GLES20.glGetUniformLocation(mEyePointProgramHandle, "u_CombinedMatrix"); + // Set handlers for skybox drawing. + GLES20.glEnable(GLES20.GL_TEXTURE_CUBE_MAP); + mSkyboxVertexShaderHandle = + ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, SKYBOX_VERTEX_SHADER); + mSkyboxFragmentShaderHandle = + ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, SKYBOX_FRAGMENT_SHADER); + mSkyboxProgramHandle = ShaderHelper.createAndLinkProgram(mSkyboxVertexShaderHandle, + mSkyboxFragmentShaderHandle, + new String[] {"a_Position", "u_CombinedMatrix", "u_TextureUnit"}); + mSkyboxPositionHandle = + GLES20.glGetAttribLocation(mSkyboxProgramHandle, "a_Position"); + mSkyboxCombinedMatrixHandle = + GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_CombinedMatrix"); + mSkyboxTextureUnitHandle = + GLES20.glGetUniformLocation(mSkyboxProgramHandle, "u_TextureUnit"); + mSkyboxTextureDataHandle = TextureHelper.createTextureHandle(); + // Position the eye at the origin. float eyeX = 0.0f; float eyeY = 0.0f; @@ -232,6 +358,7 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { headTransform.getForwardVector(mForwardVector, 0); getLookingPosition(); maybeLoadTexture(mTextureDataHandle); + maybeLoadCubeMapAndCleanImages(mSkyboxTextureDataHandle); } @Override @@ -243,6 +370,7 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { mProjectionMatrix = eye.getPerspective(Z_NEAR, Z_FAR); + drawSkybox(); drawDesktop(); drawEyePoint(); } @@ -253,7 +381,15 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { GLES20.glDeleteShader(mDesktopFragmentShaderHandle); GLES20.glDeleteShader(mEyePointVertexShaderHandle); GLES20.glDeleteShader(mEyePointFragmentShaderHandle); - GLES20.glDeleteTextures(1, new int[]{mTextureDataHandle}, 0); + GLES20.glDeleteShader(mSkyboxVertexShaderHandle); + GLES20.glDeleteShader(mSkyboxFragmentShaderHandle); + GLES20.glDeleteTextures(1, new int[] {mTextureDataHandle}, 0); + GLES20.glDeleteTextures(1, new int[] {mSkyboxTextureDataHandle}, 0); + mActivity.runOnUiThread(new Runnable() { + public void run() { + mDownloadManager.close(); + } + }); } @Override @@ -336,6 +472,28 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { GLES20.glDrawArrays(GLES20.GL_POINTS, 0, totalPointNumber); } + private void drawSkybox() { + GLES20.glUseProgram(mSkyboxProgramHandle); + + Matrix.setIdentityM(mSkyboxModelMatrix, 0); + Matrix.multiplyMM(mSkyboxCombinedMatrix, 0, mViewMatrix, 0, mSkyboxModelMatrix, 0); + Matrix.multiplyMM(mSkyboxCombinedMatrix, 0, mProjectionMatrix, + 0, mSkyboxCombinedMatrix, 0); + + GLES20.glUniformMatrix4fv(mSkyboxCombinedMatrixHandle, 1, false, + mSkyboxCombinedMatrix, 0); + GLES20.glVertexAttribPointer(mSkyboxPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, + false, 0, SKYBOX_POSITION_COORDINATES); + GLES20.glEnableVertexAttribArray(mSkyboxPositionHandle); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, mSkyboxTextureDataHandle); + GLES20.glUniform1i(mSkyboxTextureUnitHandle, 0); + + GLES20.glDrawElements(GLES20.GL_TRIANGLES, 36, GLES20.GL_UNSIGNED_BYTE, + SKYBOX_INDICES_BYTE_BUFFER); + } + /** * Returns coordinates in units of pixels in the desktop bitmap. * This can be called on any thread. @@ -387,7 +545,7 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { } } - /* + /** * Return true if user is looking at the space to the left of the dekstop. * This method can be called on any thread. */ @@ -397,7 +555,7 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { } } - /* + /** * Return true if user is looking at the space to the right of the dekstop. * This method can be called on any thread. */ @@ -488,4 +646,53 @@ public class CardboardDesktopRenderer implements CardboardView.StereoRenderer { }); } } + + /** + * Decode all skybox images to Bitmap files and return them. + * Only call this method when we have complete skybox images. + * @throws DecodeFileException if BitmapFactory fails to decode file. + */ + private Bitmap[] decodeSkyboxImages() throws DecodeFileException { + Bitmap[] result = new Bitmap[SKYBOX_IMAGE_NAMES.length]; + String fileDirectory = mDownloadManager.getDownloadDirectory(); + for (int i = 0; i < SKYBOX_IMAGE_NAMES.length; i++) { + result[i] = BitmapFactory.decodeFile(fileDirectory + "/" + SKYBOX_IMAGE_NAMES[i]); + if (result[i] == null) { + throw new DecodeFileException(); + } + } + return result; + } + + /** + * Link the skybox images with given texture handle and clean images at the end. + * Only call this method when we have complete skybox images. + */ + private void maybeLoadCubeMapAndCleanImages(int textureHandle) { + synchronized (mLoadSkyboxImagesTextureLock) { + if (!mLoadSkyboxImagesTexture) { + return; + } + mLoadSkyboxImagesTexture = false; + } + + Bitmap[] images; + try { + images = decodeSkyboxImages(); + } catch (DecodeFileException e) { + Log.i(TAG, "Failed to decode image files."); + return; + } + + TextureHelper.linkCubeMap(textureHandle, images); + for (Bitmap image : images) { + image.recycle(); + } + } + + /** + * Exception when BitmapFactory fails to decode file. + */ + private static class DecodeFileException extends Exception { + } }
\ No newline at end of file |