1 | /* |
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 | */ |
7 | |
8 | #include "include/core/SkMatrix44.h" |
9 | #include <type_traits> |
10 | #include <utility> |
11 | |
12 | // Copying SkMatrix44 byte-wise is performance-critical to Blink. This class is |
13 | // contained in several Transform classes, which are copied multiple times |
14 | // during the rendering life cycle. See crbug.com/938563 for reference. |
15 | #if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC) |
16 | // std::is_trivially_copyable is not supported for some older clang versions, |
17 | // which (at least as of this patch) are in use for Chromecast. |
18 | static_assert(std::is_trivially_copyable<SkMatrix44>::value, |
19 | "SkMatrix44 must be trivially copyable" ); |
20 | #endif |
21 | |
22 | static inline bool eq4(const SkScalar* SK_RESTRICT a, |
23 | const SkScalar* SK_RESTRICT b) { |
24 | return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]); |
25 | } |
26 | |
27 | bool SkMatrix44::operator==(const SkMatrix44& other) const { |
28 | if (this == &other) { |
29 | return true; |
30 | } |
31 | |
32 | if (this->isIdentity() && other.isIdentity()) { |
33 | return true; |
34 | } |
35 | |
36 | const SkScalar* SK_RESTRICT a = &fMat[0][0]; |
37 | const SkScalar* SK_RESTRICT b = &other.fMat[0][0]; |
38 | |
39 | #if 0 |
40 | for (int i = 0; i < 16; ++i) { |
41 | if (a[i] != b[i]) { |
42 | return false; |
43 | } |
44 | } |
45 | return true; |
46 | #else |
47 | // to reduce branch instructions, we compare 4 at a time. |
48 | // see bench/Matrix44Bench.cpp for test. |
49 | if (!eq4(&a[0], &b[0])) { |
50 | return false; |
51 | } |
52 | if (!eq4(&a[4], &b[4])) { |
53 | return false; |
54 | } |
55 | if (!eq4(&a[8], &b[8])) { |
56 | return false; |
57 | } |
58 | return eq4(&a[12], &b[12]); |
59 | #endif |
60 | } |
61 | |
62 | /////////////////////////////////////////////////////////////////////////////// |
63 | void SkMatrix44::recomputeTypeMask() { |
64 | if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) { |
65 | fTypeMask = kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask; |
66 | return; |
67 | } |
68 | |
69 | TypeMask mask = kIdentity_Mask; |
70 | if (0 != transX() || 0 != transY() || 0 != transZ()) { |
71 | mask |= kTranslate_Mask; |
72 | } |
73 | |
74 | if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) { |
75 | mask |= kScale_Mask; |
76 | } |
77 | |
78 | if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] || |
79 | 0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) { |
80 | mask |= kAffine_Mask; |
81 | } |
82 | fTypeMask = mask; |
83 | } |
84 | |
85 | /////////////////////////////////////////////////////////////////////////////// |
86 | |
87 | void SkMatrix44::asColMajorf(float dst[]) const { |
88 | const SkScalar* src = &fMat[0][0]; |
89 | for (int i = 0; i < 16; ++i) { |
90 | dst[i] = src[i]; |
91 | } |
92 | } |
93 | |
94 | void SkMatrix44::as3x4RowMajorf(float dst[]) const { |
95 | dst[0] = fMat[0][0]; dst[1] = fMat[1][0]; dst[2] = fMat[2][0]; dst[3] = fMat[3][0]; |
96 | dst[4] = fMat[0][1]; dst[5] = fMat[1][1]; dst[6] = fMat[2][1]; dst[7] = fMat[3][1]; |
97 | dst[8] = fMat[0][2]; dst[9] = fMat[1][2]; dst[10] = fMat[2][2]; dst[11] = fMat[3][2]; |
98 | } |
99 | |
100 | void SkMatrix44::asColMajord(double dst[]) const { |
101 | const SkScalar* src = &fMat[0][0]; |
102 | for (int i = 0; i < 16; ++i) { |
103 | dst[i] = src[i]; |
104 | } |
105 | } |
106 | |
107 | void SkMatrix44::asRowMajorf(float dst[]) const { |
108 | const SkScalar* src = &fMat[0][0]; |
109 | for (int i = 0; i < 4; ++i) { |
110 | dst[0] = float(src[0]); |
111 | dst[4] = float(src[1]); |
112 | dst[8] = float(src[2]); |
113 | dst[12] = float(src[3]); |
114 | src += 4; |
115 | dst += 1; |
116 | } |
117 | } |
118 | |
119 | void SkMatrix44::asRowMajord(double dst[]) const { |
120 | const SkScalar* src = &fMat[0][0]; |
121 | for (int i = 0; i < 4; ++i) { |
122 | dst[0] = src[0]; |
123 | dst[4] = src[1]; |
124 | dst[8] = src[2]; |
125 | dst[12] = src[3]; |
126 | src += 4; |
127 | dst += 1; |
128 | } |
129 | } |
130 | |
131 | void SkMatrix44::setColMajorf(const float src[]) { |
132 | SkScalar* dst = &fMat[0][0]; |
133 | for (int i = 0; i < 16; ++i) { |
134 | dst[i] = src[i]; |
135 | } |
136 | |
137 | this->recomputeTypeMask(); |
138 | } |
139 | |
140 | void SkMatrix44::setColMajord(const double src[]) { |
141 | SkScalar* dst = &fMat[0][0]; |
142 | for (int i = 0; i < 16; ++i) { |
143 | dst[i] = SkScalar(src[i]); |
144 | } |
145 | |
146 | this->recomputeTypeMask(); |
147 | } |
148 | |
149 | void SkMatrix44::setRowMajorf(const float src[]) { |
150 | SkScalar* dst = &fMat[0][0]; |
151 | for (int i = 0; i < 4; ++i) { |
152 | dst[0] = src[0]; |
153 | dst[4] = src[1]; |
154 | dst[8] = src[2]; |
155 | dst[12] = src[3]; |
156 | src += 4; |
157 | dst += 1; |
158 | } |
159 | this->recomputeTypeMask(); |
160 | } |
161 | |
162 | void SkMatrix44::setRowMajord(const double src[]) { |
163 | SkScalar* dst = &fMat[0][0]; |
164 | for (int i = 0; i < 4; ++i) { |
165 | dst[0] = SkScalar(src[0]); |
166 | dst[4] = SkScalar(src[1]); |
167 | dst[8] = SkScalar(src[2]); |
168 | dst[12] = SkScalar(src[3]); |
169 | src += 4; |
170 | dst += 1; |
171 | } |
172 | this->recomputeTypeMask(); |
173 | } |
174 | |
175 | /////////////////////////////////////////////////////////////////////////////// |
176 | |
177 | const SkMatrix44& SkMatrix44::I() { |
178 | static constexpr SkMatrix44 gIdentity44(kIdentity_Constructor); |
179 | return gIdentity44; |
180 | } |
181 | |
182 | void SkMatrix44::setIdentity() { |
183 | fMat[0][0] = 1; |
184 | fMat[0][1] = 0; |
185 | fMat[0][2] = 0; |
186 | fMat[0][3] = 0; |
187 | fMat[1][0] = 0; |
188 | fMat[1][1] = 1; |
189 | fMat[1][2] = 0; |
190 | fMat[1][3] = 0; |
191 | fMat[2][0] = 0; |
192 | fMat[2][1] = 0; |
193 | fMat[2][2] = 1; |
194 | fMat[2][3] = 0; |
195 | fMat[3][0] = 0; |
196 | fMat[3][1] = 0; |
197 | fMat[3][2] = 0; |
198 | fMat[3][3] = 1; |
199 | this->setTypeMask(kIdentity_Mask); |
200 | } |
201 | |
202 | void SkMatrix44::set3x3(SkScalar m_00, SkScalar m_10, SkScalar m_20, |
203 | SkScalar m_01, SkScalar m_11, SkScalar m_21, |
204 | SkScalar m_02, SkScalar m_12, SkScalar m_22) { |
205 | fMat[0][0] = m_00; fMat[0][1] = m_10; fMat[0][2] = m_20; fMat[0][3] = 0; |
206 | fMat[1][0] = m_01; fMat[1][1] = m_11; fMat[1][2] = m_21; fMat[1][3] = 0; |
207 | fMat[2][0] = m_02; fMat[2][1] = m_12; fMat[2][2] = m_22; fMat[2][3] = 0; |
208 | fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1; |
209 | this->recomputeTypeMask(); |
210 | } |
211 | |
212 | void SkMatrix44::set3x3RowMajorf(const float src[]) { |
213 | fMat[0][0] = src[0]; fMat[0][1] = src[3]; fMat[0][2] = src[6]; fMat[0][3] = 0; |
214 | fMat[1][0] = src[1]; fMat[1][1] = src[4]; fMat[1][2] = src[7]; fMat[1][3] = 0; |
215 | fMat[2][0] = src[2]; fMat[2][1] = src[5]; fMat[2][2] = src[8]; fMat[2][3] = 0; |
216 | fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1; |
217 | this->recomputeTypeMask(); |
218 | } |
219 | |
220 | void SkMatrix44::set3x4RowMajorf(const float src[]) { |
221 | fMat[0][0] = src[0]; fMat[1][0] = src[1]; fMat[2][0] = src[2]; fMat[3][0] = src[3]; |
222 | fMat[0][1] = src[4]; fMat[1][1] = src[5]; fMat[2][1] = src[6]; fMat[3][1] = src[7]; |
223 | fMat[0][2] = src[8]; fMat[1][2] = src[9]; fMat[2][2] = src[10]; fMat[3][2] = src[11]; |
224 | fMat[0][3] = 0; fMat[1][3] = 0; fMat[2][3] = 0; fMat[3][3] = 1; |
225 | this->recomputeTypeMask(); |
226 | } |
227 | |
228 | void SkMatrix44::set4x4(SkScalar m_00, SkScalar m_10, SkScalar m_20, SkScalar m_30, |
229 | SkScalar m_01, SkScalar m_11, SkScalar m_21, SkScalar m_31, |
230 | SkScalar m_02, SkScalar m_12, SkScalar m_22, SkScalar m_32, |
231 | SkScalar m_03, SkScalar m_13, SkScalar m_23, SkScalar m_33) { |
232 | fMat[0][0] = m_00; fMat[0][1] = m_10; fMat[0][2] = m_20; fMat[0][3] = m_30; |
233 | fMat[1][0] = m_01; fMat[1][1] = m_11; fMat[1][2] = m_21; fMat[1][3] = m_31; |
234 | fMat[2][0] = m_02; fMat[2][1] = m_12; fMat[2][2] = m_22; fMat[2][3] = m_32; |
235 | fMat[3][0] = m_03; fMat[3][1] = m_13; fMat[3][2] = m_23; fMat[3][3] = m_33; |
236 | this->recomputeTypeMask(); |
237 | } |
238 | |
239 | |
240 | /////////////////////////////////////////////////////////////////////////////// |
241 | |
242 | SkMatrix44& SkMatrix44::setTranslate(SkScalar dx, SkScalar dy, SkScalar dz) { |
243 | this->setIdentity(); |
244 | |
245 | if (!dx && !dy && !dz) { |
246 | return *this; |
247 | } |
248 | |
249 | fMat[3][0] = dx; |
250 | fMat[3][1] = dy; |
251 | fMat[3][2] = dz; |
252 | this->setTypeMask(kTranslate_Mask); |
253 | return *this; |
254 | } |
255 | |
256 | SkMatrix44& SkMatrix44::preTranslate(SkScalar dx, SkScalar dy, SkScalar dz) { |
257 | if (!dx && !dy && !dz) { |
258 | return *this; |
259 | } |
260 | |
261 | for (int i = 0; i < 4; ++i) { |
262 | fMat[3][i] = fMat[0][i] * dx + fMat[1][i] * dy + fMat[2][i] * dz + fMat[3][i]; |
263 | } |
264 | this->recomputeTypeMask(); |
265 | return *this; |
266 | } |
267 | |
268 | SkMatrix44& SkMatrix44::postTranslate(SkScalar dx, SkScalar dy, SkScalar dz) { |
269 | if (!dx && !dy && !dz) { |
270 | return *this; |
271 | } |
272 | |
273 | if (this->getType() & kPerspective_Mask) { |
274 | for (int i = 0; i < 4; ++i) { |
275 | fMat[i][0] += fMat[i][3] * dx; |
276 | fMat[i][1] += fMat[i][3] * dy; |
277 | fMat[i][2] += fMat[i][3] * dz; |
278 | } |
279 | } else { |
280 | fMat[3][0] += dx; |
281 | fMat[3][1] += dy; |
282 | fMat[3][2] += dz; |
283 | this->recomputeTypeMask(); |
284 | } |
285 | return *this; |
286 | } |
287 | |
288 | /////////////////////////////////////////////////////////////////////////////// |
289 | |
290 | SkMatrix44& SkMatrix44::setScale(SkScalar sx, SkScalar sy, SkScalar sz) { |
291 | this->setIdentity(); |
292 | |
293 | if (1 == sx && 1 == sy && 1 == sz) { |
294 | return *this; |
295 | } |
296 | |
297 | fMat[0][0] = sx; |
298 | fMat[1][1] = sy; |
299 | fMat[2][2] = sz; |
300 | this->setTypeMask(kScale_Mask); |
301 | return *this; |
302 | } |
303 | |
304 | SkMatrix44& SkMatrix44::preScale(SkScalar sx, SkScalar sy, SkScalar sz) { |
305 | if (1 == sx && 1 == sy && 1 == sz) { |
306 | return *this; |
307 | } |
308 | |
309 | // The implementation matrix * pureScale can be shortcut |
310 | // by knowing that pureScale components effectively scale |
311 | // the columns of the original matrix. |
312 | for (int i = 0; i < 4; i++) { |
313 | fMat[0][i] *= sx; |
314 | fMat[1][i] *= sy; |
315 | fMat[2][i] *= sz; |
316 | } |
317 | this->recomputeTypeMask(); |
318 | return *this; |
319 | } |
320 | |
321 | SkMatrix44& SkMatrix44::postScale(SkScalar sx, SkScalar sy, SkScalar sz) { |
322 | if (1 == sx && 1 == sy && 1 == sz) { |
323 | return *this; |
324 | } |
325 | |
326 | for (int i = 0; i < 4; i++) { |
327 | fMat[i][0] *= sx; |
328 | fMat[i][1] *= sy; |
329 | fMat[i][2] *= sz; |
330 | } |
331 | this->recomputeTypeMask(); |
332 | return *this; |
333 | } |
334 | |
335 | /////////////////////////////////////////////////////////////////////////////// |
336 | |
337 | void SkMatrix44::setRotateAbout(SkScalar x, SkScalar y, SkScalar z, SkScalar radians) { |
338 | double len2 = (double)x * x + (double)y * y + (double)z * z; |
339 | if (1 != len2) { |
340 | if (0 == len2) { |
341 | this->setIdentity(); |
342 | return; |
343 | } |
344 | double scale = 1 / sqrt(len2); |
345 | x = SkScalar(x * scale); |
346 | y = SkScalar(y * scale); |
347 | z = SkScalar(z * scale); |
348 | } |
349 | this->setRotateAboutUnit(x, y, z, radians); |
350 | } |
351 | |
352 | void SkMatrix44::setRotateAboutUnit(SkScalar x, SkScalar y, SkScalar z, SkScalar radians) { |
353 | double c = cos(radians); |
354 | double s = sin(radians); |
355 | double C = 1 - c; |
356 | double xs = x * s; |
357 | double ys = y * s; |
358 | double zs = z * s; |
359 | double xC = x * C; |
360 | double yC = y * C; |
361 | double zC = z * C; |
362 | double xyC = x * yC; |
363 | double yzC = y * zC; |
364 | double zxC = z * xC; |
365 | |
366 | // if you're looking at wikipedia, remember that we're column major. |
367 | this->set3x3(SkScalar(x * xC + c), // scale x |
368 | SkScalar(xyC + zs), // skew x |
369 | SkScalar(zxC - ys), // trans x |
370 | |
371 | SkScalar(xyC - zs), // skew y |
372 | SkScalar(y * yC + c), // scale y |
373 | SkScalar(yzC + xs), // trans y |
374 | |
375 | SkScalar(zxC + ys), // persp x |
376 | SkScalar(yzC - xs), // persp y |
377 | SkScalar(z * zC + c)); // persp 2 |
378 | } |
379 | |
380 | /////////////////////////////////////////////////////////////////////////////// |
381 | |
382 | static bool bits_isonly(int value, int mask) { |
383 | return 0 == (value & ~mask); |
384 | } |
385 | |
386 | void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) { |
387 | const SkMatrix44::TypeMask a_mask = a.getType(); |
388 | const SkMatrix44::TypeMask b_mask = b.getType(); |
389 | |
390 | if (kIdentity_Mask == a_mask) { |
391 | *this = b; |
392 | return; |
393 | } |
394 | if (kIdentity_Mask == b_mask) { |
395 | *this = a; |
396 | return; |
397 | } |
398 | |
399 | bool useStorage = (this == &a || this == &b); |
400 | SkScalar storage[16]; |
401 | SkScalar* result = useStorage ? storage : &fMat[0][0]; |
402 | |
403 | // Both matrices are at most scale+translate |
404 | if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) { |
405 | result[0] = a.fMat[0][0] * b.fMat[0][0]; |
406 | result[1] = result[2] = result[3] = result[4] = 0; |
407 | result[5] = a.fMat[1][1] * b.fMat[1][1]; |
408 | result[6] = result[7] = result[8] = result[9] = 0; |
409 | result[10] = a.fMat[2][2] * b.fMat[2][2]; |
410 | result[11] = 0; |
411 | result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0]; |
412 | result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1]; |
413 | result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2]; |
414 | result[15] = 1; |
415 | } else { |
416 | for (int j = 0; j < 4; j++) { |
417 | for (int i = 0; i < 4; i++) { |
418 | double value = 0; |
419 | for (int k = 0; k < 4; k++) { |
420 | value += double(a.fMat[k][i]) * b.fMat[j][k]; |
421 | } |
422 | *result++ = SkScalar(value); |
423 | } |
424 | } |
425 | } |
426 | |
427 | if (useStorage) { |
428 | memcpy(fMat, storage, sizeof(storage)); |
429 | } |
430 | this->recomputeTypeMask(); |
431 | } |
432 | |
433 | /////////////////////////////////////////////////////////////////////////////// |
434 | |
435 | /** We always perform the calculation in doubles, to avoid prematurely losing |
436 | precision along the way. This relies on the compiler automatically |
437 | promoting our SkScalar values to double (if needed). |
438 | */ |
439 | double SkMatrix44::determinant() const { |
440 | if (this->isIdentity()) { |
441 | return 1; |
442 | } |
443 | if (this->isScaleTranslate()) { |
444 | return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3]; |
445 | } |
446 | |
447 | double a00 = fMat[0][0]; |
448 | double a01 = fMat[0][1]; |
449 | double a02 = fMat[0][2]; |
450 | double a03 = fMat[0][3]; |
451 | double a10 = fMat[1][0]; |
452 | double a11 = fMat[1][1]; |
453 | double a12 = fMat[1][2]; |
454 | double a13 = fMat[1][3]; |
455 | double a20 = fMat[2][0]; |
456 | double a21 = fMat[2][1]; |
457 | double a22 = fMat[2][2]; |
458 | double a23 = fMat[2][3]; |
459 | double a30 = fMat[3][0]; |
460 | double a31 = fMat[3][1]; |
461 | double a32 = fMat[3][2]; |
462 | double a33 = fMat[3][3]; |
463 | |
464 | double b00 = a00 * a11 - a01 * a10; |
465 | double b01 = a00 * a12 - a02 * a10; |
466 | double b02 = a00 * a13 - a03 * a10; |
467 | double b03 = a01 * a12 - a02 * a11; |
468 | double b04 = a01 * a13 - a03 * a11; |
469 | double b05 = a02 * a13 - a03 * a12; |
470 | double b06 = a20 * a31 - a21 * a30; |
471 | double b07 = a20 * a32 - a22 * a30; |
472 | double b08 = a20 * a33 - a23 * a30; |
473 | double b09 = a21 * a32 - a22 * a31; |
474 | double b10 = a21 * a33 - a23 * a31; |
475 | double b11 = a22 * a33 - a23 * a32; |
476 | |
477 | // Calculate the determinant |
478 | return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; |
479 | } |
480 | |
481 | /////////////////////////////////////////////////////////////////////////////// |
482 | |
483 | static bool is_matrix_finite(const SkMatrix44& matrix) { |
484 | SkScalar accumulator = 0; |
485 | for (int row = 0; row < 4; ++row) { |
486 | for (int col = 0; col < 4; ++col) { |
487 | accumulator *= matrix.get(row, col); |
488 | } |
489 | } |
490 | return accumulator == 0; |
491 | } |
492 | |
493 | bool SkMatrix44::invert(SkMatrix44* storage) const { |
494 | if (this->isIdentity()) { |
495 | if (storage) { |
496 | storage->setIdentity(); |
497 | } |
498 | return true; |
499 | } |
500 | |
501 | if (this->isTranslate()) { |
502 | if (storage) { |
503 | storage->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]); |
504 | } |
505 | return true; |
506 | } |
507 | |
508 | SkMatrix44 tmp; |
509 | // Use storage if it's available and distinct from this matrix. |
510 | SkMatrix44* inverse = (storage && storage != this) ? storage : &tmp; |
511 | if (this->isScaleTranslate()) { |
512 | if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) { |
513 | return false; |
514 | } |
515 | |
516 | double invXScale = 1 / fMat[0][0]; |
517 | double invYScale = 1 / fMat[1][1]; |
518 | double invZScale = 1 / fMat[2][2]; |
519 | |
520 | inverse->fMat[0][0] = SkDoubleToScalar(invXScale); |
521 | inverse->fMat[0][1] = 0; |
522 | inverse->fMat[0][2] = 0; |
523 | inverse->fMat[0][3] = 0; |
524 | |
525 | inverse->fMat[1][0] = 0; |
526 | inverse->fMat[1][1] = SkDoubleToScalar(invYScale); |
527 | inverse->fMat[1][2] = 0; |
528 | inverse->fMat[1][3] = 0; |
529 | |
530 | inverse->fMat[2][0] = 0; |
531 | inverse->fMat[2][1] = 0; |
532 | inverse->fMat[2][2] = SkDoubleToScalar(invZScale); |
533 | inverse->fMat[2][3] = 0; |
534 | |
535 | inverse->fMat[3][0] = SkDoubleToScalar(-fMat[3][0] * invXScale); |
536 | inverse->fMat[3][1] = SkDoubleToScalar(-fMat[3][1] * invYScale); |
537 | inverse->fMat[3][2] = SkDoubleToScalar(-fMat[3][2] * invZScale); |
538 | inverse->fMat[3][3] = 1; |
539 | |
540 | inverse->setTypeMask(this->getType()); |
541 | |
542 | if (!is_matrix_finite(*inverse)) { |
543 | return false; |
544 | } |
545 | if (storage && inverse != storage) { |
546 | *storage = *inverse; |
547 | } |
548 | return true; |
549 | } |
550 | |
551 | double a00 = fMat[0][0]; |
552 | double a01 = fMat[0][1]; |
553 | double a02 = fMat[0][2]; |
554 | double a03 = fMat[0][3]; |
555 | double a10 = fMat[1][0]; |
556 | double a11 = fMat[1][1]; |
557 | double a12 = fMat[1][2]; |
558 | double a13 = fMat[1][3]; |
559 | double a20 = fMat[2][0]; |
560 | double a21 = fMat[2][1]; |
561 | double a22 = fMat[2][2]; |
562 | double a23 = fMat[2][3]; |
563 | double a30 = fMat[3][0]; |
564 | double a31 = fMat[3][1]; |
565 | double a32 = fMat[3][2]; |
566 | double a33 = fMat[3][3]; |
567 | |
568 | if (!(this->getType() & kPerspective_Mask)) { |
569 | // If we know the matrix has no perspective, then the perspective |
570 | // component is (0, 0, 0, 1). We can use this information to save a lot |
571 | // of arithmetic that would otherwise be spent to compute the inverse |
572 | // of a general matrix. |
573 | |
574 | SkASSERT(a03 == 0); |
575 | SkASSERT(a13 == 0); |
576 | SkASSERT(a23 == 0); |
577 | SkASSERT(a33 == 1); |
578 | |
579 | double b00 = a00 * a11 - a01 * a10; |
580 | double b01 = a00 * a12 - a02 * a10; |
581 | double b03 = a01 * a12 - a02 * a11; |
582 | double b06 = a20 * a31 - a21 * a30; |
583 | double b07 = a20 * a32 - a22 * a30; |
584 | double b08 = a20; |
585 | double b09 = a21 * a32 - a22 * a31; |
586 | double b10 = a21; |
587 | double b11 = a22; |
588 | |
589 | // Calculate the determinant |
590 | double det = b00 * b11 - b01 * b10 + b03 * b08; |
591 | |
592 | double invdet = sk_ieee_double_divide(1.0, det); |
593 | // If det is zero, we want to return false. However, we also want to return false |
594 | // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are |
595 | // handled by checking that 1/det is finite. |
596 | if (!sk_float_isfinite(sk_double_to_float(invdet))) { |
597 | return false; |
598 | } |
599 | |
600 | b00 *= invdet; |
601 | b01 *= invdet; |
602 | b03 *= invdet; |
603 | b06 *= invdet; |
604 | b07 *= invdet; |
605 | b08 *= invdet; |
606 | b09 *= invdet; |
607 | b10 *= invdet; |
608 | b11 *= invdet; |
609 | |
610 | inverse->fMat[0][0] = SkDoubleToScalar(a11 * b11 - a12 * b10); |
611 | inverse->fMat[0][1] = SkDoubleToScalar(a02 * b10 - a01 * b11); |
612 | inverse->fMat[0][2] = SkDoubleToScalar(b03); |
613 | inverse->fMat[0][3] = 0; |
614 | inverse->fMat[1][0] = SkDoubleToScalar(a12 * b08 - a10 * b11); |
615 | inverse->fMat[1][1] = SkDoubleToScalar(a00 * b11 - a02 * b08); |
616 | inverse->fMat[1][2] = SkDoubleToScalar(-b01); |
617 | inverse->fMat[1][3] = 0; |
618 | inverse->fMat[2][0] = SkDoubleToScalar(a10 * b10 - a11 * b08); |
619 | inverse->fMat[2][1] = SkDoubleToScalar(a01 * b08 - a00 * b10); |
620 | inverse->fMat[2][2] = SkDoubleToScalar(b00); |
621 | inverse->fMat[2][3] = 0; |
622 | inverse->fMat[3][0] = SkDoubleToScalar(a11 * b07 - a10 * b09 - a12 * b06); |
623 | inverse->fMat[3][1] = SkDoubleToScalar(a00 * b09 - a01 * b07 + a02 * b06); |
624 | inverse->fMat[3][2] = SkDoubleToScalar(a31 * b01 - a30 * b03 - a32 * b00); |
625 | inverse->fMat[3][3] = 1; |
626 | |
627 | inverse->setTypeMask(this->getType()); |
628 | if (!is_matrix_finite(*inverse)) { |
629 | return false; |
630 | } |
631 | if (storage && inverse != storage) { |
632 | *storage = *inverse; |
633 | } |
634 | return true; |
635 | } |
636 | |
637 | double b00 = a00 * a11 - a01 * a10; |
638 | double b01 = a00 * a12 - a02 * a10; |
639 | double b02 = a00 * a13 - a03 * a10; |
640 | double b03 = a01 * a12 - a02 * a11; |
641 | double b04 = a01 * a13 - a03 * a11; |
642 | double b05 = a02 * a13 - a03 * a12; |
643 | double b06 = a20 * a31 - a21 * a30; |
644 | double b07 = a20 * a32 - a22 * a30; |
645 | double b08 = a20 * a33 - a23 * a30; |
646 | double b09 = a21 * a32 - a22 * a31; |
647 | double b10 = a21 * a33 - a23 * a31; |
648 | double b11 = a22 * a33 - a23 * a32; |
649 | |
650 | // Calculate the determinant |
651 | double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; |
652 | |
653 | double invdet = sk_ieee_double_divide(1.0, det); |
654 | // If det is zero, we want to return false. However, we also want to return false |
655 | // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are |
656 | // handled by checking that 1/det is finite. |
657 | if (!sk_float_isfinite(sk_double_to_float(invdet))) { |
658 | return false; |
659 | } |
660 | |
661 | b00 *= invdet; |
662 | b01 *= invdet; |
663 | b02 *= invdet; |
664 | b03 *= invdet; |
665 | b04 *= invdet; |
666 | b05 *= invdet; |
667 | b06 *= invdet; |
668 | b07 *= invdet; |
669 | b08 *= invdet; |
670 | b09 *= invdet; |
671 | b10 *= invdet; |
672 | b11 *= invdet; |
673 | |
674 | inverse->fMat[0][0] = SkDoubleToScalar(a11 * b11 - a12 * b10 + a13 * b09); |
675 | inverse->fMat[0][1] = SkDoubleToScalar(a02 * b10 - a01 * b11 - a03 * b09); |
676 | inverse->fMat[0][2] = SkDoubleToScalar(a31 * b05 - a32 * b04 + a33 * b03); |
677 | inverse->fMat[0][3] = SkDoubleToScalar(a22 * b04 - a21 * b05 - a23 * b03); |
678 | inverse->fMat[1][0] = SkDoubleToScalar(a12 * b08 - a10 * b11 - a13 * b07); |
679 | inverse->fMat[1][1] = SkDoubleToScalar(a00 * b11 - a02 * b08 + a03 * b07); |
680 | inverse->fMat[1][2] = SkDoubleToScalar(a32 * b02 - a30 * b05 - a33 * b01); |
681 | inverse->fMat[1][3] = SkDoubleToScalar(a20 * b05 - a22 * b02 + a23 * b01); |
682 | inverse->fMat[2][0] = SkDoubleToScalar(a10 * b10 - a11 * b08 + a13 * b06); |
683 | inverse->fMat[2][1] = SkDoubleToScalar(a01 * b08 - a00 * b10 - a03 * b06); |
684 | inverse->fMat[2][2] = SkDoubleToScalar(a30 * b04 - a31 * b02 + a33 * b00); |
685 | inverse->fMat[2][3] = SkDoubleToScalar(a21 * b02 - a20 * b04 - a23 * b00); |
686 | inverse->fMat[3][0] = SkDoubleToScalar(a11 * b07 - a10 * b09 - a12 * b06); |
687 | inverse->fMat[3][1] = SkDoubleToScalar(a00 * b09 - a01 * b07 + a02 * b06); |
688 | inverse->fMat[3][2] = SkDoubleToScalar(a31 * b01 - a30 * b03 - a32 * b00); |
689 | inverse->fMat[3][3] = SkDoubleToScalar(a20 * b03 - a21 * b01 + a22 * b00); |
690 | inverse->setTypeMask(this->getType()); |
691 | if (!is_matrix_finite(*inverse)) { |
692 | return false; |
693 | } |
694 | if (storage && inverse != storage) { |
695 | *storage = *inverse; |
696 | } |
697 | return true; |
698 | } |
699 | |
700 | /////////////////////////////////////////////////////////////////////////////// |
701 | |
702 | void SkMatrix44::transpose() { |
703 | if (!this->isIdentity()) { |
704 | using std::swap; |
705 | swap(fMat[0][1], fMat[1][0]); |
706 | swap(fMat[0][2], fMat[2][0]); |
707 | swap(fMat[0][3], fMat[3][0]); |
708 | swap(fMat[1][2], fMat[2][1]); |
709 | swap(fMat[1][3], fMat[3][1]); |
710 | swap(fMat[2][3], fMat[3][2]); |
711 | this->recomputeTypeMask(); |
712 | } |
713 | } |
714 | |
715 | /////////////////////////////////////////////////////////////////////////////// |
716 | |
717 | void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const { |
718 | SkScalar storage[4]; |
719 | SkScalar* result = (src == dst) ? storage : dst; |
720 | |
721 | for (int i = 0; i < 4; i++) { |
722 | SkScalar value = 0; |
723 | for (int j = 0; j < 4; j++) { |
724 | value += fMat[j][i] * src[j]; |
725 | } |
726 | result[i] = value; |
727 | } |
728 | |
729 | if (storage == result) { |
730 | memcpy(dst, storage, sizeof(storage)); |
731 | } |
732 | } |
733 | |
734 | typedef void (*Map2Procf)(const SkScalar mat[][4], const float src2[], int count, float dst4[]); |
735 | typedef void (*Map2Procd)(const SkScalar mat[][4], const double src2[], int count, double dst4[]); |
736 | |
737 | static void map2_if(const SkScalar mat[][4], const float* SK_RESTRICT src2, |
738 | int count, float* SK_RESTRICT dst4) { |
739 | for (int i = 0; i < count; ++i) { |
740 | dst4[0] = src2[0]; |
741 | dst4[1] = src2[1]; |
742 | dst4[2] = 0; |
743 | dst4[3] = 1; |
744 | src2 += 2; |
745 | dst4 += 4; |
746 | } |
747 | } |
748 | |
749 | static void map2_id(const SkScalar mat[][4], const double* SK_RESTRICT src2, |
750 | int count, double* SK_RESTRICT dst4) { |
751 | for (int i = 0; i < count; ++i) { |
752 | dst4[0] = src2[0]; |
753 | dst4[1] = src2[1]; |
754 | dst4[2] = 0; |
755 | dst4[3] = 1; |
756 | src2 += 2; |
757 | dst4 += 4; |
758 | } |
759 | } |
760 | |
761 | static void map2_tf(const SkScalar mat[][4], const float* SK_RESTRICT src2, |
762 | int count, float* SK_RESTRICT dst4) { |
763 | const float mat30 = float(mat[3][0]); |
764 | const float mat31 = float(mat[3][1]); |
765 | const float mat32 = float(mat[3][2]); |
766 | for (int n = 0; n < count; ++n) { |
767 | dst4[0] = src2[0] + mat30; |
768 | dst4[1] = src2[1] + mat31; |
769 | dst4[2] = mat32; |
770 | dst4[3] = 1; |
771 | src2 += 2; |
772 | dst4 += 4; |
773 | } |
774 | } |
775 | |
776 | static void map2_td(const SkScalar mat[][4], const double* SK_RESTRICT src2, |
777 | int count, double* SK_RESTRICT dst4) { |
778 | for (int n = 0; n < count; ++n) { |
779 | dst4[0] = src2[0] + mat[3][0]; |
780 | dst4[1] = src2[1] + mat[3][1]; |
781 | dst4[2] = mat[3][2]; |
782 | dst4[3] = 1; |
783 | src2 += 2; |
784 | dst4 += 4; |
785 | } |
786 | } |
787 | |
788 | static void map2_sf(const SkScalar mat[][4], const float* SK_RESTRICT src2, |
789 | int count, float* SK_RESTRICT dst4) { |
790 | const float mat32 = float(mat[3][2]); |
791 | for (int n = 0; n < count; ++n) { |
792 | dst4[0] = float(mat[0][0] * src2[0] + mat[3][0]); |
793 | dst4[1] = float(mat[1][1] * src2[1] + mat[3][1]); |
794 | dst4[2] = mat32; |
795 | dst4[3] = 1; |
796 | src2 += 2; |
797 | dst4 += 4; |
798 | } |
799 | } |
800 | |
801 | static void map2_sd(const SkScalar mat[][4], const double* SK_RESTRICT src2, |
802 | int count, double* SK_RESTRICT dst4) { |
803 | for (int n = 0; n < count; ++n) { |
804 | dst4[0] = mat[0][0] * src2[0] + mat[3][0]; |
805 | dst4[1] = mat[1][1] * src2[1] + mat[3][1]; |
806 | dst4[2] = mat[3][2]; |
807 | dst4[3] = 1; |
808 | src2 += 2; |
809 | dst4 += 4; |
810 | } |
811 | } |
812 | |
813 | static void map2_af(const SkScalar mat[][4], const float* SK_RESTRICT src2, |
814 | int count, float* SK_RESTRICT dst4) { |
815 | SkScalar r; |
816 | for (int n = 0; n < count; ++n) { |
817 | SkScalar sx = src2[0]; |
818 | SkScalar sy = src2[1]; |
819 | r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0]; |
820 | dst4[0] = float(r); |
821 | r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1]; |
822 | dst4[1] = float(r); |
823 | r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2]; |
824 | dst4[2] = float(r); |
825 | dst4[3] = 1; |
826 | src2 += 2; |
827 | dst4 += 4; |
828 | } |
829 | } |
830 | |
831 | static void map2_ad(const SkScalar mat[][4], const double* SK_RESTRICT src2, |
832 | int count, double* SK_RESTRICT dst4) { |
833 | for (int n = 0; n < count; ++n) { |
834 | double sx = src2[0]; |
835 | double sy = src2[1]; |
836 | dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0]; |
837 | dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1]; |
838 | dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2]; |
839 | dst4[3] = 1; |
840 | src2 += 2; |
841 | dst4 += 4; |
842 | } |
843 | } |
844 | |
845 | static void map2_pf(const SkScalar mat[][4], const float* SK_RESTRICT src2, |
846 | int count, float* SK_RESTRICT dst4) { |
847 | SkScalar r; |
848 | for (int n = 0; n < count; ++n) { |
849 | SkScalar sx = src2[0]; |
850 | SkScalar sy = src2[1]; |
851 | for (int i = 0; i < 4; i++) { |
852 | r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i]; |
853 | dst4[i] = float(r); |
854 | } |
855 | src2 += 2; |
856 | dst4 += 4; |
857 | } |
858 | } |
859 | |
860 | static void map2_pd(const SkScalar mat[][4], const double* SK_RESTRICT src2, |
861 | int count, double* SK_RESTRICT dst4) { |
862 | for (int n = 0; n < count; ++n) { |
863 | double sx = src2[0]; |
864 | double sy = src2[1]; |
865 | for (int i = 0; i < 4; i++) { |
866 | dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i]; |
867 | } |
868 | src2 += 2; |
869 | dst4 += 4; |
870 | } |
871 | } |
872 | |
873 | void SkMatrix44::map2(const float src2[], int count, float dst4[]) const { |
874 | static const Map2Procf gProc[] = { |
875 | map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af |
876 | }; |
877 | |
878 | TypeMask mask = this->getType(); |
879 | Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask]; |
880 | proc(fMat, src2, count, dst4); |
881 | } |
882 | |
883 | void SkMatrix44::map2(const double src2[], int count, double dst4[]) const { |
884 | static const Map2Procd gProc[] = { |
885 | map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad |
886 | }; |
887 | |
888 | TypeMask mask = this->getType(); |
889 | Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask]; |
890 | proc(fMat, src2, count, dst4); |
891 | } |
892 | |
893 | bool SkMatrix44::preserves2dAxisAlignment (SkScalar epsilon) const { |
894 | |
895 | // Can't check (mask & kPerspective_Mask) because Z isn't relevant here. |
896 | if (0 != perspX() || 0 != perspY()) return false; |
897 | |
898 | // A matrix with two non-zeroish values in any of the upper right |
899 | // rows or columns will skew. If only one value in each row or |
900 | // column is non-zeroish, we get a scale plus perhaps a 90-degree |
901 | // rotation. |
902 | int col0 = 0; |
903 | int col1 = 0; |
904 | int row0 = 0; |
905 | int row1 = 0; |
906 | |
907 | // Must test against epsilon, not 0, because we can get values |
908 | // around 6e-17 in the matrix that "should" be 0. |
909 | |
910 | if (SkScalarAbs(fMat[0][0]) > epsilon) { |
911 | col0++; |
912 | row0++; |
913 | } |
914 | if (SkScalarAbs(fMat[0][1]) > epsilon) { |
915 | col1++; |
916 | row0++; |
917 | } |
918 | if (SkScalarAbs(fMat[1][0]) > epsilon) { |
919 | col0++; |
920 | row1++; |
921 | } |
922 | if (SkScalarAbs(fMat[1][1]) > epsilon) { |
923 | col1++; |
924 | row1++; |
925 | } |
926 | if (col0 > 1 || col1 > 1 || row0 > 1 || row1 > 1) { |
927 | return false; |
928 | } |
929 | |
930 | return true; |
931 | } |
932 | |
933 | /////////////////////////////////////////////////////////////////////////////// |
934 | |
935 | void SkMatrix44::dump() const { |
936 | static const char* format = "|%g %g %g %g|\n" |
937 | "|%g %g %g %g|\n" |
938 | "|%g %g %g %g|\n" |
939 | "|%g %g %g %g|\n" ; |
940 | SkDebugf(format, |
941 | fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0], |
942 | fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1], |
943 | fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2], |
944 | fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]); |
945 | } |
946 | |
947 | /////////////////////////////////////////////////////////////////////////////// |
948 | |
949 | static void initFromMatrix(SkScalar dst[4][4], const SkMatrix& src) { |
950 | dst[0][0] = src[SkMatrix::kMScaleX]; |
951 | dst[1][0] = src[SkMatrix::kMSkewX]; |
952 | dst[2][0] = 0; |
953 | dst[3][0] = src[SkMatrix::kMTransX]; |
954 | dst[0][1] = src[SkMatrix::kMSkewY]; |
955 | dst[1][1] = src[SkMatrix::kMScaleY]; |
956 | dst[2][1] = 0; |
957 | dst[3][1] = src[SkMatrix::kMTransY]; |
958 | dst[0][2] = 0; |
959 | dst[1][2] = 0; |
960 | dst[2][2] = 1; |
961 | dst[3][2] = 0; |
962 | dst[0][3] = src[SkMatrix::kMPersp0]; |
963 | dst[1][3] = src[SkMatrix::kMPersp1]; |
964 | dst[2][3] = 0; |
965 | dst[3][3] = src[SkMatrix::kMPersp2]; |
966 | } |
967 | |
968 | SkMatrix44::SkMatrix44(const SkMatrix& src) { |
969 | this->operator=(src); |
970 | } |
971 | |
972 | SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) { |
973 | initFromMatrix(fMat, src); |
974 | |
975 | if (src.isIdentity()) { |
976 | this->setTypeMask(kIdentity_Mask); |
977 | } else { |
978 | this->recomputeTypeMask(); |
979 | } |
980 | return *this; |
981 | } |
982 | |
983 | SkMatrix44::operator SkMatrix() const { |
984 | SkMatrix dst; |
985 | |
986 | dst[SkMatrix::kMScaleX] = fMat[0][0]; |
987 | dst[SkMatrix::kMSkewX] = fMat[1][0]; |
988 | dst[SkMatrix::kMTransX] = fMat[3][0]; |
989 | |
990 | dst[SkMatrix::kMSkewY] = fMat[0][1]; |
991 | dst[SkMatrix::kMScaleY] = fMat[1][1]; |
992 | dst[SkMatrix::kMTransY] = fMat[3][1]; |
993 | |
994 | dst[SkMatrix::kMPersp0] = fMat[0][3]; |
995 | dst[SkMatrix::kMPersp1] = fMat[1][3]; |
996 | dst[SkMatrix::kMPersp2] = fMat[3][3]; |
997 | |
998 | return dst; |
999 | } |
1000 | |