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