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