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