Matrix4f.java revision ec6f200cd8a882458c57a63e1740731f0563cbcc
1/*
2 * Copyright (C) 2009-2012 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.renderscript;
18
19import java.lang.Math;
20import android.util.Log;
21
22
23/**
24 * Class for exposing the native Renderscript rs_matrix4x4 type back to the Android system.
25 *
26 **/
27public class Matrix4f {
28
29    /**
30    * Creates a new identity 4x4 matrix
31    */
32    public Matrix4f() {
33        mMat = new float[16];
34        loadIdentity();
35    }
36
37    /**
38    * Creates a new matrix and sets its values from the given
39    * parameter
40    *
41    * @param dataArray values to set the matrix to, must be 16
42    *                  floats long
43    */
44    public Matrix4f(float[] dataArray) {
45        mMat = new float[16];
46        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
47    }
48
49    /**
50    * Return a reference to the internal array representing matrix
51    * values. Modifying this array will also change the matrix
52    *
53    * @return internal array representing the matrix
54    */
55    public float[] getArray() {
56        return mMat;
57    }
58
59    /**
60    * Returns the value for a given row and column
61    *
62    * @param x column of the value to return
63    * @param y row of the value to return
64    *
65    * @return value in the yth row and xth column
66    */
67    public float get(int x, int y) {
68        return mMat[x*4 + y];
69    }
70
71    /**
72    * Sets the value for a given row and column
73    *
74    * @param x column of the value to set
75    * @param y row of the value to set
76    */
77    public void set(int x, int y, float v) {
78        mMat[x*4 + y] = v;
79    }
80
81    /**
82    * Sets the matrix values to identity
83    */
84    public void loadIdentity() {
85        mMat[0] = 1;
86        mMat[1] = 0;
87        mMat[2] = 0;
88        mMat[3] = 0;
89
90        mMat[4] = 0;
91        mMat[5] = 1;
92        mMat[6] = 0;
93        mMat[7] = 0;
94
95        mMat[8] = 0;
96        mMat[9] = 0;
97        mMat[10] = 1;
98        mMat[11] = 0;
99
100        mMat[12] = 0;
101        mMat[13] = 0;
102        mMat[14] = 0;
103        mMat[15] = 1;
104    }
105
106    /**
107    * Sets the values of the matrix to those of the parameter
108    *
109    * @param src matrix to load the values from
110    */
111    public void load(Matrix4f src) {
112        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
113    }
114
115    /**
116    * Sets current values to be a rotation matrix of certain angle
117    * about a given axis
118    *
119    * @param rot angle of rotation
120    * @param x rotation axis x
121    * @param y rotation axis y
122    * @param z rotation axis z
123    */
124    public void loadRotate(float rot, float x, float y, float z) {
125        float c, s;
126        mMat[3] = 0;
127        mMat[7] = 0;
128        mMat[11]= 0;
129        mMat[12]= 0;
130        mMat[13]= 0;
131        mMat[14]= 0;
132        mMat[15]= 1;
133        rot *= (float)(java.lang.Math.PI / 180.0f);
134        c = (float)java.lang.Math.cos(rot);
135        s = (float)java.lang.Math.sin(rot);
136
137        float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
138        if (!(len != 1)) {
139            float recipLen = 1.f / len;
140            x *= recipLen;
141            y *= recipLen;
142            z *= recipLen;
143        }
144        float nc = 1.0f - c;
145        float xy = x * y;
146        float yz = y * z;
147        float zx = z * x;
148        float xs = x * s;
149        float ys = y * s;
150        float zs = z * s;
151        mMat[ 0] = x*x*nc +  c;
152        mMat[ 4] =  xy*nc - zs;
153        mMat[ 8] =  zx*nc + ys;
154        mMat[ 1] =  xy*nc + zs;
155        mMat[ 5] = y*y*nc +  c;
156        mMat[ 9] =  yz*nc - xs;
157        mMat[ 2] =  zx*nc - ys;
158        mMat[ 6] =  yz*nc + xs;
159        mMat[10] = z*z*nc +  c;
160    }
161
162    /**
163    * Sets current values to be a scale matrix of given dimensions
164    *
165    * @param x scale component x
166    * @param y scale component y
167    * @param z scale component z
168    */
169    public void loadScale(float x, float y, float z) {
170        loadIdentity();
171        mMat[0] = x;
172        mMat[5] = y;
173        mMat[10] = z;
174    }
175
176    /**
177    * Sets current values to be a translation matrix of given
178    * dimensions
179    *
180    * @param x translation component x
181    * @param y translation component y
182    * @param z translation component z
183    */
184    public void loadTranslate(float x, float y, float z) {
185        loadIdentity();
186        mMat[12] = x;
187        mMat[13] = y;
188        mMat[14] = z;
189    }
190
191    /**
192    * Sets current values to be the result of multiplying two given
193    * matrices
194    *
195    * @param lhs left hand side matrix
196    * @param rhs right hand side matrix
197    */
198    public void loadMultiply(Matrix4f lhs, Matrix4f rhs) {
199        for (int i=0 ; i<4 ; i++) {
200            float ri0 = 0;
201            float ri1 = 0;
202            float ri2 = 0;
203            float ri3 = 0;
204            for (int j=0 ; j<4 ; j++) {
205                float rhs_ij = rhs.get(i,j);
206                ri0 += lhs.get(j,0) * rhs_ij;
207                ri1 += lhs.get(j,1) * rhs_ij;
208                ri2 += lhs.get(j,2) * rhs_ij;
209                ri3 += lhs.get(j,3) * rhs_ij;
210            }
211            set(i,0, ri0);
212            set(i,1, ri1);
213            set(i,2, ri2);
214            set(i,3, ri3);
215        }
216    }
217
218    /**
219    * Set current values to be an orthographic projection matrix
220    *
221    * @param l location of the left vertical clipping plane
222    * @param r location of the right vertical clipping plane
223    * @param b location of the bottom horizontal clipping plane
224    * @param t location of the top horizontal clipping plane
225    * @param n location of the near clipping plane
226    * @param f location of the far clipping plane
227    */
228    public void loadOrtho(float l, float r, float b, float t, float n, float f) {
229        loadIdentity();
230        mMat[0] = 2 / (r - l);
231        mMat[5] = 2 / (t - b);
232        mMat[10]= -2 / (f - n);
233        mMat[12]= -(r + l) / (r - l);
234        mMat[13]= -(t + b) / (t - b);
235        mMat[14]= -(f + n) / (f - n);
236    }
237
238    /**
239    * Set current values to be an orthographic projection matrix
240    * with the right and bottom clipping planes set to the given
241    * values. Left and top clipping planes are set to 0. Near and
242    * far are set to -1, 1 respectively
243    *
244    * @param w location of the right vertical clipping plane
245    * @param h location of the bottom horizontal clipping plane
246    *
247    */
248    public void loadOrthoWindow(int w, int h) {
249        loadOrtho(0,w, h,0, -1,1);
250    }
251
252    /**
253    * Sets current values to be a perspective projection matrix
254    *
255    * @param l location of the left vertical clipping plane
256    * @param r location of the right vertical clipping plane
257    * @param b location of the bottom horizontal clipping plane
258    * @param t location of the top horizontal clipping plane
259    * @param n location of the near clipping plane, must be positive
260    * @param f location of the far clipping plane, must be positive
261    *
262    */
263    public void loadFrustum(float l, float r, float b, float t, float n, float f) {
264        loadIdentity();
265        mMat[0] = 2 * n / (r - l);
266        mMat[5] = 2 * n / (t - b);
267        mMat[8] = (r + l) / (r - l);
268        mMat[9] = (t + b) / (t - b);
269        mMat[10]= -(f + n) / (f - n);
270        mMat[11]= -1;
271        mMat[14]= -2*f*n / (f - n);
272        mMat[15]= 0;
273    }
274
275    /**
276    * Sets current values to be a perspective projection matrix
277    *
278    * @param fovy vertical field of view angle in degrees
279    * @param aspect aspect ratio of the screen
280    * @param near near cliping plane, must be positive
281    * @param far far clipping plane, must be positive
282    */
283    public void loadPerspective(float fovy, float aspect, float near, float far) {
284        float top = near * (float)Math.tan((float) (fovy * Math.PI / 360.0f));
285        float bottom = -top;
286        float left = bottom * aspect;
287        float right = top * aspect;
288        loadFrustum(left, right, bottom, top, near, far);
289    }
290
291    /**
292    * Helper function to set the current values to a perspective
293    * projection matrix with aspect ratio defined by the parameters
294    * and (near, far), (bottom, top) mapping to (-1, 1) at z = 0
295    *
296    * @param w screen width
297    * @param h screen height
298    */
299    public void loadProjectionNormalized(int w, int h) {
300        // range -1,1 in the narrow axis at z = 0.
301        Matrix4f m1 = new Matrix4f();
302        Matrix4f m2 = new Matrix4f();
303
304        if(w > h) {
305            float aspect = ((float)w) / h;
306            m1.loadFrustum(-aspect,aspect,  -1,1,  1,100);
307        } else {
308            float aspect = ((float)h) / w;
309            m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
310        }
311
312        m2.loadRotate(180, 0, 1, 0);
313        m1.loadMultiply(m1, m2);
314
315        m2.loadScale(-2, 2, 1);
316        m1.loadMultiply(m1, m2);
317
318        m2.loadTranslate(0, 0, 2);
319        m1.loadMultiply(m1, m2);
320
321        load(m1);
322    }
323
324    /**
325    * Post-multiplies the current matrix by a given parameter
326    *
327    * @param rhs right hand side to multiply by
328    */
329    public void multiply(Matrix4f rhs) {
330        Matrix4f tmp = new Matrix4f();
331        tmp.loadMultiply(this, rhs);
332        load(tmp);
333    }
334    /**
335    * Modifies the current matrix by post-multiplying it with a
336    * rotation matrix of certain angle about a given axis
337    *
338    * @param rot angle of rotation
339    * @param x rotation axis x
340    * @param y rotation axis y
341    * @param z rotation axis z
342    */
343    public void rotate(float rot, float x, float y, float z) {
344        Matrix4f tmp = new Matrix4f();
345        tmp.loadRotate(rot, x, y, z);
346        multiply(tmp);
347    }
348
349    /**
350    * Modifies the current matrix by post-multiplying it with a
351    * scale matrix of given dimensions
352    *
353    * @param x scale component x
354    * @param y scale component y
355    * @param z scale component z
356    */
357    public void scale(float x, float y, float z) {
358        Matrix4f tmp = new Matrix4f();
359        tmp.loadScale(x, y, z);
360        multiply(tmp);
361    }
362
363    /**
364    * Modifies the current matrix by post-multiplying it with a
365    * translation matrix of given dimensions
366    *
367    * @param x translation component x
368    * @param y translation component y
369    * @param z translation component z
370    */
371    public void translate(float x, float y, float z) {
372        Matrix4f tmp = new Matrix4f();
373        tmp.loadTranslate(x, y, z);
374        multiply(tmp);
375    }
376    private float computeCofactor(int i, int j) {
377        int c0 = (i+1) % 4;
378        int c1 = (i+2) % 4;
379        int c2 = (i+3) % 4;
380        int r0 = (j+1) % 4;
381        int r1 = (j+2) % 4;
382        int r2 = (j+3) % 4;
383
384        float minor = (mMat[c0 + 4*r0] * (mMat[c1 + 4*r1] * mMat[c2 + 4*r2] -
385                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r1]))
386                     - (mMat[c0 + 4*r1] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r2] -
387                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r0]))
388                     + (mMat[c0 + 4*r2] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r1] -
389                                            mMat[c1 + 4*r1] * mMat[c2 + 4*r0]));
390
391        float cofactor = ((i+j) & 1) != 0 ? -minor : minor;
392        return cofactor;
393    }
394
395    /**
396    * Sets the current matrix to its inverse
397    */
398    public boolean inverse() {
399
400        Matrix4f result = new Matrix4f();
401
402        for (int i = 0; i < 4; ++i) {
403            for (int j = 0; j < 4; ++j) {
404                result.mMat[4*i + j] = computeCofactor(i, j);
405            }
406        }
407
408        // Dot product of 0th column of source and 0th row of result
409        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[1] +
410                     mMat[8]*result.mMat[2] + mMat[12]*result.mMat[3];
411
412        if (Math.abs(det) < 1e-6) {
413            return false;
414        }
415
416        det = 1.0f / det;
417        for (int i = 0; i < 16; ++i) {
418            mMat[i] = result.mMat[i] * det;
419        }
420
421        return true;
422    }
423
424    /**
425    * Sets the current matrix to its inverse transpose
426    */
427    public boolean inverseTranspose() {
428
429        Matrix4f result = new Matrix4f();
430
431        for (int i = 0; i < 4; ++i) {
432            for (int j = 0; j < 4; ++j) {
433                result.mMat[4*j + i] = computeCofactor(i, j);
434            }
435        }
436
437        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[4] +
438                     mMat[8]*result.mMat[8] + mMat[12]*result.mMat[12];
439
440        if (Math.abs(det) < 1e-6) {
441            return false;
442        }
443
444        det = 1.0f / det;
445        for (int i = 0; i < 16; ++i) {
446            mMat[i] = result.mMat[i] * det;
447        }
448
449        return true;
450    }
451
452    /**
453    * Sets the current matrix to its transpose
454    */
455    public void transpose() {
456        for(int i = 0; i < 3; ++i) {
457            for(int j = i + 1; j < 4; ++j) {
458                float temp = mMat[i*4 + j];
459                mMat[i*4 + j] = mMat[j*4 + i];
460                mMat[j*4 + i] = temp;
461            }
462        }
463    }
464
465    final float[] mMat;
466}
467