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