blob: 9a2e6600156f1b421bc66ab50d6de6e9d8edc856 [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,
138 GrScalar persp1,
139 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 }
256
257 /**
258 * Transform the 4 corners of the src rect, and return the bounding rect
259 * in the dst rect. Note: src and dst may point to the same memory.
260 */
261 void mapRect(GrRect* dst, const GrRect& src) const;
262
263 /**
264 * Transform the 4 corners of the rect, and return their bounds in the rect
265 */
266 void mapRect(GrRect* rect) const {
267 this->mapRect(rect, *rect);
268 }
269
270 /**
271 * Checks if matrix is a perspective matrix.
272 * @return true if third row is not (0, 0, 1)
273 */
274 bool hasPerspective() const;
275
276 /**
277 * Checks whether matrix is identity
278 * @return true if matrix is idenity
279 */
280 bool isIdentity() const;
281
282 /**
283 * Calculates the maximum stretching factor of the matrix. Only defined if
284 * the matrix does not have perspective.
285 *
286 * @return maximum strecthing factor or negative if matrix has perspective.
287 */
288 GrScalar getMaxStretch() const;
289
290 /**
291 * Checks for matrix equality. Test is element-by-element equality,
292 * not a homogeneous test.
293 * @return true if matrices are equal, false otherwise
294 */
295 bool operator == (const GrMatrix& m) const;
296
297 /**
298 * Checks for matrix inequality. Test is element-by-element inequality,
299 * not a homogeneous test.
300 * @return true if matrices are not equal, false otherwise
301 */
302 bool operator != (const GrMatrix& m) const;
303
304 static void UnitTest();
305
306private:
307 static const GrScalar gRESCALE;
308
309 void computeTypeMask() {
310 fTypeMask = 0;
311 if (0 != fM[kPersp0] || 0 != fM[kPersp1] || gRESCALE != fM[kPersp2]) {
312 fTypeMask |= kPerspective_TypeBit;
313 }
314 if (GR_Scalar1 != fM[kScaleX] || GR_Scalar1 != fM[kScaleY]) {
315 fTypeMask |= kScale_TypeBit;
316 if (0 == fM[kScaleX] && 0 == fM[kScaleY]) {
317 fTypeMask |= kZeroScale_TypeBit;
318 }
319 }
320 if (0 != fM[kSkewX] || 0 != fM[kSkewY]) {
321 fTypeMask |= kSkew_TypeBit;
322 }
323 if (0 != fM[kTransX] || 0 != fM[kTransY]) {
324 fTypeMask |= kTranslate_TypeBit;
325 }
326 }
327
328
329 double determinant() const;
330
331 enum TypeBits {
332 kScale_TypeBit = 1 << 0, // set if scales are not both 1
333 kTranslate_TypeBit = 1 << 1, // set if translates are not both 0
334 kSkew_TypeBit = 1 << 2, // set if skews are not both 0
335 kPerspective_TypeBit = 1 << 3, // set if perspective
336 kZeroScale_TypeBit = 1 << 4, // set if scales are both zero
337 };
338
339 void mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const;
340 void mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const;
341 void mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
342 void mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
343 void mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const;
344 void mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const;
345 void mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
346 void mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const;
347 void mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const;
348 void mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const;
349 void mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
350 void mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const;
351 void mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const;
352
353 void mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const;
354
355 typedef void (GrMatrix::*MapProc) (GrPoint* dst, const GrPoint* src, uint32_t count) const;
356 static const MapProc gMapProcs[];
357
358 int fTypeMask;
359
360 GrScalar fM[9];
361};
362
363void GrMatrix::set(int idx, GrScalar value) {
364 GrAssert((unsigned)idx < 9);
365 fM[idx] = value;
366 if (idx > 5) {
367 if (0 != fM[kPersp0] || 0 != fM[kPersp1] ||
368 gRESCALE != fM[kPersp2]) {
369 fTypeMask |= kPerspective_TypeBit;
370 } else {
371 fTypeMask &= ~kPerspective_TypeBit;
372 }
373 } else if (!(idx % 4)) {
374 if ((GR_Scalar1 == fM[kScaleX] && GR_Scalar1 == fM[kScaleY])) {
375 fTypeMask &= ~kScale_TypeBit;
376 fTypeMask &= ~kZeroScale_TypeBit;
377 } else {
378 fTypeMask |= kScale_TypeBit;
379 if ((0 == fM[kScaleX] && 0 == fM[kScaleY])) {
380 fTypeMask |= kZeroScale_TypeBit;
381 } else {
382 fTypeMask &= ~kZeroScale_TypeBit;
383 }
384 }
385 } else if (2 == (idx % 3)) {
386 if (0 != fM[kTransX] || 0 != fM[kTransY]) {
387 fTypeMask |= kTranslate_TypeBit;
388 } else {
389 fTypeMask &= ~kTranslate_TypeBit;
390 }
391 } else {
392 if (0 != fM[kSkewX] || 0 != fM[kSkewY]) {
393 fTypeMask |= kSkew_TypeBit;
394 } else {
395 fTypeMask &= ~kSkew_TypeBit;
396 }
397 }
398}
399
reed@google.comac10a2d2010-12-22 21:39:39 +0000400#endif