Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import android.opengl.Matrix;
      4 import org.robolectric.annotation.Implementation;
      5 import org.robolectric.annotation.Implements;
      6 
      7 @Implements(Matrix.class)
      8 public class ShadowOpenGLMatrix {
      9 
     10   /**
     11    * Multiplies two 4x4 matrices together and stores the result in a third 4x4 matrix. In matrix
     12    * notation: result = lhs x rhs. Due to the way matrix multiplication works, the result matrix
     13    * will have the same effect as first multiplying by the rhs matrix, then multiplying by the lhs
     14    * matrix. This is the opposite of what you might expect.
     15    *
     16    * <p>The same float array may be passed for result, lhs, and/or rhs. However, the result element
     17    * values are undefined if the result elements overlap either the lhs or rhs elements.
     18    *
     19    * @param result The float array that holds the result.
     20    * @param resultOffset The offset into the result array where the result is stored.
     21    * @param lhs The float array that holds the left-hand-side matrix.
     22    * @param lhsOffset The offset into the lhs array where the lhs is stored
     23    * @param rhs The float array that holds the right-hand-side matrix.
     24    * @param rhsOffset The offset into the rhs array where the rhs is stored.
     25    * @throws IllegalArgumentException if result, lhs, or rhs are null, or if resultOffset + 16 >
     26    *     result.length or lhsOffset + 16 > lhs.length or rhsOffset + 16 > rhs.length.
     27    */
     28   @Implementation
     29   protected static void multiplyMM(
     30       float[] result, int resultOffset, float[] lhs, int lhsOffset, float[] rhs, int rhsOffset) {
     31     if (result == null) {
     32       throw new IllegalArgumentException("result == null");
     33     }
     34     if (lhs == null) {
     35       throw new IllegalArgumentException("lhs == null");
     36     }
     37     if (rhs == null) {
     38       throw new IllegalArgumentException("rhs == null");
     39     }
     40     if (resultOffset + 16 > result.length) {
     41       throw new IllegalArgumentException("resultOffset + 16 > result.length");
     42     }
     43     if (lhsOffset + 16 > lhs.length) {
     44       throw new IllegalArgumentException("lhsOffset + 16 > lhs.length");
     45     }
     46     if (rhsOffset + 16 > rhs.length) {
     47       throw new IllegalArgumentException("rhsOffset + 16 > rhs.length");
     48     }
     49     for (int i = 0; i < 4; i++) {
     50       final float rhs_i0 = rhs[I(i, 0, rhsOffset)];
     51       float ri0 = lhs[I(0, 0, lhsOffset)] * rhs_i0;
     52       float ri1 = lhs[I(0, 1, lhsOffset)] * rhs_i0;
     53       float ri2 = lhs[I(0, 2, lhsOffset)] * rhs_i0;
     54       float ri3 = lhs[I(0, 3, lhsOffset)] * rhs_i0;
     55       for (int j = 1; j < 4; j++) {
     56         final float rhs_ij = rhs[I(i, j, rhsOffset)];
     57         ri0 += lhs[I(j, 0, lhsOffset)] * rhs_ij;
     58         ri1 += lhs[I(j, 1, lhsOffset)] * rhs_ij;
     59         ri2 += lhs[I(j, 2, lhsOffset)] * rhs_ij;
     60         ri3 += lhs[I(j, 3, lhsOffset)] * rhs_ij;
     61       }
     62       result[I(i, 0, resultOffset)] = ri0;
     63       result[I(i, 1, resultOffset)] = ri1;
     64       result[I(i, 2, resultOffset)] = ri2;
     65       result[I(i, 3, resultOffset)] = ri3;
     66     }
     67   }
     68 
     69   /**
     70    * Multiplies a 4 element vector by a 4x4 matrix and stores the result in a 4-element column
     71    * vector. In matrix notation: result = lhs x rhs
     72    *
     73    * <p>The same float array may be passed for resultVec, lhsMat, and/or rhsVec. However, the
     74    * resultVec element values are undefined if the resultVec elements overlap either the lhsMat or
     75    * rhsVec elements.
     76    *
     77    * @param resultVec The float array that holds the result vector.
     78    * @param resultVecOffset The offset into the result array where the result 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 is stored.
     83    * @throws IllegalArgumentException if resultVec, lhsMat, or rhsVec are null, or if
     84    *     resultVecOffset + 4 > resultVec.length or lhsMatOffset + 16 > lhsMat.length or rhsVecOffset
     85    *     + 4 > rhsVec.length.
     86    */
     87   @Implementation
     88   protected static void multiplyMV(
     89       float[] resultVec,
     90       int resultVecOffset,
     91       float[] lhsMat,
     92       int lhsMatOffset,
     93       float[] rhsVec,
     94       int rhsVecOffset) {
     95     if (resultVec == null) {
     96       throw new IllegalArgumentException("resultVec == null");
     97     }
     98     if (lhsMat == null) {
     99       throw new IllegalArgumentException("lhsMat == null");
    100     }
    101     if (rhsVec == null) {
    102       throw new IllegalArgumentException("rhsVec == null");
    103     }
    104     if (resultVecOffset + 4 > resultVec.length) {
    105       throw new IllegalArgumentException("resultVecOffset + 4 > resultVec.length");
    106     }
    107     if (lhsMatOffset + 16 > lhsMat.length) {
    108       throw new IllegalArgumentException("lhsMatOffset + 16 > lhsMat.length");
    109     }
    110     if (rhsVecOffset + 4 > rhsVec.length) {
    111       throw new IllegalArgumentException("rhsVecOffset + 4 > rhsVec.length");
    112     }
    113     final float x = rhsVec[rhsVecOffset + 0];
    114     final float y = rhsVec[rhsVecOffset + 1];
    115     final float z = rhsVec[rhsVecOffset + 2];
    116     final float w = rhsVec[rhsVecOffset + 3];
    117     resultVec[resultVecOffset + 0] = lhsMat[I(0, 0, lhsMatOffset)] * x + lhsMat[I(1, 0, lhsMatOffset)] * y + lhsMat[I(2, 0, lhsMatOffset)] * z + lhsMat[I(3, 0, lhsMatOffset)] * w;
    118     resultVec[resultVecOffset + 1] = lhsMat[I(0, 1, lhsMatOffset)] * x + lhsMat[I(1, 1, lhsMatOffset)] * y + lhsMat[I(2, 1, lhsMatOffset)] * z + lhsMat[I(3, 1, lhsMatOffset)] * w;
    119     resultVec[resultVecOffset + 2] = lhsMat[I(0, 2, lhsMatOffset)] * x + lhsMat[I(1, 2, lhsMatOffset)] * y + lhsMat[I(2, 2, lhsMatOffset)] * z + lhsMat[I(3, 2, lhsMatOffset)] * w;
    120     resultVec[resultVecOffset + 3] = lhsMat[I(0, 3, lhsMatOffset)] * x + lhsMat[I(1, 3, lhsMatOffset)] * y + lhsMat[I(2, 3, lhsMatOffset)] * z + lhsMat[I(3, 3, lhsMatOffset)] * w;
    121   }
    122 
    123   private static int I(int i, int j, int offset) {
    124     // #define I(_i, _j) ((_j)+ 4*(_i))
    125     return offset + j + 4 * i;
    126   }
    127 
    128 }
    129