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