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