blob: 3178163c2d54e4ed7d5800e84ae770d9ec8fa9d3 [file] [log] [blame]
package com.android.gallery3d.ui;
import android.graphics.Bitmap;
import android.opengl.GLUtils;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;
abstract class UploadedTexture extends BasicTexture {
@SuppressWarnings("unused")
private static final String TAG = "Texture";
private boolean mOpaque;
private boolean mContentValid = true;
protected Bitmap mBitmap;
protected UploadedTexture() {
super(null, 0, STATE_UNLOADED);
}
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("cannot change content size");
}
}
return mBitmap;
}
private void freeBitmap() {
Util.Assert(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();
if (mState == STATE_LOADED) 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)) {
uploadToGL(canvas.getGLInstance());
} else if (!mContentValid) {
Bitmap bitmap = getBitmap();
int format = GLUtils.getInternalFormat(bitmap);
int type = GLUtils.getType(bitmap);
mGL.glBindTexture(GL11.GL_TEXTURE_2D, mId);
GLUtils.texSubImage2D(
GL11.GL_TEXTURE_2D, 0, 0, 0, bitmap, format, type);
freeBitmap();
mContentValid = true;
}
}
static int[] sTextureId = new int[1];
static int[] sCropRect = new int[4];
private void uploadToGL(GL11 gl) {
Bitmap bitmap = getBitmap();
int glError = GL11.GL_NO_ERROR;
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.glTexParameteriv(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);
int widthExt = Util.nextPowerOf2(width);
int heightExt = Util.nextPowerOf2(height);
int format = GLUtils.getInternalFormat(bitmap);
mOpaque = !bitmap.hasAlpha();
int type = GLUtils.getType(bitmap);
mTextureWidth = widthExt;
mTextureHeight = heightExt;
gl.glTexImage2D(GL11.GL_TEXTURE_2D, 0, format,
widthExt, heightExt, 0, format, type, null);
GLUtils.texSubImage2D(
GL11.GL_TEXTURE_2D, 0, 0, 0, bitmap, format, type);
} finally {
freeBitmap();
}
if (glError == GL11.GL_OUT_OF_MEMORY) {
throw new GLOutOfMemoryException();
}
if (glError != GL11.GL_NO_ERROR) {
mId = 0;
mState = STATE_UNLOADED;
throw new RuntimeException(
"Texture upload fail, glError " + glError);
} else {
// Update texture state.
mGL = gl;
mId = sTextureId[0];
mState = UploadedTexture.STATE_LOADED;
}
} else {
mState = STATE_ERROR;
throw new RuntimeException("Texture load fail, no bitmap");
}
}
@Override
protected void onBind(GLCanvas canvas) {
updateContent(canvas);
}
public boolean isOpaque() {
return mOpaque;
}
public void recycle() {
if (mBitmap != null) freeBitmap();
}
}