diff options
-rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 42 | ||||
-rw-r--r-- | core/jni/android/graphics/Graphics.cpp | 10 | ||||
-rw-r--r-- | core/jni/android/graphics/GraphicsJNI.h | 13 | ||||
-rw-r--r-- | graphics/java/android/graphics/utils/BoundaryPatch.java | 173 |
4 files changed, 230 insertions, 8 deletions
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index dc72008..e1e9536 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -27,6 +27,9 @@ #include "SkShader.h" #include "SkTemplates.h" +#include "SkBoundaryPatch.h" +#include "SkMeshUtils.h" + #define TIME_DRAWx static uint32_t get_thread_msec() { @@ -861,8 +864,6 @@ public: *matrix = canvas->getTotalMatrix(); } }; - -/////////////////////////////////////////////////////////////////////////////// static JNINativeMethod gCanvasMethods[] = { {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer}, @@ -965,6 +966,42 @@ static JNINativeMethod gCanvasMethods[] = { {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches} }; +/////////////////////////////////////////////////////////////////////////////// + +static void BoundaryPatch_computeCubic(JNIEnv* env, jobject, jfloatArray jpts, + int texW, int texH, int rows, int cols, + jfloatArray jverts, jshortArray jidx) { + AutoJavaFloatArray ptsArray(env, jpts, 24, kRO_JNIAccess); + + int vertCount = rows * cols; + AutoJavaFloatArray vertsArray(env, jverts, vertCount * 4, kRW_JNIAccess); + SkPoint* verts = (SkPoint*)vertsArray.ptr(); + SkPoint* texs = verts + vertCount; + + int idxCount = (rows - 1) * (cols - 1) * 6; + AutoJavaShortArray idxArray(env, jidx, idxCount, kRW_JNIAccess); + uint16_t* idx = (uint16_t*)idxArray.ptr(); // cast from int16_t* + + SkCubicBoundary cubic; + memcpy(cubic.fPts, ptsArray.ptr(), 12 * sizeof(SkPoint)); + + SkBoundaryPatch patch; + patch.setBoundary(&cubic); + // generate our verts + patch.evalPatch(verts, rows, cols); + + SkMeshIndices mesh; + // generate our texs and idx + mesh.init(texs, idx, texW, texH, rows, cols); +} + +static JNINativeMethod gBoundaryPatchMethods[] = { + {"nativeComputeCubicPatch", "([FIIII[F[S)V", + (void*)BoundaryPatch_computeCubic }, +}; + +/////////////////////////////////////////////////////////////////////////////// + #include <android_runtime/AndroidRuntime.h> #define REG(env, name, array) \ @@ -976,6 +1013,7 @@ int register_android_graphics_Canvas(JNIEnv* env) { int result; REG(env, "android/graphics/Canvas", gCanvasMethods); + REG(env, "android/graphics/utils/BoundaryPatch", gBoundaryPatchMethods); return result; } diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 2e0caed..01aad93 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -56,7 +56,7 @@ bool GraphicsJNI::hasException(JNIEnv *env) { /////////////////////////////////////////////////////////////////////////////// AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array, - int minLength) + int minLength, JNIAccess access) : fEnv(env), fArray(array), fPtr(NULL), fLen(0) { SkASSERT(env); if (array) { @@ -66,11 +66,12 @@ AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array, } fPtr = env->GetFloatArrayElements(array, NULL); } + fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0; } AutoJavaFloatArray::~AutoJavaFloatArray() { if (fPtr) { - fEnv->ReleaseFloatArrayElements(fArray, fPtr, 0); + fEnv->ReleaseFloatArrayElements(fArray, fPtr, fReleaseMode); } } @@ -94,7 +95,7 @@ AutoJavaIntArray::~AutoJavaIntArray() { } AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array, - int minLength) + int minLength, JNIAccess access) : fEnv(env), fArray(array), fPtr(NULL), fLen(0) { SkASSERT(env); if (array) { @@ -104,11 +105,12 @@ AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array, } fPtr = env->GetShortArrayElements(array, NULL); } + fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0; } AutoJavaShortArray::~AutoJavaShortArray() { if (fPtr) { - fEnv->ReleaseShortArrayElements(fArray, fPtr, 0); + fEnv->ReleaseShortArrayElements(fArray, fPtr, fReleaseMode); } } diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 7adadbc..fe24b05 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -80,9 +80,15 @@ private: bool fReportSizeToVM; }; +enum JNIAccess { + kRO_JNIAccess, + kRW_JNIAccess +}; + class AutoJavaFloatArray { public: - AutoJavaFloatArray(JNIEnv* env, jfloatArray array, int minLength = 0); + AutoJavaFloatArray(JNIEnv* env, jfloatArray array, + int minLength = 0, JNIAccess = kRW_JNIAccess); ~AutoJavaFloatArray(); float* ptr() const { return fPtr; } @@ -93,6 +99,7 @@ private: jfloatArray fArray; float* fPtr; int fLen; + int fReleaseMode; }; class AutoJavaIntArray { @@ -112,7 +119,8 @@ private: class AutoJavaShortArray { public: - AutoJavaShortArray(JNIEnv* env, jshortArray array, int minLength = 0); + AutoJavaShortArray(JNIEnv* env, jshortArray array, + int minLength = 0, JNIAccess = kRW_JNIAccess); ~AutoJavaShortArray(); jshort* ptr() const { return fPtr; } @@ -123,6 +131,7 @@ private: jshortArray fArray; jshort* fPtr; int fLen; + int fReleaseMode; }; class AutoJavaByteArray { diff --git a/graphics/java/android/graphics/utils/BoundaryPatch.java b/graphics/java/android/graphics/utils/BoundaryPatch.java new file mode 100644 index 0000000..1cd5e13 --- /dev/null +++ b/graphics/java/android/graphics/utils/BoundaryPatch.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.utils; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Shader; +import android.graphics.Xfermode; + +/** + * @hide + */ +public class BoundaryPatch { + private Paint mPaint; + private Bitmap mTexture; + private int mRows; + private int mCols; + private float[] mCubicPoints; + private boolean mDirty; + // these are the computed output of the native code + private float[] mVerts; + private short[] mIndices; + + public BoundaryPatch() { + mRows = mCols = 2; // default minimum + mCubicPoints = new float[24]; + mPaint = new Paint(); + mPaint.setDither(true); + mPaint.setFilterBitmap(true); + mDirty = true; + } + + /** + * Set the boundary to be 4 cubics. This takes a single array of floats, + * and picks up the 12 pairs starting at offset, and treats them as + * the x,y coordinates of the cubic control points. The points wrap around + * a patch, as follows. For documentation purposes, pts[i] will mean the + * x,y pair of floats, as if pts[] were an array of "points". + * + * Top: pts[0..3] + * Right: pts[3..6] + * Bottom: pts[6..9] + * Right: pts[9..11], pts[0] + * + * The coordinates are copied from the input array, so subsequent changes + * to pts[] will not be reflected in the boundary. + * + * @param pts The src array of x,y pairs for the boundary cubics + * @param offset The index into pts of the first pair + * @param rows The number of points across to approximate the boundary. + * Must be >= 2, though very large values may slow down drawing + * @param cols The number of points down to approximate the boundary. + * Must be >= 2, though very large values may slow down drawing + */ + public void setCubicBoundary(float[] pts, int offset, int rows, int cols) { + if (rows < 2 || cols < 2) { + throw new RuntimeException("rows and cols must be >= 2"); + } + System.arraycopy(pts, offset, mCubicPoints, 0, 24); + if (mRows != rows || mCols != cols) { + mRows = rows; + mCols = cols; + } + mDirty = true; + } + + /** + * Reference a bitmap texture to be mapped onto the patch. + */ + public void setTexture(Bitmap texture) { + if (mTexture != texture) { + if (mTexture == null || + mTexture.getWidth() != texture.getWidth() || + mTexture.getHeight() != texture.getHeight()) { + // need to recompute texture coordinates + mDirty = true; + } + mTexture = texture; + mPaint.setShader(new BitmapShader(texture, + Shader.TileMode.CLAMP, + Shader.TileMode.CLAMP)); + } + } + + /** + * Return the paint flags for the patch + */ + public int getPaintFlags() { + return mPaint.getFlags(); + } + + /** + * Set the paint flags for the patch + */ + public void setPaintFlags(int flags) { + mPaint.setFlags(flags); + } + + /** + * Set the xfermode for the patch + */ + public void setXfermode(Xfermode mode) { + mPaint.setXfermode(mode); + } + + /** + * Set the alpha for the patch + */ + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + } + + /** + * Draw the patch onto the canvas. + * + * setCubicBoundary() and setTexture() must be called before drawing. + */ + public void draw(Canvas canvas) { + if (mDirty) { + buildCache(); + mDirty = false; + } + + // cut the count in half, since mVerts.length is really the length of + // the verts[] and tex[] arrays combined + // (tex[] are stored after verts[]) + int vertCount = mVerts.length >> 1; + canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertCount, + mVerts, 0, mVerts, vertCount, null, 0, + mIndices, 0, mIndices.length, + mPaint); + } + + private void buildCache() { + // we need mRows * mCols points, for verts and another set for textures + // so *2 for going from points -> floats, and *2 for verts and textures + int vertCount = mRows * mCols * 4; + if (mVerts == null || mVerts.length != vertCount) { + mVerts = new float[vertCount]; + } + + int indexCount = (mRows - 1) * (mCols - 1) * 6; + if (mIndices == null || mIndices.length != indexCount) { + mIndices = new short[indexCount]; + } + + nativeComputeCubicPatch(mCubicPoints, + mTexture.getWidth(), mTexture.getHeight(), + mRows, mCols, mVerts, mIndices); + } + + private static native + void nativeComputeCubicPatch(float[] cubicPoints, + int texW, int texH, int rows, int cols, + float[] verts, short[] indices); +} + |