package org.robolectric.shadows;
import android.opengl.Matrix;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.TestRunners;
import org.robolectric.annotation.Config;
import static android.os.Build.VERSION_CODES.JELLY_BEAN;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.withPrecision;
@RunWith(TestRunners.MultiApiSelfTest.class)
public class ShadowOpenGLMatrixTest {
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfResIsNull() throws Exception {
Matrix.multiplyMM(null, 0, new float[16], 0, new float[16], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfLhsIsNull() throws Exception {
Matrix.multiplyMM(new float[16], 0, null, 0, new float[16], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfRhsIsNull() throws Exception {
Matrix.multiplyMM(new float[16], 0, new float[16], 0, null, 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfResIsSmall() throws Exception {
Matrix.multiplyMM(new float[15], 0, new float[16], 0, new float[16], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfLhsIsSmall() throws Exception {
Matrix.multiplyMM(new float[16], 0, new float[15], 0, new float[16], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfRhsIsSmall() throws Exception {
Matrix.multiplyMM(new float[16], 0, new float[16], 0, new float[15], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfResOffsetIsOutOfBounds() throws Exception {
Matrix.multiplyMM(new float[32], 30, new float[16], 0, new float[16], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfLhsOffsetIsOutOfBounds() throws Exception {
Matrix.multiplyMM(new float[16], 0, new float[32], 30, new float[16], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMM_failIfRhsOffsetIsOutOfBounds() throws Exception {
Matrix.multiplyMM(new float[16], 0, new float[16], 0, new float[32], 30);
}
@Test
public void multiplyIdentity() throws Exception {
final float[] res = new float[16];
final float[] i = new float[16];
Matrix.setIdentityM(i, 0);
final float[] m1 = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
Matrix.multiplyMM(res, 0, m1, 0, i, 0);
assertThat(res).containsSequence(m1, withPrecision(0.0001f));
Matrix.multiplyMM(res, 0, i, 0, m1, 0);
assertThat(res).containsSequence(m1, withPrecision(0.0001f));
}
@Test
public void multiplyIdentityWithOffset() throws Exception {
final float[] res = new float[32];
final float[] i = new float[32];
Matrix.setIdentityM(i, 16);
final float[] m1 = new float[]{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
Matrix.multiplyMM(res, 16, m1, 16, i, 16);
assertThat(res).containsSequence(m1, withPrecision(0.0001f));
Matrix.multiplyMM(res, 16, i, 16, m1, 16);
assertThat(res).containsSequence(m1, withPrecision(0.0001f));
}
@Test
public void multiplyMM() throws Exception {
final float[] res = new float[16];
final float[] m1 = new float[]{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15
};
final float[] m2 = new float[]{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15
};
final float[] expected = new float[]{
56, 62, 68, 74,
152, 174, 196, 218,
248, 286, 324, 362,
344, 398, 452, 506
};
Matrix.multiplyMM(res, 0, m1, 0, m2, 0);
assertThat(res).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void multiplyMMWithOffset() throws Exception {
final float[] res = new float[32];
final float[] m1 = new float[]{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15
};
final float[] m2 = new float[]{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
56, 62, 68, 74,
152, 174, 196, 218,
248, 286, 324, 362,
344, 398, 452, 506
};
final float[] expected = new float[]{
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1680, 1940, 2200, 2460,
4880, 5620, 6360, 7100,
8080, 9300, 10520, 11740,
11280, 12980, 14680, 16380
};
Matrix.multiplyMM(res, 16, m1, 16, m2, 16);
assertThat(res).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void multiplyMMRandom() throws Exception {
final float[] m1 = new float[]{
0.730964f, 0.006556f, 0.999294f, 0.886486f,
0.703636f, 0.865595f, 0.464857f, 0.861619f,
0.304945f, 0.740410f, 0.059668f, 0.876067f,
0.048256f, 0.259968f, 0.915555f, 0.356720f,
};
final float[] m2 = new float[]{
0.462205f, 0.868120f, 0.520904f, 0.959729f,
0.531887f, 0.882446f, 0.293452f, 0.878477f,
0.938628f, 0.796945f, 0.757566f, 0.983955f,
0.346051f, 0.972866f, 0.773706f, 0.895736f,
};
final float[] expected = new float[]{
1.153855f, 1.389652f, 1.775197f, 1.956428f,
1.141589f, 1.212979f, 1.763527f, 1.802296f,
1.525360f, 1.512691f, 2.254498f, 2.533418f,
1.216656f, 1.650098f, 1.664312f, 2.142354f,
};
final float[] res = new float[16];
Matrix.multiplyMM(res, 0, m1, 0, m2, 0);
assertThat(res).containsSequence(expected, withPrecision(0.0001f));
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfResIsNull() throws Exception {
Matrix.multiplyMV(null, 0, new float[16], 0, new float[4], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfLhsIsNull() throws Exception {
Matrix.multiplyMV(new float[4], 0, null, 0, new float[4], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfRhsIsNull() throws Exception {
Matrix.multiplyMV(new float[4], 0, new float[16], 0, null, 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfResIsSmall() throws Exception {
Matrix.multiplyMV(new float[3], 0, new float[16], 0, new float[4], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfLhsIsSmall() throws Exception {
Matrix.multiplyMV(new float[4], 0, new float[15], 0, new float[4], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfRhsIsSmall() throws Exception {
Matrix.multiplyMV(new float[4], 0, new float[16], 0, new float[3], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfResOffsetIsOutOfBounds() throws Exception {
Matrix.multiplyMV(new float[4], 1, new float[16], 0, new float[4], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfLhsOffsetIsOutOfBounds() throws Exception {
Matrix.multiplyMV(new float[4], 0, new float[16], 1, new float[4], 0);
}
@Test(expected = IllegalArgumentException.class)
public void multiplyMVFailsIfRhsOffsetIsOutOfBounds() throws Exception {
Matrix.multiplyMV(new float[4], 0, new float[16], 0, new float[4], 1);
}
@Test
public void multiplyMVIdentity() throws Exception {
final float[] res = new float[4];
final float[] i = new float[16];
Matrix.setIdentityM(i, 0);
float[] v1 = new float[]{1, 2, 3, 4};
Matrix.multiplyMV(res, 0, i, 0, v1, 0);
assertThat(res).containsSequence(v1, withPrecision(0.0001f));
}
@Test
public void multiplyMV() throws Exception {
final float[] res = new float[4];
final float[] m1 = new float[]{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15
};
float[] v1 = new float[]{42, 239, 128, 1024};
float[] expected = new float[]{14268, 15701, 17134, 18567};
Matrix.multiplyMV(res, 0, m1, 0, v1, 0);
assertThat(res).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void multiplyMVWithOffset() throws Exception {
final float[] res = new float[5];
final float[] m1 = new float[]{
0, 0, 0, 0,
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15
};
float[] v1 = new float[]{
0, 0,
42, 239, 128, 1024
};
float[] expected = new float[]{
0,
14268, 15701, 17134, 18567
};
Matrix.multiplyMV(res, 1, m1, 4, v1, 2);
assertThat(res).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void multiplyMVRandom() throws Exception {
final float[] m1 = new float[]{
0.575544f, 0.182558f, 0.097663f, 0.413832f,
0.781248f, 0.466904f, 0.353418f, 0.790540f,
0.074133f, 0.690470f, 0.619758f, 0.191669f,
0.953532f, 0.018836f, 0.336544f, 0.972782f,
};
final float[] v2 = new float[]{
0.573973f, 0.096736f, 0.330662f, 0.758732f,
};
final float[] expected = new float[]{
1.153910f, 0.392554f, 0.550521f, 1.115460f,
};
final float[] res = new float[4];
Matrix.multiplyMV(res, 0, m1, 0, v2, 0);
assertThat(res).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testLength() {
assertThat(Matrix.length(3, 4, 5)).isEqualTo(7.071f, withPrecision(0.0001f));
}
@Test
public void testInvertM() {
float[] matrix = new float[]{
10, 0, 0, 0,
0, 20, 0, 0,
0, 0, 30, 0,
40, 50, 60, 1
};
float[] inverse = new float[]{
0.1f, 0, 0, 0,
0, 0.05f, 0, 0,
0, 0, 0.03333f, 0,
-4, -2.5f, -2, 1
};
float[] output = new float[16];
assertThat(Matrix.invertM(output, 0, matrix, 0)).isTrue();
assertThat(output).containsSequence(inverse, withPrecision(0.0001f));
}
@Test
public void testMultiplyMM() {
float[] matrix1 = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] matrix2 = new float[]{
16, 15, 14, 13,
12, 11, 10, 9,
8, 7, 6, 5,
4, 3, 2, 1
};
float[] expected = new float[]{
386, 444, 502, 560,
274, 316, 358, 400,
162, 188, 214, 240,
50, 60, 70, 80,
};
float[] output = new float[16];
Matrix.multiplyMM(output, 0, matrix1, 0, matrix2, 0);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
@Config(minSdk = JELLY_BEAN, maxSdk = JELLY_BEAN)
public void testFrustumM() {
// this is actually a bug
// https://android.googlesource.com/platform/frameworks/base/+/0a088f5d4681fd2da6f610de157bf905df787bf7
// expected[8] should be 1.5
// see testFrustumJB_MR1 below
float[] expected = new float[]{
0.005f, 0, 0, 0,
0, 0.02f, 0, 0,
3f, 5, -1.020202f, -1,
0, 0, -2.020202f, 0,
};
float[] output = new float[16];
Matrix.frustumM(output, 0, 100, 500, 200, 300, 1, 100);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
@Config(minSdk = JELLY_BEAN_MR1)
public void testFrustumJB_MR1() {
float[] expected = new float[]{
0.005f, 0, 0, 0,
0, 0.02f, 0, 0,
1.5f, 5, -1.020202f, -1,
0, 0, -2.020202f, 0,
};
float[] output = new float[16];
Matrix.frustumM(output, 0, 100, 500, 200, 300, 1, 100);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testPerspectiveM() {
float[] expected = new float[]{
1145.9144f, 0, 0, 0,
0, 572.9572f, 0, 0,
0, 0, -1.020202f, -1,
0, 0, -2.020202f, 0,
};
float[] output = new float[16];
Matrix.perspectiveM(output, 0, 0.2f, 0.5f, 1, 100);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testMultiplyMV() {
float[] matrix = new float[]{
2, 0, 0, 0,
0, 4, 0, 0,
0, 0, 6, 0,
1, 2, 3, 1
};
float[] vector = new float[]{5, 7, 9, 1};
float[] expected = new float[]{11, 30, 57, 1};
float[] output = new float[4];
Matrix.multiplyMV(output, 0, matrix, 0, vector, 0);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testSetIdentityM() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
Matrix.setIdentityM(matrix, 0);
assertThat(matrix).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testScaleM() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
2, 4, 6, 8,
20, 24, 28, 32,
54, 60, 66, 72,
13, 14, 15, 16
};
float[] output = new float[16];
Matrix.scaleM(output, 0, matrix, 0, 2, 4, 6);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testScaleMInPlace() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
2, 4, 6, 8,
20, 24, 28, 32,
54, 60, 66, 72,
13, 14, 15, 16
};
Matrix.scaleM(matrix, 0, 2, 4, 6);
assertThat(matrix).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testTranslateM() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
89, 102, 115, 128
};
float[] output = new float[16];
Matrix.translateM(output, 0, matrix, 0, 2, 4, 6);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testTranslateMInPlace() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
89, 102, 115, 128
};
Matrix.translateM(matrix, 0, 2, 4, 6);
assertThat(matrix).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testRotateM() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
0.95625275f, 1.9625025f, 2.968752f, 3.9750016f,
5.0910234f, 6.07802f, 7.0650167f, 8.052013f,
8.953606f, 9.960234f, 10.966862f, 11.973489f,
13, 14, 15, 16
};
float[] output = new float[16];
Matrix.rotateM(output, 0, matrix, 0, 2, 4, 6, 8);
assertThat(output).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testRotateMInPlace() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
0.95625275f, 1.9625025f, 2.968752f, 3.9750016f,
5.0910234f, 6.07802f, 7.0650167f, 8.052013f,
8.953606f, 9.960234f, 10.966862f, 11.973489f,
13, 14, 15, 16
};
Matrix.rotateM(matrix, 0, 2, 4, 6, 8);
assertThat(matrix).containsSequence(expected, withPrecision(0.0001f));
}
@Test
public void testSetRotateM() {
float[] matrix = new float[]{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
};
float[] expected = new float[]{
0.9998687f, 0.01299483f, -0.00968048f, 0,
-0.012931813f, 0.999895f, 0.006544677f, 0,
0.009764502f, -0.006418644f, 0.99993175f, 0,
0, 0, 0, 1
};
Matrix.setRotateM(matrix, 0, 1, 2, 3, 4);
assertThat(matrix).containsSequence(expected, withPrecision(0.0001f));
}
}