Home | History | Annotate | Download | only in renderscript
      1 /*
      2  * Copyright (C) 2009 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 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     */
     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 i row of the value to return
     63     * @param j column of the value to return
     64     *
     65     * @return value in the ith row and jth column
     66     */
     67     public float get(int i, int j) {
     68         return mMat[i*4 + j];
     69     }
     70 
     71     /**
     72     * Sets the value for a given row and column
     73     *
     74     * @param i row of the value to set
     75     * @param j column of the value to set
     76     */
     77     public void set(int i, int j, float v) {
     78         mMat[i*4 + j] = 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