blob: 1ebc0b4e2aefbe8b92011e1e751b8baec537cfc6 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
bsalomon@google.comc6cf7232011-02-17 16:43:10 +000017
18#ifndef GrMatrix_DEFINED
19#define GrMatrix_DEFINED
20
21#include "GrPoint.h"
22
23struct GrRect;
24
25/*
26 * 3x3 matrix
27 */
28class GrMatrix {
29public:
30 static const GrMatrix& I() {
31 static const GrMatrix I = GrMatrix(GR_Scalar1, 0, 0,
32 0, GR_Scalar1, 0,
33 0, 0, gRESCALE);
34 return I;
35 };
36 static const GrMatrix& InvalidMatrix() {
37 static const GrMatrix INV =
38 GrMatrix(GR_ScalarMax, GR_ScalarMax, GR_ScalarMax,
39 GR_ScalarMax, GR_ScalarMax, GR_ScalarMax,
40 GR_ScalarMax, GR_ScalarMax, GR_ScalarMax);
41 return INV;
42 }
43 /**
44 * Handy index constants
45 */
46 enum {
47 kScaleX,
48 kSkewX,
49 kTransX,
50 kSkewY,
51 kScaleY,
52 kTransY,
53 kPersp0,
54 kPersp1,
55 kPersp2
56 };
57
58 /**
59 * Create an uninitialized matrix
60 */
61 GrMatrix() {
62 fTypeMask = 0;
63 }
64
65 /**
66 * Create a matrix from an array of values
67 * @param values row-major array of matrix components
68 */
69 explicit GrMatrix(const GrScalar values[]) {
70 setToArray(values);
71 }
72
73 /**
74 * Create a matrix from values
75 * @param scaleX (0,0) matrix element
76 * @param skewX (0,1) matrix element
77 * @param transX (0,2) matrix element
78 * @param skewY (1,0) matrix element
79 * @param scaleY (1,1) matrix element
80 * @param transY (1,2) matrix element
81 * @param persp0 (2,0) matrix element
82 * @param persp1 (2,1) matrix element
83 * @param persp2 (2,2) matrix element
84 */
85 GrMatrix(GrScalar scaleX,
86 GrScalar skewX,
87 GrScalar transX,
88 GrScalar skewY,
89 GrScalar scaleY,
90 GrScalar transY,
91 GrScalar persp0,
92 GrScalar persp1,
93 GrScalar persp2) {
94 setAll(scaleX, skewX, transX,
95 skewY, scaleY, transY,
96 persp0, persp1, persp2);
97 }
98
99 /**
100 * access matrix component
101 * @return matrix component value
102 */
103 const GrScalar& operator[] (int idx) const {
104 GrAssert((unsigned)idx < 9);
105 return fM[idx];
106 }
107
108 /**
109 * Set a matrix from an array of values
110 * @param values row-major array of matrix components
111 */
112 void setToArray(const GrScalar values[]) {
113 for (int i = 0; i < 9; ++i) {
114 fM[i] = values[i];
115 }
116 this->computeTypeMask();
117 }
118
119 /**
120 * Create a matrix from values
121 * @param scaleX (0,0) matrix element
122 * @param skewX (0,1) matrix element
123 * @param transX (0,2) matrix element
124 * @param skewY (1,0) matrix element
125 * @param scaleY (1,1) matrix element
126 * @param transY (1,2) matrix element
127 * @param persp0 (2,0) matrix element
128 * @param persp1 (2,1) matrix element
129 * @param persp2 (2,2) matrix element
130 */
131 void setAll(GrScalar scaleX,
132 GrScalar skewX,
133 GrScalar transX,
134 GrScalar skewY,
135 GrScalar scaleY,
136 GrScalar transY,
137 GrScalar persp0,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000138 GrScalar persp1,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000139 GrScalar persp2) {
140 fM[kScaleX] = scaleX;
141 fM[kSkewX] = skewX;
142 fM[kTransX] = transX;
143 fM[kSkewY] = skewY;
144 fM[kScaleY] = scaleY;
145 fM[kTransY] = transY;
146 fM[kPersp0] = persp0;
147 fM[kPersp1] = persp1;
148 fM[kPersp2] = persp2;
149
150 this->computeTypeMask();
151 }
152
153 /**
154 * set matrix component
155 * @param idx index of component to set
156 * @param value value to set component to
157 */
158 inline void set(int idx, GrScalar value);
159
160 /**
161 * make this matrix an identity matrix
162 */
163 void setIdentity();
164
165 /**
166 * overwrite entire matrix to be a translation matrix
167 * @param dx amount to translate by in x
168 * @param dy amount to translate by in y
169 */
170 void setTranslate(GrScalar dx, GrScalar dy);
171
172 /**
173 * overwrite entire matrix to be a scaling matrix
174 * @param sx x scale factor
175 * @param sy y scale factor
176 */
177 void setScale(GrScalar sx, GrScalar sy);
178
179 /**
180 * overwrite entire matrix to be a skew matrix
181 * @param skx x skew factor
182 * @param sky y skew factor
183 */
184 void setSkew(GrScalar skx, GrScalar sky);
185
186 /**
187 * set this matrix to be a concantenation of two
188 * matrices (a*b). Either a, b, or both can be this matrix.
189 * @param a first matrix to multiply
190 * @param b second matrix to multiply
191 */
192 void setConcat(const GrMatrix& a, const GrMatrix& b);
193
194 /**
195 * Set this matrix to this*m
196 * @param m matrix to concatenate
197 */
198 void preConcat(const GrMatrix& m);
199
200 /**
201 * Set this matrix to m*this
202 * @param m matrix to concatenate
203 */
204 void postConcat(const GrMatrix& m);
205
206 /**
207 * Compute the inverse of this matrix, and return true if it is invertible,
208 * or false if not.
209 *
210 * If inverted is not null, and the matrix is invertible, then the inverse
211 * is written into it. If the matrix is not invertible (this method returns
212 * false) then inverted is left unchanged.
213 */
214 bool invert(GrMatrix* inverted) const;
215
216 /**
217 * Transforms a point by the matrix
218 *
219 * @param src the point to transform
220 * @return the transformed point
221 */
222 GrPoint mapPoint(const GrPoint& src) const {
223 GrPoint result;
224 (this->*gMapProcs[fTypeMask])(&result, &src, 1);
225 return result;
226 }
227
228 /**
229 * Transforms an array of points by the matrix.
230 *
231 * @param dstPts the array to write transformed points into
232 * @param srcPts the array of points to transform
233 @ @param count the number of points to transform
234 */
235 void mapPoints(GrPoint dstPts[],
236 const GrPoint srcPts[],
237 uint32_t count) const {
238 (this->*gMapProcs[fTypeMask])(dstPts, srcPts, count);
239 }
240
241 /**
242 * Transforms pts with arbitrary stride in place.
243 *
244 * @param start pointer to first point to transform
245 * @param stride distance in bytes between consecutive points
246 @ @param count the number of points to transform
247 */
248 void mapPointsWithStride(GrPoint* start,
249 size_t stride,
250 uint32_t count) const {
251 for (uint32_t i = 0; i < count; ++i) {
252 this->mapPoints(start, start, 1);
253 start = (GrPoint*)((intptr_t)start + stride);
254 }
255 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000256
257 /**
258 * Transforms a vector by the matrix. Doesn't handle cases when a
259 * homogeneous vector maps to a point (i.e. perspective transform).
260 * In this case the desired answer is dependent on where the tail of
261 * the vector is in space.
262 */
263 void mapVec(GrVec* vec) {
264 GrAssert(!this->hasPerspective());
265 if (!this->isIdentity()) {
266 GrScalar x = vec->fX;
267 vec->fX = (*this)[kScaleX] * x + (*this)[kSkewX] * vec->fY;
268 vec->fY = (*this)[kSkewY ] * x + (*this)[kScaleY] * vec->fY;
269 }
270 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000271
272 /**
273 * Transform the 4 corners of the src rect, and return the bounding rect
274 * in the dst rect. Note: src and dst may point to the same memory.
275 */
276 void mapRect(GrRect* dst, const GrRect& src) const;
277
278 /**
279 * Transform the 4 corners of the rect, and return their bounds in the rect
280 */
281 void mapRect(GrRect* rect) const {
282 this->mapRect(rect, *rect);
283 }
284
285 /**
286 * Checks if matrix is a perspective matrix.
287 * @return true if third row is not (0, 0, 1)
288 */
289 bool hasPerspective() const;
290
291 /**
292 * Checks whether matrix is identity
293 * @return true if matrix is idenity
294 */
295 bool isIdentity() const;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000296
297 /**
298 * Do axis-aligned lines stay axis aligned? May do 90 degree rotation / mirroring.
299 */
300 bool preservesAxisAlignment() const;
301
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000302 /**
303 * Calculates the maximum stretching factor of the matrix. Only defined if
304 * the matrix does not have perspective.
305 *
306 * @return maximum strecthing factor or negative if matrix has perspective.
307 */
308 GrScalar getMaxStretch() const;
309
310 /**
311 * Checks for matrix equality. Test is element-by-element equality,
312 * not a homogeneous test.
313 * @return true if matrices are equal, false otherwise
314 */
315 bool operator == (const GrMatrix& m) const;
316
317 /**
318 * Checks for matrix inequality. Test is element-by-element inequality,
319 * not a homogeneous test.
320 * @return true if matrices are not equal, false otherwise
321 */
322 bool operator != (const GrMatrix& m) const;
323
324 static void UnitTest();
325
326private:
327 static const GrScalar gRESCALE;
328
329 void computeTypeMask() {
330 fTypeMask = 0;
331 if (0 != fM[kPersp0] || 0 != fM[kPersp1] || gRESCALE != fM[kPersp2]) {
332 fTypeMask |= kPerspective_TypeBit;
333 }
334 if (GR_Scalar1 != fM[kScaleX] || GR_Scalar1 != fM[kScaleY]) {
335 fTypeMask |= kScale_TypeBit;
336 if (0 == fM[kScaleX] && 0 == fM[kScaleY]) {
337 fTypeMask |= kZeroScale_TypeBit;
338 }
339 }
340 if (0 != fM[kSkewX] || 0 != fM[kSkewY]) {
341 fTypeMask |= kSkew_TypeBit;
342 }
343 if (0 != fM[kTransX] || 0 != fM[kTransY]) {
344 fTypeMask |= kTranslate_TypeBit;
345 }
346 }
347
348
349 double determinant() const;
350
351 enum TypeBits {
352 kScale_TypeBit = 1 << 0, // set if scales are not both 1
353 kTranslate_TypeBit = 1 << 1, // set if translates are not both 0
354 kSkew_TypeBit = 1 << 2, // set if skews are not both 0
355 kPerspective_TypeBit = 1 << 3, // set if perspective
356 kZeroScale_TypeBit = 1 << 4, // set if scales are both zero
357 };
358
359 void mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const;
360 void mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const;
361 void mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
362 void mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
363 void mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const;
364 void mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const;
365 void mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
366 void mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const;
367 void mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const;
368 void mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const;
369 void mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
370 void mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const;
371 void mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
372
373 void mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const;
374
375 typedef void (GrMatrix::*MapProc) (GrPoint* dst, const GrPoint* src, uint32_t count) const;
376 static const MapProc gMapProcs[];
377
378 int fTypeMask;
379
380 GrScalar fM[9];
381};
382
383void GrMatrix::set(int idx, GrScalar value) {
384 GrAssert((unsigned)idx < 9);
385 fM[idx] = value;
386 if (idx > 5) {
387 if (0 != fM[kPersp0] || 0 != fM[kPersp1] ||
388 gRESCALE != fM[kPersp2]) {
389 fTypeMask |= kPerspective_TypeBit;
390 } else {
391 fTypeMask &= ~kPerspective_TypeBit;
392 }
393 } else if (!(idx % 4)) {
394 if ((GR_Scalar1 == fM[kScaleX] && GR_Scalar1 == fM[kScaleY])) {
395 fTypeMask &= ~kScale_TypeBit;
396 fTypeMask &= ~kZeroScale_TypeBit;
397 } else {
398 fTypeMask |= kScale_TypeBit;
399 if ((0 == fM[kScaleX] && 0 == fM[kScaleY])) {
400 fTypeMask |= kZeroScale_TypeBit;
401 } else {
402 fTypeMask &= ~kZeroScale_TypeBit;
403 }
404 }
405 } else if (2 == (idx % 3)) {
406 if (0 != fM[kTransX] || 0 != fM[kTransY]) {
407 fTypeMask |= kTranslate_TypeBit;
408 } else {
409 fTypeMask &= ~kTranslate_TypeBit;
410 }
411 } else {
412 if (0 != fM[kSkewX] || 0 != fM[kSkewY]) {
413 fTypeMask |= kSkew_TypeBit;
414 } else {
415 fTypeMask &= ~kSkew_TypeBit;
416 }
417 }
418}
419
reed@google.comac10a2d2010-12-22 21:39:39 +0000420#endif