summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/ui/UploadedTexture.java
diff options
context:
space:
mode:
authorOwen Lin <owenlin@google.com>2011-08-17 22:07:43 +0800
committerOwen Lin <owenlin@google.com>2011-08-18 13:33:50 +0800
commita2fba687d4d2dbb3b2db8866b054ecb0e42871b2 (patch)
treedacc5a60ed945fe989aebf1f227f72bc90ebc4b8 /src/com/android/gallery3d/ui/UploadedTexture.java
parenta053a3179cfee3d2bb666eff5f4f03a96b092e04 (diff)
downloadandroid_packages_apps_Snap-a2fba687d4d2dbb3b2db8866b054ecb0e42871b2.tar.gz
android_packages_apps_Snap-a2fba687d4d2dbb3b2db8866b054ecb0e42871b2.tar.bz2
android_packages_apps_Snap-a2fba687d4d2dbb3b2db8866b054ecb0e42871b2.zip
Initial code for Gallery2.
fix: 5176434 Change-Id: I041e282b9c7b34ceb1db8b033be2b853bb3a992c
Diffstat (limited to 'src/com/android/gallery3d/ui/UploadedTexture.java')
-rw-r--r--src/com/android/gallery3d/ui/UploadedTexture.java285
1 files changed, 285 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/ui/UploadedTexture.java b/src/com/android/gallery3d/ui/UploadedTexture.java
new file mode 100644
index 000000000..b063824d2
--- /dev/null
+++ b/src/com/android/gallery3d/ui/UploadedTexture.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ui;
+
+import com.android.gallery3d.common.Utils;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.opengl.GLUtils;
+
+import java.util.HashMap;
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11Ext;
+
+// UploadedTextures use a Bitmap for the content of the texture.
+//
+// Subclasses should implement onGetBitmap() to provide the Bitmap and
+// implement onFreeBitmap(mBitmap) which will be called when the Bitmap
+// is not needed anymore.
+//
+// isContentValid() is meaningful only when the isLoaded() returns true.
+// It means whether the content needs to be updated.
+//
+// The user of this class should call recycle() when the texture is not
+// needed anymore.
+//
+// By default an UploadedTexture is opaque (so it can be drawn faster without
+// blending). The user or subclass can override it using setOpaque().
+abstract class UploadedTexture extends BasicTexture {
+
+ // To prevent keeping allocation the borders, we store those used borders here.
+ // Since the length will be power of two, it won't use too much memory.
+ private static HashMap<BorderKey, Bitmap> sBorderLines =
+ new HashMap<BorderKey, Bitmap>();
+ private static BorderKey sBorderKey = new BorderKey();
+
+ @SuppressWarnings("unused")
+ private static final String TAG = "Texture";
+ private boolean mContentValid = true;
+ private boolean mOpaque = true;
+ private boolean mThrottled = false;
+ private static int sUploadedCount;
+ private static final int UPLOAD_LIMIT = 100;
+
+ protected Bitmap mBitmap;
+
+ protected UploadedTexture() {
+ super(null, 0, STATE_UNLOADED);
+ }
+
+ private static class BorderKey implements Cloneable {
+ public boolean vertical;
+ public Config config;
+ public int length;
+
+ @Override
+ public int hashCode() {
+ int x = config.hashCode() ^ length;
+ return vertical ? x : -x;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof BorderKey)) return false;
+ BorderKey o = (BorderKey) object;
+ return vertical == o.vertical
+ && config == o.config && length == o.length;
+ }
+
+ @Override
+ public BorderKey clone() {
+ try {
+ return (BorderKey) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ protected void setThrottled(boolean throttled) {
+ mThrottled = throttled;
+ }
+
+ private static Bitmap getBorderLine(
+ boolean vertical, Config config, int length) {
+ BorderKey key = sBorderKey;
+ key.vertical = vertical;
+ key.config = config;
+ key.length = length;
+ Bitmap bitmap = sBorderLines.get(key);
+ if (bitmap == null) {
+ bitmap = vertical
+ ? Bitmap.createBitmap(1, length, config)
+ : Bitmap.createBitmap(length, 1, config);
+ sBorderLines.put(key.clone(), bitmap);
+ }
+ return bitmap;
+ }
+
+ private Bitmap getBitmap() {
+ if (mBitmap == null) {
+ mBitmap = onGetBitmap();
+ if (mWidth == UNSPECIFIED) {
+ setSize(mBitmap.getWidth(), mBitmap.getHeight());
+ } else if (mWidth != mBitmap.getWidth()
+ || mHeight != mBitmap.getHeight()) {
+ throw new IllegalStateException(String.format(
+ "cannot change size: this = %s, orig = %sx%s, new = %sx%s",
+ toString(), mWidth, mHeight, mBitmap.getWidth(),
+ mBitmap.getHeight()));
+ }
+ }
+ return mBitmap;
+ }
+
+ private void freeBitmap() {
+ Utils.assertTrue(mBitmap != null);
+ onFreeBitmap(mBitmap);
+ mBitmap = null;
+ }
+
+ @Override
+ public int getWidth() {
+ if (mWidth == UNSPECIFIED) getBitmap();
+ return mWidth;
+ }
+
+ @Override
+ public int getHeight() {
+ if (mWidth == UNSPECIFIED) getBitmap();
+ return mHeight;
+ }
+
+ protected abstract Bitmap onGetBitmap();
+
+ protected abstract void onFreeBitmap(Bitmap bitmap);
+
+ protected void invalidateContent() {
+ if (mBitmap != null) freeBitmap();
+ mContentValid = false;
+ }
+
+ /**
+ * Whether the content on GPU is valid.
+ */
+ public boolean isContentValid(GLCanvas canvas) {
+ return isLoaded(canvas) && mContentValid;
+ }
+
+ /**
+ * Updates the content on GPU's memory.
+ * @param canvas
+ */
+ public void updateContent(GLCanvas canvas) {
+ if (!isLoaded(canvas)) {
+ if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) {
+ return;
+ }
+ uploadToCanvas(canvas);
+ } else if (!mContentValid) {
+ Bitmap bitmap = getBitmap();
+ int format = GLUtils.getInternalFormat(bitmap);
+ int type = GLUtils.getType(bitmap);
+ canvas.getGLInstance().glBindTexture(GL11.GL_TEXTURE_2D, mId);
+ GLUtils.texSubImage2D(
+ GL11.GL_TEXTURE_2D, 0, 0, 0, bitmap, format, type);
+ freeBitmap();
+ mContentValid = true;
+ }
+ }
+
+ public static void resetUploadLimit() {
+ sUploadedCount = 0;
+ }
+
+ public static boolean uploadLimitReached() {
+ return sUploadedCount > UPLOAD_LIMIT;
+ }
+
+ static int[] sTextureId = new int[1];
+ static float[] sCropRect = new float[4];
+
+ private void uploadToCanvas(GLCanvas canvas) {
+ GL11 gl = canvas.getGLInstance();
+
+ Bitmap bitmap = getBitmap();
+ if (bitmap != null) {
+ try {
+ // Define a vertically flipped crop rectangle for
+ // OES_draw_texture.
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+ sCropRect[0] = 0;
+ sCropRect[1] = height;
+ sCropRect[2] = width;
+ sCropRect[3] = -height;
+
+ // Upload the bitmap to a new texture.
+ gl.glGenTextures(1, sTextureId, 0);
+ gl.glBindTexture(GL11.GL_TEXTURE_2D, sTextureId[0]);
+ gl.glTexParameterfv(GL11.GL_TEXTURE_2D,
+ GL11Ext.GL_TEXTURE_CROP_RECT_OES, sCropRect, 0);
+ gl.glTexParameteri(GL11.GL_TEXTURE_2D,
+ GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE);
+ gl.glTexParameteri(GL11.GL_TEXTURE_2D,
+ GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE);
+ gl.glTexParameterf(GL11.GL_TEXTURE_2D,
+ GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
+ gl.glTexParameterf(GL11.GL_TEXTURE_2D,
+ GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
+
+ if (width == getTextureWidth() && height == getTextureHeight()) {
+ GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0);
+ } else {
+ int format = GLUtils.getInternalFormat(bitmap);
+ int type = GLUtils.getType(bitmap);
+ Config config = bitmap.getConfig();
+
+ gl.glTexImage2D(GL11.GL_TEXTURE_2D, 0, format,
+ getTextureWidth(), getTextureHeight(),
+ 0, format, type, null);
+ GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, bitmap,
+ format, type);
+
+ if (width != getTextureWidth()) {
+ Bitmap line = getBorderLine(true, config, getTextureHeight());
+ GLUtils.texSubImage2D(
+ GL11.GL_TEXTURE_2D, 0, width, 0, line, format, type);
+ }
+
+ if (height != getTextureHeight()) {
+ Bitmap line = getBorderLine(false, config, getTextureWidth());
+ GLUtils.texSubImage2D(
+ GL11.GL_TEXTURE_2D, 0, 0, height, line, format, type);
+ }
+
+ }
+ } finally {
+ freeBitmap();
+ }
+ // Update texture state.
+ setAssociatedCanvas(canvas);
+ mId = sTextureId[0];
+ mState = UploadedTexture.STATE_LOADED;
+ mContentValid = true;
+ } else {
+ mState = STATE_ERROR;
+ throw new RuntimeException("Texture load fail, no bitmap");
+ }
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ updateContent(canvas);
+ return isContentValid(canvas);
+ }
+
+ public void setOpaque(boolean isOpaque) {
+ mOpaque = isOpaque;
+ }
+
+ public boolean isOpaque() {
+ return mOpaque;
+ }
+
+ @Override
+ public void recycle() {
+ super.recycle();
+ if (mBitmap != null) freeBitmap();
+ }
+}