blob: 772d7b2cf346f7395fd562a3b28dea1f4552f0f9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@google.com7d683352012-12-03 21:19:52 +00007
reed@google.com125002a2011-06-09 19:13:41 +00008#include "Test.h"
9#include "SkMatrix44.h"
10
vollick@chromium.org3959a762012-11-13 15:08:22 +000011static bool nearly_equal_double(double a, double b) {
12 const double tolerance = 1e-7;
13 double diff = a - b;
14 if (diff < 0)
15 diff = -diff;
16 return diff <= tolerance;
17}
18
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000019static bool nearly_equal_mscalar(SkMScalar a, SkMScalar b) {
20 const SkMScalar tolerance = SK_MScalar1 / 200000;
21
22 return SkTAbs<SkMScalar>(a - b) <= tolerance;
23}
24
25static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
reed@google.com125002a2011-06-09 19:13:41 +000026 // Note that we get more compounded error for multiple operations when
27 // SK_SCALAR_IS_FIXED.
28#ifdef SK_SCALAR_IS_FLOAT
29 const SkScalar tolerance = SK_Scalar1 / 200000;
30#else
31 const SkScalar tolerance = SK_Scalar1 / 1024;
32#endif
33
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000034 return SkScalarAbs(a - b) <= tolerance;
reed@google.com125002a2011-06-09 19:13:41 +000035}
36
reed@google.comda9fac02011-06-13 14:46:52 +000037template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
38 T m0, T m1, T m2, T m3,
39 T m4, T m5, T m6, T m7,
40 T m8, T m9, T m10, T m11,
41 T m12, T m13, T m14, T m15) {
42 REPORTER_ASSERT(reporter, data[0] == m0);
43 REPORTER_ASSERT(reporter, data[1] == m1);
44 REPORTER_ASSERT(reporter, data[2] == m2);
45 REPORTER_ASSERT(reporter, data[3] == m3);
46
47 REPORTER_ASSERT(reporter, data[4] == m4);
48 REPORTER_ASSERT(reporter, data[5] == m5);
49 REPORTER_ASSERT(reporter, data[6] == m6);
50 REPORTER_ASSERT(reporter, data[7] == m7);
51
52 REPORTER_ASSERT(reporter, data[8] == m8);
53 REPORTER_ASSERT(reporter, data[9] == m9);
54 REPORTER_ASSERT(reporter, data[10] == m10);
55 REPORTER_ASSERT(reporter, data[11] == m11);
56
57 REPORTER_ASSERT(reporter, data[12] == m12);
58 REPORTER_ASSERT(reporter, data[13] == m13);
59 REPORTER_ASSERT(reporter, data[14] == m14);
60 REPORTER_ASSERT(reporter, data[15] == m15);
61}
62
reed@google.com125002a2011-06-09 19:13:41 +000063static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
64 for (int i = 0; i < 4; ++i) {
65 for (int j = 0; j < 4; ++j) {
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000066 if (!nearly_equal_mscalar(a.get(i, j), b.get(i, j))) {
bungeman@google.comfab44db2013-10-11 18:50:45 +000067 SkDebugf("not equal %g %g\n", a.get(i, j), b.get(i, j));
reed@google.com125002a2011-06-09 19:13:41 +000068 return false;
69 }
70 }
71 }
72 return true;
73}
74
75static bool is_identity(const SkMatrix44& m) {
76 SkMatrix44 identity;
77 identity.reset();
78 return nearly_equal(m, identity);
79}
80
reed@google.com99b5c7f2012-12-05 22:13:59 +000081///////////////////////////////////////////////////////////////////////////////
82static bool bits_isonly(int value, int mask) {
83 return 0 == (value & ~mask);
84}
85
vollick@chromium.org57a54e32012-12-10 20:16:10 +000086static void test_constructor(skiatest::Reporter* reporter) {
87 // Allocate a matrix on the heap
88 SkMatrix44* placeholderMatrix = new SkMatrix44();
robertphillips@google.com35300c42013-03-21 17:38:49 +000089 SkAutoTDelete<SkMatrix44> deleteMe(placeholderMatrix);
90
vollick@chromium.org57a54e32012-12-10 20:16:10 +000091 for (int row = 0; row < 4; ++row) {
92 for (int col = 0; col < 4; ++col) {
93 placeholderMatrix->setDouble(row, col, row * col);
94 }
95 }
96
97 // Use placement-new syntax to trigger the constructor on top of the heap
98 // address we already initialized. This allows us to check that the
99 // constructor did avoid initializing the matrix contents.
100 SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
101 REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
102 REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
103 for (int row = 0; row < 4; ++row) {
104 for (int col = 0; col < 4; ++col) {
105 REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
106 }
107 }
108
109 // Verify that kIdentity_Constructor really does initialize to an identity matrix.
110 testMatrix = 0;
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000111 testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
vollick@chromium.org57a54e32012-12-10 20:16:10 +0000112 REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
113 REPORTER_ASSERT(reporter, testMatrix->isIdentity());
114 REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
115}
116
reed@google.com99b5c7f2012-12-05 22:13:59 +0000117static void test_translate(skiatest::Reporter* reporter) {
118 SkMatrix44 mat, inverse;
119
120 mat.setTranslate(0, 0, 0);
121 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
122 mat.setTranslate(1, 2, 3);
123 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
124 REPORTER_ASSERT(reporter, mat.invert(&inverse));
125 REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000126
reed@google.com99b5c7f2012-12-05 22:13:59 +0000127 SkMatrix44 a, b, c;
128 a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
129 b.setTranslate(10, 11, 12);
130
131 c.setConcat(a, b);
132 mat = a;
133 mat.preTranslate(10, 11, 12);
134 REPORTER_ASSERT(reporter, mat == c);
135
136 c.setConcat(b, a);
137 mat = a;
138 mat.postTranslate(10, 11, 12);
139 REPORTER_ASSERT(reporter, mat == c);
140}
141
142static void test_scale(skiatest::Reporter* reporter) {
143 SkMatrix44 mat, inverse;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000144
reed@google.com99b5c7f2012-12-05 22:13:59 +0000145 mat.setScale(1, 1, 1);
146 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
147 mat.setScale(1, 2, 3);
148 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
149 REPORTER_ASSERT(reporter, mat.invert(&inverse));
150 REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
151
152 SkMatrix44 a, b, c;
153 a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
154 b.setScale(10, 11, 12);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000155
reed@google.com99b5c7f2012-12-05 22:13:59 +0000156 c.setConcat(a, b);
157 mat = a;
158 mat.preScale(10, 11, 12);
159 REPORTER_ASSERT(reporter, mat == c);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000160
reed@google.com99b5c7f2012-12-05 22:13:59 +0000161 c.setConcat(b, a);
162 mat = a;
163 mat.postScale(10, 11, 12);
164 REPORTER_ASSERT(reporter, mat == c);
165}
166
167static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
168static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
169static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
170static void make_st(SkMatrix44* mat) {
171 mat->setScale(1, 2, 3);
172 mat->postTranslate(1, 2, 3);
173}
174static void make_a(SkMatrix44* mat) {
175 mat->setRotateDegreesAbout(1, 2, 3, 45);
176}
177static void make_p(SkMatrix44* mat) {
178 SkMScalar data[] = {
179 1, 2, 3, 4, 5, 6, 7, 8,
180 1, 2, 3, 4, 5, 6, 7, 8,
181 };
182 mat->setRowMajor(data);
183}
184
185typedef void (*Make44Proc)(SkMatrix44*);
186
187static const Make44Proc gMakeProcs[] = {
188 make_i, make_t, make_s, make_st, make_a, make_p
189};
190
191static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
192 SkMScalar src2[] = { 1, 2 };
193 SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
194 SkMScalar dstA[4], dstB[4];
195
196 for (int i = 0; i < 4; ++i) {
197 dstA[i] = 123456789;
198 dstB[i] = 987654321;
199 }
200
201 mat.map2(src2, 1, dstA);
202 mat.mapMScalars(src4, dstB);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000203
reed@google.com99b5c7f2012-12-05 22:13:59 +0000204 for (int i = 0; i < 4; ++i) {
205 REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
206 }
207}
208
209static void test_map2(skiatest::Reporter* reporter) {
210 SkMatrix44 mat;
211
212 for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
213 gMakeProcs[i](&mat);
214 test_map2(reporter, mat);
215 }
216}
217
reed@google.com7d683352012-12-03 21:19:52 +0000218static void test_gettype(skiatest::Reporter* reporter) {
219 SkMatrix44 matrix;
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000220
reed@google.com7d683352012-12-03 21:19:52 +0000221 REPORTER_ASSERT(reporter, matrix.isIdentity());
222 REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000223
reed@google.com7d683352012-12-03 21:19:52 +0000224 int expectedMask;
225
226 matrix.set(1, 1, 0);
227 expectedMask = SkMatrix44::kScale_Mask;
228 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
229
230 matrix.set(0, 3, 1); // translate-x
231 expectedMask |= SkMatrix44::kTranslate_Mask;
232 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
233
234 matrix.set(2, 0, 1);
235 expectedMask |= SkMatrix44::kAffine_Mask;
236 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000237
reed@google.com7d683352012-12-03 21:19:52 +0000238 matrix.set(3, 2, 1);
239 REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
reed@google.com87f99cb2013-04-19 12:25:00 +0000240
241 // ensure that negative zero is treated as zero
242 SkMScalar dx = 0;
243 SkMScalar dy = 0;
244 SkMScalar dz = 0;
245 matrix.setTranslate(-dx, -dy, -dz);
246 REPORTER_ASSERT(reporter, matrix.isIdentity());
247 matrix.preTranslate(-dx, -dy, -dz);
248 REPORTER_ASSERT(reporter, matrix.isIdentity());
249 matrix.postTranslate(-dx, -dy, -dz);
250 REPORTER_ASSERT(reporter, matrix.isIdentity());
reed@google.com7d683352012-12-03 21:19:52 +0000251}
252
reed@google.com6f2b44d2011-06-24 18:13:39 +0000253static void test_common_angles(skiatest::Reporter* reporter) {
254 SkMatrix44 rot;
255 // Test precision of rotation in common cases
256 int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
257 for (int i = 0; i < 9; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +0000258 rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
reed@google.com6f2b44d2011-06-24 18:13:39 +0000259
260 SkMatrix rot3x3 = rot;
261 REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
262 }
263}
264
reed@google.com80b577e2012-11-09 21:25:06 +0000265static void test_concat(skiatest::Reporter* reporter) {
266 int i;
267 SkMatrix44 a, b, c, d;
268
269 a.setTranslate(10, 10, 10);
270 b.setScale(2, 2, 2);
271
272 SkScalar src[8] = {
273 0, 0, 0, 1,
274 1, 1, 1, 1
275 };
276 SkScalar dst[8];
277
278 c.setConcat(a, b);
279
280 d = a;
281 d.preConcat(b);
282 REPORTER_ASSERT(reporter, d == c);
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000283
reed@google.com1ea95be2012-11-09 21:39:48 +0000284 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000285 for (i = 0; i < 3; ++i) {
286 REPORTER_ASSERT(reporter, 10 == dst[i]);
287 REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
288 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000289
reed@google.com80b577e2012-11-09 21:25:06 +0000290 c.setConcat(b, a);
291
292 d = a;
293 d.postConcat(b);
294 REPORTER_ASSERT(reporter, d == c);
295
reed@google.com1ea95be2012-11-09 21:39:48 +0000296 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000297 for (i = 0; i < 3; ++i) {
298 REPORTER_ASSERT(reporter, 20 == dst[i]);
299 REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
300 }
301}
302
vollick@chromium.org3959a762012-11-13 15:08:22 +0000303static void test_determinant(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000304 SkMatrix44 a;
305 REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000306 a.set(1, 1, 2);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000307 REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
308 SkMatrix44 b;
309 REPORTER_ASSERT(reporter, a.invert(&b));
310 REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
311 SkMatrix44 c = b = a;
reed@google.com7d683352012-12-03 21:19:52 +0000312 c.set(0, 1, 4);
313 b.set(1, 0, 4);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000314 REPORTER_ASSERT(reporter,
315 nearly_equal_double(a.determinant(),
316 b.determinant()));
317 SkMatrix44 d = a;
reed@google.com7d683352012-12-03 21:19:52 +0000318 d.set(0, 0, 8);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000319 REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000320
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000321 SkMatrix44 e = a;
322 e.postConcat(d);
323 REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000324 e.set(0, 0, 0);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000325 REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000326}
327
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000328static void test_invert(skiatest::Reporter* reporter) {
329 SkMatrix44 inverse;
330 double inverseData[16];
331
332 SkMatrix44 identity;
333 identity.setIdentity();
334 identity.invert(&inverse);
335 inverse.asRowMajord(inverseData);
336 assert16<double>(reporter, inverseData,
337 1, 0, 0, 0,
338 0, 1, 0, 0,
339 0, 0, 1, 0,
340 0, 0, 0, 1);
341
342 SkMatrix44 translation;
343 translation.setTranslate(2, 3, 4);
344 translation.invert(&inverse);
345 inverse.asRowMajord(inverseData);
346 assert16<double>(reporter, inverseData,
347 1, 0, 0, -2,
348 0, 1, 0, -3,
349 0, 0, 1, -4,
350 0, 0, 0, 1);
351
352 SkMatrix44 scale;
353 scale.setScale(2, 4, 8);
354 scale.invert(&inverse);
355 inverse.asRowMajord(inverseData);
356 assert16<double>(reporter, inverseData,
357 0.5, 0, 0, 0,
358 0, 0.25, 0, 0,
359 0, 0, 0.125, 0,
360 0, 0, 0, 1);
361
362 SkMatrix44 scaleTranslation;
363 scaleTranslation.setScale(10, 100, 1000);
364 scaleTranslation.preTranslate(2, 3, 4);
365 scaleTranslation.invert(&inverse);
366 inverse.asRowMajord(inverseData);
367 assert16<double>(reporter, inverseData,
368 0.1, 0, 0, -2,
369 0, 0.01, 0, -3,
370 0, 0, 0.001, -4,
371 0, 0, 0, 1);
372
373 SkMatrix44 rotation;
374 rotation.setRotateDegreesAbout(0, 0, 1, 90);
375 rotation.invert(&inverse);
376 SkMatrix44 expected;
377 double expectedInverseRotation[16] =
378 {0, 1, 0, 0,
379 -1, 0, 0, 0,
380 0, 0, 1, 0,
381 0, 0, 0, 1};
382 expected.setRowMajord(expectedInverseRotation);
383 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000384
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000385 SkMatrix44 affine;
386 affine.setRotateDegreesAbout(0, 0, 1, 90);
387 affine.preScale(10, 20, 100);
388 affine.preTranslate(2, 3, 4);
389 affine.invert(&inverse);
390 double expectedInverseAffine[16] =
391 {0, 0.1, 0, -2,
392 -0.05, 0, 0, -3,
393 0, 0, 0.01, -4,
394 0, 0, 0, 1};
395 expected.setRowMajord(expectedInverseAffine);
396 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
397
398 SkMatrix44 perspective;
399 perspective.setIdentity();
400 perspective.setDouble(3, 2, 1.0);
401 perspective.invert(&inverse);
402 double expectedInversePerspective[16] =
403 {1, 0, 0, 0,
404 0, 1, 0, 0,
405 0, 0, 1, 0,
406 0, 0, -1, 1};
407 expected.setRowMajord(expectedInversePerspective);
408 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
409
410 SkMatrix44 affineAndPerspective;
411 affineAndPerspective.setIdentity();
412 affineAndPerspective.setDouble(3, 2, 1.0);
413 affineAndPerspective.preScale(10, 20, 100);
414 affineAndPerspective.preTranslate(2, 3, 4);
415 affineAndPerspective.invert(&inverse);
416 double expectedInverseAffineAndPerspective[16] =
417 {0.1, 0, 2, -2,
418 0, 0.05, 3, -3,
419 0, 0, 4.01, -4,
420 0, 0, -1, 1};
421 expected.setRowMajord(expectedInverseAffineAndPerspective);
422 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
423}
424
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000425static void test_transpose(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000426 SkMatrix44 a;
427 SkMatrix44 b;
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000428
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000429 int i = 0;
430 for (int row = 0; row < 4; ++row) {
431 for (int col = 0; col < 4; ++col) {
432 a.setDouble(row, col, i);
433 b.setDouble(col, row, i++);
434 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000435 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000436
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000437 a.transpose();
438 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000439}
440
441static void test_get_set_double(skiatest::Reporter* reporter) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000442 SkMatrix44 a;
443 for (int row = 0; row < 4; ++row) {
444 for (int col = 0; col < 4; ++col) {
445 a.setDouble(row, col, 3.141592653589793);
446 REPORTER_ASSERT(reporter,
447 nearly_equal_double(3.141592653589793,
448 a.getDouble(row, col)));
449 a.setDouble(row, col, 0);
450 REPORTER_ASSERT(reporter,
451 nearly_equal_double(0, a.getDouble(row, col)));
452 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000453 }
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000454}
455
456static void test_set_row_col_major(skiatest::Reporter* reporter) {
457 SkMatrix44 a, b, c, d;
reed@google.com7d683352012-12-03 21:19:52 +0000458 for (int row = 0; row < 4; ++row) {
459 for (int col = 0; col < 4; ++col) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000460 a.setDouble(row, col, row * 4 + col);
reed@google.com7d683352012-12-03 21:19:52 +0000461 }
462 }
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000463
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000464 double bufferd[16];
465 float bufferf[16];
466 a.asColMajord(bufferd);
467 b.setColMajord(bufferd);
468 REPORTER_ASSERT(reporter, nearly_equal(a, b));
469 b.setRowMajord(bufferd);
470 b.transpose();
471 REPORTER_ASSERT(reporter, nearly_equal(a, b));
472 a.asColMajorf(bufferf);
473 b.setColMajorf(bufferf);
474 REPORTER_ASSERT(reporter, nearly_equal(a, b));
475 b.setRowMajorf(bufferf);
476 b.transpose();
477 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000478}
479
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000480static void test_3x3_conversion(skiatest::Reporter* reporter) {
481 SkMScalar values4x4[16] = { 1, 2, 3, 4,
482 5, 6, 7, 8,
483 9, 10, 11, 12,
484 13, 14, 15, 16 };
485 SkScalar values3x3[9] = { 1, 2, 4,
486 5, 6, 8,
487 13, 14, 16 };
488 SkMScalar values4x4flattened[16] = { 1, 2, 0, 4,
489 5, 6, 0, 8,
490 0, 0, 1, 0,
491 13, 14, 0, 16 };
492 SkMatrix44 a44;
493 a44.setRowMajor(values4x4);
494
495 SkMatrix a33 = a44;
496 SkMatrix expected33;
497 for (int i = 0; i < 9; i++) expected33[i] = values3x3[i];
498 REPORTER_ASSERT(reporter, expected33 == a33);
499
500 SkMatrix44 a44flattened = a33;
501 SkMatrix44 expected44flattened;
502 expected44flattened.setRowMajor(values4x4flattened);
503 REPORTER_ASSERT(reporter, nearly_equal(a44flattened, expected44flattened));
504
505 // Test that a point with a Z value of 0 is transformed the same way.
506 SkScalar vec4[4] = { 2, 4, 0, 8 };
507 SkScalar vec3[3] = { 2, 4, 8 };
508
509 SkScalar vec4transformed[4];
510 SkScalar vec3transformed[3];
511 SkScalar vec4transformed2[4];
512 a44.mapScalars(vec4, vec4transformed);
513 a33.mapHomogeneousPoints(vec3transformed, vec3, 1);
514 a44flattened.mapScalars(vec4, vec4transformed2);
515 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed[0]));
516 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed[1]));
517 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed[2]));
518 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec4transformed2[0]));
519 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec4transformed2[1]));
520 REPORTER_ASSERT(reporter, !nearly_equal_scalar(vec4transformed[2], vec4transformed2[2]));
521 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec4transformed2[3]));
522}
523
caryclark@google.com42639cd2012-06-06 12:03:39 +0000524static void TestMatrix44(skiatest::Reporter* reporter) {
reed@google.com125002a2011-06-09 19:13:41 +0000525 SkMatrix44 mat, inverse, iden1, iden2, rot;
526
527 mat.reset();
reed@google.com7d683352012-12-03 21:19:52 +0000528 mat.setTranslate(1, 1, 1);
reed@google.com125002a2011-06-09 19:13:41 +0000529 mat.invert(&inverse);
530 iden1.setConcat(mat, inverse);
531 REPORTER_ASSERT(reporter, is_identity(iden1));
532
reed@google.com7d683352012-12-03 21:19:52 +0000533 mat.setScale(2, 2, 2);
reed@google.com125002a2011-06-09 19:13:41 +0000534 mat.invert(&inverse);
535 iden1.setConcat(mat, inverse);
536 REPORTER_ASSERT(reporter, is_identity(iden1));
537
reed@google.com7d683352012-12-03 21:19:52 +0000538 mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
reed@google.com125002a2011-06-09 19:13:41 +0000539 mat.invert(&inverse);
540 iden1.setConcat(mat, inverse);
541 REPORTER_ASSERT(reporter, is_identity(iden1));
542
reed@google.com7d683352012-12-03 21:19:52 +0000543 mat.setScale(3, 3, 3);
544 rot.setRotateDegreesAbout(0, 0, -1, 90);
reed@google.com125002a2011-06-09 19:13:41 +0000545 mat.postConcat(rot);
546 REPORTER_ASSERT(reporter, mat.invert(NULL));
547 mat.invert(&inverse);
548 iden1.setConcat(mat, inverse);
549 REPORTER_ASSERT(reporter, is_identity(iden1));
550 iden2.setConcat(inverse, mat);
551 REPORTER_ASSERT(reporter, is_identity(iden2));
reed@google.comda9fac02011-06-13 14:46:52 +0000552
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000553 // test tiny-valued matrix inverse
554 mat.reset();
555 mat.setScale(1.0e-12, 1.0e-12, 1.0e-12);
556 rot.setRotateDegreesAbout(0, 0, -1, 90);
557 mat.postConcat(rot);
558 mat.postTranslate(1.0e-12, 1.0e-12, 1.0e-12);
559 REPORTER_ASSERT(reporter, mat.invert(NULL));
560 mat.invert(&inverse);
561 iden1.setConcat(mat, inverse);
562 REPORTER_ASSERT(reporter, is_identity(iden1));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000563
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000564 // test mixed-valued matrix inverse
565 mat.reset();
jvanverth@google.com25f72ed2013-09-03 19:46:16 +0000566 mat.setScale(1.0e-10, 3.0, 1.0e+10);
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000567 rot.setRotateDegreesAbout(0, 0, -1, 90);
568 mat.postConcat(rot);
jvanverth@google.com25f72ed2013-09-03 19:46:16 +0000569 mat.postTranslate(1.0e+10, 3.0, 1.0e-10);
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000570 REPORTER_ASSERT(reporter, mat.invert(NULL));
571 mat.invert(&inverse);
572 iden1.setConcat(mat, inverse);
573 REPORTER_ASSERT(reporter, is_identity(iden1));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000574
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000575 // test degenerate matrix
576 mat.reset();
577 mat.set3x3(1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0);
578 REPORTER_ASSERT(reporter, !mat.invert(NULL));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000579
reed@google.comda9fac02011-06-13 14:46:52 +0000580 // test rol/col Major getters
581 {
582 mat.setTranslate(2, 3, 4);
583 float dataf[16];
584 double datad[16];
rmistry@google.comd6176b02012-08-23 18:14:13 +0000585
reed@google.comda9fac02011-06-13 14:46:52 +0000586 mat.asColMajorf(dataf);
587 assert16<float>(reporter, dataf,
588 1, 0, 0, 0,
589 0, 1, 0, 0,
590 0, 0, 1, 0,
591 2, 3, 4, 1);
592 mat.asColMajord(datad);
593 assert16<double>(reporter, datad, 1, 0, 0, 0,
594 0, 1, 0, 0,
595 0, 0, 1, 0,
596 2, 3, 4, 1);
597 mat.asRowMajorf(dataf);
598 assert16<float>(reporter, dataf, 1, 0, 0, 2,
599 0, 1, 0, 3,
600 0, 0, 1, 4,
601 0, 0, 0, 1);
602 mat.asRowMajord(datad);
603 assert16<double>(reporter, datad, 1, 0, 0, 2,
604 0, 1, 0, 3,
605 0, 0, 1, 4,
606 0, 0, 0, 1);
607 }
reed@google.com6f2b44d2011-06-24 18:13:39 +0000608
reed@google.com80b577e2012-11-09 21:25:06 +0000609 test_concat(reporter);
610
caryclark@google.com42639cd2012-06-06 12:03:39 +0000611 if (false) { // avoid bit rot, suppress warning (working on making this pass)
612 test_common_angles(reporter);
613 }
vollick@chromium.org3959a762012-11-13 15:08:22 +0000614
vollick@chromium.org57a54e32012-12-10 20:16:10 +0000615 test_constructor(reporter);
reed@google.com7d683352012-12-03 21:19:52 +0000616 test_gettype(reporter);
vollick@chromium.org3959a762012-11-13 15:08:22 +0000617 test_determinant(reporter);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000618 test_invert(reporter);
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000619 test_transpose(reporter);
620 test_get_set_double(reporter);
reed@google.com7d683352012-12-03 21:19:52 +0000621 test_set_row_col_major(reporter);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000622 test_translate(reporter);
623 test_scale(reporter);
624 test_map2(reporter);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000625 test_3x3_conversion(reporter);
reed@google.com125002a2011-06-09 19:13:41 +0000626}
627
628#include "TestClassDef.h"
629DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44)