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