shadows/framework/src/main/java/org/robolectric/shadows/ShadowOpenGLMatrix.java
@Implementation
  protected static void multiplyMV(
      float[] resultVec,
      int resultVecOffset,
      float[] lhsMat,
      int lhsMatOffset,
      float[] rhsVec,
      int rhsVecOffset) {
    if (resultVec == null) {
      throw new IllegalArgumentException("resultVec == null");
    }
    if (lhsMat == null) {
      throw new IllegalArgumentException("lhsMat == null");
    }
    if (rhsVec == null) {
      throw new IllegalArgumentException("rhsVec == null");
    }
    if (resultVecOffset + 4 > resultVec.length) {
      throw new IllegalArgumentException("resultVecOffset + 4 > resultVec.length");
    }
    if (lhsMatOffset + 16 > lhsMat.length) {
      throw new IllegalArgumentException("lhsMatOffset + 16 > lhsMat.length");
    }
    if (rhsVecOffset + 4 > rhsVec.length) {
      throw new IllegalArgumentException("rhsVecOffset + 4 > rhsVec.length");
    }
    final float x = rhsVec[rhsVecOffset + 0];
    final float y = rhsVec[rhsVecOffset + 1];
    final float z = rhsVec[rhsVecOffset + 2];
    final float w = rhsVec[rhsVecOffset + 3];
    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;
    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;
    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;
    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;
  }
@Implementation
  protected static void multiplyMV(
      float[] resultVec,
      int resultVecOffset,
      float[] lhsMat,
      int lhsMatOffset,
      float[] rhsVec,
      int rhsVecOffset) {
    if (resultVec == null) {
      throw new IllegalArgumentException("resultVec == null");
    }
    if (lhsMat == null) {
      throw new IllegalArgumentException("lhsMat == null");
    }
    if (rhsVec == null) {
      throw new IllegalArgumentException("rhsVec == null");
    }
    if (resultVecOffset + 4 > resultVec.length) {
      throw new IllegalArgumentException("resultVecOffset + 4 > resultVec.length");
    }
    if (lhsMatOffset + 16 > lhsMat.length) {
      throw new IllegalArgumentException("lhsMatOffset + 16 > lhsMat.length");
    }
    if (rhsVecOffset + 4 > rhsVec.length) {
      throw new IllegalArgumentException("rhsVecOffset + 4 > rhsVec.length");
    }
    final float x = rhsVec[rhsVecOffset + 0];
    final float y = rhsVec[rhsVecOffset + 1];
    final float z = rhsVec[rhsVecOffset + 2];
    final float w = rhsVec[rhsVecOffset + 3];
    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;
    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;
    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;
    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;
  }
Multiplies a 4 element vector by a 4x4 matrix and stores the result in a 4-element column
vector. In matrix notation: result = lhs x rhs

<p>The same float array may be passed for resultVec, lhsMat, and/or rhsVec. However, the
resultVec element values are undefined if the resultVec elements overlap either the lhsMat or
rhsVec elements.

@param resultVec The float array that holds the result vector.
@param resultVecOffset The offset into the result array where the result vector is stored.
@param lhsMat The float array that holds the left-hand-side matrix.
@param lhsMatOffset The offset into the lhs array where the lhs is stored
@param rhsVec The float array that holds the right-hand-side vector.
@param rhsVecOffset The offset into the rhs vector where the rhs vector is stored.
@throws IllegalArgumentException if resultVec, lhsMat, or rhsVec are null, or if
resultVecOffset + 4 > resultVec.length or lhsMatOffset + 16 > lhsMat.length or rhsVecOffset
+ 4 > rhsVec.length.