OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkMatrix44_DEFINED | 8 #include "../core/SkMatrix44.h" |
9 #define SkMatrix44_DEFINED | |
10 | |
11 #include "SkMatrix.h" | |
12 #include "SkScalar.h" | |
13 | |
14 #ifdef SK_MSCALAR_IS_DOUBLE | |
15 #ifdef SK_MSCALAR_IS_FLOAT | |
16 #error "can't define MSCALAR both as DOUBLE and FLOAT" | |
17 #endif | |
18 typedef double SkMScalar; | |
19 | |
20 static inline double SkFloatToMScalar(float x) { | |
21 return static_cast<double>(x); | |
22 } | |
23 static inline float SkMScalarToFloat(double x) { | |
24 return static_cast<float>(x); | |
25 } | |
26 static inline double SkDoubleToMScalar(double x) { | |
27 return x; | |
28 } | |
29 static inline double SkMScalarToDouble(double x) { | |
30 return x; | |
31 } | |
32 static inline double SkMScalarAbs(double x) { | |
33 return fabs(x); | |
34 } | |
35 static const SkMScalar SK_MScalarPI = 3.141592653589793; | |
36 | |
37 #define SkMScalarFloor(x) sk_double_floor(x) | |
38 #define SkMScalarCeil(x) sk_double_ceil(x) | |
39 #define SkMScalarRound(x) sk_double_round(x) | |
40 | |
41 #define SkMScalarFloorToInt(x) sk_double_floor2int(x) | |
42 #define SkMScalarCeilToInt(x) sk_double_ceil2int(x) | |
43 #define SkMScalarRoundToInt(x) sk_double_round2int(x) | |
44 | |
45 | |
46 #elif defined SK_MSCALAR_IS_FLOAT | |
47 #ifdef SK_MSCALAR_IS_DOUBLE | |
48 #error "can't define MSCALAR both as DOUBLE and FLOAT" | |
49 #endif | |
50 typedef float SkMScalar; | |
51 | |
52 static inline float SkFloatToMScalar(float x) { | |
53 return x; | |
54 } | |
55 static inline float SkMScalarToFloat(float x) { | |
56 return x; | |
57 } | |
58 static inline float SkDoubleToMScalar(double x) { | |
59 return static_cast<float>(x); | |
60 } | |
61 static inline double SkMScalarToDouble(float x) { | |
62 return static_cast<double>(x); | |
63 } | |
64 static inline float SkMScalarAbs(float x) { | |
65 return sk_float_abs(x); | |
66 } | |
67 static const SkMScalar SK_MScalarPI = 3.14159265f; | |
68 | |
69 #define SkMScalarFloor(x) sk_float_floor(x) | |
70 #define SkMScalarCeil(x) sk_float_ceil(x) | |
71 #define SkMScalarRound(x) sk_float_round(x) | |
72 | |
73 #define SkMScalarFloorToInt(x) sk_float_floor2int(x) | |
74 #define SkMScalarCeilToInt(x) sk_float_ceil2int(x) | |
75 #define SkMScalarRoundToInt(x) sk_float_round2int(x) | |
76 | |
77 #endif | |
78 | |
79 #define SkIntToMScalar(n) static_cast<SkMScalar>(n) | |
80 | |
81 #define SkMScalarToScalar(x) SkMScalarToFloat(x) | |
82 #define SkScalarToMScalar(x) SkFloatToMScalar(x) | |
83 | |
84 static const SkMScalar SK_MScalar1 = 1; | |
85 | |
86 /////////////////////////////////////////////////////////////////////////////// | |
87 | |
88 struct SkVector4 { | |
89 SkScalar fData[4]; | |
90 | |
91 SkVector4() { | |
92 this->set(0, 0, 0, 1); | |
93 } | |
94 SkVector4(const SkVector4& src) { | |
95 memcpy(fData, src.fData, sizeof(fData)); | |
96 } | |
97 SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { | |
98 fData[0] = x; | |
99 fData[1] = y; | |
100 fData[2] = z; | |
101 fData[3] = w; | |
102 } | |
103 | |
104 SkVector4& operator=(const SkVector4& src) { | |
105 memcpy(fData, src.fData, sizeof(fData)); | |
106 return *this; | |
107 } | |
108 | |
109 bool operator==(const SkVector4& v) { | |
110 return fData[0] == v.fData[0] && fData[1] == v.fData[1] && | |
111 fData[2] == v.fData[2] && fData[3] == v.fData[3]; | |
112 } | |
113 bool operator!=(const SkVector4& v) { | |
114 return !(*this == v); | |
115 } | |
116 bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { | |
117 return fData[0] == x && fData[1] == y && | |
118 fData[2] == z && fData[3] == w; | |
119 } | |
120 | |
121 void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { | |
122 fData[0] = x; | |
123 fData[1] = y; | |
124 fData[2] = z; | |
125 fData[3] = w; | |
126 } | |
127 }; | |
128 | |
129 class SK_API SkMatrix44 { | |
130 public: | |
131 | |
132 enum Uninitialized_Constructor { | |
133 kUninitialized_Constructor | |
134 }; | |
135 enum Identity_Constructor { | |
136 kIdentity_Constructor | |
137 }; | |
138 | |
139 SkMatrix44(Uninitialized_Constructor) { } | |
140 SkMatrix44(Identity_Constructor) { this->setIdentity(); } | |
141 | |
142 SK_ATTR_DEPRECATED("use the constructors that take an enum") | |
143 SkMatrix44() { this->setIdentity(); } | |
144 | |
145 SkMatrix44(const SkMatrix44& src) { | |
146 memcpy(fMat, src.fMat, sizeof(fMat)); | |
147 fTypeMask = src.fTypeMask; | |
148 } | |
149 | |
150 SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) { | |
151 this->setConcat(a, b); | |
152 } | |
153 | |
154 SkMatrix44& operator=(const SkMatrix44& src) { | |
155 if (&src != this) { | |
156 memcpy(fMat, src.fMat, sizeof(fMat)); | |
157 fTypeMask = src.fTypeMask; | |
158 } | |
159 return *this; | |
160 } | |
161 | |
162 bool operator==(const SkMatrix44& other) const; | |
163 bool operator!=(const SkMatrix44& other) const { | |
164 return !(other == *this); | |
165 } | |
166 | |
167 /* When converting from SkMatrix44 to SkMatrix, the third row and | |
168 * column is dropped. When converting from SkMatrix to SkMatrix44 | |
169 * the third row and column remain as identity: | |
170 * [ a b c ] [ a b 0 c ] | |
171 * [ d e f ] -> [ d e 0 f ] | |
172 * [ g h i ] [ 0 0 1 0 ] | |
173 * [ g h 0 i ] | |
174 */ | |
175 SkMatrix44(const SkMatrix&); | |
176 SkMatrix44& operator=(const SkMatrix& src); | |
177 operator SkMatrix() const; | |
178 | |
179 /** | |
180 * Return a reference to a const identity matrix | |
181 */ | |
182 static const SkMatrix44& I(); | |
183 | |
184 enum TypeMask { | |
185 kIdentity_Mask = 0, | |
186 kTranslate_Mask = 0x01, //!< set if the matrix has translation | |
187 kScale_Mask = 0x02, //!< set if the matrix has any scale != 1 | |
188 kAffine_Mask = 0x04, //!< set if the matrix skews or rotates | |
189 kPerspective_Mask = 0x08 //!< set if the matrix is in perspective | |
190 }; | |
191 | |
192 /** | |
193 * Returns a bitfield describing the transformations the matrix may | |
194 * perform. The bitfield is computed conservatively, so it may include | |
195 * false positives. For example, when kPerspective_Mask is true, all | |
196 * other bits may be set to true even in the case of a pure perspective | |
197 * transform. | |
198 */ | |
199 inline TypeMask getType() const { | |
200 if (fTypeMask & kUnknown_Mask) { | |
201 fTypeMask = this->computeTypeMask(); | |
202 } | |
203 SkASSERT(!(fTypeMask & kUnknown_Mask)); | |
204 return (TypeMask)fTypeMask; | |
205 } | |
206 | |
207 /** | |
208 * Return true if the matrix is identity. | |
209 */ | |
210 inline bool isIdentity() const { | |
211 return kIdentity_Mask == this->getType(); | |
212 } | |
213 | |
214 /** | |
215 * Return true if the matrix contains translate or is identity. | |
216 */ | |
217 inline bool isTranslate() const { | |
218 return !(this->getType() & ~kTranslate_Mask); | |
219 } | |
220 | |
221 /** | |
222 * Return true if the matrix only contains scale or translate or is identit
y. | |
223 */ | |
224 inline bool isScaleTranslate() const { | |
225 return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); | |
226 } | |
227 | |
228 /** | |
229 * Returns true if the matrix only contains scale or is identity. | |
230 */ | |
231 inline bool isScale() const { | |
232 return !(this->getType() & ~kScale_Mask); | |
233 } | |
234 | |
235 inline bool hasPerspective() const { | |
236 return SkToBool(this->getType() & kPerspective_Mask); | |
237 } | |
238 | |
239 void setIdentity(); | |
240 inline void reset() { this->setIdentity();} | |
241 | |
242 /** | |
243 * get a value from the matrix. The row,col parameters work as follows: | |
244 * (0, 0) scale-x | |
245 * (0, 3) translate-x | |
246 * (3, 0) perspective-x | |
247 */ | |
248 inline SkMScalar get(int row, int col) const { | |
249 SkASSERT((unsigned)row <= 3); | |
250 SkASSERT((unsigned)col <= 3); | |
251 return fMat[col][row]; | |
252 } | |
253 | |
254 /** | |
255 * set a value in the matrix. The row,col parameters work as follows: | |
256 * (0, 0) scale-x | |
257 * (0, 3) translate-x | |
258 * (3, 0) perspective-x | |
259 */ | |
260 inline void set(int row, int col, SkMScalar value) { | |
261 SkASSERT((unsigned)row <= 3); | |
262 SkASSERT((unsigned)col <= 3); | |
263 fMat[col][row] = value; | |
264 this->dirtyTypeMask(); | |
265 } | |
266 | |
267 inline double getDouble(int row, int col) const { | |
268 return SkMScalarToDouble(this->get(row, col)); | |
269 } | |
270 inline void setDouble(int row, int col, double value) { | |
271 this->set(row, col, SkDoubleToMScalar(value)); | |
272 } | |
273 inline float getFloat(int row, int col) const { | |
274 return SkMScalarToFloat(this->get(row, col)); | |
275 } | |
276 inline void setFloat(int row, int col, float value) { | |
277 this->set(row, col, SkFloatToMScalar(value)); | |
278 } | |
279 | |
280 /** These methods allow one to efficiently read matrix entries into an | |
281 * array. The given array must have room for exactly 16 entries. Whenever | |
282 * possible, they will try to use memcpy rather than an entry-by-entry | |
283 * copy. | |
284 */ | |
285 void asColMajorf(float[]) const; | |
286 void asColMajord(double[]) const; | |
287 void asRowMajorf(float[]) const; | |
288 void asRowMajord(double[]) const; | |
289 | |
290 /** These methods allow one to efficiently set all matrix entries from an | |
291 * array. The given array must have room for exactly 16 entries. Whenever | |
292 * possible, they will try to use memcpy rather than an entry-by-entry | |
293 * copy. | |
294 */ | |
295 void setColMajorf(const float[]); | |
296 void setColMajord(const double[]); | |
297 void setRowMajorf(const float[]); | |
298 void setRowMajord(const double[]); | |
299 | |
300 #ifdef SK_MSCALAR_IS_FLOAT | |
301 void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); } | |
302 void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); } | |
303 #else | |
304 void setColMajor(const SkMScalar data[]) { this->setColMajord(data); } | |
305 void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); } | |
306 #endif | |
307 | |
308 /* This sets the top-left of the matrix and clears the translation and | |
309 * perspective components (with [3][3] set to 1). */ | |
310 void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02, | |
311 SkMScalar m10, SkMScalar m11, SkMScalar m12, | |
312 SkMScalar m20, SkMScalar m21, SkMScalar m22); | |
313 | |
314 void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); | |
315 void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); | |
316 void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); | |
317 | |
318 void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); | |
319 void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); | |
320 void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); | |
321 | |
322 inline void setScale(SkMScalar scale) { | |
323 this->setScale(scale, scale, scale); | |
324 } | |
325 inline void preScale(SkMScalar scale) { | |
326 this->preScale(scale, scale, scale); | |
327 } | |
328 inline void postScale(SkMScalar scale) { | |
329 this->postScale(scale, scale, scale); | |
330 } | |
331 | |
332 void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z, | |
333 SkMScalar degrees) { | |
334 this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180); | |
335 } | |
336 | |
337 /** Rotate about the vector [x,y,z]. If that vector is not unit-length, | |
338 it will be automatically resized. | |
339 */ | |
340 void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z, | |
341 SkMScalar radians); | |
342 /** Rotate about the vector [x,y,z]. Does not check the length of the | |
343 vector, assuming it is unit-length. | |
344 */ | |
345 void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z, | |
346 SkMScalar radians); | |
347 | |
348 void setConcat(const SkMatrix44& a, const SkMatrix44& b); | |
349 inline void preConcat(const SkMatrix44& m) { | |
350 this->setConcat(*this, m); | |
351 } | |
352 inline void postConcat(const SkMatrix44& m) { | |
353 this->setConcat(m, *this); | |
354 } | |
355 | |
356 friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) { | |
357 return SkMatrix44(a, b); | |
358 } | |
359 | |
360 /** If this is invertible, return that in inverse and return true. If it is | |
361 not invertible, return false and leave the inverse parameter in an | |
362 unspecified state. | |
363 */ | |
364 bool invert(SkMatrix44* inverse) const; | |
365 | |
366 /** Transpose this matrix in place. */ | |
367 void transpose(); | |
368 | |
369 /** Apply the matrix to the src vector, returning the new vector in dst. | |
370 It is legal for src and dst to point to the same memory. | |
371 */ | |
372 void mapScalars(const SkScalar src[4], SkScalar dst[4]) const; | |
373 inline void mapScalars(SkScalar vec[4]) const { | |
374 this->mapScalars(vec, vec); | |
375 } | |
376 | |
377 SK_ATTR_DEPRECATED("use mapScalars") | |
378 void map(const SkScalar src[4], SkScalar dst[4]) const { | |
379 this->mapScalars(src, dst); | |
380 } | |
381 | |
382 SK_ATTR_DEPRECATED("use mapScalars") | |
383 void map(SkScalar vec[4]) const { | |
384 this->mapScalars(vec, vec); | |
385 } | |
386 | |
387 #ifdef SK_MSCALAR_IS_DOUBLE | |
388 void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const; | |
389 #elif defined SK_MSCALAR_IS_FLOAT | |
390 inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const { | |
391 this->mapScalars(src, dst); | |
392 } | |
393 #endif | |
394 inline void mapMScalars(SkMScalar vec[4]) const { | |
395 this->mapMScalars(vec, vec); | |
396 } | |
397 | |
398 friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) { | |
399 SkVector4 dst; | |
400 m.mapScalars(src.fData, dst.fData); | |
401 return dst; | |
402 } | |
403 | |
404 /** | |
405 * map an array of [x, y, 0, 1] through the matrix, returning an array | |
406 * of [x', y', z', w']. | |
407 * | |
408 * @param src2 array of [x, y] pairs, with implied z=0 and w=1 | |
409 * @param count number of [x, y] pairs in src2 | |
410 * @param dst4 array of [x', y', z', w'] quads as the output. | |
411 */ | |
412 void map2(const float src2[], int count, float dst4[]) const; | |
413 void map2(const double src2[], int count, double dst4[]) const; | |
414 | |
415 /** Returns true if transformating an axis-aligned square in 2d by this matr
ix | |
416 will produce another 2d axis-aligned square; typically means the matrix | |
417 is a scale with perhaps a 90-degree rotation. A 3d rotation through 90 | |
418 degrees into a perpendicular plane collapses a square to a line, but | |
419 is still considered to be axis-aligned. | |
420 | |
421 By default, tolerates very slight error due to float imprecisions; | |
422 a 90-degree rotation can still end up with 10^-17 of | |
423 "non-axis-aligned" result. | |
424 */ | |
425 bool preserves2dAxisAlignment(SkMScalar epsilon = SK_ScalarNearlyZero) const
; | |
426 | |
427 void dump() const; | |
428 | |
429 double determinant() const; | |
430 | |
431 private: | |
432 SkMScalar fMat[4][4]; | |
433 mutable unsigned fTypeMask; | |
434 | |
435 enum { | |
436 kUnknown_Mask = 0x80, | |
437 | |
438 kAllPublic_Masks = 0xF | |
439 }; | |
440 | |
441 SkMScalar transX() const { return fMat[3][0]; } | |
442 SkMScalar transY() const { return fMat[3][1]; } | |
443 SkMScalar transZ() const { return fMat[3][2]; } | |
444 | |
445 SkMScalar scaleX() const { return fMat[0][0]; } | |
446 SkMScalar scaleY() const { return fMat[1][1]; } | |
447 SkMScalar scaleZ() const { return fMat[2][2]; } | |
448 | |
449 SkMScalar perspX() const { return fMat[0][3]; } | |
450 SkMScalar perspY() const { return fMat[1][3]; } | |
451 SkMScalar perspZ() const { return fMat[2][3]; } | |
452 | |
453 int computeTypeMask() const; | |
454 | |
455 inline void dirtyTypeMask() { | |
456 fTypeMask = kUnknown_Mask; | |
457 } | |
458 | |
459 inline void setTypeMask(int mask) { | |
460 SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask)); | |
461 fTypeMask = mask; | |
462 } | |
463 | |
464 /** | |
465 * Does not take the time to 'compute' the typemask. Only returns true if | |
466 * we already know that this matrix is identity. | |
467 */ | |
468 inline bool isTriviallyIdentity() const { | |
469 return 0 == fTypeMask; | |
470 } | |
471 }; | |
472 | |
473 #endif | |
OLD | NEW |