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