1104c45677660586026a7e74ef8c47d396403d50eMichael Jurka/* 2104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Copyright (C) 2010 The Android Open Source Project 3104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 4104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * you may not use this file except in compliance with the License. 6104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * You may obtain a copy of the License at 7104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 8104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 10104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Unless required by applicable law or agreed to in writing, software 11104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * See the License for the specific language governing permissions and 14104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * limitations under the License. 15104c45677660586026a7e74ef8c47d396403d50eMichael Jurka */ 16104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 17104c45677660586026a7e74ef8c47d396403d50eMichael Jurkapackage com.android.gallery3d.glrenderer; 18104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 19104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.Bitmap; 20104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.graphics.Bitmap.Config; 21104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.opengl.GLUtils; 22104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 23104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport junit.framework.Assert; 24104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 25104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport java.util.HashMap; 26104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 27104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport javax.microedition.khronos.opengles.GL11; 28104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 29104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// UploadedTextures use a Bitmap for the content of the texture. 30104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// 31104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// Subclasses should implement onGetBitmap() to provide the Bitmap and 32104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// implement onFreeBitmap(mBitmap) which will be called when the Bitmap 33104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// is not needed anymore. 34104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// 35104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// isContentValid() is meaningful only when the isLoaded() returns true. 36104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// It means whether the content needs to be updated. 37104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// 38104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// The user of this class should call recycle() when the texture is not 39104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// needed anymore. 40104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// 41104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// By default an UploadedTexture is opaque (so it can be drawn faster without 42104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// blending). The user or subclass can override it using setOpaque(). 43104c45677660586026a7e74ef8c47d396403d50eMichael Jurkapublic abstract class UploadedTexture extends BasicTexture { 44104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 45104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // To prevent keeping allocation the borders, we store those used borders here. 46104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Since the length will be power of two, it won't use too much memory. 47104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static HashMap<BorderKey, Bitmap> sBorderLines = 48104c45677660586026a7e74ef8c47d396403d50eMichael Jurka new HashMap<BorderKey, Bitmap>(); 49104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static BorderKey sBorderKey = new BorderKey(); 50104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 51104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @SuppressWarnings("unused") 52104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static final String TAG = "Texture"; 53104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private boolean mContentValid = true; 54104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 55104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // indicate this textures is being uploaded in background 56104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private boolean mIsUploading = false; 57104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private boolean mOpaque = true; 58104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private boolean mThrottled = false; 59104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static int sUploadedCount; 60104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static final int UPLOAD_LIMIT = 100; 61104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 62104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected Bitmap mBitmap; 63104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private int mBorder; 64104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 65104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected UploadedTexture() { 66104c45677660586026a7e74ef8c47d396403d50eMichael Jurka this(false); 67104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 68104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 69104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected UploadedTexture(boolean hasBorder) { 70104c45677660586026a7e74ef8c47d396403d50eMichael Jurka super(null, 0, STATE_UNLOADED); 71104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (hasBorder) { 72104c45677660586026a7e74ef8c47d396403d50eMichael Jurka setBorder(true); 73104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mBorder = 1; 74104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 75104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 76104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 77104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected void setIsUploading(boolean uploading) { 78104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mIsUploading = uploading; 79104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 80104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 81104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean isUploading() { 82104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mIsUploading; 83104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 84104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 85104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static class BorderKey implements Cloneable { 86104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean vertical; 87104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public Config config; 88104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int length; 89104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 90104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 91104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int hashCode() { 92104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int x = config.hashCode() ^ length; 93104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return vertical ? x : -x; 94104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 95104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 96104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 97104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean equals(Object object) { 98104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (!(object instanceof BorderKey)) return false; 99104c45677660586026a7e74ef8c47d396403d50eMichael Jurka BorderKey o = (BorderKey) object; 100104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return vertical == o.vertical 101104c45677660586026a7e74ef8c47d396403d50eMichael Jurka && config == o.config && length == o.length; 102104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 103104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 104104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 105104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public BorderKey clone() { 106104c45677660586026a7e74ef8c47d396403d50eMichael Jurka try { 107104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return (BorderKey) super.clone(); 108104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } catch (CloneNotSupportedException e) { 109104c45677660586026a7e74ef8c47d396403d50eMichael Jurka throw new AssertionError(e); 110104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 111104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 112104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 113104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 114104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected void setThrottled(boolean throttled) { 115104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mThrottled = throttled; 116104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 117104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 118104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static Bitmap getBorderLine( 119104c45677660586026a7e74ef8c47d396403d50eMichael Jurka boolean vertical, Config config, int length) { 120104c45677660586026a7e74ef8c47d396403d50eMichael Jurka BorderKey key = sBorderKey; 121104c45677660586026a7e74ef8c47d396403d50eMichael Jurka key.vertical = vertical; 122104c45677660586026a7e74ef8c47d396403d50eMichael Jurka key.config = config; 123104c45677660586026a7e74ef8c47d396403d50eMichael Jurka key.length = length; 124104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap bitmap = sBorderLines.get(key); 125104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (bitmap == null) { 126104c45677660586026a7e74ef8c47d396403d50eMichael Jurka bitmap = vertical 127104c45677660586026a7e74ef8c47d396403d50eMichael Jurka ? Bitmap.createBitmap(1, length, config) 128104c45677660586026a7e74ef8c47d396403d50eMichael Jurka : Bitmap.createBitmap(length, 1, config); 129104c45677660586026a7e74ef8c47d396403d50eMichael Jurka sBorderLines.put(key.clone(), bitmap); 130104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 131104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return bitmap; 132104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 133104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 134104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private Bitmap getBitmap() { 135104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mBitmap == null) { 136104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mBitmap = onGetBitmap(); 137104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int w = mBitmap.getWidth() + mBorder * 2; 138104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int h = mBitmap.getHeight() + mBorder * 2; 139104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mWidth == UNSPECIFIED) { 140104c45677660586026a7e74ef8c47d396403d50eMichael Jurka setSize(w, h); 141104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 142104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 143104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mBitmap; 144104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 145104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 146104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private void freeBitmap() { 147104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Assert.assertTrue(mBitmap != null); 148104c45677660586026a7e74ef8c47d396403d50eMichael Jurka onFreeBitmap(mBitmap); 149104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mBitmap = null; 150104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 151104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 152104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 153104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int getWidth() { 154104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mWidth == UNSPECIFIED) getBitmap(); 155104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mWidth; 156104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 157104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 158104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 159104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int getHeight() { 160104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mWidth == UNSPECIFIED) getBitmap(); 161104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mHeight; 162104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 163104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 164104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected abstract Bitmap onGetBitmap(); 165104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 166104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected abstract void onFreeBitmap(Bitmap bitmap); 167104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 168104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected void invalidateContent() { 169104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mBitmap != null) freeBitmap(); 170104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mContentValid = false; 171104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mWidth = UNSPECIFIED; 172104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mHeight = UNSPECIFIED; 173104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 174104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 175104c45677660586026a7e74ef8c47d396403d50eMichael Jurka /** 176104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Whether the content on GPU is valid. 177104c45677660586026a7e74ef8c47d396403d50eMichael Jurka */ 178104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean isContentValid() { 179104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return isLoaded() && mContentValid; 180104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 181104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 182104c45677660586026a7e74ef8c47d396403d50eMichael Jurka /** 183104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Updates the content on GPU's memory. 184104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * @param canvas 185104c45677660586026a7e74ef8c47d396403d50eMichael Jurka */ 186104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void updateContent(GLCanvas canvas) { 187104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (!isLoaded()) { 188104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) { 189104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return; 190104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 191104c45677660586026a7e74ef8c47d396403d50eMichael Jurka uploadToCanvas(canvas); 192104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } else if (!mContentValid) { 193104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap bitmap = getBitmap(); 194104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int format = GLUtils.getInternalFormat(bitmap); 195104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int type = GLUtils.getType(bitmap); 196104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type); 197104c45677660586026a7e74ef8c47d396403d50eMichael Jurka freeBitmap(); 198104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mContentValid = true; 199104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 200104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 201104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 202104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static void resetUploadLimit() { 203104c45677660586026a7e74ef8c47d396403d50eMichael Jurka sUploadedCount = 0; 204104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 205104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 206104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static boolean uploadLimitReached() { 207104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return sUploadedCount > UPLOAD_LIMIT; 208104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 209104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 210104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private void uploadToCanvas(GLCanvas canvas) { 211104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 212104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap bitmap = getBitmap(); 213104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (bitmap != null) { 214104c45677660586026a7e74ef8c47d396403d50eMichael Jurka try { 215104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int bWidth = bitmap.getWidth(); 216104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int bHeight = bitmap.getHeight(); 217104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int width = bWidth + mBorder * 2; 218104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int height = bHeight + mBorder * 2; 219104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int texWidth = getTextureWidth(); 220104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int texHeight = getTextureHeight(); 221104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 222104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight); 223104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 224104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Upload the bitmap to a new texture. 225104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mId = canvas.getGLId().generateTexture(); 226104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.setTextureParameters(this); 227104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 228104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (bWidth == texWidth && bHeight == texHeight) { 229104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.initializeTexture(this, bitmap); 230104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } else { 231104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int format = GLUtils.getInternalFormat(bitmap); 232104c45677660586026a7e74ef8c47d396403d50eMichael Jurka int type = GLUtils.getType(bitmap); 233104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Config config = bitmap.getConfig(); 234104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 235104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.initializeTextureSize(this, format, type); 236104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type); 237104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 238104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mBorder > 0) { 239104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Left border 240104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap line = getBorderLine(true, config, texHeight); 241104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.texSubImage2D(this, 0, 0, line, format, type); 242104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 243104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Top border 244104c45677660586026a7e74ef8c47d396403d50eMichael Jurka line = getBorderLine(false, config, texWidth); 245104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.texSubImage2D(this, 0, 0, line, format, type); 246104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 247104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 248104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Right border 249104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mBorder + bWidth < texWidth) { 250104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap line = getBorderLine(true, config, texHeight); 251104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.texSubImage2D(this, mBorder + bWidth, 0, line, format, type); 252104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 253104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 254104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Bottom border 255104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mBorder + bHeight < texHeight) { 256104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Bitmap line = getBorderLine(false, config, texWidth); 257104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.texSubImage2D(this, 0, mBorder + bHeight, line, format, type); 258104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 259104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 260104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } finally { 261104c45677660586026a7e74ef8c47d396403d50eMichael Jurka freeBitmap(); 262104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 263104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Update texture state. 264104c45677660586026a7e74ef8c47d396403d50eMichael Jurka setAssociatedCanvas(canvas); 265104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mState = STATE_LOADED; 266104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mContentValid = true; 267104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } else { 268104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mState = STATE_ERROR; 269104c45677660586026a7e74ef8c47d396403d50eMichael Jurka throw new RuntimeException("Texture load fail, no bitmap"); 270104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 271104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 272104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 273104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 274104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected boolean onBind(GLCanvas canvas) { 275104c45677660586026a7e74ef8c47d396403d50eMichael Jurka updateContent(canvas); 276104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return isContentValid(); 277104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 278104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 279104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 280104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected int getTarget() { 281104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return GL11.GL_TEXTURE_2D; 282104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 283104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 284104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void setOpaque(boolean isOpaque) { 285104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mOpaque = isOpaque; 286104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 287104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 288104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 289104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean isOpaque() { 290104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mOpaque; 291104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 292104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 293104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 294104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void recycle() { 295104c45677660586026a7e74ef8c47d396403d50eMichael Jurka super.recycle(); 296104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mBitmap != null) freeBitmap(); 297104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 298104c45677660586026a7e74ef8c47d396403d50eMichael Jurka} 299