blob: b169d1976706e160ccb045cd70993db18eb73cda [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +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#include "GrMatrix.h"
19#include "GrRect.h"
20#include <stddef.h>
21
22#if GR_SCALAR_IS_FLOAT
23 const GrScalar GrMatrix::gRESCALE(GR_Scalar1);
24#else
25 GR_STATIC_ASSERT(GR_SCALAR_IS_FIXED);
26 // fixed point isn't supported right now
27 GR_STATIC_ASSERT(false);
28const GrScalar GrMatrix::gRESCALE(1 << 30);
29#endif
30
31const GrMatrix::MapProc GrMatrix::gMapProcs[] = {
32// Scales are not both zero
33 &GrMatrix::mapIdentity,
34 &GrMatrix::mapScale,
35 &GrMatrix::mapTranslate,
36 &GrMatrix::mapScaleAndTranslate,
37 &GrMatrix::mapSkew,
38 &GrMatrix::mapScaleAndSkew,
39 &GrMatrix::mapSkewAndTranslate,
40 &GrMatrix::mapNonPerspective,
41 // no optimizations for perspective matrices
42 &GrMatrix::mapPerspective,
43 &GrMatrix::mapPerspective,
44 &GrMatrix::mapPerspective,
45 &GrMatrix::mapPerspective,
46 &GrMatrix::mapPerspective,
47 &GrMatrix::mapPerspective,
48 &GrMatrix::mapPerspective,
49 &GrMatrix::mapPerspective,
50
51// Scales are zero (every other is invalid because kScale_TypeBit must be set if
52// kZeroScale_TypeBit is set)
53 &GrMatrix::mapInvalid,
54 &GrMatrix::mapZero,
55 &GrMatrix::mapInvalid,
56 &GrMatrix::mapSetToTranslate,
57 &GrMatrix::mapInvalid,
58 &GrMatrix::mapSwappedScale,
59 &GrMatrix::mapInvalid,
60 &GrMatrix::mapSwappedScaleAndTranslate,
61
62 // no optimizations for perspective matrices
63 &GrMatrix::mapInvalid,
64 &GrMatrix::mapZero,
65 &GrMatrix::mapInvalid,
66 &GrMatrix::mapPerspective,
67 &GrMatrix::mapInvalid,
68 &GrMatrix::mapPerspective,
69 &GrMatrix::mapInvalid,
70 &GrMatrix::mapPerspective,
71};
72
73void GrMatrix::setIdentity() {
74 fM[0] = GR_Scalar1; fM[1] = 0; fM[2] = 0;
75 fM[3] = 0; fM[4] = GR_Scalar1; fM[5] = 0;
76 fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
77 fTypeMask = 0;
78}
79
80void GrMatrix::setTranslate(GrScalar dx, GrScalar dy) {
81 fM[0] = GR_Scalar1; fM[1] = 0; fM[2] = dx;
82 fM[3] = 0; fM[4] = GR_Scalar1; fM[5] = dy;
83 fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
84 fTypeMask = (0 != dx || 0 != dy) ? kTranslate_TypeBit : 0;
85}
86
87void GrMatrix::setScale(GrScalar sx, GrScalar sy) {
88 fM[0] = sx; fM[1] = 0; fM[2] = 0;
89 fM[3] = 0; fM[4] = sy; fM[5] = 0;
90 fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
91 fTypeMask = (GR_Scalar1 != sx || GR_Scalar1 != sy) ? kScale_TypeBit : 0;
92}
93
94void GrMatrix::setSkew(GrScalar skx, GrScalar sky) {
95 fM[0] = GR_Scalar1; fM[1] = skx; fM[2] = 0;
96 fM[3] = sky; fM[4] = GR_Scalar1; fM[5] = 0;
97 fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
98 fTypeMask = (0 != skx || 0 != sky) ? kSkew_TypeBit : 0;
99}
100
101void GrMatrix::setConcat(const GrMatrix& a, const GrMatrix& b) {
102 if (a.isIdentity()) {
103 if (this != &b) {
104 for (int i = 0; i < 9; ++i) {
105 fM[i] = b.fM[i];
106 }
107 fTypeMask = b.fTypeMask;
108 }
109 return;
110 }
111
112 if (b.isIdentity()) {
113 GrAssert(!a.isIdentity());
114 if (this != &a) {
115 for (int i = 0; i < 9; ++i) {
116 fM[i] = a.fM[i];
117 }
118 fTypeMask = a.fTypeMask;
119 }
120 return;
121 }
122
123 // a and/or b could be this
124 GrMatrix tmp;
125
126 // could do more optimizations based on type bits. Hopefully this call is
127 // low frequency.
128 // TODO: make this work for fixed point
129 if (!((b.fTypeMask | a.fTypeMask) & kPerspective_TypeBit)) {
130 tmp.fM[0] = a.fM[0] * b.fM[0] + a.fM[1] * b.fM[3];
131 tmp.fM[1] = a.fM[0] * b.fM[1] + a.fM[1] * b.fM[4];
132 tmp.fM[2] = a.fM[0] * b.fM[2] + a.fM[1] * b.fM[5] + a.fM[2] * gRESCALE;
133
134 tmp.fM[3] = a.fM[3] * b.fM[0] + a.fM[4] * b.fM[3];
135 tmp.fM[4] = a.fM[3] * b.fM[1] + a.fM[4] * b.fM[4];
136 tmp.fM[5] = a.fM[3] * b.fM[2] + a.fM[4] * b.fM[5] + a.fM[5] * gRESCALE;
137
138 tmp.fM[6] = 0;
139 tmp.fM[7] = 0;
140 tmp.fM[8] = gRESCALE * gRESCALE;
141 } else {
142 tmp.fM[0] = a.fM[0] * b.fM[0] + a.fM[1] * b.fM[3] + a.fM[2] * b.fM[6];
143 tmp.fM[1] = a.fM[0] * b.fM[1] + a.fM[1] * b.fM[4] + a.fM[2] * b.fM[7];
144 tmp.fM[2] = a.fM[0] * b.fM[2] + a.fM[1] * b.fM[5] + a.fM[2] * b.fM[8];
145
146 tmp.fM[3] = a.fM[3] * b.fM[0] + a.fM[4] * b.fM[3] + a.fM[5] * b.fM[6];
147 tmp.fM[4] = a.fM[3] * b.fM[1] + a.fM[4] * b.fM[4] + a.fM[5] * b.fM[7];
148 tmp.fM[5] = a.fM[3] * b.fM[2] + a.fM[4] * b.fM[5] + a.fM[5] * b.fM[8];
149
150 tmp.fM[6] = a.fM[6] * b.fM[0] + a.fM[7] * b.fM[3] + a.fM[8] * b.fM[6];
151 tmp.fM[7] = a.fM[6] * b.fM[1] + a.fM[7] * b.fM[4] + a.fM[8] * b.fM[7];
152 tmp.fM[8] = a.fM[6] * b.fM[2] + a.fM[7] * b.fM[5] + a.fM[8] * b.fM[8];
153 }
154 *this = tmp;
155 this->computeTypeMask();
156}
157
158void GrMatrix::preConcat(const GrMatrix& m) {
159 setConcat(*this, m);
160}
161
162void GrMatrix::postConcat(const GrMatrix& m) {
163 setConcat(m, *this);
164}
165
166double GrMatrix::determinant() const {
167 if (fTypeMask & kPerspective_TypeBit) {
168 return fM[0]*((double)fM[4]*fM[8] - (double)fM[5]*fM[7]) +
169 fM[1]*((double)fM[5]*fM[6] - (double)fM[3]*fM[8]) +
170 fM[2]*((double)fM[3]*fM[7] - (double)fM[4]*fM[6]);
171 } else {
172 return (double)fM[0]*fM[4]*gRESCALE -
173 (double)fM[1]*fM[3]*gRESCALE;
174 }
175}
176
177bool GrMatrix::invert(GrMatrix* inverted) const {
178
179 if (isIdentity()) {
180 if (inverted != this) {
181 inverted->setIdentity();
182 }
183 return true;
184 }
185 static const double MIN_DETERMINANT_SQUARED = 1.e-16;
186
187 // could do more optimizations based on type bits. Hopefully this call is
188 // low frequency.
189
190 double det = determinant();
191
192 // check if we can't be inverted
193 if (det*det <= MIN_DETERMINANT_SQUARED) {
194 return false;
195 } else if (NULL == inverted) {
196 return true;
197 }
198
199 double t[9];
200
201 if (fTypeMask & kPerspective_TypeBit) {
202 t[0] = ((double)fM[4]*fM[8] - (double)fM[5]*fM[7]);
203 t[1] = ((double)fM[2]*fM[7] - (double)fM[1]*fM[8]);
204 t[2] = ((double)fM[1]*fM[5] - (double)fM[2]*fM[4]);
205 t[3] = ((double)fM[5]*fM[6] - (double)fM[3]*fM[8]);
206 t[4] = ((double)fM[0]*fM[8] - (double)fM[2]*fM[6]);
207 t[5] = ((double)fM[2]*fM[3] - (double)fM[0]*fM[5]);
208 t[6] = ((double)fM[3]*fM[7] - (double)fM[4]*fM[6]);
209 t[7] = ((double)fM[1]*fM[6] - (double)fM[0]*fM[7]);
210 t[8] = ((double)fM[0]*fM[4] - (double)fM[1]*fM[3]);
211 det = 1.0 / det;
212 for (int i = 0; i < 9; ++i) {
213 inverted->fM[i] = (GrScalar)(t[i] * det);
214 }
215 } else {
216 t[0] = (double)fM[4]*gRESCALE;
217 t[1] = -(double)fM[1]*gRESCALE;
218 t[2] = (double)fM[1]*fM[5] - (double)fM[2]*fM[4];
219 t[3] = -(double)fM[3]*gRESCALE;
220 t[4] = (double)fM[0]*gRESCALE;
221 t[5] = (double)fM[2]*fM[3] - (double)fM[0]*fM[5];
222 //t[6] = 0.0;
223 //t[7] = 0.0;
224 t[8] = (double)fM[0]*fM[4] - (double)fM[1]*fM[3];
225 det = 1.0 / det;
226 for (int i = 0; i < 6; ++i) {
227 inverted->fM[i] = (GrScalar)(t[i] * det);
228 }
229 inverted->fM[6] = 0;
230 inverted->fM[7] = 0;
231 inverted->fM[8] = (GrScalar)(t[8] * det);
232 }
233 inverted->computeTypeMask();
234 return true;
235}
236
237void GrMatrix::mapRect(GrRect* dst, const GrRect& src) const {
238 GrPoint srcPts[4], dstPts[4];
239 srcPts[0].set(src.fLeft, src.fTop);
240 srcPts[1].set(src.fRight, src.fTop);
241 srcPts[2].set(src.fRight, src.fBottom);
242 srcPts[3].set(src.fLeft, src.fBottom);
243 this->mapPoints(dstPts, srcPts, 4);
244 dst->setBounds(dstPts, 4);
245}
246
247bool GrMatrix::hasPerspective() const {
248 GrAssert(!!(kPerspective_TypeBit & fTypeMask) ==
249 (fM[kPersp0] != 0 || fM[kPersp1] != 0 || fM[kPersp2] != gRESCALE));
250 return 0 != (kPerspective_TypeBit & fTypeMask);
251}
252
253bool GrMatrix::isIdentity() const {
254 GrAssert((0 == fTypeMask) ==
255 (GR_Scalar1 == fM[kScaleX] && 0 == fM[kSkewX] && 0 == fM[kTransX] &&
256 0 == fM[kSkewY] && GR_Scalar1 == fM[kScaleY] && 0 == fM[kTransY] &&
257 0 == fM[kPersp0] && 0 == fM[kPersp1] && gRESCALE == fM[kPersp2]));
258 return (0 == fTypeMask);
259}
260
261
bsalomon@google.com205d4602011-04-25 12:43:45 +0000262bool GrMatrix::preservesAxisAlignment() const {
263
264 // check if matrix is trans and scale only
265 static const int gAllowedMask1 = kScale_TypeBit | kTranslate_TypeBit;
266
267 if (!(~gAllowedMask1 & fTypeMask)) {
268 return true;
269 }
270
271 // check matrix is trans and skew only (0 scale)
272 static const int gAllowedMask2 = kScale_TypeBit | kSkew_TypeBit |
273 kTranslate_TypeBit | kZeroScale_TypeBit;
274
275 if (!(~gAllowedMask2 & fTypeMask) && (kZeroScale_TypeBit & fTypeMask)) {
276 return true;
277 }
278
279 return false;
280}
281
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282GrScalar GrMatrix::getMaxStretch() const {
283
284 if (fTypeMask & kPerspective_TypeBit) {
285 return -GR_Scalar1;
286 }
287
288 GrScalar stretch;
289
290 if (isIdentity()) {
291 stretch = GR_Scalar1;
292 } else if (!(fTypeMask & kSkew_TypeBit)) {
293 stretch = GrMax(GrScalarAbs(fM[kScaleX]), GrScalarAbs(fM[kScaleY]));
294 } else if (fTypeMask & kZeroScale_TypeBit) {
295 stretch = GrMax(GrScalarAbs(fM[kSkewX]), GrScalarAbs(fM[kSkewY]));
296 } else {
297 // ignore the translation part of the matrix, just look at 2x2 portion.
298 // compute singular values, take largest abs value.
299 // [a b; b c] = A^T*A
300 GrScalar a = GrMul(fM[kScaleX], fM[kScaleX]) + GrMul(fM[kSkewY], fM[kSkewY]);
301 GrScalar b = GrMul(fM[kScaleX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kSkewY]);
302 GrScalar c = GrMul(fM[kSkewX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kScaleY]);
303 // eigenvalues of A^T*A are the squared singular values of A.
304 // characteristic equation is det((A^T*A) - l*I) = 0
305 // l^2 - (a + c)l + (ac-b^2)
306 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
307 // and roots are guaraunteed to be pos and real).
308 GrScalar largerRoot;
309 GrScalar bSqd = GrMul(b,b);
310 // TODO: fixed point tolerance value.
311 if (bSqd < 1e-10) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math
312 largerRoot = GrMax(a, c);
313 } else {
314 GrScalar aminusc = a - c;
315 GrScalar apluscdiv2 = (a + c) / 2;
316 GrScalar x = sqrtf(GrMul(aminusc,aminusc) + GrMul(4,(bSqd))) / 2;
317 largerRoot = apluscdiv2 + x;
318 }
319
320 stretch = sqrtf(largerRoot);
321 }
322#if GR_DEBUG && 0
323 // test a bunch of vectors. None should be scaled by more than stretch
324 // (modulo some error) and we should find a vector that is scaled by almost
325 // stretch.
326 GrPoint pt;
327 GrScalar max = 0;
328 for (int i = 0; i < 1000; ++i) {
329 GrScalar x = (float)rand() / RAND_MAX;
330 GrScalar y = sqrtf(1 - (x*x));
331 pt.fX = fM[kScaleX]*x + fM[kSkewX]*y;
332 pt.fY = fM[kSkewY]*x + fM[kScaleY]*y;
333 GrScalar d = pt.distanceToOrigin();
334 GrAssert(d <= (1.0001 * stretch));
335 max = GrMax(max, pt.distanceToOrigin());
336 }
337 GrAssert((stretch - max) < .05*stretch);
338#endif
339 return stretch;
340}
341
342bool GrMatrix::operator == (const GrMatrix& m) const {
343 if (fTypeMask != m.fTypeMask) {
344 return false;
345 }
346 if (!fTypeMask) {
347 return true;
348 }
349 for (int i = 0; i < 9; ++i) {
350 if (m.fM[i] != fM[i]) {
351 return false;
352 }
353 }
354 return true;
355}
356
357bool GrMatrix::operator != (const GrMatrix& m) const {
358 return !(*this == m);
359}
360
361////////////////////////////////////////////////////////////////////////////////
362// Matrix transformation procs
363//////
364
365void GrMatrix::mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const {
366 if (src != dst) {
367 for (uint32_t i = 0; i < count; ++i) {
368 dst[i] = src[i];
369 }
370 }
371}
372
373void GrMatrix::mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {
374 for (uint32_t i = 0; i < count; ++i) {
375 dst[i].fX = GrMul(src[i].fX, fM[kScaleX]);
376 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]);
377 }
378}
379
380
381void GrMatrix::mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
382 for (uint32_t i = 0; i < count; ++i) {
383 dst[i].fX = src[i].fX + fM[kTransX];
384 dst[i].fY = src[i].fY + fM[kTransY];
385 }
386}
387
388void GrMatrix::mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
389 for (uint32_t i = 0; i < count; ++i) {
390 dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + fM[kTransX];
391 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + fM[kTransY];
392 }
393}
394
395void GrMatrix::mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {
396 if (src != dst) {
397 for (uint32_t i = 0; i < count; ++i) {
398 dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);
399 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);
400 }
401 } else {
402 for (uint32_t i = 0; i < count; ++i) {
403 GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);
404 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);
405 dst[i].fX = newX;
406 }
407 }
408}
409
410void GrMatrix::mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {
411 if (src != dst) {
412 for (uint32_t i = 0; i < count; ++i) {
413 dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);
414 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);
415 }
416 } else {
417 for (uint32_t i = 0; i < count; ++i) {
418 GrScalar newX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);
419 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);
420 dst[i].fX = newX;
421 }
422 }
423}
424
425void GrMatrix::mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
426 if (src != dst) {
427 for (uint32_t i = 0; i < count; ++i) {
428 dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
429 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
430 }
431 } else {
432 for (uint32_t i = 0; i < count; ++i) {
433 GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
434 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
435 dst[i].fX = newX;
436 }
437 }
438}
439
440void GrMatrix::mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {
441 if (src != dst) {
442 for (uint32_t i = 0; i < count; ++i) {
443 dst[i].fX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
444 dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
445 }
446 } else {
447 for (uint32_t i = 0; i < count; ++i) {
448 GrScalar newX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
449 dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
450 dst[i].fX = newX;
451 }
452 }
453}
454
455void GrMatrix::mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {
456 for (uint32_t i = 0; i < count; ++i) {
457 GrScalar x, y, w;
458 x = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
459 y = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
460 w = GrMul(fM[kPersp0], src[i].fX) + GrMul(fM[kPersp1], src[i].fY) + fM[kPersp2];
461 // TODO need fixed point invert
462 if (w) {
463 w = 1 / w;
464 }
465 dst[i].fX = GrMul(x, w);
466 dst[i].fY = GrMul(y, w);
467 }
468}
469
470void GrMatrix::mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const {
471 GrAssert(0);
472}
473
474void GrMatrix::mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const {
475 memset(dst, 0, sizeof(GrPoint)*count);
476}
477
478void GrMatrix::mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
479 for (uint32_t i = 0; i < count; ++i) {
480 dst[i].fX = fM[kTransX];
481 dst[i].fY = fM[kTransY];
482 }
483}
484
485void GrMatrix::mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {
486 if (src != dst) {
487 for (uint32_t i = 0; i < count; ++i) {
488 dst[i].fX = GrMul(src[i].fY, fM[kSkewX]);
489 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);
490 }
491 } else {
492 for (uint32_t i = 0; i < count; ++i) {
493 GrScalar newX = GrMul(src[i].fY, fM[kSkewX]);
494 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);
495 dst[i].fX = newX;
496 }
497 }
498}
499
500void GrMatrix::mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
501 if (src != dst) {
502 for (uint32_t i = 0; i < count; ++i) {
503 dst[i].fX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
504 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
505 }
506 } else {
507 for (uint32_t i = 0; i < count; ++i) {
508 GrScalar newX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
509 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
510 dst[i].fX = newX;
511 }
512 }
513}
514
515///////////////////////////////////////////////////////////////////////////////
516// Unit test
517//////
518
519#include "GrRandom.h"
520
521#if GR_DEBUG
522enum MatrixType {
523 kRotate_MatrixType,
524 kScaleX_MatrixType,
525 kScaleY_MatrixType,
526 kSkewX_MatrixType,
527 kSkewY_MatrixType,
528 kTranslateX_MatrixType,
529 kTranslateY_MatrixType,
530 kSwapScaleXY_MatrixType,
531 kPersp_MatrixType,
532
533 kMatrixTypeCount
534};
535
536static void create_matrix(GrMatrix* matrix, GrRandom& rand) {
537 MatrixType type = (MatrixType)(rand.nextU() % kMatrixTypeCount);
538 switch (type) {
539 case kRotate_MatrixType: {
540 float angle = rand.nextF() * 2 *3.14159265358979323846f;
541 GrScalar cosa = GrFloatToScalar(cosf(angle));
542 GrScalar sina = GrFloatToScalar(sinf(angle));
543 matrix->setAll(cosa, -sina, 0,
544 sina, cosa, 0,
545 0, 0, GrMatrix::I()[8]);
546 } break;
547 case kScaleX_MatrixType: {
548 GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));
549 matrix->setAll(scale, 0, 0,
550 0, GR_Scalar1, 0,
551 0, 0, GrMatrix::I()[8]);
552 } break;
553 case kScaleY_MatrixType: {
554 GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));
555 matrix->setAll(GR_Scalar1, 0, 0,
556 0, scale, 0,
557 0, 0, GrMatrix::I()[8]);
558 } break;
559 case kSkewX_MatrixType: {
560 GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));
561 matrix->setAll(GR_Scalar1, skew, 0,
562 0, GR_Scalar1, 0,
563 0, 0, GrMatrix::I()[8]);
564 } break;
565 case kSkewY_MatrixType: {
566 GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));
567 matrix->setAll(GR_Scalar1, 0, 0,
568 skew, GR_Scalar1, 0,
569 0, 0, GrMatrix::I()[8]);
570 } break;
571 case kTranslateX_MatrixType: {
572 GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));
573 matrix->setAll(GR_Scalar1, 0, trans,
574 0, GR_Scalar1, 0,
575 0, 0, GrMatrix::I()[8]);
576 } break;
577 case kTranslateY_MatrixType: {
578 GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));
579 matrix->setAll(GR_Scalar1, 0, 0,
580 0, GR_Scalar1, trans,
581 0, 0, GrMatrix::I()[8]);
582 } break;
583 case kSwapScaleXY_MatrixType: {
584 GrScalar xy = GrFloatToScalar(rand.nextF(-2, 2));
585 GrScalar yx = GrFloatToScalar(rand.nextF(-2, 2));
586 matrix->setAll(0, xy, 0,
587 yx, 0, 0,
588 0, 0, GrMatrix::I()[8]);
589 } break;
590 case kPersp_MatrixType: {
591 GrScalar p0 = GrFloatToScalar(rand.nextF(-2, 2));
592 GrScalar p1 = GrFloatToScalar(rand.nextF(-2, 2));
593 GrScalar p2 = GrFloatToScalar(rand.nextF(-0.5f, 0.75f));
594 matrix->setAll(GR_Scalar1, 0, 0,
595 0, GR_Scalar1, 0,
596 p0, p1, GrMul(p2,GrMatrix::I()[8]));
597 } break;
598 default:
599 GrAssert(0);
600 break;
601 }
602}
603#endif
604
605void GrMatrix::UnitTest() {
606 GrRandom rand;
607
608 // Create a bunch of matrices and test point mapping, max stretch calc,
609 // inversion and multiply-by-inverse.
610#if GR_DEBUG
611 for (int i = 0; i < 10000; ++i) {
612 GrMatrix a, b;
613 a.setIdentity();
614 int num = rand.nextU() % 6;
615 // force testing of I and swapXY
616 if (0 == i) {
617 num = 0;
618 GrAssert(a.isIdentity());
619 } else if (1 == i) {
620 num = 0;
621 a.setAll(0, GR_Scalar1, 0,
622 GR_Scalar1, 0, 0,
623 0, 0, I()[8]);
624 }
625 for (int j = 0; j < num; ++j) {
626 create_matrix(&b, rand);
627 a.preConcat(b);
628 }
629
630 GrScalar maxStretch = a.getMaxStretch();
631 if (maxStretch > 0) {
632 maxStretch = GrMul(GR_Scalar1 + GR_Scalar1 / 100, maxStretch);
633 }
reed@google.com7744c202011-05-06 19:26:26 +0000634 GrPoint origin = a.mapPoint(GrPoint::Make(0,0));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000635
636 for (int j = 0; j < 9; ++j) {
637 int mask, origMask = a.fTypeMask;
638 GrScalar old = a[j];
639
640 a.set(j, GR_Scalar1);
641 mask = a.fTypeMask;
642 a.computeTypeMask();
643 GrAssert(mask == a.fTypeMask);
644
645 a.set(j, 0);
646 mask = a.fTypeMask;
647 a.computeTypeMask();
648 GrAssert(mask == a.fTypeMask);
649
650 a.set(j, 10 * GR_Scalar1);
651 mask = a.fTypeMask;
652 a.computeTypeMask();
653 GrAssert(mask == a.fTypeMask);
654
655 a.set(j, old);
656 GrAssert(a.fTypeMask == origMask);
657 }
658
659 for (int j = 0; j < 100; ++j) {
660 GrPoint pt;
661 pt.fX = GrFloatToScalar(rand.nextF(-10, 10));
662 pt.fY = GrFloatToScalar(rand.nextF(-10, 10));
663
664 GrPoint t0, t1, t2;
665 t0 = a.mapPoint(pt); // map to a new point
666 t1 = pt;
667 a.mapPoints(&t1, &t1, 1); // in place
668 a.mapPerspective(&t2, &pt, 1); // full mult
669 GrAssert(t0 == t1 && t1 == t2);
670 if (maxStretch >= 0.f) {
reed@google.com7744c202011-05-06 19:26:26 +0000671 GrVec vec = origin - t0;
672// vec.setBetween(t0, origin);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000673 GrScalar stretch = vec.length() / pt.distanceToOrigin();
674 GrAssert(stretch <= maxStretch);
675 }
676 }
677 double det = a.determinant();
678 if (fabs(det) > 1e-3 && a.invert(&b)) {
679 GrMatrix c;
680 c.setConcat(a,b);
681 for (int i = 0; i < 9; ++i) {
682 GrScalar diff = GrScalarAbs(c[i] - I()[i]);
683 GrAssert(diff < (5*GR_Scalar1 / 100));
684 }
685 }
686 }
687#endif
688}
689
690///////////////////////////////////////////////////////////////////////////////
691
692int Gr_clz(uint32_t n) {
693 if (0 == n) {
694 return 32;
695 }
696
697 int count = 0;
698 if (0 == (n & 0xFFFF0000)) {
699 count += 16;
700 n <<= 16;
701 }
702 if (0 == (n & 0xFF000000)) {
703 count += 8;
704 n <<= 8;
705 }
706 if (0 == (n & 0xF0000000)) {
707 count += 4;
708 n <<= 4;
709 }
710 if (0 == (n & 0xC0000000)) {
711 count += 2;
712 n <<= 2;
713 }
714 if (0 == (n & 0x80000000)) {
715 count += 1;
716 }
717 return count;
718}
719
720///////////////////////////////////////////////////////////////////////////////
721#include "GrRect.h"
722
723void GrRect::setBounds(const GrPoint pts[], int count) {
724 if (count <= 0) {
725 this->setEmpty();
726 } else {
727 GrScalar L, R, T, B;
728 L = R = pts[0].fX;
729 T = B = pts[0].fY;
730 for (int i = 1; i < count; i++) {
731 GrScalar x = pts[i].fX;
732 GrScalar y = pts[i].fY;
733 if (x < L) {
734 L = x;
735 } else if (x > R) {
736 R = x;
737 }
738 if (y < T) {
739 T = y;
740 } else if (y > B) {
741 B = y;
742 }
743 }
744 this->setLTRB(L, T, R, B);
745 }
746}
747
748
749