1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17a4eae1abb4f2547dfbda84301ee764ce35464881John Reckpackage com.android.gallery3d.glrenderer; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapFactory; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 242b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils; 252b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.ByteBuffer; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.ByteOrder; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.FloatBuffer; 292b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// NinePatchTexture is a texture backed by a NinePatch resource. 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getPaddings() returns paddings specified in the NinePatch. 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getNinePatchChunk() returns the layout data specified in the NinePatch. 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class NinePatchTexture extends ResourceTexture { 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "NinePatchTexture"; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private NinePatchChunk mChunk; 3995018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang private SmallCache<NinePatchInstance> mInstanceCache 4095018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang = new SmallCache<NinePatchInstance>(); 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public NinePatchTexture(Context context, int resId) { 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(context, resId); 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected Bitmap onGetBitmap() { 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mBitmap != null) return mBitmap; 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin BitmapFactory.Options options = new BitmapFactory.Options(); 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin options.inPreferredConfig = Bitmap.Config.ARGB_8888; 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Bitmap bitmap = BitmapFactory.decodeResource( 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContext.getResources(), mResId, options); 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mBitmap = bitmap; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setSize(bitmap.getWidth(), bitmap.getHeight()); 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin byte[] chunkData = bitmap.getNinePatchChunk(); 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mChunk = chunkData == null 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? null 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : NinePatchChunk.deserialize(bitmap.getNinePatchChunk()); 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mChunk == null) { 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException("invalid nine-patch image: " + mResId); 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return bitmap; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Rect getPaddings() { 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // get the paddings from nine patch 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mChunk == null) onGetBitmap(); 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mChunk.mPaddings; 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public NinePatchChunk getNinePatchChunk() { 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mChunk == null) onGetBitmap(); 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mChunk; 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 7795018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // This is a simple cache for a small number of things. Linear search 7895018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // is used because the cache is small. It also tries to remove less used 7995018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // item when the cache is full by moving the often-used items to the front. 8095018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang private static class SmallCache<V> { 8195018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang private static final int CACHE_SIZE = 16; 8295018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang private static final int CACHE_SIZE_START_MOVE = CACHE_SIZE / 2; 8395018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang private int[] mKey = new int[CACHE_SIZE]; 8495018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang private V[] mValue = (V[]) new Object[CACHE_SIZE]; 8595018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang private int mCount; // number of items in this cache 8695018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang 8795018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // Puts a value into the cache. If the cache is full, also returns 8895018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // a less used item, otherwise returns null. 8995018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang public V put(int key, V value) { 9095018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang if (mCount == CACHE_SIZE) { 9195018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang V old = mValue[CACHE_SIZE - 1]; // remove the last item 9295018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mKey[CACHE_SIZE - 1] = key; 9395018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mValue[CACHE_SIZE - 1] = value; 9495018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang return old; 9595018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang } else { 9695018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mKey[mCount] = key; 9795018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mValue[mCount] = value; 9895018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mCount++; 9995018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang return null; 10095018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang } 10195018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang } 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 10395018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang public V get(int key) { 10495018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang for (int i = 0; i < mCount; i++) { 10595018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang if (mKey[i] == key) { 10695018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // Move the accessed item one position to the front, so it 10795018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // will less likely to be removed when cache is full. Only 10895018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang // do this if the cache is starting to get full. 10995018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang if (mCount > CACHE_SIZE_START_MOVE && i > 0) { 11095018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang int tmpKey = mKey[i]; 11195018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mKey[i] = mKey[i - 1]; 11295018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mKey[i - 1] = tmpKey; 11395018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang 11495018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang V tmpValue = mValue[i]; 11595018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mValue[i] = mValue[i - 1]; 11695018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mValue[i - 1] = tmpValue; 11795018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang } 11895018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang return mValue[i]; 11995018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang } 12095018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang } 12195018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang return null; 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 12495018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang public void clear() { 12595018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang for (int i = 0; i < mCount; i++) { 12695018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mValue[i] = null; // make sure it's can be garbage-collected. 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 12895018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang mCount = 0; 12995018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang } 13095018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang 13195018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang public int size() { 13295018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang return mCount; 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 13595018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang public V valueAt(int i) { 13695018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang return mValue[i]; 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private NinePatchInstance findInstance(GLCanvas canvas, int w, int h) { 14195018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang int key = w; 14295018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang key = (key << 16) | h; 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin NinePatchInstance instance = mInstanceCache.get(key); 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (instance == null) { 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin instance = new NinePatchInstance(this, w, h); 14795018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang NinePatchInstance removed = mInstanceCache.put(key, instance); 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (removed != null) { 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin removed.recycle(canvas); 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return instance; 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void draw(GLCanvas canvas, int x, int y, int w, int h) { 15837c605949219b8bf54c165c34d6405f5f2989f50Owen Lin if (!isLoaded()) { 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInstanceCache.clear(); 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (w != 0 && h != 0) { 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin findInstance(canvas, w, h).draw(canvas, this, x, y); 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void recycle() { 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super.recycle(); 1703950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang GLCanvas canvas = mCanvasRef; 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (canvas == null) return; 17295018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang int n = mInstanceCache.size(); 17395018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang for (int i = 0; i < n; i++) { 17495018d10aa68ecbea7ebce434733341a642510deChih-Chung Chang NinePatchInstance instance = mInstanceCache.valueAt(i); 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin instance.recycle(canvas); 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInstanceCache.clear(); 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// This keeps data for a specialization of NinePatchTexture with the size 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (width, height). We pre-compute the coordinates for efficiency. 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linclass NinePatchInstance { 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "NinePatchInstance"; 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We need 16 vertices for a normal nine-patch image (the 4x4 vertices) 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int VERTEX_BUFFER_SIZE = 16 * 2; 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We need 22 indices for a normal nine-patch image, plus 2 for each 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // transparent region. Current there are at most 1 transparent region. 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int INDEX_BUFFER_SIZE = 22 + 2; 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private FloatBuffer mXyBuffer; 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private FloatBuffer mUvBuffer; 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ByteBuffer mIndexBuffer; 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Names for buffer names: xy, uv, index. 2006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount private int mXyBufferName = -1; 2016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount private int mUvBufferName; 2026eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount private int mIndexBufferName; 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mIdxCount; 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public NinePatchInstance(NinePatchTexture tex, int width, int height) { 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin NinePatchChunk chunk = tex.getNinePatchChunk(); 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (width <= 0 || height <= 0) { 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException("invalid dimension"); 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The code should be easily extended to handle the general cases by 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // allocating more space for buffers. But let's just handle the only 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // use case. 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (chunk.mDivX.length != 2 || chunk.mDivY.length != 2) { 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException("unsupported nine patch"); 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divX[] = new float[4]; 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divY[] = new float[4]; 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divU[] = new float[4]; 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divV[] = new float[4]; 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int nx = stretch(divX, divU, chunk.mDivX, tex.getWidth(), width); 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int ny = stretch(divY, divV, chunk.mDivY, tex.getHeight(), height); 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareVertexData(divX, divY, divU, divV, nx, ny, chunk.mColor); 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Stretches the texture according to the nine-patch rules. It will 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * linearly distribute the strechy parts defined in the nine-patch chunk to 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * the target area. 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * <pre> 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * source 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * /--------------^---------------\ 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * u0 u1 u2 u3 u4 u5 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * div ---> |fffff|ssssssss|fff|ssssss|ffff| ---> u 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | div0 div1 div2 div3 | 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | / / / / 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | / / / / 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | / / / / 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * |fffff|ssss|fff|sss|ffff| ---> x 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * x0 x1 x2 x3 x4 x5 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * \----------v------------/ 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * target 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * f: fixed segment 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * s: stretchy segment 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * </pre> 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param div the stretch parts defined in nine-patch chunk 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param source the length of the texture 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param target the length on the drawing plan 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param u output, the positions of these dividers in the texture 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * coordinate 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param x output, the corresponding position of these dividers on the 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * drawing plan 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the number of these dividers. 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static int stretch( 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float x[], float u[], int div[], int source, int target) { 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int textureSize = Utils.nextPowerOf2(source); 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float textureBound = (float) source / textureSize; 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float stretch = 0; 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = div.length; i < n; i += 2) { 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin stretch += div[i + 1] - div[i]; 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float remaining = target - source + stretch; 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float lastX = 0; 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float lastU = 0; 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[0] = 0; 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[0] = 0; 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = div.length; i < n; i += 2) { 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Make the stretchy segment a little smaller to prevent sampling 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // on neighboring fixed segments. 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // fixed segment 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[i + 1] = lastX + (div[i] - lastU) + 0.5f; 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[i + 1] = Math.min((div[i] + 0.5f) / textureSize, textureBound); 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // stretchy segment 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float partU = div[i + 1] - div[i]; 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float partX = remaining * partU / stretch; 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin remaining -= partX; 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin stretch -= partU; 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin lastX = x[i + 1] + partX; 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin lastU = div[i + 1]; 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[i + 2] = lastX - 0.5f; 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[i + 2] = Math.min((lastU - 0.5f)/ textureSize, textureBound); 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // the last fixed segment 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[div.length + 1] = target; 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[div.length + 1] = textureBound; 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // remove segments with length 0. 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int last = 0; 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 1, n = div.length + 2; i < n; ++i) { 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if ((x[i] - x[last]) < 1f) continue; 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[++last] = x[i]; 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[last] = u[i]; 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return last + 1; 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void prepareVertexData(float x[], float y[], float u[], float v[], 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int nx, int ny, int[] color) { 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /* 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Given a 3x3 nine-patch image, the vertex order is defined as the 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * following graph: 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (0) (1) (2) (3) 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | /| /| /| 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | / | / | / | 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (4) (5) (6) (7) 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | \ | \ | \ | 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | \| \| \| 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (8) (9) (A) (B) 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | /| /| /| 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | / | / | / | 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (C) (D) (E) (F) 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * And we draw the triangle strip in the following index order: 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * index: 04152637B6A5948C9DAEBF 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int pntCount = 0; 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float xy[] = new float[VERTEX_BUFFER_SIZE]; 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float uv[] = new float[VERTEX_BUFFER_SIZE]; 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int j = 0; j < ny; ++j) { 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < nx; ++i) { 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int xIndex = (pntCount++) << 1; 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int yIndex = xIndex + 1; 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin xy[xIndex] = x[i]; 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin xy[yIndex] = y[j]; 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin uv[xIndex] = u[i]; 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin uv[yIndex] = v[j]; 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int idxCount = 1; 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean isForward = false; 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin byte index[] = new byte[INDEX_BUFFER_SIZE]; 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int row = 0; row < ny - 1; row++) { 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin --idxCount; 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin isForward = !isForward; 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start, end, inc; 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isForward) { 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start = 0; 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin end = nx; 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin inc = 1; 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start = nx - 1; 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin end = -1; 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin inc = -1; 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int col = start; col != end; col += inc) { 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int k = row * nx + col; 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (col != start) { 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int colorIdx = row * (nx - 1) + col; 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isForward) colorIdx--; 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (color[colorIdx] == NinePatchChunk.TRANSPARENT_COLOR) { 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount] = index[idxCount - 1]; 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ++idxCount; 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount++] = (byte) k; 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount++] = (byte) k; 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount++] = (byte) (k + nx); 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIdxCount = idxCount; 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int size = (pntCount * 2) * (Float.SIZE / Byte.SIZE); 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer = allocateDirectNativeOrderBuffer(mIdxCount); 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer.put(xy, 0, pntCount * 2).position(0); 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer.put(uv, 0, pntCount * 2).position(0); 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer.put(index, 0, idxCount).position(0); 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static ByteBuffer allocateDirectNativeOrderBuffer(int size) { 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void prepareBuffers(GLCanvas canvas) { 3996eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount mXyBufferName = canvas.uploadBuffer(mXyBuffer); 4006eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount mUvBufferName = canvas.uploadBuffer(mUvBuffer); 4016eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount mIndexBufferName = canvas.uploadBuffer(mIndexBuffer); 402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // These buffers are never used again. 404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer = null; 405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer = null; 406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer = null; 407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void draw(GLCanvas canvas, NinePatchTexture tex, int x, int y) { 4106eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount if (mXyBufferName == -1) { 411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareBuffers(canvas); 412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 4136eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount canvas.drawMesh(tex, x, y, mXyBufferName, mUvBufferName, mIndexBufferName, mIdxCount); 414f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 415f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 416f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void recycle(GLCanvas canvas) { 4176eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount if (mXyBuffer == null) { 4186eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount canvas.deleteBuffer(mXyBufferName); 4196eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount canvas.deleteBuffer(mUvBufferName); 4206eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount canvas.deleteBuffer(mIndexBufferName); 4216eb33768a15e2b4cc647bc55474568cf710876dbGeorge Mount mXyBufferName = -1; 422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 425