blob: 6a42a4405826b735c35c110f526eda18927c382a [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 "SkMatrix44.h"
Cary Clarke4442cb2017-10-18 11:46:18 -04009#include "SkPoint3.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000010#include "Test.h"
reed@google.com125002a2011-06-09 19:13:41 +000011
vollick@chromium.org3959a762012-11-13 15:08:22 +000012static bool nearly_equal_double(double a, double b) {
13 const double tolerance = 1e-7;
14 double diff = a - b;
15 if (diff < 0)
16 diff = -diff;
17 return diff <= tolerance;
18}
19
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000020static bool nearly_equal_mscalar(SkMScalar a, SkMScalar b) {
21 const SkMScalar tolerance = SK_MScalar1 / 200000;
22
23 return SkTAbs<SkMScalar>(a - b) <= tolerance;
24}
25
26static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
reed@google.com125002a2011-06-09 19:13:41 +000027 const SkScalar tolerance = SK_Scalar1 / 200000;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000028 return SkScalarAbs(a - b) <= tolerance;
reed@google.com125002a2011-06-09 19:13:41 +000029}
30
reed@google.comda9fac02011-06-13 14:46:52 +000031template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
32 T m0, T m1, T m2, T m3,
33 T m4, T m5, T m6, T m7,
34 T m8, T m9, T m10, T m11,
35 T m12, T m13, T m14, T m15) {
36 REPORTER_ASSERT(reporter, data[0] == m0);
37 REPORTER_ASSERT(reporter, data[1] == m1);
38 REPORTER_ASSERT(reporter, data[2] == m2);
39 REPORTER_ASSERT(reporter, data[3] == m3);
40
41 REPORTER_ASSERT(reporter, data[4] == m4);
42 REPORTER_ASSERT(reporter, data[5] == m5);
43 REPORTER_ASSERT(reporter, data[6] == m6);
44 REPORTER_ASSERT(reporter, data[7] == m7);
45
46 REPORTER_ASSERT(reporter, data[8] == m8);
47 REPORTER_ASSERT(reporter, data[9] == m9);
48 REPORTER_ASSERT(reporter, data[10] == m10);
49 REPORTER_ASSERT(reporter, data[11] == m11);
50
51 REPORTER_ASSERT(reporter, data[12] == m12);
52 REPORTER_ASSERT(reporter, data[13] == m13);
53 REPORTER_ASSERT(reporter, data[14] == m14);
54 REPORTER_ASSERT(reporter, data[15] == m15);
55}
56
reed@google.com125002a2011-06-09 19:13:41 +000057static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
58 for (int i = 0; i < 4; ++i) {
59 for (int j = 0; j < 4; ++j) {
commit-bot@chromium.org722555b2013-10-05 01:16:30 +000060 if (!nearly_equal_mscalar(a.get(i, j), b.get(i, j))) {
bungeman@google.comfab44db2013-10-11 18:50:45 +000061 SkDebugf("not equal %g %g\n", a.get(i, j), b.get(i, j));
reed@google.com125002a2011-06-09 19:13:41 +000062 return false;
63 }
64 }
65 }
66 return true;
67}
68
69static bool is_identity(const SkMatrix44& m) {
reed@google.com44699382013-10-31 17:28:30 +000070 SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
reed@google.com125002a2011-06-09 19:13:41 +000071 return nearly_equal(m, identity);
72}
73
reed@google.com99b5c7f2012-12-05 22:13:59 +000074///////////////////////////////////////////////////////////////////////////////
75static bool bits_isonly(int value, int mask) {
76 return 0 == (value & ~mask);
77}
78
vollick@chromium.org57a54e32012-12-10 20:16:10 +000079static void test_constructor(skiatest::Reporter* reporter) {
80 // Allocate a matrix on the heap
reed@google.com44699382013-10-31 17:28:30 +000081 SkMatrix44* placeholderMatrix = new SkMatrix44(SkMatrix44::kUninitialized_Constructor);
Ben Wagner145dbcd2016-11-03 14:40:50 -040082 std::unique_ptr<SkMatrix44> deleteMe(placeholderMatrix);
robertphillips@google.com35300c42013-03-21 17:38:49 +000083
vollick@chromium.org57a54e32012-12-10 20:16:10 +000084 for (int row = 0; row < 4; ++row) {
85 for (int col = 0; col < 4; ++col) {
86 placeholderMatrix->setDouble(row, col, row * col);
87 }
88 }
89
90 // Use placement-new syntax to trigger the constructor on top of the heap
91 // address we already initialized. This allows us to check that the
92 // constructor did avoid initializing the matrix contents.
93 SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
94 REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
95 REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
96 for (int row = 0; row < 4; ++row) {
97 for (int col = 0; col < 4; ++col) {
98 REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
99 }
100 }
101
102 // Verify that kIdentity_Constructor really does initialize to an identity matrix.
103 testMatrix = 0;
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000104 testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
vollick@chromium.org57a54e32012-12-10 20:16:10 +0000105 REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
106 REPORTER_ASSERT(reporter, testMatrix->isIdentity());
107 REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
fs88640cf2014-12-16 08:36:11 -0800108
109 // Verify that that constructing from an SkMatrix initializes everything.
110 SkMatrix44 scaleMatrix(SkMatrix44::kUninitialized_Constructor);
111 scaleMatrix.setScale(3, 4, 5);
112 REPORTER_ASSERT(reporter, scaleMatrix.isScale());
113 testMatrix = new(&scaleMatrix) SkMatrix44(SkMatrix::I());
114 REPORTER_ASSERT(reporter, testMatrix->isIdentity());
115 REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
vollick@chromium.org57a54e32012-12-10 20:16:10 +0000116}
117
reed@google.com99b5c7f2012-12-05 22:13:59 +0000118static void test_translate(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000119 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
120 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000121
122 mat.setTranslate(0, 0, 0);
123 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
124 mat.setTranslate(1, 2, 3);
125 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
126 REPORTER_ASSERT(reporter, mat.invert(&inverse));
127 REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000128
reed@google.com44699382013-10-31 17:28:30 +0000129 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
130 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
131 SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000132 a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
133 b.setTranslate(10, 11, 12);
134
135 c.setConcat(a, b);
136 mat = a;
137 mat.preTranslate(10, 11, 12);
138 REPORTER_ASSERT(reporter, mat == c);
139
140 c.setConcat(b, a);
141 mat = a;
142 mat.postTranslate(10, 11, 12);
143 REPORTER_ASSERT(reporter, mat == c);
144}
145
146static void test_scale(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000147 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
148 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000149
reed@google.com99b5c7f2012-12-05 22:13:59 +0000150 mat.setScale(1, 1, 1);
151 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
152 mat.setScale(1, 2, 3);
153 REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
154 REPORTER_ASSERT(reporter, mat.invert(&inverse));
155 REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
156
reed@google.com44699382013-10-31 17:28:30 +0000157 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
158 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
159 SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000160 a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
161 b.setScale(10, 11, 12);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000162
reed@google.com99b5c7f2012-12-05 22:13:59 +0000163 c.setConcat(a, b);
164 mat = a;
165 mat.preScale(10, 11, 12);
166 REPORTER_ASSERT(reporter, mat == c);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000167
reed@google.com99b5c7f2012-12-05 22:13:59 +0000168 c.setConcat(b, a);
169 mat = a;
170 mat.postScale(10, 11, 12);
171 REPORTER_ASSERT(reporter, mat == c);
172}
173
174static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
175static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
176static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
177static void make_st(SkMatrix44* mat) {
178 mat->setScale(1, 2, 3);
179 mat->postTranslate(1, 2, 3);
180}
181static void make_a(SkMatrix44* mat) {
182 mat->setRotateDegreesAbout(1, 2, 3, 45);
183}
184static void make_p(SkMatrix44* mat) {
185 SkMScalar data[] = {
186 1, 2, 3, 4, 5, 6, 7, 8,
187 1, 2, 3, 4, 5, 6, 7, 8,
188 };
189 mat->setRowMajor(data);
190}
191
192typedef void (*Make44Proc)(SkMatrix44*);
193
194static const Make44Proc gMakeProcs[] = {
195 make_i, make_t, make_s, make_st, make_a, make_p
196};
197
198static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
199 SkMScalar src2[] = { 1, 2 };
200 SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
201 SkMScalar dstA[4], dstB[4];
202
203 for (int i = 0; i < 4; ++i) {
mtklein1831f992015-06-09 11:47:01 -0700204 dstA[i] = SkDoubleToMScalar(123456789);
205 dstB[i] = SkDoubleToMScalar(987654321);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000206 }
207
208 mat.map2(src2, 1, dstA);
209 mat.mapMScalars(src4, dstB);
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000210
reed@google.com99b5c7f2012-12-05 22:13:59 +0000211 for (int i = 0; i < 4; ++i) {
212 REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
213 }
214}
215
216static void test_map2(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000217 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000218
219 for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
220 gMakeProcs[i](&mat);
221 test_map2(reporter, mat);
222 }
223}
224
reed@google.com7d683352012-12-03 21:19:52 +0000225static void test_gettype(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000226 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000227
reed@google.com7d683352012-12-03 21:19:52 +0000228 REPORTER_ASSERT(reporter, matrix.isIdentity());
229 REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000230
reed@google.com7d683352012-12-03 21:19:52 +0000231 int expectedMask;
232
233 matrix.set(1, 1, 0);
234 expectedMask = SkMatrix44::kScale_Mask;
235 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
236
237 matrix.set(0, 3, 1); // translate-x
238 expectedMask |= SkMatrix44::kTranslate_Mask;
239 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
240
241 matrix.set(2, 0, 1);
242 expectedMask |= SkMatrix44::kAffine_Mask;
243 REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000244
reed@google.com7d683352012-12-03 21:19:52 +0000245 matrix.set(3, 2, 1);
246 REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
reed@google.com87f99cb2013-04-19 12:25:00 +0000247
248 // ensure that negative zero is treated as zero
249 SkMScalar dx = 0;
250 SkMScalar dy = 0;
251 SkMScalar dz = 0;
252 matrix.setTranslate(-dx, -dy, -dz);
253 REPORTER_ASSERT(reporter, matrix.isIdentity());
254 matrix.preTranslate(-dx, -dy, -dz);
255 REPORTER_ASSERT(reporter, matrix.isIdentity());
256 matrix.postTranslate(-dx, -dy, -dz);
257 REPORTER_ASSERT(reporter, matrix.isIdentity());
reed@google.com7d683352012-12-03 21:19:52 +0000258}
259
reed@google.com6f2b44d2011-06-24 18:13:39 +0000260static void test_common_angles(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000261 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
reed@google.com6f2b44d2011-06-24 18:13:39 +0000262 // Test precision of rotation in common cases
263 int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
264 for (int i = 0; i < 9; ++i) {
robertphillips@google.com09042b82012-04-06 20:01:46 +0000265 rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
reed@google.com6f2b44d2011-06-24 18:13:39 +0000266
267 SkMatrix rot3x3 = rot;
268 REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
269 }
270}
271
reed@google.com80b577e2012-11-09 21:25:06 +0000272static void test_concat(skiatest::Reporter* reporter) {
273 int i;
reed@google.com44699382013-10-31 17:28:30 +0000274 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
275 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
276 SkMatrix44 c(SkMatrix44::kUninitialized_Constructor);
277 SkMatrix44 d(SkMatrix44::kUninitialized_Constructor);
reed@google.com80b577e2012-11-09 21:25:06 +0000278
279 a.setTranslate(10, 10, 10);
280 b.setScale(2, 2, 2);
281
282 SkScalar src[8] = {
283 0, 0, 0, 1,
284 1, 1, 1, 1
285 };
286 SkScalar dst[8];
287
288 c.setConcat(a, b);
289
290 d = a;
291 d.preConcat(b);
292 REPORTER_ASSERT(reporter, d == c);
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000293
reed@google.com1ea95be2012-11-09 21:39:48 +0000294 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000295 for (i = 0; i < 3; ++i) {
296 REPORTER_ASSERT(reporter, 10 == dst[i]);
297 REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
298 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000299
reed@google.com80b577e2012-11-09 21:25:06 +0000300 c.setConcat(b, a);
301
302 d = a;
303 d.postConcat(b);
304 REPORTER_ASSERT(reporter, d == c);
305
reed@google.com1ea95be2012-11-09 21:39:48 +0000306 c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
reed@google.com80b577e2012-11-09 21:25:06 +0000307 for (i = 0; i < 3; ++i) {
308 REPORTER_ASSERT(reporter, 20 == dst[i]);
309 REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
310 }
311}
312
vollick@chromium.org3959a762012-11-13 15:08:22 +0000313static void test_determinant(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000314 SkMatrix44 a(SkMatrix44::kIdentity_Constructor);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000315 REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000316 a.set(1, 1, 2);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000317 REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
reed@google.com44699382013-10-31 17:28:30 +0000318 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000319 REPORTER_ASSERT(reporter, a.invert(&b));
320 REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
321 SkMatrix44 c = b = a;
reed@google.com7d683352012-12-03 21:19:52 +0000322 c.set(0, 1, 4);
323 b.set(1, 0, 4);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000324 REPORTER_ASSERT(reporter,
325 nearly_equal_double(a.determinant(),
326 b.determinant()));
327 SkMatrix44 d = a;
reed@google.com7d683352012-12-03 21:19:52 +0000328 d.set(0, 0, 8);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000329 REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000330
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000331 SkMatrix44 e = a;
332 e.postConcat(d);
333 REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
reed@google.com7d683352012-12-03 21:19:52 +0000334 e.set(0, 0, 0);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000335 REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
vollick@chromium.org3959a762012-11-13 15:08:22 +0000336}
337
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000338static void test_invert(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000339 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000340 double inverseData[16];
341
reed@google.com44699382013-10-31 17:28:30 +0000342 SkMatrix44 identity(SkMatrix44::kIdentity_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000343 identity.invert(&inverse);
344 inverse.asRowMajord(inverseData);
345 assert16<double>(reporter, inverseData,
346 1, 0, 0, 0,
347 0, 1, 0, 0,
348 0, 0, 1, 0,
349 0, 0, 0, 1);
350
reed@google.com44699382013-10-31 17:28:30 +0000351 SkMatrix44 translation(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000352 translation.setTranslate(2, 3, 4);
353 translation.invert(&inverse);
354 inverse.asRowMajord(inverseData);
355 assert16<double>(reporter, inverseData,
356 1, 0, 0, -2,
357 0, 1, 0, -3,
358 0, 0, 1, -4,
359 0, 0, 0, 1);
360
reed@google.com44699382013-10-31 17:28:30 +0000361 SkMatrix44 scale(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000362 scale.setScale(2, 4, 8);
363 scale.invert(&inverse);
364 inverse.asRowMajord(inverseData);
365 assert16<double>(reporter, inverseData,
366 0.5, 0, 0, 0,
367 0, 0.25, 0, 0,
368 0, 0, 0.125, 0,
369 0, 0, 0, 1);
370
reed@google.com44699382013-10-31 17:28:30 +0000371 SkMatrix44 scaleTranslation(SkMatrix44::kUninitialized_Constructor);
mtklein51958052015-06-09 15:06:22 -0700372 scaleTranslation.setScale(32, 128, 1024);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000373 scaleTranslation.preTranslate(2, 3, 4);
374 scaleTranslation.invert(&inverse);
375 inverse.asRowMajord(inverseData);
376 assert16<double>(reporter, inverseData,
mtklein51958052015-06-09 15:06:22 -0700377 0.03125, 0, 0, -2,
378 0, 0.0078125, 0, -3,
379 0, 0, 0.0009765625, -4,
380 0, 0, 0, 1);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000381
reed@google.com44699382013-10-31 17:28:30 +0000382 SkMatrix44 rotation(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000383 rotation.setRotateDegreesAbout(0, 0, 1, 90);
384 rotation.invert(&inverse);
reed@google.com44699382013-10-31 17:28:30 +0000385 SkMatrix44 expected(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000386 double expectedInverseRotation[16] =
387 {0, 1, 0, 0,
388 -1, 0, 0, 0,
389 0, 0, 1, 0,
390 0, 0, 0, 1};
391 expected.setRowMajord(expectedInverseRotation);
392 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000393
reed@google.com44699382013-10-31 17:28:30 +0000394 SkMatrix44 affine(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000395 affine.setRotateDegreesAbout(0, 0, 1, 90);
396 affine.preScale(10, 20, 100);
397 affine.preTranslate(2, 3, 4);
398 affine.invert(&inverse);
399 double expectedInverseAffine[16] =
400 {0, 0.1, 0, -2,
401 -0.05, 0, 0, -3,
402 0, 0, 0.01, -4,
403 0, 0, 0, 1};
404 expected.setRowMajord(expectedInverseAffine);
405 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
406
reed@google.com44699382013-10-31 17:28:30 +0000407 SkMatrix44 perspective(SkMatrix44::kIdentity_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000408 perspective.setDouble(3, 2, 1.0);
409 perspective.invert(&inverse);
410 double expectedInversePerspective[16] =
411 {1, 0, 0, 0,
412 0, 1, 0, 0,
413 0, 0, 1, 0,
414 0, 0, -1, 1};
415 expected.setRowMajord(expectedInversePerspective);
416 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
417
reed@google.com44699382013-10-31 17:28:30 +0000418 SkMatrix44 affineAndPerspective(SkMatrix44::kIdentity_Constructor);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000419 affineAndPerspective.setDouble(3, 2, 1.0);
420 affineAndPerspective.preScale(10, 20, 100);
421 affineAndPerspective.preTranslate(2, 3, 4);
422 affineAndPerspective.invert(&inverse);
423 double expectedInverseAffineAndPerspective[16] =
424 {0.1, 0, 2, -2,
425 0, 0.05, 3, -3,
426 0, 0, 4.01, -4,
427 0, 0, -1, 1};
428 expected.setRowMajord(expectedInverseAffineAndPerspective);
429 REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
vmpstra8d45592015-06-30 13:36:04 -0700430
431 SkMatrix44 tinyScale(SkMatrix44::kIdentity_Constructor);
432 tinyScale.setDouble(0, 0, 1e-39);
433 REPORTER_ASSERT(reporter, tinyScale.getType() == SkMatrix44::kScale_Mask);
halcanary96fcdcc2015-08-27 07:41:13 -0700434 REPORTER_ASSERT(reporter, !tinyScale.invert(nullptr));
vmpstra8d45592015-06-30 13:36:04 -0700435 REPORTER_ASSERT(reporter, !tinyScale.invert(&inverse));
436
437 SkMatrix44 tinyScaleTranslate(SkMatrix44::kIdentity_Constructor);
438 tinyScaleTranslate.setDouble(0, 0, 1e-38);
halcanary96fcdcc2015-08-27 07:41:13 -0700439 REPORTER_ASSERT(reporter, tinyScaleTranslate.invert(nullptr));
vmpstra8d45592015-06-30 13:36:04 -0700440 tinyScaleTranslate.setDouble(0, 3, 10);
441 REPORTER_ASSERT(
442 reporter, tinyScaleTranslate.getType() ==
443 (SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask));
halcanary96fcdcc2015-08-27 07:41:13 -0700444 REPORTER_ASSERT(reporter, !tinyScaleTranslate.invert(nullptr));
vmpstra8d45592015-06-30 13:36:04 -0700445 REPORTER_ASSERT(reporter, !tinyScaleTranslate.invert(&inverse));
446
447 SkMatrix44 tinyScalePerspective(SkMatrix44::kIdentity_Constructor);
448 tinyScalePerspective.setDouble(0, 0, 1e-39);
449 tinyScalePerspective.setDouble(3, 2, -1);
450 REPORTER_ASSERT(reporter, (tinyScalePerspective.getType() &
451 SkMatrix44::kPerspective_Mask) ==
452 SkMatrix44::kPerspective_Mask);
halcanary96fcdcc2015-08-27 07:41:13 -0700453 REPORTER_ASSERT(reporter, !tinyScalePerspective.invert(nullptr));
vmpstra8d45592015-06-30 13:36:04 -0700454 REPORTER_ASSERT(reporter, !tinyScalePerspective.invert(&inverse));
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000455}
456
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000457static void test_transpose(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000458 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
459 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000460
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000461 int i = 0;
462 for (int row = 0; row < 4; ++row) {
463 for (int col = 0; col < 4; ++col) {
464 a.setDouble(row, col, i);
465 b.setDouble(col, row, i++);
466 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000467 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000468
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000469 a.transpose();
470 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000471}
472
473static void test_get_set_double(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000474 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000475 for (int row = 0; row < 4; ++row) {
476 for (int col = 0; col < 4; ++col) {
477 a.setDouble(row, col, 3.141592653589793);
478 REPORTER_ASSERT(reporter,
479 nearly_equal_double(3.141592653589793,
480 a.getDouble(row, col)));
481 a.setDouble(row, col, 0);
482 REPORTER_ASSERT(reporter,
483 nearly_equal_double(0, a.getDouble(row, col)));
484 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000485 }
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000486}
487
msarettc1a3e242016-06-23 12:42:29 -0700488static void test_set_3x3(skiatest::Reporter* r) {
489 static float vals[9] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, };
490
491 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
492 mat.set3x3RowMajorf(vals);
493
494 REPORTER_ASSERT(r, 1.0f == mat.getFloat(0, 0));
495 REPORTER_ASSERT(r, 2.0f == mat.getFloat(0, 1));
496 REPORTER_ASSERT(r, 3.0f == mat.getFloat(0, 2));
497 REPORTER_ASSERT(r, 4.0f == mat.getFloat(1, 0));
498 REPORTER_ASSERT(r, 5.0f == mat.getFloat(1, 1));
499 REPORTER_ASSERT(r, 6.0f == mat.getFloat(1, 2));
500 REPORTER_ASSERT(r, 7.0f == mat.getFloat(2, 0));
501 REPORTER_ASSERT(r, 8.0f == mat.getFloat(2, 1));
502 REPORTER_ASSERT(r, 9.0f == mat.getFloat(2, 2));
503}
504
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000505static void test_set_row_col_major(skiatest::Reporter* reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000506 SkMatrix44 a(SkMatrix44::kUninitialized_Constructor);
507 SkMatrix44 b(SkMatrix44::kUninitialized_Constructor);
508
reed@google.com7d683352012-12-03 21:19:52 +0000509 for (int row = 0; row < 4; ++row) {
510 for (int col = 0; col < 4; ++col) {
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000511 a.setDouble(row, col, row * 4 + col);
reed@google.com7d683352012-12-03 21:19:52 +0000512 }
513 }
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000514
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000515 double bufferd[16];
516 float bufferf[16];
517 a.asColMajord(bufferd);
518 b.setColMajord(bufferd);
519 REPORTER_ASSERT(reporter, nearly_equal(a, b));
520 b.setRowMajord(bufferd);
521 b.transpose();
522 REPORTER_ASSERT(reporter, nearly_equal(a, b));
523 a.asColMajorf(bufferf);
524 b.setColMajorf(bufferf);
525 REPORTER_ASSERT(reporter, nearly_equal(a, b));
526 b.setRowMajorf(bufferf);
527 b.transpose();
528 REPORTER_ASSERT(reporter, nearly_equal(a, b));
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000529}
530
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000531static void test_3x3_conversion(skiatest::Reporter* reporter) {
532 SkMScalar values4x4[16] = { 1, 2, 3, 4,
533 5, 6, 7, 8,
534 9, 10, 11, 12,
535 13, 14, 15, 16 };
536 SkScalar values3x3[9] = { 1, 2, 4,
537 5, 6, 8,
538 13, 14, 16 };
539 SkMScalar values4x4flattened[16] = { 1, 2, 0, 4,
540 5, 6, 0, 8,
541 0, 0, 1, 0,
542 13, 14, 0, 16 };
reed@google.com44699382013-10-31 17:28:30 +0000543 SkMatrix44 a44(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000544 a44.setRowMajor(values4x4);
545
546 SkMatrix a33 = a44;
547 SkMatrix expected33;
548 for (int i = 0; i < 9; i++) expected33[i] = values3x3[i];
549 REPORTER_ASSERT(reporter, expected33 == a33);
550
551 SkMatrix44 a44flattened = a33;
reed@google.com44699382013-10-31 17:28:30 +0000552 SkMatrix44 expected44flattened(SkMatrix44::kUninitialized_Constructor);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000553 expected44flattened.setRowMajor(values4x4flattened);
554 REPORTER_ASSERT(reporter, nearly_equal(a44flattened, expected44flattened));
555
556 // Test that a point with a Z value of 0 is transformed the same way.
557 SkScalar vec4[4] = { 2, 4, 0, 8 };
Cary Clarke4442cb2017-10-18 11:46:18 -0400558 SkPoint3 vec3 = { 2, 4, 8 };
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000559
560 SkScalar vec4transformed[4];
Cary Clarke4442cb2017-10-18 11:46:18 -0400561 SkPoint3 vec3transformed;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000562 SkScalar vec4transformed2[4];
563 a44.mapScalars(vec4, vec4transformed);
Cary Clarke4442cb2017-10-18 11:46:18 -0400564 a33.mapHomogeneousPoints(&vec3transformed, &vec3, 1);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000565 a44flattened.mapScalars(vec4, vec4transformed2);
Cary Clarke4442cb2017-10-18 11:46:18 -0400566 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed.fX));
567 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed.fY));
568 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed.fZ));
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000569 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec4transformed2[0]));
570 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec4transformed2[1]));
571 REPORTER_ASSERT(reporter, !nearly_equal_scalar(vec4transformed[2], vec4transformed2[2]));
572 REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec4transformed2[3]));
573}
574
tomhudsona32f1752014-09-16 08:29:29 -0700575static void test_has_perspective(skiatest::Reporter* reporter) {
576 SkMatrix44 transform(SkMatrix44::kIdentity_Constructor);
577
mtklein1831f992015-06-09 11:47:01 -0700578 transform.setDouble(3, 2, -0.1);
tomhudsona32f1752014-09-16 08:29:29 -0700579 REPORTER_ASSERT(reporter, transform.hasPerspective());
580
581 transform.reset();
582 REPORTER_ASSERT(reporter, !transform.hasPerspective());
583
mtklein1831f992015-06-09 11:47:01 -0700584 transform.setDouble(3, 0, -1.0);
tomhudsona32f1752014-09-16 08:29:29 -0700585 REPORTER_ASSERT(reporter, transform.hasPerspective());
586
587 transform.reset();
mtklein1831f992015-06-09 11:47:01 -0700588 transform.setDouble(3, 1, -1.0);
tomhudsona32f1752014-09-16 08:29:29 -0700589 REPORTER_ASSERT(reporter, transform.hasPerspective());
590
591 transform.reset();
mtklein1831f992015-06-09 11:47:01 -0700592 transform.setDouble(3, 2, -0.3);
tomhudsona32f1752014-09-16 08:29:29 -0700593 REPORTER_ASSERT(reporter, transform.hasPerspective());
594
595 transform.reset();
mtklein1831f992015-06-09 11:47:01 -0700596 transform.setDouble(3, 3, 0.5);
tomhudsona32f1752014-09-16 08:29:29 -0700597 REPORTER_ASSERT(reporter, transform.hasPerspective());
mtklein1831f992015-06-09 11:47:01 -0700598
tomhudsona32f1752014-09-16 08:29:29 -0700599 transform.reset();
mtklein1831f992015-06-09 11:47:01 -0700600 transform.setDouble(3, 3, 0.0);
tomhudsona32f1752014-09-16 08:29:29 -0700601 REPORTER_ASSERT(reporter, transform.hasPerspective());
602}
603
tomhudsonfaccb8e2014-09-26 11:45:48 -0700604static bool is_rectilinear (SkVector4& p1, SkVector4& p2, SkVector4& p3, SkVector4& p4) {
605 return (SkScalarNearlyEqual(p1.fData[0], p2.fData[0]) &&
606 SkScalarNearlyEqual(p2.fData[1], p3.fData[1]) &&
607 SkScalarNearlyEqual(p3.fData[0], p4.fData[0]) &&
608 SkScalarNearlyEqual(p4.fData[1], p1.fData[1])) ||
609 (SkScalarNearlyEqual(p1.fData[1], p2.fData[1]) &&
610 SkScalarNearlyEqual(p2.fData[0], p3.fData[0]) &&
611 SkScalarNearlyEqual(p3.fData[1], p4.fData[1]) &&
612 SkScalarNearlyEqual(p4.fData[0], p1.fData[0]));
613}
614
615static SkVector4 mul_with_persp_divide(const SkMatrix44& transform, const SkVector4& target) {
616 SkVector4 result = transform * target;
617 if (result.fData[3] != 0.0f && result.fData[3] != SK_Scalar1) {
618 float wInverse = SK_Scalar1 / result.fData[3];
619 result.set(result.fData[0] * wInverse,
620 result.fData[1] * wInverse,
621 result.fData[2] * wInverse,
622 SK_Scalar1);
623 }
624 return result;
625}
626
627static bool empirically_preserves_2d_axis_alignment(skiatest::Reporter* reporter,
628 const SkMatrix44& transform) {
629 SkVector4 p1(5.0f, 5.0f, 0.0f);
630 SkVector4 p2(10.0f, 5.0f, 0.0f);
631 SkVector4 p3(10.0f, 20.0f, 0.0f);
632 SkVector4 p4(5.0f, 20.0f, 0.0f);
633
634 REPORTER_ASSERT(reporter, is_rectilinear(p1, p2, p3, p4));
635
636 p1 = mul_with_persp_divide(transform, p1);
637 p2 = mul_with_persp_divide(transform, p2);
638 p3 = mul_with_persp_divide(transform, p3);
639 p4 = mul_with_persp_divide(transform, p4);
640
641 return is_rectilinear(p1, p2, p3, p4);
642}
643
644static void test(bool expected, skiatest::Reporter* reporter, const SkMatrix44& transform) {
645 if (expected) {
646 REPORTER_ASSERT(reporter, empirically_preserves_2d_axis_alignment(reporter, transform));
647 REPORTER_ASSERT(reporter, transform.preserves2dAxisAlignment());
648 } else {
649 REPORTER_ASSERT(reporter, !empirically_preserves_2d_axis_alignment(reporter, transform));
650 REPORTER_ASSERT(reporter, !transform.preserves2dAxisAlignment());
651 }
652}
653
654static void test_preserves_2d_axis_alignment(skiatest::Reporter* reporter) {
655 SkMatrix44 transform(SkMatrix44::kUninitialized_Constructor);
656 SkMatrix44 transform2(SkMatrix44::kUninitialized_Constructor);
657
658 static const struct TestCase {
659 SkMScalar a; // row 1, column 1
660 SkMScalar b; // row 1, column 2
661 SkMScalar c; // row 2, column 1
662 SkMScalar d; // row 2, column 2
663 bool expected;
664 } test_cases[] = {
665 { 3.f, 0.f,
666 0.f, 4.f, true }, // basic case
667 { 0.f, 4.f,
668 3.f, 0.f, true }, // rotate by 90
669 { 0.f, 0.f,
670 0.f, 4.f, true }, // degenerate x
671 { 3.f, 0.f,
672 0.f, 0.f, true }, // degenerate y
673 { 0.f, 0.f,
674 3.f, 0.f, true }, // degenerate x + rotate by 90
675 { 0.f, 4.f,
676 0.f, 0.f, true }, // degenerate y + rotate by 90
677 { 3.f, 4.f,
678 0.f, 0.f, false },
679 { 0.f, 0.f,
680 3.f, 4.f, false },
681 { 0.f, 3.f,
682 0.f, 4.f, false },
683 { 3.f, 0.f,
684 4.f, 0.f, false },
685 { 3.f, 4.f,
686 5.f, 0.f, false },
687 { 3.f, 4.f,
688 0.f, 5.f, false },
689 { 3.f, 0.f,
690 4.f, 5.f, false },
691 { 0.f, 3.f,
692 4.f, 5.f, false },
693 { 2.f, 3.f,
694 4.f, 5.f, false },
695 };
696
697 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
698 const TestCase& value = test_cases[i];
699 transform.setIdentity();
700 transform.set(0, 0, value.a);
701 transform.set(0, 1, value.b);
702 transform.set(1, 0, value.c);
703 transform.set(1, 1, value.d);
704
705 test(value.expected, reporter, transform);
706 }
707
708 // Try the same test cases again, but this time make sure that other matrix
709 // elements (except perspective) have entries, to test that they are ignored.
710 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
711 const TestCase& value = test_cases[i];
712 transform.setIdentity();
713 transform.set(0, 0, value.a);
714 transform.set(0, 1, value.b);
715 transform.set(1, 0, value.c);
716 transform.set(1, 1, value.d);
717
718 transform.set(0, 2, 1.f);
719 transform.set(0, 3, 2.f);
720 transform.set(1, 2, 3.f);
721 transform.set(1, 3, 4.f);
722 transform.set(2, 0, 5.f);
723 transform.set(2, 1, 6.f);
724 transform.set(2, 2, 7.f);
725 transform.set(2, 3, 8.f);
726
727 test(value.expected, reporter, transform);
728 }
729
730 // Try the same test cases again, but this time add perspective which is
731 // always assumed to not-preserve axis alignment.
732 for (size_t i = 0; i < sizeof(test_cases)/sizeof(TestCase); ++i) {
733 const TestCase& value = test_cases[i];
734 transform.setIdentity();
735 transform.set(0, 0, value.a);
736 transform.set(0, 1, value.b);
737 transform.set(1, 0, value.c);
738 transform.set(1, 1, value.d);
739
740 transform.set(0, 2, 1.f);
741 transform.set(0, 3, 2.f);
742 transform.set(1, 2, 3.f);
743 transform.set(1, 3, 4.f);
744 transform.set(2, 0, 5.f);
745 transform.set(2, 1, 6.f);
746 transform.set(2, 2, 7.f);
747 transform.set(2, 3, 8.f);
748 transform.set(3, 0, 9.f);
749 transform.set(3, 1, 10.f);
750 transform.set(3, 2, 11.f);
751 transform.set(3, 3, 12.f);
752
753 test(false, reporter, transform);
754 }
755
756 // Try a few more practical situations to check precision
757 // Reuse TestCase (a, b, c, d) as (x, y, z, degrees) axis to rotate about.
758 TestCase rotation_tests[] = {
759 { 0.0, 0.0, 1.0, 90.0, true },
760 { 0.0, 0.0, 1.0, 180.0, true },
761 { 0.0, 0.0, 1.0, 270.0, true },
762 { 0.0, 1.0, 0.0, 90.0, true },
763 { 1.0, 0.0, 0.0, 90.0, true },
764 { 0.0, 0.0, 1.0, 45.0, false },
765 // In 3d these next two are non-preserving, but we're testing in 2d after
766 // orthographic projection, where they are.
767 { 0.0, 1.0, 0.0, 45.0, true },
768 { 1.0, 0.0, 0.0, 45.0, true },
769 };
770
771 for (size_t i = 0; i < sizeof(rotation_tests)/sizeof(TestCase); ++i) {
772 const TestCase& value = rotation_tests[i];
773 transform.setRotateDegreesAbout(value.a, value.b, value.c, value.d);
774 test(value.expected, reporter, transform);
775 }
776
777 static const struct DoubleRotationCase {
778 SkMScalar x1;
779 SkMScalar y1;
780 SkMScalar z1;
781 SkMScalar degrees1;
782 SkMScalar x2;
783 SkMScalar y2;
784 SkMScalar z2;
785 SkMScalar degrees2;
786 bool expected;
787 } double_rotation_tests[] = {
788 { 0.0, 0.0, 1.0, 90.0, 0.0, 1.0, 0.0, 90.0, true },
789 { 0.0, 0.0, 1.0, 90.0, 1.0, 0.0, 0.0, 90.0, true },
790 { 0.0, 1.0, 0.0, 90.0, 0.0, 0.0, 1.0, 90.0, true },
791 };
792
793 for (size_t i = 0; i < sizeof(double_rotation_tests)/sizeof(DoubleRotationCase); ++i) {
794 const DoubleRotationCase& value = double_rotation_tests[i];
795 transform.setRotateDegreesAbout(value.x1, value.y1, value.z1, value.degrees1);
796 transform2.setRotateDegreesAbout(value.x2, value.y2, value.z2, value.degrees2);
797 transform.postConcat(transform2);
798 test(value.expected, reporter, transform);
799 }
800
801 // Perspective cases.
802 transform.setIdentity();
mtklein1831f992015-06-09 11:47:01 -0700803 transform.setDouble(3, 2, -0.1); // Perspective depth 10
tomhudsonfaccb8e2014-09-26 11:45:48 -0700804 transform2.setRotateDegreesAbout(0.0, 1.0, 0.0, 45.0);
805 transform.preConcat(transform2);
806 test(false, reporter, transform);
807
808 transform.setIdentity();
mtklein1831f992015-06-09 11:47:01 -0700809 transform.setDouble(3, 2, -0.1); // Perspective depth 10
tomhudsonfaccb8e2014-09-26 11:45:48 -0700810 transform2.setRotateDegreesAbout(0.0, 0.0, 1.0, 90.0);
811 transform.preConcat(transform2);
812 test(true, reporter, transform);
813}
814
reed39393e32014-10-21 12:33:21 -0700815// just want to exercise the various converters for MScalar
816static void test_toint(skiatest::Reporter* reporter) {
817 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
818 mat.setScale(3, 3, 3);
819
820 SkMScalar sum = SkMScalarFloor(mat.get(0, 0)) +
821 SkMScalarRound(mat.get(1, 0)) +
822 SkMScalarCeil(mat.get(2, 0));
823 int isum = SkMScalarFloorToInt(mat.get(0, 1)) +
824 SkMScalarRoundToInt(mat.get(1, 2)) +
825 SkMScalarCeilToInt(mat.get(2, 3));
826 REPORTER_ASSERT(reporter, sum >= 0);
827 REPORTER_ASSERT(reporter, isum >= 0);
828 REPORTER_ASSERT(reporter, static_cast<SkMScalar>(isum) == SkIntToMScalar(isum));
829}
tomhudsonfaccb8e2014-09-26 11:45:48 -0700830
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000831DEF_TEST(Matrix44, reporter) {
reed@google.com44699382013-10-31 17:28:30 +0000832 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
833 SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
834 SkMatrix44 iden1(SkMatrix44::kUninitialized_Constructor);
835 SkMatrix44 iden2(SkMatrix44::kUninitialized_Constructor);
836 SkMatrix44 rot(SkMatrix44::kUninitialized_Constructor);
reed@google.com125002a2011-06-09 19:13:41 +0000837
reed@google.com7d683352012-12-03 21:19:52 +0000838 mat.setTranslate(1, 1, 1);
reed@google.com125002a2011-06-09 19:13:41 +0000839 mat.invert(&inverse);
840 iden1.setConcat(mat, inverse);
841 REPORTER_ASSERT(reporter, is_identity(iden1));
842
reed@google.com7d683352012-12-03 21:19:52 +0000843 mat.setScale(2, 2, 2);
reed@google.com125002a2011-06-09 19:13:41 +0000844 mat.invert(&inverse);
845 iden1.setConcat(mat, inverse);
846 REPORTER_ASSERT(reporter, is_identity(iden1));
847
reed@google.com7d683352012-12-03 21:19:52 +0000848 mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
reed@google.com125002a2011-06-09 19:13:41 +0000849 mat.invert(&inverse);
850 iden1.setConcat(mat, inverse);
851 REPORTER_ASSERT(reporter, is_identity(iden1));
852
reed@google.com7d683352012-12-03 21:19:52 +0000853 mat.setScale(3, 3, 3);
854 rot.setRotateDegreesAbout(0, 0, -1, 90);
reed@google.com125002a2011-06-09 19:13:41 +0000855 mat.postConcat(rot);
halcanary96fcdcc2015-08-27 07:41:13 -0700856 REPORTER_ASSERT(reporter, mat.invert(nullptr));
reed@google.com125002a2011-06-09 19:13:41 +0000857 mat.invert(&inverse);
858 iden1.setConcat(mat, inverse);
859 REPORTER_ASSERT(reporter, is_identity(iden1));
860 iden2.setConcat(inverse, mat);
861 REPORTER_ASSERT(reporter, is_identity(iden2));
reed@google.comda9fac02011-06-13 14:46:52 +0000862
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000863 // test tiny-valued matrix inverse
864 mat.reset();
mtklein1831f992015-06-09 11:47:01 -0700865 auto v = SkDoubleToMScalar(1.0e-12);
866 mat.setScale(v,v,v);
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000867 rot.setRotateDegreesAbout(0, 0, -1, 90);
868 mat.postConcat(rot);
mtklein1831f992015-06-09 11:47:01 -0700869 mat.postTranslate(v,v,v);
halcanary96fcdcc2015-08-27 07:41:13 -0700870 REPORTER_ASSERT(reporter, mat.invert(nullptr));
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000871 mat.invert(&inverse);
872 iden1.setConcat(mat, inverse);
873 REPORTER_ASSERT(reporter, is_identity(iden1));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000874
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000875 // test mixed-valued matrix inverse
876 mat.reset();
mtklein51958052015-06-09 15:06:22 -0700877 mat.setScale(SkDoubleToMScalar(1.0e-2),
mtklein1831f992015-06-09 11:47:01 -0700878 SkDoubleToMScalar(3.0),
mtklein51958052015-06-09 15:06:22 -0700879 SkDoubleToMScalar(1.0e+2));
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000880 rot.setRotateDegreesAbout(0, 0, -1, 90);
881 mat.postConcat(rot);
mtklein51958052015-06-09 15:06:22 -0700882 mat.postTranslate(SkDoubleToMScalar(1.0e+2),
mtklein1831f992015-06-09 11:47:01 -0700883 SkDoubleToMScalar(3.0),
mtklein51958052015-06-09 15:06:22 -0700884 SkDoubleToMScalar(1.0e-2));
halcanary96fcdcc2015-08-27 07:41:13 -0700885 REPORTER_ASSERT(reporter, mat.invert(nullptr));
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000886 mat.invert(&inverse);
887 iden1.setConcat(mat, inverse);
888 REPORTER_ASSERT(reporter, is_identity(iden1));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000889
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000890 // test degenerate matrix
891 mat.reset();
892 mat.set3x3(1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0);
halcanary96fcdcc2015-08-27 07:41:13 -0700893 REPORTER_ASSERT(reporter, !mat.invert(nullptr));
skia.committer@gmail.comb74bdf02013-08-21 07:01:29 +0000894
reed@google.comda9fac02011-06-13 14:46:52 +0000895 // test rol/col Major getters
896 {
897 mat.setTranslate(2, 3, 4);
898 float dataf[16];
899 double datad[16];
rmistry@google.comd6176b02012-08-23 18:14:13 +0000900
reed@google.comda9fac02011-06-13 14:46:52 +0000901 mat.asColMajorf(dataf);
902 assert16<float>(reporter, dataf,
903 1, 0, 0, 0,
904 0, 1, 0, 0,
905 0, 0, 1, 0,
906 2, 3, 4, 1);
907 mat.asColMajord(datad);
908 assert16<double>(reporter, datad, 1, 0, 0, 0,
909 0, 1, 0, 0,
910 0, 0, 1, 0,
911 2, 3, 4, 1);
912 mat.asRowMajorf(dataf);
913 assert16<float>(reporter, dataf, 1, 0, 0, 2,
914 0, 1, 0, 3,
915 0, 0, 1, 4,
916 0, 0, 0, 1);
917 mat.asRowMajord(datad);
918 assert16<double>(reporter, datad, 1, 0, 0, 2,
919 0, 1, 0, 3,
920 0, 0, 1, 4,
921 0, 0, 0, 1);
922 }
reed@google.com6f2b44d2011-06-24 18:13:39 +0000923
reed@google.com80b577e2012-11-09 21:25:06 +0000924 test_concat(reporter);
925
caryclark@google.com42639cd2012-06-06 12:03:39 +0000926 if (false) { // avoid bit rot, suppress warning (working on making this pass)
927 test_common_angles(reporter);
928 }
vollick@chromium.org3959a762012-11-13 15:08:22 +0000929
vollick@chromium.org57a54e32012-12-10 20:16:10 +0000930 test_constructor(reporter);
reed@google.com7d683352012-12-03 21:19:52 +0000931 test_gettype(reporter);
vollick@chromium.org3959a762012-11-13 15:08:22 +0000932 test_determinant(reporter);
commit-bot@chromium.org95045752013-08-20 20:15:24 +0000933 test_invert(reporter);
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000934 test_transpose(reporter);
935 test_get_set_double(reporter);
reed@google.com7d683352012-12-03 21:19:52 +0000936 test_set_row_col_major(reporter);
msarettc1a3e242016-06-23 12:42:29 -0700937 test_set_3x3(reporter);
reed@google.com99b5c7f2012-12-05 22:13:59 +0000938 test_translate(reporter);
939 test_scale(reporter);
940 test_map2(reporter);
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000941 test_3x3_conversion(reporter);
tomhudsona32f1752014-09-16 08:29:29 -0700942 test_has_perspective(reporter);
tomhudsonfaccb8e2014-09-26 11:45:48 -0700943 test_preserves_2d_axis_alignment(reporter);
reed39393e32014-10-21 12:33:21 -0700944 test_toint(reporter);
reed@google.com125002a2011-06-09 19:13:41 +0000945}