summaryrefslogtreecommitdiffstats
path: root/opengl/java/android/opengl/Matrix.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch)
tree35051494d2af230dce54d6b31c6af8fc24091316 /opengl/java/android/opengl/Matrix.java
downloadframeworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2
Initial Contribution
Diffstat (limited to 'opengl/java/android/opengl/Matrix.java')
-rw-r--r--opengl/java/android/opengl/Matrix.java582
1 files changed, 582 insertions, 0 deletions
diff --git a/opengl/java/android/opengl/Matrix.java b/opengl/java/android/opengl/Matrix.java
new file mode 100644
index 0000000..38be6be
--- /dev/null
+++ b/opengl/java/android/opengl/Matrix.java
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2007 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.opengl;
+
+/**
+ * Matrix math utilities. These methods operate on OpenGL ES format
+ * matrices and vectors stored in float arrays.
+ *
+ * Matrices are 4 x 4 column-vector matrices stored in column-major
+ * order:
+ * <pre>
+ * m[offset + 0] m[offset + 4] m[offset + 8] m[offset + 12]
+ * m[offset + 1] m[offset + 5] m[offset + 9] m[offset + 13]
+ * m[offset + 2] m[offset + 6] m[offset + 10] m[offset + 14]
+ * m[offset + 3] m[offset + 7] m[offset + 11] m[offset + 15]
+ * </pre>
+ *
+ * Vectors are 4 row x 1 column column-vectors stored in order:
+ * <pre>
+ * v[offset + 0]
+ * v[offset + 1]
+ * v[offset + 2]
+ * v[offset + 3]
+ * </pre>
+ *
+ */
+public class Matrix {
+ /**
+ * Multiply two 4x4 matrices together and store the result in a third 4x4
+ * matrix. In matrix notation: result = lhs x rhs. Due to the way
+ * matrix multiplication works, the result matrix will have the same
+ * effect as first multiplying by the rhs matrix, then multiplying by
+ * the lhs matrix. This is the opposite of what you might expect.
+ *
+ * The same float array may be passed for result, lhs, and/or rhs. However,
+ * the result element values are undefined if the result elements overlap
+ * either the lhs or rhs elements.
+ *
+ * @param result The float array that holds the result.
+ * @param resultOffset The offset into the result array where the result is
+ * stored.
+ * @param lhs The float array that holds the left-hand-side matrix.
+ * @param lhsOffset The offset into the lhs array where the lhs is stored
+ * @param rhs The float array that holds the right-hand-side matrix.
+ * @param rhsOffset The offset into the rhs array where the rhs is stored.
+ *
+ * @throws IllegalArgumentException if result, lhs, or rhs are null, or if
+ * resultOffset + 16 > result.length or lhsOffset + 16 > lhs.length or
+ * rhsOffset + 16 > rhs.length.
+ */
+ public static native void multiplyMM(float[] result, int resultOffset,
+ float[] lhs, int lhsOffset, float[] rhs, int rhsOffset);
+
+ /**
+ * Multiply a 4 element vector by a 4x4 matrix and store the result in a 4
+ * element column vector. In matrix notation: result = lhs x rhs
+ *
+ * The same float array may be passed for resultVec, lhsMat, and/or rhsVec.
+ * However, the resultVec element values are undefined if the resultVec
+ * elements overlap either the lhsMat or rhsVec elements.
+ *
+ * @param resultVec The float array that holds the result vector.
+ * @param resultVecOffset The offset into the result array where the result
+ * vector is stored.
+ * @param lhsMat The float array that holds the left-hand-side matrix.
+ * @param lhsMatOffset The offset into the lhs array where the lhs is stored
+ * @param rhsVec The float array that holds the right-hand-side vector.
+ * @param rhsVecOffset The offset into the rhs vector where the rhs vector
+ * is stored.
+ *
+ * @throws IllegalArgumentException if resultVec, lhsMat,
+ * or rhsVec are null, or if resultVecOffset + 4 > resultVec.length
+ * or lhsMatOffset + 16 > lhsMat.length or
+ * rhsVecOffset + 4 > rhsVec.length.
+ */
+ public static native void multiplyMV(float[] resultVec,
+ int resultVecOffset, float[] lhsMat, int lhsMatOffset,
+ float[] rhsVec, int rhsVecOffset);
+
+ /**
+ * Transposes a 4 x 4 matrix.
+ *
+ * @param mTrans the array that holds the output inverted matrix
+ * @param mTransOffset an offset into mInv where the inverted matrix is
+ * stored.
+ * @param m the input array
+ * @param mOffset an offset into m where the matrix is stored.
+ */
+ public static void transposeM(float[] mTrans, int mTransOffset, float[] m,
+ int mOffset) {
+ for (int i = 0; i < 4; i++) {
+ int mBase = i * 4 + mOffset;
+ mTrans[i + mTransOffset] = m[mBase];
+ mTrans[i + 4 + mTransOffset] = m[mBase + 1];
+ mTrans[i + 8 + mTransOffset] = m[mBase + 2];
+ mTrans[i + 12 + mTransOffset] = m[mBase + 3];
+ }
+ }
+
+ /**
+ * Inverts a 4 x 4 matrix.
+ *
+ * @param mInv the array that holds the output inverted matrix
+ * @param mInvOffset an offset into mInv where the inverted matrix is
+ * stored.
+ * @param m the input array
+ * @param mOffset an offset into m where the matrix is stored.
+ * @return true if the matrix could be inverted, false if it could not.
+ */
+ public static boolean invertM(float[] mInv, int mInvOffset, float[] m,
+ int mOffset) {
+ // Invert a 4 x 4 matrix using Cramer's Rule
+
+ // array of transpose source matrix
+ float[] src = new float[16];
+
+ // transpose matrix
+ transposeM(src, 0, m, mOffset);
+
+ // temp array for pairs
+ float[] tmp = new float[12];
+
+ // calculate pairs for first 8 elements (cofactors)
+ tmp[0] = src[10] * src[15];
+ tmp[1] = src[11] * src[14];
+ tmp[2] = src[9] * src[15];
+ tmp[3] = src[11] * src[13];
+ tmp[4] = src[9] * src[14];
+ tmp[5] = src[10] * src[13];
+ tmp[6] = src[8] * src[15];
+ tmp[7] = src[11] * src[12];
+ tmp[8] = src[8] * src[14];
+ tmp[9] = src[10] * src[12];
+ tmp[10] = src[8] * src[13];
+ tmp[11] = src[9] * src[12];
+
+ // Holds the destination matrix while we're building it up.
+ float[] dst = new float[16];
+
+ // calculate first 8 elements (cofactors)
+ dst[0] = tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7];
+ dst[0] -= tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7];
+ dst[1] = tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7];
+ dst[1] -= tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7];
+ dst[2] = tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7];
+ dst[2] -= tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7];
+ dst[3] = tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6];
+ dst[3] -= tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6];
+ dst[4] = tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3];
+ dst[4] -= tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3];
+ dst[5] = tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3];
+ dst[5] -= tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3];
+ dst[6] = tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3];
+ dst[6] -= tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3];
+ dst[7] = tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2];
+ dst[7] -= tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2];
+
+ // calculate pairs for second 8 elements (cofactors)
+ tmp[0] = src[2] * src[7];
+ tmp[1] = src[3] * src[6];
+ tmp[2] = src[1] * src[7];
+ tmp[3] = src[3] * src[5];
+ tmp[4] = src[1] * src[6];
+ tmp[5] = src[2] * src[5];
+ tmp[6] = src[0] * src[7];
+ tmp[7] = src[3] * src[4];
+ tmp[8] = src[0] * src[6];
+ tmp[9] = src[2] * src[4];
+ tmp[10] = src[0] * src[5];
+ tmp[11] = src[1] * src[4];
+
+ // calculate second 8 elements (cofactors)
+ dst[8] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15];
+ dst[8] -= tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15];
+ dst[9] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15];
+ dst[9] -= tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15];
+ dst[10] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15];
+ dst[10] -= tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15];
+ dst[11] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14];
+ dst[11] -= tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14];
+ dst[12] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9];
+ dst[12] -= tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10];
+ dst[13] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10];
+ dst[13] -= tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8];
+ dst[14] = tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8];
+ dst[14] -= tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9];
+ dst[15] = tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9];
+ dst[15] -= tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8];
+
+ // calculate determinant
+ float det =
+ src[0] * dst[0] + src[1] * dst[1] + src[2] * dst[2] + src[3]
+ * dst[3];
+
+ if (det == 0.0f) {
+
+ }
+
+ // calculate matrix inverse
+ det = 1 / det;
+ for (int j = 0; j < 16; j++)
+ mInv[j + mInvOffset] = dst[j] * det;
+
+ return true;
+ }
+
+ /**
+ * Computes an orthographic projection matrix.
+ *
+ * @param m returns the result
+ * @param mOffset
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param near
+ * @param far
+ */
+ public static void orthoM(float[] m, int mOffset,
+ float left, float right, float bottom, float top,
+ float near, float far) {
+ if (left == right) {
+ throw new IllegalArgumentException("left == right");
+ }
+ if (bottom == top) {
+ throw new IllegalArgumentException("bottom == top");
+ }
+ if (near == far) {
+ throw new IllegalArgumentException("near == far");
+ }
+
+ final float r_width = 1.0f / (right - left);
+ final float r_height = 1.0f / (top - bottom);
+ final float r_depth = 1.0f / (far - near);
+ final float x = 2.0f * (r_width);
+ final float y = 2.0f * (r_height);
+ final float z = -2.0f * (r_depth);
+ final float tx = -(right + left) * r_width;
+ final float ty = -(top + bottom) * r_height;
+ final float tz = -(far + near) * r_depth;
+ m[mOffset + 0] = x;
+ m[mOffset + 5] = y;
+ m[mOffset +10] = z;
+ m[mOffset +12] = tx;
+ m[mOffset +13] = ty;
+ m[mOffset +14] = tz;
+ m[mOffset +15] = 1.0f;
+ m[mOffset + 1] = 0.0f;
+ m[mOffset + 2] = 0.0f;
+ m[mOffset + 3] = 0.0f;
+ m[mOffset + 4] = 0.0f;
+ m[mOffset + 6] = 0.0f;
+ m[mOffset + 7] = 0.0f;
+ m[mOffset + 8] = 0.0f;
+ m[mOffset + 9] = 0.0f;
+ m[mOffset + 11] = 0.0f;
+ }
+
+
+ /**
+ * Define a projection matrix in terms of six clip planes
+ * @param m the float array that holds the perspective matrix
+ * @param offset the offset into float array m where the perspective
+ * matrix data is written
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param near
+ * @param far
+ */
+
+ public static void frustumM(float[] m, int offset,
+ float left, float right, float bottom, float top,
+ float near, float far) {
+ if (left == right) {
+ throw new IllegalArgumentException("left == right");
+ }
+ if (top == bottom) {
+ throw new IllegalArgumentException("top == bottom");
+ }
+ if (near == far) {
+ throw new IllegalArgumentException("near == far");
+ }
+ if (near <= 0.0f) {
+ throw new IllegalArgumentException("near <= 0.0f");
+ }
+ if (far <= 0.0f) {
+ throw new IllegalArgumentException("far <= 0.0f");
+ }
+ final float r_width = 1.0f / (right - left);
+ final float r_height = 1.0f / (top - bottom);
+ final float r_depth = 1.0f / (near - far);
+ final float x = 2.0f * (near * r_width);
+ final float y = 2.0f * (near * r_height);
+ final float A = 2.0f * ((right + left) * r_width);
+ final float B = (top + bottom) * r_height;
+ final float C = (far + near) * r_depth;
+ final float D = 2.0f * (far * near * r_depth);
+ m[offset + 0] = x;
+ m[offset + 5] = y;
+ m[offset + 8] = A;
+ m[offset + 9] = B;
+ m[offset + 10] = C;
+ m[offset + 14] = D;
+ m[offset + 11] = -1.0f;
+ m[offset + 1] = 0.0f;
+ m[offset + 2] = 0.0f;
+ m[offset + 3] = 0.0f;
+ m[offset + 4] = 0.0f;
+ m[offset + 6] = 0.0f;
+ m[offset + 7] = 0.0f;
+ m[offset + 12] = 0.0f;
+ m[offset + 13] = 0.0f;
+ m[offset + 15] = 0.0f;
+ }
+
+ /**
+ * Computes the length of a vector
+ *
+ * @param x x coordinate of a vector
+ * @param y y coordinate of a vector
+ * @param z z coordinate of a vector
+ * @return the length of a vector
+ */
+ public static float length(float x, float y, float z) {
+ return (float) Math.sqrt(x * x + y * y + z * z);
+ }
+
+ /**
+ * Sets matrix m to the identity matrix.
+ * @param sm returns the result
+ * @param smOffset index into sm where the result matrix starts
+ */
+ public static void setIdentityM(float[] sm, int smOffset) {
+ for (int i=0 ; i<16 ; i++) {
+ sm[smOffset + i] = 0;
+ }
+ for(int i = 0; i < 16; i += 5) {
+ sm[smOffset + i] = 1.0f;
+ }
+ }
+
+ /**
+ * Scales matrix m by sx, sy, and sz, putting the result in sm
+ * @param sm returns the result
+ * @param smOffset index into sm where the result matrix starts
+ * @param m source matrix
+ * @param mOffset index into m where the source matrix starts
+ * @param x scale factor x
+ * @param y scale factor y
+ * @param z scale factor z
+ */
+ public static void scaleM(float[] sm, int smOffset,
+ float[] m, int mOffset,
+ float x, float y, float z) {
+ for (int i=0 ; i<4 ; i++) {
+ int smi = smOffset + i;
+ int mi = mOffset + i;
+ sm[ smi] = m[ mi] * x;
+ sm[ 4 + smi] = m[ 4 + mi] * y;
+ sm[ 8 + smi] = m[ 8 + mi] * z;
+ sm[12 + smi] = m[12 + mi];
+ }
+ }
+
+ /**
+ * Scales matrix m in place by sx, sy, and sz
+ * @param m matrix to scale
+ * @param mOffset index into m where the matrix starts
+ * @param x scale factor x
+ * @param y scale factor y
+ * @param z scale factor z
+ */
+ public static void scaleM(float[] m, int mOffset,
+ float x, float y, float z) {
+ for (int i=0 ; i<4 ; i++) {
+ int mi = mOffset + i;
+ m[ mi] *= x;
+ m[ 4 + mi] *= y;
+ m[ 8 + mi] *= z;
+ }
+ }
+
+ /**
+ * Translates matrix m by sx, sy, and sz, putting the result in tm
+ * @param tm returns the result
+ * @param tmOffset index into sm where the result matrix starts
+ * @param m source matrix
+ * @param mOffset index into m where the source matrix starts
+ * @param x translation factor x
+ * @param y translation factor y
+ * @param z translation factor z
+ */
+ public static void translateM(float[] tm, int tmOffset,
+ float[] m, int mOffset,
+ float x, float y, float z) {
+ for (int i=0 ; i<4 ; i++) {
+ int tmi = tmOffset + i;
+ int mi = mOffset + i;
+ tm[12 + tmi] = m[mi] * x + m[4 + mi] * y + m[8 + mi] * z +
+ m[12 + mi];
+ }
+ }
+
+ /**
+ * Translates matrix m by sx, sy, and sz in place.
+ * @param m matrix
+ * @param mOffset index into m where the matrix starts
+ * @param x translation factor x
+ * @param y translation factor y
+ * @param z translation factor z
+ */
+ public static void translateM(
+ float[] m, int mOffset,
+ float x, float y, float z) {
+ for (int i=0 ; i<4 ; i++) {
+ int mi = mOffset + i;
+ m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;
+ }
+ }
+
+ /**
+ * Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
+ * @param rm returns the result
+ * @param rmOffset index into rm where the result matrix starts
+ * @param m source matrix
+ * @param mOffset index into m where the source matrix starts
+ * @param a angle to rotate in degrees
+ * @param x scale factor x
+ * @param y scale factor y
+ * @param z scale factor z
+ */
+ public static void rotateM(float[] rm, int rmOffset,
+ float[] m, int mOffset,
+ float a, float x, float y, float z) {
+ float[] r = new float[16];
+ setRotateM(r, 0, a, x, y, z);
+ multiplyMM(rm, rmOffset, m, mOffset, r, 0);
+ }
+
+ /**
+ * Rotates matrix m in place by angle a (in degrees)
+ * around the axis (x, y, z)
+ * @param m source matrix
+ * @param mOffset index into m where the matrix starts
+ * @param a angle to rotate in degrees
+ * @param x scale factor x
+ * @param y scale factor y
+ * @param z scale factor z
+ */
+ public static void rotateM(float[] m, int mOffset,
+ float a, float x, float y, float z) {
+ float[] temp = new float[32];
+ setRotateM(temp, 0, a, x, y, z);
+ multiplyMM(temp, 16, m, mOffset, temp, 0);
+ System.arraycopy(temp, 16, m, mOffset, 16);
+ }
+
+ /**
+ * Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
+ * @param rm returns the result
+ * @param rmOffset index into rm where the result matrix starts
+ * @param a angle to rotate in degrees
+ * @param x scale factor x
+ * @param y scale factor y
+ * @param z scale factor z
+ */
+ public static void setRotateM(float[] rm, int rmOffset,
+ float a, float x, float y, float z) {
+ rm[rmOffset + 3] = 0;
+ rm[rmOffset + 7] = 0;
+ rm[rmOffset + 11]= 0;
+ rm[rmOffset + 12]= 0;
+ rm[rmOffset + 13]= 0;
+ rm[rmOffset + 14]= 0;
+ rm[rmOffset + 15]= 1;
+ a *= (float) (Math.PI / 180.0f);
+ float s = (float) Math.sin(a);
+ float c = (float) Math.cos(a);
+ if (1.0f == x && 0.0f == y && 0.0f == z) {
+ rm[rmOffset + 5] = c; rm[rmOffset + 10]= c;
+ rm[rmOffset + 6] = s; rm[rmOffset + 9] = -s;
+ rm[rmOffset + 1] = 0; rm[rmOffset + 2] = 0;
+ rm[rmOffset + 4] = 0; rm[rmOffset + 8] = 0;
+ rm[rmOffset + 0] = 1;
+ } else if (0.0f == x && 1.0f == y && 0.0f == z) {
+ rm[rmOffset + 0] = c; rm[rmOffset + 10]= c;
+ rm[rmOffset + 8] = s; rm[rmOffset + 2] = -s;
+ rm[rmOffset + 1] = 0; rm[rmOffset + 4] = 0;
+ rm[rmOffset + 6] = 0; rm[rmOffset + 9] = 0;
+ rm[rmOffset + 5] = 1;
+ } else if (0.0f == x && 0.0f == y && 1.0f == z) {
+ rm[rmOffset + 0] = c; rm[rmOffset + 5] = c;
+ rm[rmOffset + 1] = s; rm[rmOffset + 4] = -s;
+ rm[rmOffset + 2] = 0; rm[rmOffset + 6] = 0;
+ rm[rmOffset + 8] = 0; rm[rmOffset + 9] = 0;
+ rm[rmOffset + 10]= 1;
+ } else {
+ float len = length(x, y, z);
+ if (1.0f != len) {
+ float recipLen = 1.0f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ float nc = 1.0f - c;
+ float xy = x * y;
+ float yz = y * z;
+ float zx = z * x;
+ float xs = x * s;
+ float ys = y * s;
+ float zs = z * s;
+ rm[rmOffset + 0] = x*x*nc + c;
+ rm[rmOffset + 4] = xy*nc - zs;
+ rm[rmOffset + 8] = zx*nc + ys;
+ rm[rmOffset + 1] = xy*nc + zs;
+ rm[rmOffset + 5] = y*y*nc + c;
+ rm[rmOffset + 9] = yz*nc - xs;
+ rm[rmOffset + 2] = zx*nc - ys;
+ rm[rmOffset + 6] = yz*nc + xs;
+ rm[rmOffset + 10] = z*z*nc + c;
+ }
+ }
+
+ /**
+ * Converts Euler angles to a rotation matrix
+ * @param rm returns the result
+ * @param rmOffset index into rm where the result matrix starts
+ * @param x angle of rotation, in degrees
+ * @param y angle of rotation, in degrees
+ * @param z angle of rotation, in degrees
+ */
+ public static void setRotateEulerM(float[] rm, int rmOffset,
+ float x, float y, float z) {
+ x *= (float) (Math.PI / 180.0f);
+ y *= (float) (Math.PI / 180.0f);
+ z *= (float) (Math.PI / 180.0f);
+ float cx = (float) Math.cos(x);
+ float sx = (float) Math.sin(x);
+ float cy = (float) Math.cos(y);
+ float sy = (float) Math.sin(y);
+ float cz = (float) Math.cos(z);
+ float sz = (float) Math.sin(z);
+ float cxsy = cx * sy;
+ float sxsy = sx * sy;
+
+ rm[rmOffset + 0] = cy * cz;
+ rm[rmOffset + 1] = -cy * sz;
+ rm[rmOffset + 2] = sy;
+ rm[rmOffset + 3] = 0.0f;
+
+ rm[rmOffset + 4] = cxsy * cz + cx * sz;
+ rm[rmOffset + 5] = -cxsy * sz + cx * cz;
+ rm[rmOffset + 6] = -sx * cy;
+ rm[rmOffset + 7] = 0.0f;
+
+ rm[rmOffset + 8] = -sxsy * cz + sx * sz;
+ rm[rmOffset + 9] = sxsy * sz + sx * cz;
+ rm[rmOffset + 10] = cx * cy;
+ rm[rmOffset + 11] = 0.0f;
+
+ rm[rmOffset + 12] = 0.0f;
+ rm[rmOffset + 13] = 0.0f;
+ rm[rmOffset + 14] = 0.0f;
+ rm[rmOffset + 15] = 1.0f;
+ }
+}