diff options
author | shichengfeng <shichengfeng@google.com> | 2015-08-18 10:22:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-18 17:22:58 +0000 |
commit | 2b9538c0238061c4a4c1d33a710901708977ffc7 (patch) | |
tree | cd83af2c80ab78a52a58233ecda6a0685dc05730 /remoting | |
parent | 4d53661a33c0dcff4da2fab8ad49329c2d1055e9 (diff) | |
download | chromium_src-2b9538c0238061c4a4c1d33a710901708977ffc7.zip chromium_src-2b9538c0238061c4a4c1d33a710901708977ffc7.tar.gz chromium_src-2b9538c0238061c4a4c1d33a710901708977ffc7.tar.bz2 |
Android Chromoting: Add skybox environment for the Cardboard desktop activity.
Surround the view environment with a skybox environment.
Note: the skybox image could be replaced easily later.
BUG = 516871
Review URL: https://codereview.chromium.org/1271333002
Cr-Commit-Position: refs/heads/master@{#343950}
Diffstat (limited to 'remoting')
3 files changed, 410 insertions, 20 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 diff --git a/remoting/android/java/src/org/chromium/chromoting/ChromotingDownloadManager.java b/remoting/android/java/src/org/chromium/chromoting/ChromotingDownloadManager.java new file mode 100644 index 0000000..5d08f45 --- /dev/null +++ b/remoting/android/java/src/org/chromium/chromoting/ChromotingDownloadManager.java @@ -0,0 +1,146 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chromoting; + +import android.app.Activity; +import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; + +import java.io.File; +import java.util.HashSet; +import java.util.Set; + +/** + * Class that manages download operation for Chromoting activity. + */ +public class ChromotingDownloadManager { + /** + * Callback for download manager. This will be executed on application's main thread. + */ + public interface Callback { + /** + * Called when batch download is successfully finished. + */ + public void onBatchDownloadComplete(); + } + + private Activity mActivity; + private BroadcastReceiver mDownloadReceiver; + private DownloadManager mDownloadManager; + private Set<Long> mUnfinishedDownloadIds; + private Callback mCallback; + private String[] mNames; + private String[] mUris; + + public ChromotingDownloadManager(Activity activity, String[] names, String[] uris, + Callback callback) { + assert names.length == uris.length; + + mActivity = activity; + mCallback = callback; + mDownloadManager = + (DownloadManager) mActivity.getSystemService(Context.DOWNLOAD_SERVICE); + mNames = names.clone(); + mUris = uris.clone(); + mUnfinishedDownloadIds = new HashSet<Long>(); + } + + /** + * Download files according to given URIs and store them as given names. + */ + public void download() { + for (int i = 0; i < mNames.length; i++) { + if (needToBeDownloaded(i)) { + DownloadManager.Request request = + new DownloadManager.Request(Uri.parse(mUris[i])); + request.setDestinationInExternalFilesDir(mActivity.getApplicationContext(), + Environment.DIRECTORY_DOWNLOADS, mNames[i]); + mUnfinishedDownloadIds.add(mDownloadManager.enqueue(request)); + } + } + + if (mUnfinishedDownloadIds.isEmpty()) { + mActivity.runOnUiThread(new Runnable() { + public void run() { + mCallback.onBatchDownloadComplete(); + } + }); + } else { + mDownloadReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { + Query query = new Query(); + query.setFilterById(convertToArray(mUnfinishedDownloadIds)); + query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL); + Cursor cursor = mDownloadManager.query(query); + + // Delete finished download id from unfinished download id set. + for (int i = 0; i < cursor.getCount(); i++) { + cursor.moveToPosition(i); + int downloadIdIndex = cursor.getColumnIndex(DownloadManager.COLUMN_ID); + mUnfinishedDownloadIds.remove(cursor.getLong(downloadIdIndex)); + } + + if (mUnfinishedDownloadIds.isEmpty()) { + mCallback.onBatchDownloadComplete(); + } + cursor.close(); + } + } + }; + + mActivity.registerReceiver(mDownloadReceiver, + new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + } + } + + /** + * Perform necessary operations to close the download manager. + */ + public void close() { + if (!mUnfinishedDownloadIds.isEmpty()) { + mDownloadManager.remove(convertToArray(mUnfinishedDownloadIds)); + } + if (mDownloadReceiver != null) { + mActivity.unregisterReceiver(mDownloadReceiver); + } + } + + /** + * Check whether the file corresponding to the given index needs to be downloaded. + */ + private boolean needToBeDownloaded(int index) { + return !new File(getDownloadDirectory() + "/" + mNames[index]).exists(); + } + + /** + * Get download directory path. + */ + public String getDownloadDirectory() { + return mActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(); + } + + /** + * Convert a Set of Long to an array of long. + */ + private long[] convertToArray(Set<Long> data) { + long[] result = new long[data.size()]; + int index = 0; + for (long number : data) { + result[index] = number; + index++; + } + return result; + } +}
\ No newline at end of file diff --git a/remoting/android/java/src/org/chromium/chromoting/TextureHelper.java b/remoting/android/java/src/org/chromium/chromoting/TextureHelper.java index f5708c8..fb710eb 100644 --- a/remoting/android/java/src/org/chromium/chromoting/TextureHelper.java +++ b/remoting/android/java/src/org/chromium/chromoting/TextureHelper.java @@ -4,9 +4,25 @@ package org.chromium.chromoting; +import static android.opengl.GLES20.GL_LINEAR; +import static android.opengl.GLES20.GL_NEAREST; +import static android.opengl.GLES20.GL_TEXTURE_2D; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; +import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; +import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; +import static android.opengl.GLES20.glBindTexture; +import static android.opengl.GLES20.glDeleteTextures; +import static android.opengl.GLES20.glGenTextures; +import static android.opengl.GLES20.glTexParameteri; +import static android.opengl.GLUtils.texImage2D; + import android.graphics.Bitmap; -import android.opengl.GLES20; -import android.opengl.GLUtils; /** * Helper class for working with OpenGL textures. @@ -18,7 +34,7 @@ public class TextureHelper { */ public static int createTextureHandle() { int[] textureDataHandle = new int[1]; - GLES20.glGenTextures(1, textureDataHandle, 0); + glGenTextures(1, textureDataHandle, 0); if (textureDataHandle[0] != 0) { return textureDataHandle[0]; } else { @@ -32,17 +48,38 @@ public class TextureHelper { */ public static void linkTexture(int textureDataHandle, Bitmap bitmap) { // Delete previously attached texture. - GLES20.glDeleteTextures(1, new int[]{textureDataHandle}, 0); + glDeleteTextures(1, new int[]{textureDataHandle}, 0); // Bind to the texture in OpenGL. - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandle); + glBindTexture(GL_TEXTURE_2D, textureDataHandle); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Load the bitmap into the bound texture. - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); + texImage2D(GL_TEXTURE_2D, 0, bitmap, 0); + } + + /** + * Link the cubemap images with a given texture handle. + */ + public static void linkCubeMap(int textureDataHandle, Bitmap[] cubeBitmaps) { + glBindTexture(GL_TEXTURE_CUBE_MAP, textureDataHandle); + + // Linear filtering for minification and magnification. + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Link left, right, bottom, top, back and front image in order. + texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, cubeBitmaps[0], 0); + texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, cubeBitmaps[1], 0); + + texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, cubeBitmaps[2], 0); + texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, cubeBitmaps[3], 0); + + texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, cubeBitmaps[4], 0); + texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, cubeBitmaps[5], 0); } }
\ No newline at end of file |