1e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka/*
2e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Copyright (C) 2010 The Android Open Source Project
3e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
4e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
5e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * you may not use this file except in compliance with the License.
6e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * You may obtain a copy of the License at
7e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
8e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
9e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka *
10e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * Unless required by applicable law or agreed to in writing, software
11e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
12e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * See the License for the specific language governing permissions and
14e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka * limitations under the License.
15e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka */
16e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
17e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapackage com.android.gallery3d.glrenderer;
18e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
19e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap;
20e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.graphics.Bitmap.Config;
21e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport android.opengl.GLUtils;
22e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
230589d8287ef05b701754dcb916cc3079c907f847Paul Duffinimport com.android.gallery3d.common.Utils;
240589d8287ef05b701754dcb916cc3079c907f847Paul Duffin
25e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport java.util.HashMap;
26e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
27e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkaimport javax.microedition.khronos.opengles.GL11;
28e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
29e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// UploadedTextures use a Bitmap for the content of the texture.
30e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka//
31e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// Subclasses should implement onGetBitmap() to provide the Bitmap and
32e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// implement onFreeBitmap(mBitmap) which will be called when the Bitmap
33e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// is not needed anymore.
34e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka//
35e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// isContentValid() is meaningful only when the isLoaded() returns true.
36e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// It means whether the content needs to be updated.
37e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka//
38e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// The user of this class should call recycle() when the texture is not
39e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// needed anymore.
40e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka//
41e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// By default an UploadedTexture is opaque (so it can be drawn faster without
42e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka// blending). The user or subclass can override it using setOpaque().
43e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurkapublic abstract class UploadedTexture extends BasicTexture {
44e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
45e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // To prevent keeping allocation the borders, we store those used borders here.
46e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // Since the length will be power of two, it won't use too much memory.
47e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static HashMap<BorderKey, Bitmap> sBorderLines =
48e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            new HashMap<BorderKey, Bitmap>();
49e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static BorderKey sBorderKey = new BorderKey();
50e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
51e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @SuppressWarnings("unused")
52e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final String TAG = "Texture";
53e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private boolean mContentValid = true;
54e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
55e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    // indicate this textures is being uploaded in background
56e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private boolean mIsUploading = false;
57e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private boolean mOpaque = true;
58e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private boolean mThrottled = false;
59e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static int sUploadedCount;
60e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static final int UPLOAD_LIMIT = 100;
61e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
62e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected Bitmap mBitmap;
63e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private int mBorder;
64e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
65e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected UploadedTexture() {
66e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        this(false);
67e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
68e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
69e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected UploadedTexture(boolean hasBorder) {
70e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super(null, 0, STATE_UNLOADED);
71e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (hasBorder) {
72e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            setBorder(true);
73e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mBorder = 1;
74e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
75e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
76e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
77e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void setIsUploading(boolean uploading) {
78e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mIsUploading = uploading;
79e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
80e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
81e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public boolean isUploading() {
82e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mIsUploading;
83e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
84e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
85e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static class BorderKey implements Cloneable {
86e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public boolean vertical;
87e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public Config config;
88e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int length;
89e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
90e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
91e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public int hashCode() {
92e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int x = config.hashCode() ^ length;
93e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return vertical ? x : -x;
94e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
95e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
96e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
97e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public boolean equals(Object object) {
98e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (!(object instanceof BorderKey)) return false;
99e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            BorderKey o = (BorderKey) object;
100e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            return vertical == o.vertical
101e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    && config == o.config && length == o.length;
102e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
103e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
104e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        @Override
105e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        public BorderKey clone() {
106e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            try {
107e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                return (BorderKey) super.clone();
108e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } catch (CloneNotSupportedException e) {
109e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                throw new AssertionError(e);
110e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
111e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
112e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
113e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
114e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void setThrottled(boolean throttled) {
115e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mThrottled = throttled;
116e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
117e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
118e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private static Bitmap getBorderLine(
119e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            boolean vertical, Config config, int length) {
120e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        BorderKey key = sBorderKey;
121e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        key.vertical = vertical;
122e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        key.config = config;
123e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        key.length = length;
124e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap bitmap = sBorderLines.get(key);
125e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (bitmap == null) {
126e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            bitmap = vertical
127e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    ? Bitmap.createBitmap(1, length, config)
128e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    : Bitmap.createBitmap(length, 1, config);
129e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            sBorderLines.put(key.clone(), bitmap);
130e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
131e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return bitmap;
132e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
133e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
134e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private Bitmap getBitmap() {
135e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mBitmap == null) {
136e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mBitmap = onGetBitmap();
137e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int w = mBitmap.getWidth() + mBorder * 2;
138e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int h = mBitmap.getHeight() + mBorder * 2;
139e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mWidth == UNSPECIFIED) {
140e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                setSize(w, h);
141e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
142e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
143e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mBitmap;
144e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
145e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
146e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private void freeBitmap() {
1470589d8287ef05b701754dcb916cc3079c907f847Paul Duffin        Utils.assertTrue(mBitmap != null);
148e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        onFreeBitmap(mBitmap);
149e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mBitmap = null;
150e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
151e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
152e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
153e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public int getWidth() {
154e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mWidth == UNSPECIFIED) getBitmap();
155e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mWidth;
156e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
157e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
158e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
159e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public int getHeight() {
160e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mWidth == UNSPECIFIED) getBitmap();
161e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mHeight;
162e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
163e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
164e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected abstract Bitmap onGetBitmap();
165e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
166e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected abstract void onFreeBitmap(Bitmap bitmap);
167e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
168e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected void invalidateContent() {
169e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mBitmap != null) freeBitmap();
170e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mContentValid = false;
171e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mWidth = UNSPECIFIED;
172e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mHeight = UNSPECIFIED;
173e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
174e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
175e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /**
176e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Whether the content on GPU is valid.
177e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     */
178e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public boolean isContentValid() {
179e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return isLoaded() && mContentValid;
180e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
181e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
182e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    /**
183e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * Updates the content on GPU's memory.
184e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     * @param canvas
185e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka     */
186e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void updateContent(GLCanvas canvas) {
187e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (!isLoaded()) {
188e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) {
189e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                return;
190e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
191e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            uploadToCanvas(canvas);
192e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else if (!mContentValid) {
193e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            Bitmap bitmap = getBitmap();
194e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int format = GLUtils.getInternalFormat(bitmap);
195e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            int type = GLUtils.getType(bitmap);
196e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
197e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            freeBitmap();
198e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mContentValid = true;
199e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
200e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
201e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
202e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static void resetUploadLimit() {
203e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        sUploadedCount = 0;
204e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
205e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
206e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public static boolean uploadLimitReached() {
207e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return sUploadedCount > UPLOAD_LIMIT;
208e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
209e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
210e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    private void uploadToCanvas(GLCanvas canvas) {
211e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
212e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        Bitmap bitmap = getBitmap();
213e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (bitmap != null) {
214e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            try {
215e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int bWidth = bitmap.getWidth();
216e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int bHeight = bitmap.getHeight();
217e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int width = bWidth + mBorder * 2;
218e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int height = bHeight + mBorder * 2;
219e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int texWidth = getTextureWidth();
220e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                int texHeight = getTextureHeight();
221e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
2220589d8287ef05b701754dcb916cc3079c907f847Paul Duffin                Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
223e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
224e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                // Upload the bitmap to a new texture.
225e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                mId = canvas.getGLId().generateTexture();
226e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                canvas.setTextureParameters(this);
227e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
228e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                if (bWidth == texWidth && bHeight == texHeight) {
229e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    canvas.initializeTexture(this, bitmap);
230e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                } else {
231e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    int format = GLUtils.getInternalFormat(bitmap);
232e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    int type = GLUtils.getType(bitmap);
233e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    Config config = bitmap.getConfig();
234e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
235e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    canvas.initializeTextureSize(this, format, type);
236e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
237e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
238e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mBorder > 0) {
239e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        // Left border
240e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        Bitmap line = getBorderLine(true, config, texHeight);
241e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        canvas.texSubImage2D(this, 0, 0, line, format, type);
242e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
243e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        // Top border
244e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        line = getBorderLine(false, config, texWidth);
245e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        canvas.texSubImage2D(this, 0, 0, line, format, type);
246e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
247e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
248e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // Right border
249e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mBorder + bWidth < texWidth) {
250e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        Bitmap line = getBorderLine(true, config, texHeight);
251e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        canvas.texSubImage2D(this, mBorder + bWidth, 0, line, format, type);
252e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
253e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
254e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    // Bottom border
255e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    if (mBorder + bHeight < texHeight) {
256e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        Bitmap line = getBorderLine(false, config, texWidth);
257e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                        canvas.texSubImage2D(this, 0, mBorder + bHeight, line, format, type);
258e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                    }
259e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                }
260e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            } finally {
261e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka                freeBitmap();
262e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            }
263e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            // Update texture state.
264e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            setAssociatedCanvas(canvas);
265e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mState = STATE_LOADED;
266e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mContentValid = true;
267e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        } else {
268e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            mState = STATE_ERROR;
269e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka            throw new RuntimeException("Texture load fail, no bitmap");
270e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        }
271e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
272e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
273e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
274e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected boolean onBind(GLCanvas canvas) {
275e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        updateContent(canvas);
276e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return isContentValid();
277e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
278e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
279e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
280e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    protected int getTarget() {
281e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return GL11.GL_TEXTURE_2D;
282e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
283e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
284e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void setOpaque(boolean isOpaque) {
285e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        mOpaque = isOpaque;
286e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
287e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
288e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
289e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public boolean isOpaque() {
290e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        return mOpaque;
291e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
292e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka
293e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    @Override
294e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    public void recycle() {
295e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        super.recycle();
296e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka        if (mBitmap != null) freeBitmap();
297e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka    }
298e8d1bf7a439450b9979701909164a6baffbe8baeMichael Jurka}
299