summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/support/glrenderer/NinePatchTexture.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/support/glrenderer/NinePatchTexture.java')
-rw-r--r--src/com/android/camera/support/glrenderer/NinePatchTexture.java408
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