diff options
Diffstat (limited to 'src/com/android/camera/support/glrenderer/NinePatchTexture.java')
-rw-r--r-- | src/com/android/camera/support/glrenderer/NinePatchTexture.java | 408 |
1 files changed, 0 insertions, 408 deletions
diff --git a/src/com/android/camera/support/glrenderer/NinePatchTexture.java b/src/com/android/camera/support/glrenderer/NinePatchTexture.java deleted file mode 100644 index c69afd682..000000000 --- a/src/com/android/camera/support/glrenderer/NinePatchTexture.java +++ /dev/null @@ -1,408 +0,0 @@ -package com.android.camera.support.glrenderer; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Rect; - -import com.android.camera.support.common.Utils; - -// NinePatchTexture is a texture backed by a NinePatch resource. -// -// getPaddings() returns paddings specified in the NinePatch. -// getNinePatchChunk() returns the layout data specified in the NinePatch. -// -public class NinePatchTexture extends ResourceTexture { - @SuppressWarnings("unused") - private static final String TAG = "NinePatchTexture"; - private NinePatchChunk mChunk; - private SmallCache<NinePatchInstance> mInstanceCache - = new SmallCache<NinePatchInstance>(); - - public NinePatchTexture(Context context, int resId) { - super(context, resId); - } - - @Override - protected Bitmap onGetBitmap() { - if (mBitmap != null) return mBitmap; - - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - Bitmap bitmap = BitmapFactory.decodeResource( - mContext.getResources(), mResId, options); - mBitmap = bitmap; - setSize(bitmap.getWidth(), bitmap.getHeight()); - byte[] chunkData = bitmap.getNinePatchChunk(); - mChunk = chunkData == null - ? null - : NinePatchChunk.deserialize(bitmap.getNinePatchChunk()); - if (mChunk == null) { - throw new RuntimeException("invalid nine-patch image: " + mResId); - } - return bitmap; - } - - public Rect getPaddings() { - // get the paddings from nine patch - if (mChunk == null) onGetBitmap(); - return mChunk.mPaddings; - } - - public NinePatchChunk getNinePatchChunk() { - if (mChunk == null) onGetBitmap(); - return mChunk; - } - - // This is a simple cache for a small number of things. Linear search - // is used because the cache is small. It also tries to remove less used - // item when the cache is full by moving the often-used items to the front. - private static class SmallCache<V> { - private static final int CACHE_SIZE = 16; - private static final int CACHE_SIZE_START_MOVE = CACHE_SIZE / 2; - private int[] mKey = new int[CACHE_SIZE]; - private V[] mValue = (V[]) new Object[CACHE_SIZE]; - private int mCount; // number of items in this cache - - // Puts a value into the cache. If the cache is full, also returns - // a less used item, otherwise returns null. - public V put(int key, V value) { - if (mCount == CACHE_SIZE) { - V old = mValue[CACHE_SIZE - 1]; // remove the last item - mKey[CACHE_SIZE - 1] = key; - mValue[CACHE_SIZE - 1] = value; - return old; - } else { - mKey[mCount] = key; - mValue[mCount] = value; - mCount++; - return null; - } - } - - public V get(int key) { - for (int i = 0; i < mCount; i++) { - if (mKey[i] == key) { - // Move the accessed item one position to the front, so it - // will less likely to be removed when cache is full. Only - // do this if the cache is starting to get full. - if (mCount > CACHE_SIZE_START_MOVE && i > 0) { - int tmpKey = mKey[i]; - mKey[i] = mKey[i - 1]; - mKey[i - 1] = tmpKey; - - V tmpValue = mValue[i]; - mValue[i] = mValue[i - 1]; - mValue[i - 1] = tmpValue; - } - return mValue[i]; - } - } - return null; - } - - public void clear() { - for (int i = 0; i < mCount; i++) { - mValue[i] = null; // make sure it's can be garbage-collected. - } - mCount = 0; - } - - public int size() { - return mCount; - } - - public V valueAt(int i) { - return mValue[i]; - } - } - - private NinePatchInstance findInstance(GLCanvas canvas, int w, int h) { - int key = w; - key = (key << 16) | h; - NinePatchInstance instance = mInstanceCache.get(key); - - if (instance == null) { - instance = new NinePatchInstance(this, w, h); - NinePatchInstance removed = mInstanceCache.put(key, instance); - if (removed != null) { - removed.recycle(canvas); - } - } - - return instance; - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int w, int h) { - if (!isLoaded()) { - mInstanceCache.clear(); - } - - if (w != 0 && h != 0) { - findInstance(canvas, w, h).draw(canvas, this, x, y); - } - } - - @Override - public void recycle() { - super.recycle(); - GLCanvas canvas = mCanvasRef; - if (canvas == null) return; - int n = mInstanceCache.size(); - for (int i = 0; i < n; i++) { - NinePatchInstance instance = mInstanceCache.valueAt(i); - instance.recycle(canvas); - } - mInstanceCache.clear(); - } -} - -// This keeps data for a specialization of NinePatchTexture with the size -// (width, height). We pre-compute the coordinates for efficiency. -class NinePatchInstance { - - @SuppressWarnings("unused") - private static final String TAG = "NinePatchInstance"; - - // We need 16 vertices for a normal nine-patch image (the 4x4 vertices) - private static final int VERTEX_BUFFER_SIZE = 16 * 2; - - // We need 22 indices for a normal nine-patch image, plus 2 for each - // transparent region. Current there are at most 1 transparent region. - private static final int INDEX_BUFFER_SIZE = 22 + 2; - - private FloatBuffer mXyBuffer; - private FloatBuffer mUvBuffer; - private ByteBuffer mIndexBuffer; - - // Names for buffer names: xy, uv, index. - private int mXyBufferName = -1; - private int mUvBufferName; - private int mIndexBufferName; - - private int mIdxCount; - - public NinePatchInstance(NinePatchTexture tex, int width, int height) { - NinePatchChunk chunk = tex.getNinePatchChunk(); - - if (width <= 0 || height <= 0) { - throw new RuntimeException("invalid dimension"); - } - - // The code should be easily extended to handle the general cases by - // allocating more space for buffers. But let's just handle the only - // use case. - if (chunk.mDivX.length != 2 || chunk.mDivY.length != 2) { - throw new RuntimeException("unsupported nine patch"); - } - - float divX[] = new float[4]; - float divY[] = new float[4]; - float divU[] = new float[4]; - float divV[] = new float[4]; - - int nx = stretch(divX, divU, chunk.mDivX, tex.getWidth(), width); - int ny = stretch(divY, divV, chunk.mDivY, tex.getHeight(), height); - - prepareVertexData(divX, divY, divU, divV, nx, ny, chunk.mColor); - } - - /** - * Stretches the texture according to the nine-patch rules. It will - * linearly distribute the strechy parts defined in the nine-patch chunk to - * the target area. - * - * <pre> - * source - * /--------------^---------------\ - * u0 u1 u2 u3 u4 u5 - * div ---> |fffff|ssssssss|fff|ssssss|ffff| ---> u - * | div0 div1 div2 div3 | - * | | / / / / - * | | / / / / - * | | / / / / - * |fffff|ssss|fff|sss|ffff| ---> x - * x0 x1 x2 x3 x4 x5 - * \----------v------------/ - * target - * - * f: fixed segment - * s: stretchy segment - * </pre> - * - * @param div the stretch parts defined in nine-patch chunk - * @param source the length of the texture - * @param target the length on the drawing plan - * @param u output, the positions of these dividers in the texture - * coordinate - * @param x output, the corresponding position of these dividers on the - * drawing plan - * @return the number of these dividers. - */ - private static int stretch( - float x[], float u[], int div[], int source, int target) { - int textureSize = Utils.nextPowerOf2(source); - float textureBound = (float) source / textureSize; - - float stretch = 0; - for (int i = 0, n = div.length; i < n; i += 2) { - stretch += div[i + 1] - div[i]; - } - - float remaining = target - source + stretch; - - float lastX = 0; - float lastU = 0; - - x[0] = 0; - u[0] = 0; - for (int i = 0, n = div.length; i < n; i += 2) { - // Make the stretchy segment a little smaller to prevent sampling - // on neighboring fixed segments. - // fixed segment - x[i + 1] = lastX + (div[i] - lastU) + 0.5f; - u[i + 1] = Math.min((div[i] + 0.5f) / textureSize, textureBound); - - // stretchy segment - float partU = div[i + 1] - div[i]; - float partX = remaining * partU / stretch; - remaining -= partX; - stretch -= partU; - - lastX = x[i + 1] + partX; - lastU = div[i + 1]; - x[i + 2] = lastX - 0.5f; - u[i + 2] = Math.min((lastU - 0.5f)/ textureSize, textureBound); - } - // the last fixed segment - x[div.length + 1] = target; - u[div.length + 1] = textureBound; - - // remove segments with length 0. - int last = 0; - for (int i = 1, n = div.length + 2; i < n; ++i) { - if ((x[i] - x[last]) < 1f) continue; - x[++last] = x[i]; - u[last] = u[i]; - } - return last + 1; - } - - private void prepareVertexData(float x[], float y[], float u[], float v[], - int nx, int ny, int[] color) { - /* - * Given a 3x3 nine-patch image, the vertex order is defined as the - * following graph: - * - * (0) (1) (2) (3) - * | /| /| /| - * | / | / | / | - * (4) (5) (6) (7) - * | \ | \ | \ | - * | \| \| \| - * (8) (9) (A) (B) - * | /| /| /| - * | / | / | / | - * (C) (D) (E) (F) - * - * And we draw the triangle strip in the following index order: - * - * index: 04152637B6A5948C9DAEBF - */ - int pntCount = 0; - float xy[] = new float[VERTEX_BUFFER_SIZE]; - float uv[] = new float[VERTEX_BUFFER_SIZE]; - for (int j = 0; j < ny; ++j) { - for (int i = 0; i < nx; ++i) { - int xIndex = (pntCount++) << 1; - int yIndex = xIndex + 1; - xy[xIndex] = x[i]; - xy[yIndex] = y[j]; - uv[xIndex] = u[i]; - uv[yIndex] = v[j]; - } - } - - int idxCount = 1; - boolean isForward = false; - byte index[] = new byte[INDEX_BUFFER_SIZE]; - for (int row = 0; row < ny - 1; row++) { - --idxCount; - isForward = !isForward; - - int start, end, inc; - if (isForward) { - start = 0; - end = nx; - inc = 1; - } else { - start = nx - 1; - end = -1; - inc = -1; - } - - for (int col = start; col != end; col += inc) { - int k = row * nx + col; - if (col != start) { - int colorIdx = row * (nx - 1) + col; - if (isForward) colorIdx--; - if (color[colorIdx] == NinePatchChunk.TRANSPARENT_COLOR) { - index[idxCount] = index[idxCount - 1]; - ++idxCount; - index[idxCount++] = (byte) k; - } - } - - index[idxCount++] = (byte) k; - index[idxCount++] = (byte) (k + nx); - } - } - - mIdxCount = idxCount; - - int size = (pntCount * 2) * (Float.SIZE / Byte.SIZE); - mXyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); - mUvBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer(); - mIndexBuffer = allocateDirectNativeOrderBuffer(mIdxCount); - - mXyBuffer.put(xy, 0, pntCount * 2).position(0); - mUvBuffer.put(uv, 0, pntCount * 2).position(0); - mIndexBuffer.put(index, 0, idxCount).position(0); - } - - private static ByteBuffer allocateDirectNativeOrderBuffer(int size) { - return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); - } - - private void prepareBuffers(GLCanvas canvas) { - mXyBufferName = canvas.uploadBuffer(mXyBuffer); - mUvBufferName = canvas.uploadBuffer(mUvBuffer); - mIndexBufferName = canvas.uploadBuffer(mIndexBuffer); - - // These buffers are never used again. - mXyBuffer = null; - mUvBuffer = null; - mIndexBuffer = null; - } - - public void draw(GLCanvas canvas, NinePatchTexture tex, int x, int y) { - if (mXyBufferName == -1) { - prepareBuffers(canvas); - } - canvas.drawMesh(tex, x, y, mXyBufferName, mUvBufferName, mIndexBufferName, mIdxCount); - } - - public void recycle(GLCanvas canvas) { - if (mXyBuffer == null) { - canvas.deleteBuffer(mXyBufferName); - canvas.deleteBuffer(mUvBufferName); - canvas.deleteBuffer(mIndexBufferName); - mXyBufferName = -1; - } - } -}
\ No newline at end of file |