1 package org.robolectric.shadows; 2 3 import static com.google.common.truth.Truth.assertThat; 4 5 import android.opengl.Matrix; 6 import androidx.test.ext.junit.runners.AndroidJUnit4; 7 import org.junit.Test; 8 import org.junit.runner.RunWith; 9 10 @RunWith(AndroidJUnit4.class) 11 public class ShadowOpenGLMatrixTest { 12 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfResIsNull()13 public void multiplyMM_failIfResIsNull() { 14 Matrix.multiplyMM(null, 0, new float[16], 0, new float[16], 0); 15 } 16 17 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfLhsIsNull()18 public void multiplyMM_failIfLhsIsNull() { 19 Matrix.multiplyMM(new float[16], 0, null, 0, new float[16], 0); 20 } 21 22 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfRhsIsNull()23 public void multiplyMM_failIfRhsIsNull() { 24 Matrix.multiplyMM(new float[16], 0, new float[16], 0, null, 0); 25 } 26 27 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfResIsSmall()28 public void multiplyMM_failIfResIsSmall() { 29 Matrix.multiplyMM(new float[15], 0, new float[16], 0, new float[16], 0); 30 } 31 32 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfLhsIsSmall()33 public void multiplyMM_failIfLhsIsSmall() { 34 Matrix.multiplyMM(new float[16], 0, new float[15], 0, new float[16], 0); 35 } 36 37 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfRhsIsSmall()38 public void multiplyMM_failIfRhsIsSmall() { 39 Matrix.multiplyMM(new float[16], 0, new float[16], 0, new float[15], 0); 40 } 41 42 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfResOffsetIsOutOfBounds()43 public void multiplyMM_failIfResOffsetIsOutOfBounds() { 44 Matrix.multiplyMM(new float[32], 30, new float[16], 0, new float[16], 0); 45 } 46 47 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfLhsOffsetIsOutOfBounds()48 public void multiplyMM_failIfLhsOffsetIsOutOfBounds() { 49 Matrix.multiplyMM(new float[16], 0, new float[32], 30, new float[16], 0); 50 } 51 52 @Test(expected = IllegalArgumentException.class) multiplyMM_failIfRhsOffsetIsOutOfBounds()53 public void multiplyMM_failIfRhsOffsetIsOutOfBounds() { 54 Matrix.multiplyMM(new float[16], 0, new float[16], 0, new float[32], 30); 55 } 56 57 @Test multiplyIdentity()58 public void multiplyIdentity() { 59 final float[] res = new float[16]; 60 final float[] i = new float[16]; 61 Matrix.setIdentityM(i, 0); 62 final float[] m1 = new float[]{ 63 1, 2, 3, 4, 64 5, 6, 7, 8, 65 9, 10, 11, 12, 66 13, 14, 15, 16 67 }; 68 Matrix.multiplyMM(res, 0, m1, 0, i, 0); 69 assertThat(res).usingExactEquality().containsAtLeast(m1); 70 71 Matrix.multiplyMM(res, 0, i, 0, m1, 0); 72 assertThat(res).usingExactEquality().containsAtLeast(m1); 73 } 74 75 @Test multiplyIdentityWithOffset()76 public void multiplyIdentityWithOffset() { 77 final float[] res = new float[32]; 78 final float[] i = new float[32]; 79 Matrix.setIdentityM(i, 16); 80 final float[] m1 = new float[]{ 81 0, 0, 0, 0, 82 0, 0, 0, 0, 83 0, 0, 0, 0, 84 0, 0, 0, 0, 85 86 1, 2, 3, 4, 87 5, 6, 7, 8, 88 9, 10, 11, 12, 89 13, 14, 15, 16 90 }; 91 Matrix.multiplyMM(res, 16, m1, 16, i, 16); 92 assertThat(res).usingExactEquality().containsAtLeast(m1); 93 94 Matrix.multiplyMM(res, 16, i, 16, m1, 16); 95 assertThat(res).usingExactEquality().containsAtLeast(m1); 96 } 97 98 @Test multiplyMM()99 public void multiplyMM() { 100 final float[] res = new float[16]; 101 final float[] m1 = new float[]{ 102 0, 1, 2, 3, 103 4, 5, 6, 7, 104 8, 9, 10, 11, 105 12, 13, 14, 15 106 }; 107 final float[] m2 = new float[]{ 108 0, 1, 2, 3, 109 4, 5, 6, 7, 110 8, 9, 10, 11, 111 12, 13, 14, 15 112 }; 113 114 final float[] expected = new float[]{ 115 56, 62, 68, 74, 116 152, 174, 196, 218, 117 248, 286, 324, 362, 118 344, 398, 452, 506 119 }; 120 121 122 Matrix.multiplyMM(res, 0, m1, 0, m2, 0); 123 assertThat(res).usingExactEquality().containsAtLeast(expected); 124 } 125 126 @Test multiplyMMWithOffset()127 public void multiplyMMWithOffset() { 128 final float[] res = new float[32]; 129 final float[] m1 = new float[]{ 130 0, 0, 0, 0, 131 0, 0, 0, 0, 132 0, 0, 0, 0, 133 0, 0, 0, 0, 134 135 0, 1, 2, 3, 136 4, 5, 6, 7, 137 8, 9, 10, 11, 138 12, 13, 14, 15 139 }; 140 final float[] m2 = new float[]{ 141 0, 0, 0, 0, 142 0, 0, 0, 0, 143 0, 0, 0, 0, 144 0, 0, 0, 0, 145 56, 62, 68, 74, 146 152, 174, 196, 218, 147 248, 286, 324, 362, 148 344, 398, 452, 506 149 }; 150 final float[] expected = new float[]{ 151 0, 0, 0, 0, 152 0, 0, 0, 0, 153 0, 0, 0, 0, 154 0, 0, 0, 0, 155 1680, 1940, 2200, 2460, 156 4880, 5620, 6360, 7100, 157 8080, 9300, 10520, 11740, 158 11280, 12980, 14680, 16380 159 }; 160 161 Matrix.multiplyMM(res, 16, m1, 16, m2, 16); 162 assertThat(res).usingExactEquality().containsAtLeast(expected); 163 } 164 165 @Test multiplyMMRandom()166 public void multiplyMMRandom() { 167 final float[] m1 = new float[]{ 168 0.730964f, 0.006556f, 0.999294f, 0.886486f, 169 0.703636f, 0.865595f, 0.464857f, 0.861619f, 170 0.304945f, 0.740410f, 0.059668f, 0.876067f, 171 0.048256f, 0.259968f, 0.915555f, 0.356720f, 172 }; 173 final float[] m2 = new float[]{ 174 0.462205f, 0.868120f, 0.520904f, 0.959729f, 175 0.531887f, 0.882446f, 0.293452f, 0.878477f, 176 0.938628f, 0.796945f, 0.757566f, 0.983955f, 177 0.346051f, 0.972866f, 0.773706f, 0.895736f, 178 }; 179 180 final float[] expected = new float[]{ 181 1.153855f, 1.389652f, 1.775197f, 1.956428f, 182 1.141589f, 1.212979f, 1.763527f, 1.802296f, 183 1.525360f, 1.512691f, 2.254498f, 2.533418f, 184 1.216656f, 1.650098f, 1.664312f, 2.142354f, 185 }; 186 final float[] res = new float[16]; 187 Matrix.multiplyMM(res, 0, m1, 0, m2, 0); 188 assertMatrixWithPrecision(res, expected, 0.0001f); 189 } 190 191 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfResIsNull()192 public void multiplyMVFailsIfResIsNull() { 193 Matrix.multiplyMV(null, 0, new float[16], 0, new float[4], 0); 194 } 195 196 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfLhsIsNull()197 public void multiplyMVFailsIfLhsIsNull() { 198 Matrix.multiplyMV(new float[4], 0, null, 0, new float[4], 0); 199 } 200 201 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfRhsIsNull()202 public void multiplyMVFailsIfRhsIsNull() { 203 Matrix.multiplyMV(new float[4], 0, new float[16], 0, null, 0); 204 } 205 206 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfResIsSmall()207 public void multiplyMVFailsIfResIsSmall() { 208 Matrix.multiplyMV(new float[3], 0, new float[16], 0, new float[4], 0); 209 } 210 211 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfLhsIsSmall()212 public void multiplyMVFailsIfLhsIsSmall() { 213 Matrix.multiplyMV(new float[4], 0, new float[15], 0, new float[4], 0); 214 } 215 216 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfRhsIsSmall()217 public void multiplyMVFailsIfRhsIsSmall() { 218 Matrix.multiplyMV(new float[4], 0, new float[16], 0, new float[3], 0); 219 } 220 221 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfResOffsetIsOutOfBounds()222 public void multiplyMVFailsIfResOffsetIsOutOfBounds() { 223 Matrix.multiplyMV(new float[4], 1, new float[16], 0, new float[4], 0); 224 } 225 226 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfLhsOffsetIsOutOfBounds()227 public void multiplyMVFailsIfLhsOffsetIsOutOfBounds() { 228 Matrix.multiplyMV(new float[4], 0, new float[16], 1, new float[4], 0); 229 } 230 231 @Test(expected = IllegalArgumentException.class) multiplyMVFailsIfRhsOffsetIsOutOfBounds()232 public void multiplyMVFailsIfRhsOffsetIsOutOfBounds() { 233 Matrix.multiplyMV(new float[4], 0, new float[16], 0, new float[4], 1); 234 } 235 236 @Test multiplyMVIdentity()237 public void multiplyMVIdentity() { 238 final float[] res = new float[4]; 239 final float[] i = new float[16]; 240 Matrix.setIdentityM(i, 0); 241 float[] v1 = new float[]{1, 2, 3, 4}; 242 Matrix.multiplyMV(res, 0, i, 0, v1, 0); 243 assertThat(res).usingExactEquality().containsAtLeast(v1); 244 } 245 246 @Test multiplyMV()247 public void multiplyMV() { 248 final float[] res = new float[4]; 249 final float[] m1 = new float[]{ 250 0, 1, 2, 3, 251 4, 5, 6, 7, 252 8, 9, 10, 11, 253 12, 13, 14, 15 254 }; 255 256 float[] v1 = new float[]{42, 239, 128, 1024}; 257 float[] expected = new float[]{14268, 15701, 17134, 18567}; 258 Matrix.multiplyMV(res, 0, m1, 0, v1, 0); 259 assertThat(res).usingExactEquality().containsAtLeast(expected); 260 } 261 262 @Test multiplyMVWithOffset()263 public void multiplyMVWithOffset() { 264 final float[] res = new float[5]; 265 final float[] m1 = new float[]{ 266 0, 0, 0, 0, 267 0, 1, 2, 3, 268 4, 5, 6, 7, 269 8, 9, 10, 11, 270 12, 13, 14, 15 271 }; 272 273 float[] v1 = new float[]{ 274 0, 0, 275 42, 239, 128, 1024 276 }; 277 float[] expected = new float[]{ 278 0, 279 14268, 15701, 17134, 18567 280 }; 281 Matrix.multiplyMV(res, 1, m1, 4, v1, 2); 282 assertThat(res).usingExactEquality().containsAtLeast(expected); 283 } 284 285 @Test multiplyMVRandom()286 public void multiplyMVRandom() { 287 final float[] m1 = new float[]{ 288 0.575544f, 0.182558f, 0.097663f, 0.413832f, 289 0.781248f, 0.466904f, 0.353418f, 0.790540f, 290 0.074133f, 0.690470f, 0.619758f, 0.191669f, 291 0.953532f, 0.018836f, 0.336544f, 0.972782f, 292 }; 293 final float[] v2 = new float[]{ 294 0.573973f, 0.096736f, 0.330662f, 0.758732f, 295 }; 296 final float[] expected = new float[]{ 297 1.153910f, 0.392554f, 0.550521f, 1.115460f, 298 }; 299 final float[] res = new float[4]; 300 Matrix.multiplyMV(res, 0, m1, 0, v2, 0); 301 assertMatrixWithPrecision(res, expected, 0.0001f); 302 } 303 304 @Test testLength()305 public void testLength() { 306 assertThat(Matrix.length(3, 4, 5)).isWithin(0.001f).of(7.071f); 307 } 308 309 @Test testInvertM()310 public void testInvertM() { 311 float[] matrix = new float[]{ 312 10, 0, 0, 0, 313 0, 20, 0, 0, 314 0, 0, 30, 0, 315 40, 50, 60, 1 316 }; 317 318 float[] inverse = new float[]{ 319 0.1f, 0, 0, 0, 320 0, 0.05f, 0, 0, 321 0, 0, 0.03333f, 0, 322 -4, -2.5f, -2, 1 323 }; 324 float[] output = new float[16]; 325 assertThat(Matrix.invertM(output, 0, matrix, 0)).isTrue(); 326 327 assertMatrixWithPrecision(output, inverse, 0.0001f); 328 } 329 330 @Test testMultiplyMM()331 public void testMultiplyMM() { 332 float[] matrix1 = new float[]{ 333 1, 2, 3, 4, 334 5, 6, 7, 8, 335 9, 10, 11, 12, 336 13, 14, 15, 16 337 }; 338 float[] matrix2 = new float[]{ 339 16, 15, 14, 13, 340 12, 11, 10, 9, 341 8, 7, 6, 5, 342 4, 3, 2, 1 343 }; 344 float[] expected = new float[]{ 345 386, 444, 502, 560, 346 274, 316, 358, 400, 347 162, 188, 214, 240, 348 50, 60, 70, 80, 349 }; 350 351 float[] output = new float[16]; 352 Matrix.multiplyMM(output, 0, matrix1, 0, matrix2, 0); 353 assertThat(output).usingExactEquality().containsAtLeast(expected); 354 } 355 356 @Test testFrustum()357 public void testFrustum() { 358 float[] expected = new float[]{ 359 0.005f, 0, 0, 0, 360 0, 0.02f, 0, 0, 361 1.5f, 5, -1.020202f, -1, 362 0, 0, -2.020202f, 0, 363 }; 364 float[] output = new float[16]; 365 Matrix.frustumM(output, 0, 100, 500, 200, 300, 1, 100); 366 assertThat(output).usingExactEquality().containsAtLeast(expected); 367 } 368 369 @Test testPerspectiveM()370 public void testPerspectiveM() { 371 float[] expected = new float[]{ 372 1145.9144f, 0, 0, 0, 373 0, 572.9572f, 0, 0, 374 0, 0, -1.020202f, -1, 375 0, 0, -2.020202f, 0, 376 }; 377 float[] output = new float[16]; 378 Matrix.perspectiveM(output, 0, 0.2f, 0.5f, 1, 100); 379 assertThat(output).usingExactEquality().containsAtLeast(expected); 380 } 381 382 @Test testMultiplyMV()383 public void testMultiplyMV() { 384 float[] matrix = new float[]{ 385 2, 0, 0, 0, 386 0, 4, 0, 0, 387 0, 0, 6, 0, 388 1, 2, 3, 1 389 }; 390 391 float[] vector = new float[]{5, 7, 9, 1}; 392 float[] expected = new float[]{11, 30, 57, 1}; 393 float[] output = new float[4]; 394 Matrix.multiplyMV(output, 0, matrix, 0, vector, 0); 395 assertThat(output).usingExactEquality().containsAtLeast(expected); 396 } 397 398 @Test testSetIdentityM()399 public void testSetIdentityM() { 400 float[] matrix = new float[]{ 401 1, 2, 3, 4, 402 5, 6, 7, 8, 403 9, 10, 11, 12, 404 13, 14, 15, 16 405 }; 406 float[] expected = new float[]{ 407 1, 0, 0, 0, 408 0, 1, 0, 0, 409 0, 0, 1, 0, 410 0, 0, 0, 1 411 }; 412 Matrix.setIdentityM(matrix, 0); 413 assertThat(matrix).usingExactEquality().containsAtLeast(expected); 414 } 415 416 @Test testScaleM()417 public void testScaleM() { 418 float[] matrix = new float[]{ 419 1, 2, 3, 4, 420 5, 6, 7, 8, 421 9, 10, 11, 12, 422 13, 14, 15, 16 423 }; 424 float[] expected = new float[]{ 425 2, 4, 6, 8, 426 20, 24, 28, 32, 427 54, 60, 66, 72, 428 13, 14, 15, 16 429 }; 430 float[] output = new float[16]; 431 Matrix.scaleM(output, 0, matrix, 0, 2, 4, 6); 432 assertThat(output).usingExactEquality().containsAtLeast(expected); 433 } 434 435 @Test testScaleMInPlace()436 public void testScaleMInPlace() { 437 float[] matrix = new float[]{ 438 1, 2, 3, 4, 439 5, 6, 7, 8, 440 9, 10, 11, 12, 441 13, 14, 15, 16 442 }; 443 float[] expected = new float[]{ 444 2, 4, 6, 8, 445 20, 24, 28, 32, 446 54, 60, 66, 72, 447 13, 14, 15, 16 448 }; 449 Matrix.scaleM(matrix, 0, 2, 4, 6); 450 assertThat(matrix).usingExactEquality().containsAtLeast(expected); 451 } 452 453 @Test testTranslateM()454 public void testTranslateM() { 455 float[] matrix = new float[]{ 456 1, 2, 3, 4, 457 5, 6, 7, 8, 458 9, 10, 11, 12, 459 13, 14, 15, 16 460 }; 461 float[] expected = new float[]{ 462 1, 2, 3, 4, 463 5, 6, 7, 8, 464 9, 10, 11, 12, 465 89, 102, 115, 128 466 }; 467 float[] output = new float[16]; 468 Matrix.translateM(output, 0, matrix, 0, 2, 4, 6); 469 assertThat(output).usingExactEquality().containsAtLeast(expected); 470 } 471 472 @Test testTranslateMInPlace()473 public void testTranslateMInPlace() { 474 float[] matrix = new float[]{ 475 1, 2, 3, 4, 476 5, 6, 7, 8, 477 9, 10, 11, 12, 478 13, 14, 15, 16 479 }; 480 float[] expected = new float[]{ 481 1, 2, 3, 4, 482 5, 6, 7, 8, 483 9, 10, 11, 12, 484 89, 102, 115, 128 485 }; 486 Matrix.translateM(matrix, 0, 2, 4, 6); 487 assertThat(matrix).usingExactEquality().containsAtLeast(expected); 488 } 489 490 @Test testRotateM()491 public void testRotateM() { 492 float[] matrix = new float[]{ 493 1, 2, 3, 4, 494 5, 6, 7, 8, 495 9, 10, 11, 12, 496 13, 14, 15, 16 497 }; 498 float[] expected = new float[]{ 499 0.95625275f, 1.9625025f, 2.968752f, 3.9750016f, 500 5.0910234f, 6.07802f, 7.0650167f, 8.052013f, 501 8.953606f, 9.960234f, 10.966862f, 11.973489f, 502 13, 14, 15, 16 503 }; 504 float[] output = new float[16]; 505 Matrix.rotateM(output, 0, matrix, 0, 2, 4, 6, 8); 506 assertThat(output).usingExactEquality().containsAtLeast(expected); 507 } 508 509 @Test testRotateMInPlace()510 public void testRotateMInPlace() { 511 float[] matrix = new float[]{ 512 1, 2, 3, 4, 513 5, 6, 7, 8, 514 9, 10, 11, 12, 515 13, 14, 15, 16 516 }; 517 float[] expected = new float[]{ 518 0.95625275f, 1.9625025f, 2.968752f, 3.9750016f, 519 5.0910234f, 6.07802f, 7.0650167f, 8.052013f, 520 8.953606f, 9.960234f, 10.966862f, 11.973489f, 521 13, 14, 15, 16 522 }; 523 Matrix.rotateM(matrix, 0, 2, 4, 6, 8); 524 assertThat(matrix).usingExactEquality().containsAtLeast(expected); 525 } 526 527 @Test testSetRotateM()528 public void testSetRotateM() { 529 float[] matrix = new float[]{ 530 1, 2, 3, 4, 531 5, 6, 7, 8, 532 9, 10, 11, 12, 533 13, 14, 15, 16 534 }; 535 float[] expected = new float[]{ 536 0.9998687f, 0.01299483f, -0.00968048f, 0, 537 -0.012931813f, 0.999895f, 0.006544677f, 0, 538 0.009764502f, -0.006418644f, 0.99993175f, 0, 539 0, 0, 0, 1 540 }; 541 Matrix.setRotateM(matrix, 0, 1, 2, 3, 4); 542 assertThat(matrix).usingExactEquality().containsAtLeast(expected); 543 } 544 assertMatrixWithPrecision(float[] actual, float[] expected, float precision)545 private static void assertMatrixWithPrecision(float[] actual, float[] expected, float precision) { 546 assertThat(actual).hasLength(expected.length); 547 for (int i = 0; i < actual.length; i++) { 548 assertThat(actual[i]).isWithin(precision).of(expected[i]); 549 } 550 } 551 } 552