Home | History | Annotate | Download | only in opengl
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.opengl;
     18 
     19 /**
     20  * Matrix math utilities. These methods operate on OpenGL ES format
     21  * matrices and vectors stored in float arrays.
     22  * <p>
     23  * Matrices are 4 x 4 column-vector matrices stored in column-major
     24  * order:
     25  * <pre>
     26  *  m[offset +  0] m[offset +  4] m[offset +  8] m[offset + 12]
     27  *  m[offset +  1] m[offset +  5] m[offset +  9] m[offset + 13]
     28  *  m[offset +  2] m[offset +  6] m[offset + 10] m[offset + 14]
     29  *  m[offset +  3] m[offset +  7] m[offset + 11] m[offset + 15]</pre>
     30  *
     31  * Vectors are 4 x 1 column vectors stored in order:
     32  * <pre>
     33  * v[offset + 0]
     34  * v[offset + 1]
     35  * v[offset + 2]
     36  * v[offset + 3]</pre>
     37  */
     38 public class Matrix {
     39 
     40     /** Temporary memory for operations that need temporary matrix data. */
     41     private final static float[] sTemp = new float[32];
     42 
     43     /**
     44      * @deprecated All methods are static, do not instantiate this class.
     45      */
     46     @Deprecated
     47     public Matrix() {}
     48 
     49     /**
     50      * Multiplies two 4x4 matrices together and stores the result in a third 4x4
     51      * matrix. In matrix notation: result = lhs x rhs. Due to the way
     52      * matrix multiplication works, the result matrix will have the same
     53      * effect as first multiplying by the rhs matrix, then multiplying by
     54      * the lhs matrix. This is the opposite of what you might expect.
     55      * <p>
     56      * The same float array may be passed for result, lhs, and/or rhs. However,
     57      * the result element values are undefined if the result elements overlap
     58      * either the lhs or rhs elements.
     59      *
     60      * @param result The float array that holds the result.
     61      * @param resultOffset The offset into the result array where the result is
     62      *        stored.
     63      * @param lhs The float array that holds the left-hand-side matrix.
     64      * @param lhsOffset The offset into the lhs array where the lhs is stored
     65      * @param rhs The float array that holds the right-hand-side matrix.
     66      * @param rhsOffset The offset into the rhs array where the rhs is stored.
     67      *
     68      * @throws IllegalArgumentException if result, lhs, or rhs are null, or if
     69      * resultOffset + 16 > result.length or lhsOffset + 16 > lhs.length or
     70      * rhsOffset + 16 > rhs.length.
     71      */
     72     public static native void multiplyMM(float[] result, int resultOffset,
     73             float[] lhs, int lhsOffset, float[] rhs, int rhsOffset);
     74 
     75     /**
     76      * Multiplies a 4 element vector by a 4x4 matrix and stores the result in a
     77      * 4-element column vector. In matrix notation: result = lhs x rhs
     78      * <p>
     79      * The same float array may be passed for resultVec, lhsMat, and/or rhsVec.
     80      * However, the resultVec element values are undefined if the resultVec
     81      * elements overlap either the lhsMat or rhsVec elements.
     82      *
     83      * @param resultVec The float array that holds the result vector.
     84      * @param resultVecOffset The offset into the result array where the result
     85      *        vector is stored.
     86      * @param lhsMat The float array that holds the left-hand-side matrix.
     87      * @param lhsMatOffset The offset into the lhs array where the lhs is stored
     88      * @param rhsVec The float array that holds the right-hand-side vector.
     89      * @param rhsVecOffset The offset into the rhs vector where the rhs vector
     90      *        is stored.
     91      *
     92      * @throws IllegalArgumentException if resultVec, lhsMat,
     93      * or rhsVec are null, or if resultVecOffset + 4 > resultVec.length
     94      * or lhsMatOffset + 16 > lhsMat.length or
     95      * rhsVecOffset + 4 > rhsVec.length.
     96      */
     97     public static native void multiplyMV(float[] resultVec,
     98             int resultVecOffset, float[] lhsMat, int lhsMatOffset,
     99             float[] rhsVec, int rhsVecOffset);
    100 
    101     /**
    102      * Transposes a 4 x 4 matrix.
    103      * <p>
    104      * mTrans and m must not overlap.
    105      *
    106      * @param mTrans the array that holds the output transposed matrix
    107      * @param mTransOffset an offset into mTrans where the transposed matrix is
    108      *        stored.
    109      * @param m the input array
    110      * @param mOffset an offset into m where the input matrix is stored.
    111      */
    112     public static void transposeM(float[] mTrans, int mTransOffset, float[] m,
    113             int mOffset) {
    114         for (int i = 0; i < 4; i++) {
    115             int mBase = i * 4 + mOffset;
    116             mTrans[i + mTransOffset] = m[mBase];
    117             mTrans[i + 4 + mTransOffset] = m[mBase + 1];
    118             mTrans[i + 8 + mTransOffset] = m[mBase + 2];
    119             mTrans[i + 12 + mTransOffset] = m[mBase + 3];
    120         }
    121     }
    122 
    123     /**
    124      * Inverts a 4 x 4 matrix.
    125      * <p>
    126      * mInv and m must not overlap.
    127      *
    128      * @param mInv the array that holds the output inverted matrix
    129      * @param mInvOffset an offset into mInv where the inverted matrix is
    130      *        stored.
    131      * @param m the input array
    132      * @param mOffset an offset into m where the input matrix is stored.
    133      * @return true if the matrix could be inverted, false if it could not.
    134      */
    135     public static boolean invertM(float[] mInv, int mInvOffset, float[] m,
    136             int mOffset) {
    137         // Invert a 4 x 4 matrix using Cramer's Rule
    138 
    139         // transpose matrix
    140         final float src0  = m[mOffset +  0];
    141         final float src4  = m[mOffset +  1];
    142         final float src8  = m[mOffset +  2];
    143         final float src12 = m[mOffset +  3];
    144 
    145         final float src1  = m[mOffset +  4];
    146         final float src5  = m[mOffset +  5];
    147         final float src9  = m[mOffset +  6];
    148         final float src13 = m[mOffset +  7];
    149 
    150         final float src2  = m[mOffset +  8];
    151         final float src6  = m[mOffset +  9];
    152         final float src10 = m[mOffset + 10];
    153         final float src14 = m[mOffset + 11];
    154 
    155         final float src3  = m[mOffset + 12];
    156         final float src7  = m[mOffset + 13];
    157         final float src11 = m[mOffset + 14];
    158         final float src15 = m[mOffset + 15];
    159 
    160         // calculate pairs for first 8 elements (cofactors)
    161         final float atmp0  = src10 * src15;
    162         final float atmp1  = src11 * src14;
    163         final float atmp2  = src9  * src15;
    164         final float atmp3  = src11 * src13;
    165         final float atmp4  = src9  * src14;
    166         final float atmp5  = src10 * src13;
    167         final float atmp6  = src8  * src15;
    168         final float atmp7  = src11 * src12;
    169         final float atmp8  = src8  * src14;
    170         final float atmp9  = src10 * src12;
    171         final float atmp10 = src8  * src13;
    172         final float atmp11 = src9  * src12;
    173 
    174         // calculate first 8 elements (cofactors)
    175         final float dst0  = (atmp0 * src5 + atmp3 * src6 + atmp4  * src7)
    176                           - (atmp1 * src5 + atmp2 * src6 + atmp5  * src7);
    177         final float dst1  = (atmp1 * src4 + atmp6 * src6 + atmp9  * src7)
    178                           - (atmp0 * src4 + atmp7 * src6 + atmp8  * src7);
    179         final float dst2  = (atmp2 * src4 + atmp7 * src5 + atmp10 * src7)
    180                           - (atmp3 * src4 + atmp6 * src5 + atmp11 * src7);
    181         final float dst3  = (atmp5 * src4 + atmp8 * src5 + atmp11 * src6)
    182                           - (atmp4 * src4 + atmp9 * src5 + atmp10 * src6);
    183         final float dst4  = (atmp1 * src1 + atmp2 * src2 + atmp5  * src3)
    184                           - (atmp0 * src1 + atmp3 * src2 + atmp4  * src3);
    185         final float dst5  = (atmp0 * src0 + atmp7 * src2 + atmp8  * src3)
    186                           - (atmp1 * src0 + atmp6 * src2 + atmp9  * src3);
    187         final float dst6  = (atmp3 * src0 + atmp6 * src1 + atmp11 * src3)
    188                           - (atmp2 * src0 + atmp7 * src1 + atmp10 * src3);
    189         final float dst7  = (atmp4 * src0 + atmp9 * src1 + atmp10 * src2)
    190                           - (atmp5 * src0 + atmp8 * src1 + atmp11 * src2);
    191 
    192         // calculate pairs for second 8 elements (cofactors)
    193         final float btmp0  = src2 * src7;
    194         final float btmp1  = src3 * src6;
    195         final float btmp2  = src1 * src7;
    196         final float btmp3  = src3 * src5;
    197         final float btmp4  = src1 * src6;
    198         final float btmp5  = src2 * src5;
    199         final float btmp6  = src0 * src7;
    200         final float btmp7  = src3 * src4;
    201         final float btmp8  = src0 * src6;
    202         final float btmp9  = src2 * src4;
    203         final float btmp10 = src0 * src5;
    204         final float btmp11 = src1 * src4;
    205 
    206         // calculate second 8 elements (cofactors)
    207         final float dst8  = (btmp0  * src13 + btmp3  * src14 + btmp4  * src15)
    208                           - (btmp1  * src13 + btmp2  * src14 + btmp5  * src15);
    209         final float dst9  = (btmp1  * src12 + btmp6  * src14 + btmp9  * src15)
    210                           - (btmp0  * src12 + btmp7  * src14 + btmp8  * src15);
    211         final float dst10 = (btmp2  * src12 + btmp7  * src13 + btmp10 * src15)
    212                           - (btmp3  * src12 + btmp6  * src13 + btmp11 * src15);
    213         final float dst11 = (btmp5  * src12 + btmp8  * src13 + btmp11 * src14)
    214                           - (btmp4  * src12 + btmp9  * src13 + btmp10 * src14);
    215         final float dst12 = (btmp2  * src10 + btmp5  * src11 + btmp1  * src9 )
    216                           - (btmp4  * src11 + btmp0  * src9  + btmp3  * src10);
    217         final float dst13 = (btmp8  * src11 + btmp0  * src8  + btmp7  * src10)
    218                           - (btmp6  * src10 + btmp9  * src11 + btmp1  * src8 );
    219         final float dst14 = (btmp6  * src9  + btmp11 * src11 + btmp3  * src8 )
    220                           - (btmp10 * src11 + btmp2  * src8  + btmp7  * src9 );
    221         final float dst15 = (btmp10 * src10 + btmp4  * src8  + btmp9  * src9 )
    222                           - (btmp8  * src9  + btmp11 * src10 + btmp5  * src8 );
    223 
    224         // calculate determinant
    225         final float det =
    226                 src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3;
    227 
    228         if (det == 0.0f) {
    229             return false;
    230         }
    231 
    232         // calculate matrix inverse
    233         final float invdet = 1.0f / det;
    234         mInv[     mInvOffset] = dst0  * invdet;
    235         mInv[ 1 + mInvOffset] = dst1  * invdet;
    236         mInv[ 2 + mInvOffset] = dst2  * invdet;
    237         mInv[ 3 + mInvOffset] = dst3  * invdet;
    238 
    239         mInv[ 4 + mInvOffset] = dst4  * invdet;
    240         mInv[ 5 + mInvOffset] = dst5  * invdet;
    241         mInv[ 6 + mInvOffset] = dst6  * invdet;
    242         mInv[ 7 + mInvOffset] = dst7  * invdet;
    243 
    244         mInv[ 8 + mInvOffset] = dst8  * invdet;
    245         mInv[ 9 + mInvOffset] = dst9  * invdet;
    246         mInv[10 + mInvOffset] = dst10 * invdet;
    247         mInv[11 + mInvOffset] = dst11 * invdet;
    248 
    249         mInv[12 + mInvOffset] = dst12 * invdet;
    250         mInv[13 + mInvOffset] = dst13 * invdet;
    251         mInv[14 + mInvOffset] = dst14 * invdet;
    252         mInv[15 + mInvOffset] = dst15 * invdet;
    253 
    254         return true;
    255     }
    256 
    257     /**
    258      * Computes an orthographic projection matrix.
    259      *
    260      * @param m returns the result
    261      * @param mOffset
    262      * @param left
    263      * @param right
    264      * @param bottom
    265      * @param top
    266      * @param near
    267      * @param far
    268      */
    269     public static void orthoM(float[] m, int mOffset,
    270         float left, float right, float bottom, float top,
    271         float near, float far) {
    272         if (left == right) {
    273             throw new IllegalArgumentException("left == right");
    274         }
    275         if (bottom == top) {
    276             throw new IllegalArgumentException("bottom == top");
    277         }
    278         if (near == far) {
    279             throw new IllegalArgumentException("near == far");
    280         }
    281 
    282         final float r_width  = 1.0f / (right - left);
    283         final float r_height = 1.0f / (top - bottom);
    284         final float r_depth  = 1.0f / (far - near);
    285         final float x =  2.0f * (r_width);
    286         final float y =  2.0f * (r_height);
    287         final float z = -2.0f * (r_depth);
    288         final float tx = -(right + left) * r_width;
    289         final float ty = -(top + bottom) * r_height;
    290         final float tz = -(far + near) * r_depth;
    291         m[mOffset + 0] = x;
    292         m[mOffset + 5] = y;
    293         m[mOffset +10] = z;
    294         m[mOffset +12] = tx;
    295         m[mOffset +13] = ty;
    296         m[mOffset +14] = tz;
    297         m[mOffset +15] = 1.0f;
    298         m[mOffset + 1] = 0.0f;
    299         m[mOffset + 2] = 0.0f;
    300         m[mOffset + 3] = 0.0f;
    301         m[mOffset + 4] = 0.0f;
    302         m[mOffset + 6] = 0.0f;
    303         m[mOffset + 7] = 0.0f;
    304         m[mOffset + 8] = 0.0f;
    305         m[mOffset + 9] = 0.0f;
    306         m[mOffset + 11] = 0.0f;
    307     }
    308 
    309 
    310     /**
    311      * Defines a projection matrix in terms of six clip planes.
    312      *
    313      * @param m the float array that holds the output perspective matrix
    314      * @param offset the offset into float array m where the perspective
    315      *        matrix data is written
    316      * @param left
    317      * @param right
    318      * @param bottom
    319      * @param top
    320      * @param near
    321      * @param far
    322      */
    323     public static void frustumM(float[] m, int offset,
    324             float left, float right, float bottom, float top,
    325             float near, float far) {
    326         if (left == right) {
    327             throw new IllegalArgumentException("left == right");
    328         }
    329         if (top == bottom) {
    330             throw new IllegalArgumentException("top == bottom");
    331         }
    332         if (near == far) {
    333             throw new IllegalArgumentException("near == far");
    334         }
    335         if (near <= 0.0f) {
    336             throw new IllegalArgumentException("near <= 0.0f");
    337         }
    338         if (far <= 0.0f) {
    339             throw new IllegalArgumentException("far <= 0.0f");
    340         }
    341         final float r_width  = 1.0f / (right - left);
    342         final float r_height = 1.0f / (top - bottom);
    343         final float r_depth  = 1.0f / (near - far);
    344         final float x = 2.0f * (near * r_width);
    345         final float y = 2.0f * (near * r_height);
    346         final float A = (right + left) * r_width;
    347         final float B = (top + bottom) * r_height;
    348         final float C = (far + near) * r_depth;
    349         final float D = 2.0f * (far * near * r_depth);
    350         m[offset + 0] = x;
    351         m[offset + 5] = y;
    352         m[offset + 8] = A;
    353         m[offset +  9] = B;
    354         m[offset + 10] = C;
    355         m[offset + 14] = D;
    356         m[offset + 11] = -1.0f;
    357         m[offset +  1] = 0.0f;
    358         m[offset +  2] = 0.0f;
    359         m[offset +  3] = 0.0f;
    360         m[offset +  4] = 0.0f;
    361         m[offset +  6] = 0.0f;
    362         m[offset +  7] = 0.0f;
    363         m[offset + 12] = 0.0f;
    364         m[offset + 13] = 0.0f;
    365         m[offset + 15] = 0.0f;
    366     }
    367 
    368     /**
    369      * Defines a projection matrix in terms of a field of view angle, an
    370      * aspect ratio, and z clip planes.
    371      *
    372      * @param m the float array that holds the perspective matrix
    373      * @param offset the offset into float array m where the perspective
    374      *        matrix data is written
    375      * @param fovy field of view in y direction, in degrees
    376      * @param aspect width to height aspect ratio of the viewport
    377      * @param zNear
    378      * @param zFar
    379      */
    380     public static void perspectiveM(float[] m, int offset,
    381           float fovy, float aspect, float zNear, float zFar) {
    382         float f = 1.0f / (float) Math.tan(fovy * (Math.PI / 360.0));
    383         float rangeReciprocal = 1.0f / (zNear - zFar);
    384 
    385         m[offset + 0] = f / aspect;
    386         m[offset + 1] = 0.0f;
    387         m[offset + 2] = 0.0f;
    388         m[offset + 3] = 0.0f;
    389 
    390         m[offset + 4] = 0.0f;
    391         m[offset + 5] = f;
    392         m[offset + 6] = 0.0f;
    393         m[offset + 7] = 0.0f;
    394 
    395         m[offset + 8] = 0.0f;
    396         m[offset + 9] = 0.0f;
    397         m[offset + 10] = (zFar + zNear) * rangeReciprocal;
    398         m[offset + 11] = -1.0f;
    399 
    400         m[offset + 12] = 0.0f;
    401         m[offset + 13] = 0.0f;
    402         m[offset + 14] = 2.0f * zFar * zNear * rangeReciprocal;
    403         m[offset + 15] = 0.0f;
    404     }
    405 
    406     /**
    407      * Computes the length of a vector.
    408      *
    409      * @param x x coordinate of a vector
    410      * @param y y coordinate of a vector
    411      * @param z z coordinate of a vector
    412      * @return the length of a vector
    413      */
    414     public static float length(float x, float y, float z) {
    415         return (float) Math.sqrt(x * x + y * y + z * z);
    416     }
    417 
    418     /**
    419      * Sets matrix m to the identity matrix.
    420      *
    421      * @param sm returns the result
    422      * @param smOffset index into sm where the result matrix starts
    423      */
    424     public static void setIdentityM(float[] sm, int smOffset) {
    425         for (int i=0 ; i<16 ; i++) {
    426             sm[smOffset + i] = 0;
    427         }
    428         for(int i = 0; i < 16; i += 5) {
    429             sm[smOffset + i] = 1.0f;
    430         }
    431     }
    432 
    433     /**
    434      * Scales matrix m by x, y, and z, putting the result in sm.
    435      * <p>
    436      * m and sm must not overlap.
    437      *
    438      * @param sm returns the result
    439      * @param smOffset index into sm where the result matrix starts
    440      * @param m source matrix
    441      * @param mOffset index into m where the source matrix starts
    442      * @param x scale factor x
    443      * @param y scale factor y
    444      * @param z scale factor z
    445      */
    446     public static void scaleM(float[] sm, int smOffset,
    447             float[] m, int mOffset,
    448             float x, float y, float z) {
    449         for (int i=0 ; i<4 ; i++) {
    450             int smi = smOffset + i;
    451             int mi = mOffset + i;
    452             sm[     smi] = m[     mi] * x;
    453             sm[ 4 + smi] = m[ 4 + mi] * y;
    454             sm[ 8 + smi] = m[ 8 + mi] * z;
    455             sm[12 + smi] = m[12 + mi];
    456         }
    457     }
    458 
    459     /**
    460      * Scales matrix m in place by sx, sy, and sz.
    461      *
    462      * @param m matrix to scale
    463      * @param mOffset index into m where the matrix starts
    464      * @param x scale factor x
    465      * @param y scale factor y
    466      * @param z scale factor z
    467      */
    468     public static void scaleM(float[] m, int mOffset,
    469             float x, float y, float z) {
    470         for (int i=0 ; i<4 ; i++) {
    471             int mi = mOffset + i;
    472             m[     mi] *= x;
    473             m[ 4 + mi] *= y;
    474             m[ 8 + mi] *= z;
    475         }
    476     }
    477 
    478     /**
    479      * Translates matrix m by x, y, and z, putting the result in tm.
    480      * <p>
    481      * m and tm must not overlap.
    482      *
    483      * @param tm returns the result
    484      * @param tmOffset index into sm where the result matrix starts
    485      * @param m source matrix
    486      * @param mOffset index into m where the source matrix starts
    487      * @param x translation factor x
    488      * @param y translation factor y
    489      * @param z translation factor z
    490      */
    491     public static void translateM(float[] tm, int tmOffset,
    492             float[] m, int mOffset,
    493             float x, float y, float z) {
    494         for (int i=0 ; i<12 ; i++) {
    495             tm[tmOffset + i] = m[mOffset + i];
    496         }
    497         for (int i=0 ; i<4 ; i++) {
    498             int tmi = tmOffset + i;
    499             int mi = mOffset + i;
    500             tm[12 + tmi] = m[mi] * x + m[4 + mi] * y + m[8 + mi] * z +
    501                 m[12 + mi];
    502         }
    503     }
    504 
    505     /**
    506      * Translates matrix m by x, y, and z in place.
    507      *
    508      * @param m matrix
    509      * @param mOffset index into m where the matrix starts
    510      * @param x translation factor x
    511      * @param y translation factor y
    512      * @param z translation factor z
    513      */
    514     public static void translateM(
    515             float[] m, int mOffset,
    516             float x, float y, float z) {
    517         for (int i=0 ; i<4 ; i++) {
    518             int mi = mOffset + i;
    519             m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;
    520         }
    521     }
    522 
    523     /**
    524      * Rotates matrix m by angle a (in degrees) around the axis (x, y, z).
    525      * <p>
    526      * m and rm must not overlap.
    527      *
    528      * @param rm returns the result
    529      * @param rmOffset index into rm where the result matrix starts
    530      * @param m source matrix
    531      * @param mOffset index into m where the source matrix starts
    532      * @param a angle to rotate in degrees
    533      * @param x X axis component
    534      * @param y Y axis component
    535      * @param z Z axis component
    536      */
    537     public static void rotateM(float[] rm, int rmOffset,
    538             float[] m, int mOffset,
    539             float a, float x, float y, float z) {
    540         synchronized(sTemp) {
    541             setRotateM(sTemp, 0, a, x, y, z);
    542             multiplyMM(rm, rmOffset, m, mOffset, sTemp, 0);
    543         }
    544     }
    545 
    546     /**
    547      * Rotates matrix m in place by angle a (in degrees)
    548      * around the axis (x, y, z).
    549      *
    550      * @param m source matrix
    551      * @param mOffset index into m where the matrix starts
    552      * @param a angle to rotate in degrees
    553      * @param x X axis component
    554      * @param y Y axis component
    555      * @param z Z axis component
    556      */
    557     public static void rotateM(float[] m, int mOffset,
    558             float a, float x, float y, float z) {
    559         synchronized(sTemp) {
    560             setRotateM(sTemp, 0, a, x, y, z);
    561             multiplyMM(sTemp, 16, m, mOffset, sTemp, 0);
    562             System.arraycopy(sTemp, 16, m, mOffset, 16);
    563         }
    564     }
    565 
    566     /**
    567      * Creates a matrix for rotation by angle a (in degrees)
    568      * around the axis (x, y, z).
    569      * <p>
    570      * An optimized path will be used for rotation about a major axis
    571      * (e.g. x=1.0f y=0.0f z=0.0f).
    572      *
    573      * @param rm returns the result
    574      * @param rmOffset index into rm where the result matrix starts
    575      * @param a angle to rotate in degrees
    576      * @param x X axis component
    577      * @param y Y axis component
    578      * @param z Z axis component
    579      */
    580     public static void setRotateM(float[] rm, int rmOffset,
    581             float a, float x, float y, float z) {
    582         rm[rmOffset + 3] = 0;
    583         rm[rmOffset + 7] = 0;
    584         rm[rmOffset + 11]= 0;
    585         rm[rmOffset + 12]= 0;
    586         rm[rmOffset + 13]= 0;
    587         rm[rmOffset + 14]= 0;
    588         rm[rmOffset + 15]= 1;
    589         a *= (float) (Math.PI / 180.0f);
    590         float s = (float) Math.sin(a);
    591         float c = (float) Math.cos(a);
    592         if (1.0f == x && 0.0f == y && 0.0f == z) {
    593             rm[rmOffset + 5] = c;   rm[rmOffset + 10]= c;
    594             rm[rmOffset + 6] = s;   rm[rmOffset + 9] = -s;
    595             rm[rmOffset + 1] = 0;   rm[rmOffset + 2] = 0;
    596             rm[rmOffset + 4] = 0;   rm[rmOffset + 8] = 0;
    597             rm[rmOffset + 0] = 1;
    598         } else if (0.0f == x && 1.0f == y && 0.0f == z) {
    599             rm[rmOffset + 0] = c;   rm[rmOffset + 10]= c;
    600             rm[rmOffset + 8] = s;   rm[rmOffset + 2] = -s;
    601             rm[rmOffset + 1] = 0;   rm[rmOffset + 4] = 0;
    602             rm[rmOffset + 6] = 0;   rm[rmOffset + 9] = 0;
    603             rm[rmOffset + 5] = 1;
    604         } else if (0.0f == x && 0.0f == y && 1.0f == z) {
    605             rm[rmOffset + 0] = c;   rm[rmOffset + 5] = c;
    606             rm[rmOffset + 1] = s;   rm[rmOffset + 4] = -s;
    607             rm[rmOffset + 2] = 0;   rm[rmOffset + 6] = 0;
    608             rm[rmOffset + 8] = 0;   rm[rmOffset + 9] = 0;
    609             rm[rmOffset + 10]= 1;
    610         } else {
    611             float len = length(x, y, z);
    612             if (1.0f != len) {
    613                 float recipLen = 1.0f / len;
    614                 x *= recipLen;
    615                 y *= recipLen;
    616                 z *= recipLen;
    617             }
    618             float nc = 1.0f - c;
    619             float xy = x * y;
    620             float yz = y * z;
    621             float zx = z * x;
    622             float xs = x * s;
    623             float ys = y * s;
    624             float zs = z * s;
    625             rm[rmOffset +  0] = x*x*nc +  c;
    626             rm[rmOffset +  4] =  xy*nc - zs;
    627             rm[rmOffset +  8] =  zx*nc + ys;
    628             rm[rmOffset +  1] =  xy*nc + zs;
    629             rm[rmOffset +  5] = y*y*nc +  c;
    630             rm[rmOffset +  9] =  yz*nc - xs;
    631             rm[rmOffset +  2] =  zx*nc - ys;
    632             rm[rmOffset +  6] =  yz*nc + xs;
    633             rm[rmOffset + 10] = z*z*nc +  c;
    634         }
    635     }
    636 
    637     /**
    638      * Converts Euler angles to a rotation matrix.
    639      *
    640      * @param rm returns the result
    641      * @param rmOffset index into rm where the result matrix starts
    642      * @param x angle of rotation, in degrees
    643      * @param y angle of rotation, in degrees
    644      * @param z angle of rotation, in degrees
    645      */
    646     public static void setRotateEulerM(float[] rm, int rmOffset,
    647             float x, float y, float z) {
    648         x *= (float) (Math.PI / 180.0f);
    649         y *= (float) (Math.PI / 180.0f);
    650         z *= (float) (Math.PI / 180.0f);
    651         float cx = (float) Math.cos(x);
    652         float sx = (float) Math.sin(x);
    653         float cy = (float) Math.cos(y);
    654         float sy = (float) Math.sin(y);
    655         float cz = (float) Math.cos(z);
    656         float sz = (float) Math.sin(z);
    657         float cxsy = cx * sy;
    658         float sxsy = sx * sy;
    659 
    660         rm[rmOffset + 0]  =   cy * cz;
    661         rm[rmOffset + 1]  =  -cy * sz;
    662         rm[rmOffset + 2]  =   sy;
    663         rm[rmOffset + 3]  =  0.0f;
    664 
    665         rm[rmOffset + 4]  =  cxsy * cz + cx * sz;
    666         rm[rmOffset + 5]  = -cxsy * sz + cx * cz;
    667         rm[rmOffset + 6]  =  -sx * cy;
    668         rm[rmOffset + 7]  =  0.0f;
    669 
    670         rm[rmOffset + 8]  = -sxsy * cz + sx * sz;
    671         rm[rmOffset + 9]  =  sxsy * sz + sx * cz;
    672         rm[rmOffset + 10] =  cx * cy;
    673         rm[rmOffset + 11] =  0.0f;
    674 
    675         rm[rmOffset + 12] =  0.0f;
    676         rm[rmOffset + 13] =  0.0f;
    677         rm[rmOffset + 14] =  0.0f;
    678         rm[rmOffset + 15] =  1.0f;
    679     }
    680 
    681     /**
    682      * Defines a viewing transformation in terms of an eye point, a center of
    683      * view, and an up vector.
    684      *
    685      * @param rm returns the result
    686      * @param rmOffset index into rm where the result matrix starts
    687      * @param eyeX eye point X
    688      * @param eyeY eye point Y
    689      * @param eyeZ eye point Z
    690      * @param centerX center of view X
    691      * @param centerY center of view Y
    692      * @param centerZ center of view Z
    693      * @param upX up vector X
    694      * @param upY up vector Y
    695      * @param upZ up vector Z
    696      */
    697     public static void setLookAtM(float[] rm, int rmOffset,
    698             float eyeX, float eyeY, float eyeZ,
    699             float centerX, float centerY, float centerZ, float upX, float upY,
    700             float upZ) {
    701 
    702         // See the OpenGL GLUT documentation for gluLookAt for a description
    703         // of the algorithm. We implement it in a straightforward way:
    704 
    705         float fx = centerX - eyeX;
    706         float fy = centerY - eyeY;
    707         float fz = centerZ - eyeZ;
    708 
    709         // Normalize f
    710         float rlf = 1.0f / Matrix.length(fx, fy, fz);
    711         fx *= rlf;
    712         fy *= rlf;
    713         fz *= rlf;
    714 
    715         // compute s = f x up (x means "cross product")
    716         float sx = fy * upZ - fz * upY;
    717         float sy = fz * upX - fx * upZ;
    718         float sz = fx * upY - fy * upX;
    719 
    720         // and normalize s
    721         float rls = 1.0f / Matrix.length(sx, sy, sz);
    722         sx *= rls;
    723         sy *= rls;
    724         sz *= rls;
    725 
    726         // compute u = s x f
    727         float ux = sy * fz - sz * fy;
    728         float uy = sz * fx - sx * fz;
    729         float uz = sx * fy - sy * fx;
    730 
    731         rm[rmOffset + 0] = sx;
    732         rm[rmOffset + 1] = ux;
    733         rm[rmOffset + 2] = -fx;
    734         rm[rmOffset + 3] = 0.0f;
    735 
    736         rm[rmOffset + 4] = sy;
    737         rm[rmOffset + 5] = uy;
    738         rm[rmOffset + 6] = -fy;
    739         rm[rmOffset + 7] = 0.0f;
    740 
    741         rm[rmOffset + 8] = sz;
    742         rm[rmOffset + 9] = uz;
    743         rm[rmOffset + 10] = -fz;
    744         rm[rmOffset + 11] = 0.0f;
    745 
    746         rm[rmOffset + 12] = 0.0f;
    747         rm[rmOffset + 13] = 0.0f;
    748         rm[rmOffset + 14] = 0.0f;
    749         rm[rmOffset + 15] = 1.0f;
    750 
    751         translateM(rm, rmOffset, -eyeX, -eyeY, -eyeZ);
    752     }
    753 }
    754