NinePatchTexture.java revision f9a0a4306d589b4a4e20554fed512a603426bfa1
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 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.BitmapFactory; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.ByteBuffer; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.ByteOrder; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.nio.FloatBuffer; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.LinkedHashMap; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.Map; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL11; 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// NinePatchTexture is a texture backed by a NinePatch resource. 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getPaddings() returns paddings specified in the NinePatch. 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getNinePatchChunk() returns the layout data specified in the NinePatch. 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class NinePatchTexture extends ResourceTexture { 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "NinePatchTexture"; 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private NinePatchChunk mChunk; 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private MyCacheMap<Long, NinePatchInstance> mInstanceCache = 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new MyCacheMap<Long, NinePatchInstance>(); 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public NinePatchTexture(Context context, int resId) { 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(context, resId); 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected Bitmap onGetBitmap() { 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mBitmap != null) return mBitmap; 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin BitmapFactory.Options options = new BitmapFactory.Options(); 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin options.inPreferredConfig = Bitmap.Config.ARGB_8888; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Bitmap bitmap = BitmapFactory.decodeResource( 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContext.getResources(), mResId, options); 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mBitmap = bitmap; 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setSize(bitmap.getWidth(), bitmap.getHeight()); 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin byte[] chunkData = bitmap.getNinePatchChunk(); 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mChunk = chunkData == null 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? null 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : NinePatchChunk.deserialize(bitmap.getNinePatchChunk()); 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mChunk == null) { 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException("invalid nine-patch image: " + mResId); 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return bitmap; 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Rect getPaddings() { 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // get the paddings from nine patch 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mChunk == null) onGetBitmap(); 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mChunk.mPaddings; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public NinePatchChunk getNinePatchChunk() { 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mChunk == null) onGetBitmap(); 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mChunk; 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class MyCacheMap<K, V> extends LinkedHashMap<K, V> { 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int CACHE_SIZE = 16; 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private V mJustRemoved; 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MyCacheMap() { 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(4, 0.75f, true); 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (size() > CACHE_SIZE) { 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mJustRemoved = eldest.getValue(); 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public V getJustRemoved() { 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin V result = mJustRemoved; 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mJustRemoved = null; 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return result; 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private NinePatchInstance findInstance(GLCanvas canvas, int w, int h) { 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long key = w; 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin key = (key << 32) | h; 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin NinePatchInstance instance = mInstanceCache.get(key); 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (instance == null) { 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin instance = new NinePatchInstance(this, w, h); 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInstanceCache.put(key, instance); 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin NinePatchInstance removed = mInstanceCache.getJustRemoved(); 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (removed != null) { 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin removed.recycle(canvas); 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return instance; 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void draw(GLCanvas canvas, int x, int y, int w, int h) { 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!isLoaded(canvas)) { 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInstanceCache.clear(); 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (w != 0 && h != 0) { 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin findInstance(canvas, w, h).draw(canvas, this, x, y); 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void recycle() { 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super.recycle(); 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin GLCanvas canvas = mCanvasRef == null ? null : mCanvasRef.get(); 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (canvas == null) return; 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (NinePatchInstance instance : mInstanceCache.values()) { 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin instance.recycle(canvas); 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mInstanceCache.clear(); 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// This keeps data for a specialization of NinePatchTexture with the size 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (width, height). We pre-compute the coordinates for efficiency. 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linclass NinePatchInstance { 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "NinePatchInstance"; 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We need 16 vertices for a normal nine-patch image (the 4x4 vertices) 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int VERTEX_BUFFER_SIZE = 16 * 2; 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We need 22 indices for a normal nine-patch image, plus 2 for each 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // transparent region. Current there are at most 1 transparent region. 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int INDEX_BUFFER_SIZE = 22 + 2; 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private FloatBuffer mXyBuffer; 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private FloatBuffer mUvBuffer; 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ByteBuffer mIndexBuffer; 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Names for buffer names: xy, uv, index. 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int[] mBufferNames; 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mIdxCount; 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public NinePatchInstance(NinePatchTexture tex, int width, int height) { 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin NinePatchChunk chunk = tex.getNinePatchChunk(); 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (width <= 0 || height <= 0) { 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException("invalid dimension"); 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The code should be easily extended to handle the general cases by 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // allocating more space for buffers. But let's just handle the only 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // use case. 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (chunk.mDivX.length != 2 || chunk.mDivY.length != 2) { 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException("unsupported nine patch"); 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divX[] = new float[4]; 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divY[] = new float[4]; 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divU[] = new float[4]; 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float divV[] = new float[4]; 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int nx = stretch(divX, divU, chunk.mDivX, tex.getWidth(), width); 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int ny = stretch(divY, divV, chunk.mDivY, tex.getHeight(), height); 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareVertexData(divX, divY, divU, divV, nx, ny, chunk.mColor); 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Stretches the texture according to the nine-patch rules. It will 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * linearly distribute the strechy parts defined in the nine-patch chunk to 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * the target area. 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * <pre> 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * source 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * /--------------^---------------\ 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * u0 u1 u2 u3 u4 u5 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * div ---> |fffff|ssssssss|fff|ssssss|ffff| ---> u 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | div0 div1 div2 div3 | 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | / / / / 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | / / / / 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | / / / / 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * |fffff|ssss|fff|sss|ffff| ---> x 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * x0 x1 x2 x3 x4 x5 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * \----------v------------/ 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * target 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * f: fixed segment 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * s: stretchy segment 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * </pre> 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param div the stretch parts defined in nine-patch chunk 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param source the length of the texture 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param target the length on the drawing plan 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param u output, the positions of these dividers in the texture 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * coordinate 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param x output, the corresponding position of these dividers on the 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * drawing plan 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the number of these dividers. 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static int stretch( 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float x[], float u[], int div[], int source, int target) { 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int textureSize = Utils.nextPowerOf2(source); 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float textureBound = (float) source / textureSize; 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float stretch = 0; 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = div.length; i < n; i += 2) { 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin stretch += div[i + 1] - div[i]; 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float remaining = target - source + stretch; 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float lastX = 0; 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float lastU = 0; 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[0] = 0; 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[0] = 0; 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = div.length; i < n; i += 2) { 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Make the stretchy segment a little smaller to prevent sampling 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // on neighboring fixed segments. 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // fixed segment 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[i + 1] = lastX + (div[i] - lastU) + 0.5f; 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[i + 1] = Math.min((div[i] + 0.5f) / textureSize, textureBound); 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // stretchy segment 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float partU = div[i + 1] - div[i]; 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float partX = remaining * partU / stretch; 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin remaining -= partX; 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin stretch -= partU; 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin lastX = x[i + 1] + partX; 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin lastU = div[i + 1]; 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[i + 2] = lastX - 0.5f; 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[i + 2] = Math.min((lastU - 0.5f)/ textureSize, textureBound); 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // the last fixed segment 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[div.length + 1] = target; 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[div.length + 1] = textureBound; 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // remove segments with length 0. 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int last = 0; 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 1, n = div.length + 2; i < n; ++i) { 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if ((x[i] - x[last]) < 1f) continue; 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin x[++last] = x[i]; 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin u[last] = u[i]; 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return last + 1; 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void prepareVertexData(float x[], float y[], float u[], float v[], 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int nx, int ny, int[] color) { 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /* 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Given a 3x3 nine-patch image, the vertex order is defined as the 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * following graph: 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (0) (1) (2) (3) 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | /| /| /| 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | / | / | / | 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (4) (5) (6) (7) 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | \ | \ | \ | 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | \| \| \| 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (8) (9) (A) (B) 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | /| /| /| 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | / | / | / | 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (C) (D) (E) (F) 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * And we draw the triangle strip in the following index order: 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * index: 04152637B6A5948C9DAEBF 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int pntCount = 0; 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float xy[] = new float[VERTEX_BUFFER_SIZE]; 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float uv[] = new float[VERTEX_BUFFER_SIZE]; 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int j = 0; j < ny; ++j) { 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < nx; ++i) { 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int xIndex = (pntCount++) << 1; 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int yIndex = xIndex + 1; 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin xy[xIndex] = x[i]; 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin xy[yIndex] = y[j]; 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin uv[xIndex] = u[i]; 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin uv[yIndex] = v[j]; 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int idxCount = 1; 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean isForward = false; 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin byte index[] = new byte[INDEX_BUFFER_SIZE]; 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int row = 0; row < ny - 1; row++) { 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin --idxCount; 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin isForward = !isForward; 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start, end, inc; 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isForward) { 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start = 0; 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin end = nx; 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin inc = 1; 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start = nx - 1; 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin end = -1; 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin inc = -1; 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int col = start; col != end; col += inc) { 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int k = row * nx + col; 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (col != start) { 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int colorIdx = row * (nx - 1) + col; 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isForward) colorIdx--; 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (color[colorIdx] == NinePatchChunk.TRANSPARENT_COLOR) { 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount] = index[idxCount - 1]; 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ++idxCount; 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount++] = (byte) k; 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount++] = (byte) k; 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index[idxCount++] = (byte) (k + nx); 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIdxCount = idxCount; 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int size = (pntCount * 2) * (Float.SIZE / Byte.SIZE); 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer = allocateDirectNativeOrderBuffer(mIdxCount); 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer.put(xy, 0, pntCount * 2).position(0); 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer.put(uv, 0, pntCount * 2).position(0); 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer.put(index, 0, idxCount).position(0); 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static ByteBuffer allocateDirectNativeOrderBuffer(int size) { 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void prepareBuffers(GLCanvas canvas) { 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mBufferNames = new int[3]; 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin GL11 gl = canvas.getGLInstance(); 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glGenBuffers(3, mBufferNames, 0); 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBufferNames[0]); 365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glBufferData(GL11.GL_ARRAY_BUFFER, 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer.capacity() * (Float.SIZE / Byte.SIZE), 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer, GL11.GL_STATIC_DRAW); 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBufferNames[1]); 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glBufferData(GL11.GL_ARRAY_BUFFER, 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer.capacity() * (Float.SIZE / Byte.SIZE), 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer, GL11.GL_STATIC_DRAW); 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mBufferNames[2]); 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer.capacity(), 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer, GL11.GL_STATIC_DRAW); 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // These buffers are never used again. 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mXyBuffer = null; 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUvBuffer = null; 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIndexBuffer = null; 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void draw(GLCanvas canvas, NinePatchTexture tex, int x, int y) { 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mBufferNames == null) { 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareBuffers(canvas); 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.drawMesh(tex, x, y, mBufferNames[0], mBufferNames[1], 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mBufferNames[2], mIdxCount); 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void recycle(GLCanvas canvas) { 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mBufferNames != null) { 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.deleteBuffer(mBufferNames[0]); 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.deleteBuffer(mBufferNames[1]); 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.deleteBuffer(mBufferNames[2]); 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mBufferNames = null; 399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 402