diff options
Diffstat (limited to 'tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java')
-rw-r--r-- | tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java | 1011 |
1 files changed, 1011 insertions, 0 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java new file mode 100644 index 0000000..ed2eff2 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -0,0 +1,1011 @@ +/* + * Copyright (C) 2010 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; + + +import com.android.layoutlib.bridge.DelegateManager; + +import android.graphics.Matrix.ScaleToFit; + +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; + +/** + * Delegate implementing the native methods of android.graphics.Matrix + * + * Through the layoutlib_create tool, the original native methods of Matrix have been replaced + * by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original Matrix class. + * + * @see DelegateManager + * + */ +public final class Matrix_Delegate { + + private final static int MATRIX_SIZE = 9; + + // ---- delegate manager ---- + private static final DelegateManager<Matrix_Delegate> sManager = + new DelegateManager<Matrix_Delegate>(); + + // ---- delegate data ---- + private float mValues[] = new float[MATRIX_SIZE]; + + // ---- Public Helper methods ---- + + /** + * Returns an {@link AffineTransform} matching the given Matrix. + */ + public static AffineTransform getAffineTransform(Matrix m) { + Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); + if (delegate == null) { + assert false; + return null; + } + + return getAffineTransform(delegate); + } + + public static boolean hasPerspective(Matrix m) { + Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); + if (delegate == null) { + assert false; + return false; + } + + return (delegate.mValues[6] != 0 || delegate.mValues[7] != 0 || delegate.mValues[8] != 1); + } + + + // ---- native methods ---- + + public static int native_create(int native_src_or_zero) { + // create the delegate + Matrix_Delegate newDelegate = new Matrix_Delegate(); + + // copy from values if needed. + if (native_src_or_zero > 0) { + Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero); + if (oldDelegate != null) { + System.arraycopy( + oldDelegate.mValues, 0, + newDelegate.mValues, 0, + MATRIX_SIZE); + } + } + + return sManager.addDelegate(newDelegate); + } + + public static boolean native_isIdentity(int native_object) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + for (int i = 0, k = 0; i < 3; i++) { + for (int j = 0; j < 3; j++, k++) { + if (d.mValues[k] != ((i==j) ? 1 : 0)) { + return false; + } + } + } + + return true; + } + + public static boolean native_rectStaysRect(int native_object) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return true; + } + + return (d.computeTypeMask() & kRectStaysRect_Mask) != 0; + } + + public static void native_reset(int native_object) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + reset(d.mValues); + } + + public static void native_set(int native_object, int other) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + Matrix_Delegate src = sManager.getDelegate(other); + if (src == null) { + assert false; + return; + } + + System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE); + } + + public static void native_setTranslate(int native_object, float dx, float dy) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + setTranslate(d.mValues, dx, dy); + } + + public static void native_setScale(int native_object, float sx, float sy, float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + d.mValues = getScale(sx, sy, px, py); + } + + public static void native_setScale(int native_object, float sx, float sy) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + d.mValues[0] = sx; + d.mValues[1] = 0; + d.mValues[2] = 0; + d.mValues[3] = 0; + d.mValues[4] = sy; + d.mValues[5] = 0; + d.mValues[6] = 0; + d.mValues[7] = 0; + d.mValues[8] = 1; + } + + public static void native_setRotate(int native_object, float degrees, float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + d.mValues = getRotate(degrees, px, py); + } + + public static void native_setRotate(int native_object, float degrees) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + setRotate(d.mValues, degrees); + } + + public static void native_setSinCos(int native_object, float sinValue, float cosValue, + float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + // TODO: do it in one pass + + // translate so that the pivot is in 0,0 + setTranslate(d.mValues, -px, -py); + + // scale + d.postTransform(getRotate(sinValue, cosValue)); + // translate back the pivot + d.postTransform(getTranslate(px, py)); + } + + public static void native_setSinCos(int native_object, float sinValue, float cosValue) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + setRotate(d.mValues, sinValue, cosValue); + } + + public static void native_setSkew(int native_object, float kx, float ky, float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + d.mValues = getSkew(kx, ky, px, py); + } + + public static void native_setSkew(int native_object, float kx, float ky) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + d.mValues[0] = 1; + d.mValues[1] = kx; + d.mValues[2] = -0; + d.mValues[3] = ky; + d.mValues[4] = 1; + d.mValues[5] = 0; + d.mValues[6] = 0; + d.mValues[7] = 0; + d.mValues[8] = 1; + } + + public static boolean native_setConcat(int native_object, int a, int b) { + if (a == native_object) { + return native_preConcat(native_object, b); + } else if (b == native_object) { + return native_postConcat(native_object, a); + } + + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + Matrix_Delegate a_mtx = sManager.getDelegate(a); + if (a_mtx == null) { + assert false; + return false; + } + + Matrix_Delegate b_mtx = sManager.getDelegate(b); + if (b_mtx == null) { + assert false; + return false; + } + + multiply(d.mValues, a_mtx.mValues, b_mtx.mValues); + + return true; + } + + public static boolean native_preTranslate(int native_object, float dx, float dy) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.preTransform(getTranslate(dx, dy)); + return true; + } + + public static boolean native_preScale(int native_object, float sx, float sy, + float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.preTransform(getScale(sx, sy, px, py)); + return true; + } + + public static boolean native_preScale(int native_object, float sx, float sy) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.preTransform(getScale(sx, sy)); + return true; + } + + public static boolean native_preRotate(int native_object, float degrees, float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.preTransform(getRotate(degrees, px, py)); + return true; + } + + public static boolean native_preRotate(int native_object, float degrees) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + double rad = Math.toRadians(degrees); + float sin = (float)Math.sin(rad); + float cos = (float)Math.cos(rad); + + d.preTransform(getRotate(sin, cos)); + return true; + } + + public static boolean native_preSkew(int native_object, float kx, float ky, + float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.preTransform(getSkew(kx, ky, px, py)); + return true; + } + + public static boolean native_preSkew(int native_object, float kx, float ky) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.preTransform(getSkew(kx, ky)); + return true; + } + + public static boolean native_preConcat(int native_object, int other_matrix) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + Matrix_Delegate other = sManager.getDelegate(other_matrix); + if (d == null) { + assert false; + return false; + } + + d.preTransform(other.mValues); + return true; + } + + public static boolean native_postTranslate(int native_object, float dx, float dy) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.postTransform(getTranslate(dx, dy)); + return true; + } + + public static boolean native_postScale(int native_object, float sx, float sy, + float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.postTransform(getScale(sx, sy, px, py)); + return true; + } + + public static boolean native_postScale(int native_object, float sx, float sy) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.postTransform(getScale(sx, sy)); + return true; + } + + public static boolean native_postRotate(int native_object, float degrees, float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.preTransform(getRotate(degrees, px, py)); + return true; + } + + public static boolean native_postRotate(int native_object, float degrees) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.postTransform(getRotate(degrees)); + return true; + } + + public static boolean native_postSkew(int native_object, float kx, float ky, + float px, float py) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.postTransform(getSkew(kx, ky, px, py)); + return true; + } + + public static boolean native_postSkew(int native_object, float kx, float ky) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + d.postTransform(getSkew(kx, ky)); + return true; + } + + public static boolean native_postConcat(int native_object, int other_matrix) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + Matrix_Delegate other = sManager.getDelegate(other_matrix); + if (d == null) { + assert false; + return false; + } + + d.postTransform(other.mValues); + return true; + } + + public static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + if (src.isEmpty()) { + reset(d.mValues); + return false; + } + + if (dst.isEmpty()) { + d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5] + = d.mValues[6] = d.mValues[7] = 0; + d.mValues[8] = 1; + } else { + float tx, sx = dst.width() / src.width(); + float ty, sy = dst.height() / src.height(); + boolean xLarger = false; + + if (stf != ScaleToFit.FILL.nativeInt) { + if (sx > sy) { + xLarger = true; + sx = sy; + } else { + sy = sx; + } + } + + tx = dst.left - src.left * sx; + ty = dst.top - src.top * sy; + if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) { + float diff; + + if (xLarger) { + diff = dst.width() - src.width() * sy; + } else { + diff = dst.height() - src.height() * sy; + } + + if (stf == ScaleToFit.CENTER.nativeInt) { + diff = diff / 2; + } + + if (xLarger) { + tx += diff; + } else { + ty += diff; + } + } + + d.mValues[0] = sx; + d.mValues[4] = sy; + d.mValues[2] = tx; + d.mValues[5] = ty; + d.mValues[1] = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0; + + } + // shared cleanup + d.mValues[8] = 1; + return true; + } + + public static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex, + float[] dst, int dstIndex, int pointCount) { + // FIXME + throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED"); + } + + public static boolean native_invert(int native_object, int inverse) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + Matrix_Delegate inv_mtx = sManager.getDelegate(inverse); + if (inv_mtx == null) { + assert false; + return false; + } + + + try { + AffineTransform affineTransform = getAffineTransform(d); + AffineTransform inverseTransform = affineTransform.createInverse(); + inv_mtx.mValues[0] = (float)inverseTransform.getScaleX(); + inv_mtx.mValues[1] = (float)inverseTransform.getShearX(); + inv_mtx.mValues[2] = (float)inverseTransform.getTranslateX(); + inv_mtx.mValues[3] = (float)inverseTransform.getScaleX(); + inv_mtx.mValues[4] = (float)inverseTransform.getShearY(); + inv_mtx.mValues[5] = (float)inverseTransform.getTranslateY(); + + return true; + } catch (NoninvertibleTransformException e) { + return false; + } + } + + public static void native_mapPoints(int native_object, float[] dst, int dstIndex, + float[] src, int srcIndex, int ptCount, boolean isPts) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + if (isPts) { + d.mapPoints(dst, dstIndex, src, srcIndex, ptCount); + } else { + // src is vectors + // FIXME + throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED"); + } + } + + public static boolean native_mapRect(int native_object, RectF dst, RectF src) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return false; + } + + // array with 4 corners + float[] corners = new float[] { + src.left, src.top, + src.right, src.top, + src.right, src.bottom, + src.left, src.bottom, + }; + + // apply the transform to them. + d.mapPoints(corners); + + // now put the result in the rect. We take the min/max of Xs and min/max of Ys + dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6])); + dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6])); + + dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7])); + dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7])); + + + return (d.computeTypeMask() & kRectStaysRect_Mask) != 0; + } + + public static float native_mapRadius(int native_object, float radius) { + // FIXME + throw new UnsupportedOperationException(); + } + + public static void native_getValues(int native_object, float[] values) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE); + } + + public static void native_setValues(int native_object, float[] values) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + assert false; + return; + } + + System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE); + } + + public static boolean native_equals(int native_a, int native_b) { + Matrix_Delegate a = sManager.getDelegate(native_a); + if (a == null) { + assert false; + return false; + } + + Matrix_Delegate b = sManager.getDelegate(native_b); + if (b == null) { + assert false; + return false; + } + + for (int i = 0 ; i < MATRIX_SIZE ; i++) { + if (a.mValues[i] != b.mValues[i]) { + return false; + } + } + + return true; + } + + public static void finalizer(int native_instance) { + sManager.removeDelegate(native_instance); + } + + // ---- Private helper methods ---- + + private static AffineTransform getAffineTransform(Matrix_Delegate d) { + // the AffineTransform constructor takes the value in a different order + // for a matrix [ 0 1 2 ] + // [ 3 4 5 ] + // the order is 0, 3, 1, 4, 2, 5... + return new AffineTransform( + d.mValues[0], d.mValues[3], d.mValues[1], + d.mValues[4], d.mValues[2], d.mValues[5]); + } + + + /** + * Reset a matrix to the identity + */ + private static void reset(float[] mtx) { + for (int i = 0, k = 0; i < 3; i++) { + for (int j = 0; j < 3; j++, k++) { + mtx[k] = ((i==j) ? 1 : 0); + } + } + } + + @SuppressWarnings("unused") + private final static int kIdentity_Mask = 0; + private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation + private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale + private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates + private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective + private final static int kRectStaysRect_Mask = 0x10; + @SuppressWarnings("unused") + private final static int kUnknown_Mask = 0x80; + + @SuppressWarnings("unused") + private final static int kAllMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask | + kRectStaysRect_Mask; + + // these guys align with the masks, so we can compute a mask from a variable 0/1 + @SuppressWarnings("unused") + private final static int kTranslate_Shift = 0; + @SuppressWarnings("unused") + private final static int kScale_Shift = 1; + @SuppressWarnings("unused") + private final static int kAffine_Shift = 2; + @SuppressWarnings("unused") + private final static int kPerspective_Shift = 3; + private final static int kRectStaysRect_Shift = 4; + + private int computeTypeMask() { + int mask = 0; + + if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) { + mask |= kPerspective_Mask; + } + + if (mValues[2] != 0. || mValues[5] != 0.) { + mask |= kTranslate_Mask; + } + + float m00 = mValues[0]; + float m01 = mValues[1]; + float m10 = mValues[3]; + float m11 = mValues[4]; + + if (m01 != 0. || m10 != 0.) { + mask |= kAffine_Mask; + } + + if (m00 != 1. || m11 != 1.) { + mask |= kScale_Mask; + } + + if ((mask & kPerspective_Mask) == 0) { + // map non-zero to 1 + int im00 = m00 != 0 ? 1 : 0; + int im01 = m01 != 0 ? 1 : 0; + int im10 = m10 != 0 ? 1 : 0; + int im11 = m11 != 0 ? 1 : 0; + + // record if the (p)rimary and (s)econdary diagonals are all 0 or + // all non-zero (answer is 0 or 1) + int dp0 = (im00 | im11) ^ 1; // true if both are 0 + int dp1 = im00 & im11; // true if both are 1 + int ds0 = (im01 | im10) ^ 1; // true if both are 0 + int ds1 = im01 & im10; // true if both are 1 + + // return 1 if primary is 1 and secondary is 0 or + // primary is 0 and secondary is 1 + mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; + } + + return mask; + } + + /** + * Adds the given transformation to the current Matrix + * <p/>This in effect does this = this*matrix + * @param matrix + */ + private void postTransform(float[] matrix) { + float[] tmp = new float[9]; + multiply(tmp, mValues, matrix); + mValues = tmp; + } + + /** + * Adds the given transformation to the current Matrix + * <p/>This in effect does this = matrix*this + * @param matrix + */ + private void preTransform(float[] matrix) { + float[] tmp = new float[9]; + multiply(tmp, matrix, mValues); + mValues = tmp; + } + + /** + * Apply this matrix to the array of 2D points specified by src, and write + * the transformed points into the array of points specified by dst. The + * two arrays represent their "points" as pairs of floats [x, y]. + * + * @param dst The array of dst points (x,y pairs) + * @param dstIndex The index of the first [x,y] pair of dst floats + * @param src The array of src points (x,y pairs) + * @param srcIndex The index of the first [x,y] pair of src floats + * @param pointCount The number of points (x,y pairs) to transform + */ + + private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, + int pointCount) { + //checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); + + float[] tmpDest = dst; + boolean inPlace = dst == src; + if (inPlace) { + tmpDest = new float[dstIndex + pointCount * 2]; + } + + for (int i = 0 ; i < pointCount ; i++) { + // just in case we are doing in place, we better put this in temp vars + float x = mValues[0] * src[i + srcIndex] + + mValues[1] * src[i + srcIndex + 1] + + mValues[2]; + float y = mValues[3] * src[i + srcIndex] + + mValues[4] * src[i + srcIndex + 1] + + mValues[5]; + + tmpDest[i + dstIndex] = x; + tmpDest[i + dstIndex + 1] = y; + } + + if (inPlace) { + System.arraycopy(tmpDest, dstIndex, dst, dstIndex, pointCount * 2); + } + } + + /** + * Apply this matrix to the array of 2D points, and write the transformed + * points back into the array + * + * @param pts The array [x0, y0, x1, y1, ...] of points to transform. + */ + + private void mapPoints(float[] pts) { + mapPoints(pts, 0, pts, 0, pts.length >> 1); + } + + /** + * multiply two matrices and store them in a 3rd. + * <p/>This in effect does dest = a*b + * dest cannot be the same as a or b. + */ + private static void multiply(float dest[], float[] a, float[] b) { + // first row + dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6]; + dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7]; + dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8]; + + // 2nd row + dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6]; + dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7]; + dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8]; + + // 3rd row + dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6]; + dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7]; + dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8]; + } + + /** + * Returns a matrix that represents a given translate + * @param dx + * @param dy + * @return + */ + private static float[] getTranslate(float dx, float dy) { + return setTranslate(new float[9], dx, dy); + } + + private static float[] setTranslate(float[] dest, float dx, float dy) { + dest[0] = 1; + dest[1] = 0; + dest[2] = dx; + dest[3] = 0; + dest[4] = 1; + dest[5] = dy; + dest[6] = 0; + dest[7] = 0; + dest[8] = 1; + return dest; + } + + private static float[] getScale(float sx, float sy) { + return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; + } + + /** + * Returns a matrix that represents the given scale info. + * @param sx + * @param sy + * @param px + * @param py + */ + private static float[] getScale(float sx, float sy, float px, float py) { + float[] tmp = new float[9]; + float[] tmp2 = new float[9]; + + // TODO: do it in one pass + + // translate tmp so that the pivot is in 0,0 + setTranslate(tmp, -px, -py); + + // scale into tmp2 + multiply(tmp2, tmp, getScale(sx, sy)); + + // translate back the pivot back into tmp + multiply(tmp, tmp2, getTranslate(px, py)); + + return tmp; + } + + + private static float[] getRotate(float degrees) { + double rad = Math.toRadians(degrees); + float sin = (float)Math.sin(rad); + float cos = (float)Math.cos(rad); + + return getRotate(sin, cos); + } + + private static float[] getRotate(float sin, float cos) { + return setRotate(new float[9], sin, cos); + } + + private static float[] setRotate(float[] dest, float degrees) { + double rad = Math.toRadians(degrees); + float sin = (float)Math.sin(rad); + float cos = (float)Math.cos(rad); + + return setRotate(dest, sin, cos); + } + + private static float[] setRotate(float[] dest, float sin, float cos) { + dest[0] = cos; + dest[1] = -sin; + dest[2] = 0; + dest[3] = sin; + dest[4] = cos; + dest[5] = 0; + dest[6] = 0; + dest[7] = 0; + dest[8] = 1; + return dest; + } + + private static float[] getRotate(float degrees, float px, float py) { + float[] tmp = new float[9]; + float[] tmp2 = new float[9]; + + // TODO: do it in one pass + + // translate so that the pivot is in 0,0 + setTranslate(tmp, -px, -py); + + // rotate into tmp2 + double rad = Math.toRadians(degrees); + float cos = (float)Math.cos(rad); + float sin = (float)Math.sin(rad); + multiply(tmp2, tmp, getRotate(sin, cos)); + + // translate back the pivot back into tmp + multiply(tmp, tmp2, getTranslate(px, py)); + + return tmp; + } + + private static float[] getSkew(float kx, float ky) { + return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }; + } + + private static float[] getSkew(float kx, float ky, float px, float py) { + float[] tmp = new float[9]; + float[] tmp2 = new float[9]; + + // TODO: do it in one pass + + // translate so that the pivot is in 0,0 + setTranslate(tmp, -px, -py); + + // skew into tmp2 + multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }); + // translate back the pivot back into tmp + multiply(tmp, tmp2, getTranslate(px, py)); + + return tmp; + } + + +} |