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