package com.cooliris.media; import javax.microedition.khronos.opengles.GL11; import javax.microedition.khronos.opengles.GL11Ext; import android.graphics.Bitmap; import android.graphics.Canvas; import android.opengl.GLUtils; public abstract class CanvasLayer extends Layer { private int mTextureId; private int mTextureWidth; private int mTextureHeight; private float mNormalizedWidth; private float mNormalizedHeight; private final Canvas mCanvas = new Canvas(); private final Bitmap.Config mBitmapConfig; private Bitmap mBitmap = null; private boolean mNeedsDraw = false; private boolean mNeedsResize = false; public CanvasLayer(Bitmap.Config bitmapConfig) { mBitmapConfig = bitmapConfig; } public void setNeedsDraw() { mNeedsDraw = true; } public final float getNormalizedWidth() { return mNormalizedWidth; } public final float getNormalizedHeight() { return mNormalizedHeight; } @Override protected void onSizeChanged() { mNeedsResize = true; } @Override protected void onSurfaceCreated(RenderView view, GL11 gl) { mTextureId = 0; } protected boolean bind(GL11 gl) { int width = (int) mWidth; int height = (int) mHeight; int textureId = mTextureId; int textureWidth = mTextureWidth; int textureHeight = mTextureHeight; Canvas canvas = mCanvas; Bitmap bitmap = mBitmap; boolean updateSubTexture = true; if (mNeedsResize) { // Clear the resize flag and mark as needing draw. mNeedsResize = false; mNeedsDraw = true; // Compute the power-of-2 padded size for the texture. int newTextureWidth = Shared.nextPowerOf2(width); int newTextureHeight = Shared.nextPowerOf2(height); // Reallocate the bitmap only if the padded size has changed. if (textureWidth != newTextureWidth || textureHeight != newTextureHeight) { // Mark that the partial texture update should not be used. updateSubTexture = false; // Allocate a texture if needed. if (textureId == 0) { int[] textureIdOut = new int[1]; gl.glGenTextures(1, textureIdOut, 0); textureId = textureIdOut[0]; mTextureId = textureId; // Set texture parameters. gl.glBindTexture(GL11.GL_TEXTURE_2D, textureId); 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); } // Set the new texture width and height. textureWidth = newTextureWidth; textureHeight = newTextureHeight; mTextureWidth = newTextureWidth; mTextureHeight = newTextureHeight; mNormalizedWidth = (float) width / textureWidth; mNormalizedHeight = (float) height / textureHeight; // Recycle the existing bitmap and create a new one. if (bitmap != null) bitmap.recycle(); bitmap = Bitmap.createBitmap(textureWidth, textureHeight, mBitmapConfig); canvas.setBitmap(bitmap); mBitmap = bitmap; } } // Bind the texture to the context. if (textureId == 0) return false; gl.glBindTexture(GL11.GL_TEXTURE_2D, textureId); // Redraw the contents of the texture if needed. if (mNeedsDraw) { mNeedsDraw = false; draw(canvas, bitmap, width, height); if (updateSubTexture) { GLUtils.texSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, bitmap); } else { int[] cropRect = { 0, height, width, -height }; gl.glTexParameteriv(GL11.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, 0); GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0); } } return true; } protected abstract void draw(Canvas canvas, Bitmap backing, int width, int height); }