blob: 0a2d1b2b55c5e789130130899b6db43e2e5601bb [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
262GrScalar GrMatrix::getMaxStretch() const {
263
264 if (fTypeMask & kPerspective_TypeBit) {
265 return -GR_Scalar1;
266 }
267
268 GrScalar stretch;
269
270 if (isIdentity()) {
271 stretch = GR_Scalar1;
272 } else if (!(fTypeMask & kSkew_TypeBit)) {
273 stretch = GrMax(GrScalarAbs(fM[kScaleX]), GrScalarAbs(fM[kScaleY]));
274 } else if (fTypeMask & kZeroScale_TypeBit) {
275 stretch = GrMax(GrScalarAbs(fM[kSkewX]), GrScalarAbs(fM[kSkewY]));
276 } else {
277 // ignore the translation part of the matrix, just look at 2x2 portion.
278 // compute singular values, take largest abs value.
279 // [a b; b c] = A^T*A
280 GrScalar a = GrMul(fM[kScaleX], fM[kScaleX]) + GrMul(fM[kSkewY], fM[kSkewY]);
281 GrScalar b = GrMul(fM[kScaleX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kSkewY]);
282 GrScalar c = GrMul(fM[kSkewX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kScaleY]);
283 // eigenvalues of A^T*A are the squared singular values of A.
284 // characteristic equation is det((A^T*A) - l*I) = 0
285 // l^2 - (a + c)l + (ac-b^2)
286 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
287 // and roots are guaraunteed to be pos and real).
288 GrScalar largerRoot;
289 GrScalar bSqd = GrMul(b,b);
290 // TODO: fixed point tolerance value.
291 if (bSqd < 1e-10) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math
292 largerRoot = GrMax(a, c);
293 } else {
294 GrScalar aminusc = a - c;
295 GrScalar apluscdiv2 = (a + c) / 2;
296 GrScalar x = sqrtf(GrMul(aminusc,aminusc) + GrMul(4,(bSqd))) / 2;
297 largerRoot = apluscdiv2 + x;
298 }
299
300 stretch = sqrtf(largerRoot);
301 }
302#if GR_DEBUG && 0
303 // test a bunch of vectors. None should be scaled by more than stretch
304 // (modulo some error) and we should find a vector that is scaled by almost
305 // stretch.
306 GrPoint pt;
307 GrScalar max = 0;
308 for (int i = 0; i < 1000; ++i) {
309 GrScalar x = (float)rand() / RAND_MAX;
310 GrScalar y = sqrtf(1 - (x*x));
311 pt.fX = fM[kScaleX]*x + fM[kSkewX]*y;
312 pt.fY = fM[kSkewY]*x + fM[kScaleY]*y;
313 GrScalar d = pt.distanceToOrigin();
314 GrAssert(d <= (1.0001 * stretch));
315 max = GrMax(max, pt.distanceToOrigin());
316 }
317 GrAssert((stretch - max) < .05*stretch);
318#endif
319 return stretch;
320}
321
322bool GrMatrix::operator == (const GrMatrix& m) const {
323 if (fTypeMask != m.fTypeMask) {
324 return false;
325 }
326 if (!fTypeMask) {
327 return true;
328 }
329 for (int i = 0; i < 9; ++i) {
330 if (m.fM[i] != fM[i]) {
331 return false;
332 }
333 }
334 return true;
335}
336
337bool GrMatrix::operator != (const GrMatrix& m) const {
338 return !(*this == m);
339}
340
341////////////////////////////////////////////////////////////////////////////////
342// Matrix transformation procs
343//////
344
345void GrMatrix::mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const {
346 if (src != dst) {
347 for (uint32_t i = 0; i < count; ++i) {
348 dst[i] = src[i];
349 }
350 }
351}
352
353void GrMatrix::mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {
354 for (uint32_t i = 0; i < count; ++i) {
355 dst[i].fX = GrMul(src[i].fX, fM[kScaleX]);
356 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]);
357 }
358}
359
360
361void GrMatrix::mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
362 for (uint32_t i = 0; i < count; ++i) {
363 dst[i].fX = src[i].fX + fM[kTransX];
364 dst[i].fY = src[i].fY + fM[kTransY];
365 }
366}
367
368void GrMatrix::mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
369 for (uint32_t i = 0; i < count; ++i) {
370 dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + fM[kTransX];
371 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + fM[kTransY];
372 }
373}
374
375void GrMatrix::mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {
376 if (src != dst) {
377 for (uint32_t i = 0; i < count; ++i) {
378 dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);
379 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);
380 }
381 } else {
382 for (uint32_t i = 0; i < count; ++i) {
383 GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);
384 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);
385 dst[i].fX = newX;
386 }
387 }
388}
389
390void GrMatrix::mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {
391 if (src != dst) {
392 for (uint32_t i = 0; i < count; ++i) {
393 dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);
394 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);
395 }
396 } else {
397 for (uint32_t i = 0; i < count; ++i) {
398 GrScalar newX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);
399 dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);
400 dst[i].fX = newX;
401 }
402 }
403}
404
405void GrMatrix::mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
406 if (src != dst) {
407 for (uint32_t i = 0; i < count; ++i) {
408 dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
409 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
410 }
411 } else {
412 for (uint32_t i = 0; i < count; ++i) {
413 GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
414 dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
415 dst[i].fX = newX;
416 }
417 }
418}
419
420void GrMatrix::mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {
421 if (src != dst) {
422 for (uint32_t i = 0; i < count; ++i) {
423 dst[i].fX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
424 dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
425 }
426 } else {
427 for (uint32_t i = 0; i < count; ++i) {
428 GrScalar newX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
429 dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
430 dst[i].fX = newX;
431 }
432 }
433}
434
435void GrMatrix::mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {
436 for (uint32_t i = 0; i < count; ++i) {
437 GrScalar x, y, w;
438 x = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
439 y = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
440 w = GrMul(fM[kPersp0], src[i].fX) + GrMul(fM[kPersp1], src[i].fY) + fM[kPersp2];
441 // TODO need fixed point invert
442 if (w) {
443 w = 1 / w;
444 }
445 dst[i].fX = GrMul(x, w);
446 dst[i].fY = GrMul(y, w);
447 }
448}
449
450void GrMatrix::mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const {
451 GrAssert(0);
452}
453
454void GrMatrix::mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const {
455 memset(dst, 0, sizeof(GrPoint)*count);
456}
457
458void GrMatrix::mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
459 for (uint32_t i = 0; i < count; ++i) {
460 dst[i].fX = fM[kTransX];
461 dst[i].fY = fM[kTransY];
462 }
463}
464
465void GrMatrix::mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {
466 if (src != dst) {
467 for (uint32_t i = 0; i < count; ++i) {
468 dst[i].fX = GrMul(src[i].fY, fM[kSkewX]);
469 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);
470 }
471 } else {
472 for (uint32_t i = 0; i < count; ++i) {
473 GrScalar newX = GrMul(src[i].fY, fM[kSkewX]);
474 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);
475 dst[i].fX = newX;
476 }
477 }
478}
479
480void GrMatrix::mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
481 if (src != dst) {
482 for (uint32_t i = 0; i < count; ++i) {
483 dst[i].fX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
484 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
485 }
486 } else {
487 for (uint32_t i = 0; i < count; ++i) {
488 GrScalar newX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
489 dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
490 dst[i].fX = newX;
491 }
492 }
493}
494
495///////////////////////////////////////////////////////////////////////////////
496// Unit test
497//////
498
499#include "GrRandom.h"
500
501#if GR_DEBUG
502enum MatrixType {
503 kRotate_MatrixType,
504 kScaleX_MatrixType,
505 kScaleY_MatrixType,
506 kSkewX_MatrixType,
507 kSkewY_MatrixType,
508 kTranslateX_MatrixType,
509 kTranslateY_MatrixType,
510 kSwapScaleXY_MatrixType,
511 kPersp_MatrixType,
512
513 kMatrixTypeCount
514};
515
516static void create_matrix(GrMatrix* matrix, GrRandom& rand) {
517 MatrixType type = (MatrixType)(rand.nextU() % kMatrixTypeCount);
518 switch (type) {
519 case kRotate_MatrixType: {
520 float angle = rand.nextF() * 2 *3.14159265358979323846f;
521 GrScalar cosa = GrFloatToScalar(cosf(angle));
522 GrScalar sina = GrFloatToScalar(sinf(angle));
523 matrix->setAll(cosa, -sina, 0,
524 sina, cosa, 0,
525 0, 0, GrMatrix::I()[8]);
526 } break;
527 case kScaleX_MatrixType: {
528 GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));
529 matrix->setAll(scale, 0, 0,
530 0, GR_Scalar1, 0,
531 0, 0, GrMatrix::I()[8]);
532 } break;
533 case kScaleY_MatrixType: {
534 GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));
535 matrix->setAll(GR_Scalar1, 0, 0,
536 0, scale, 0,
537 0, 0, GrMatrix::I()[8]);
538 } break;
539 case kSkewX_MatrixType: {
540 GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));
541 matrix->setAll(GR_Scalar1, skew, 0,
542 0, GR_Scalar1, 0,
543 0, 0, GrMatrix::I()[8]);
544 } break;
545 case kSkewY_MatrixType: {
546 GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));
547 matrix->setAll(GR_Scalar1, 0, 0,
548 skew, GR_Scalar1, 0,
549 0, 0, GrMatrix::I()[8]);
550 } break;
551 case kTranslateX_MatrixType: {
552 GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));
553 matrix->setAll(GR_Scalar1, 0, trans,
554 0, GR_Scalar1, 0,
555 0, 0, GrMatrix::I()[8]);
556 } break;
557 case kTranslateY_MatrixType: {
558 GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));
559 matrix->setAll(GR_Scalar1, 0, 0,
560 0, GR_Scalar1, trans,
561 0, 0, GrMatrix::I()[8]);
562 } break;
563 case kSwapScaleXY_MatrixType: {
564 GrScalar xy = GrFloatToScalar(rand.nextF(-2, 2));
565 GrScalar yx = GrFloatToScalar(rand.nextF(-2, 2));
566 matrix->setAll(0, xy, 0,
567 yx, 0, 0,
568 0, 0, GrMatrix::I()[8]);
569 } break;
570 case kPersp_MatrixType: {
571 GrScalar p0 = GrFloatToScalar(rand.nextF(-2, 2));
572 GrScalar p1 = GrFloatToScalar(rand.nextF(-2, 2));
573 GrScalar p2 = GrFloatToScalar(rand.nextF(-0.5f, 0.75f));
574 matrix->setAll(GR_Scalar1, 0, 0,
575 0, GR_Scalar1, 0,
576 p0, p1, GrMul(p2,GrMatrix::I()[8]));
577 } break;
578 default:
579 GrAssert(0);
580 break;
581 }
582}
583#endif
584
585void GrMatrix::UnitTest() {
586 GrRandom rand;
587
588 // Create a bunch of matrices and test point mapping, max stretch calc,
589 // inversion and multiply-by-inverse.
590#if GR_DEBUG
591 for (int i = 0; i < 10000; ++i) {
592 GrMatrix a, b;
593 a.setIdentity();
594 int num = rand.nextU() % 6;
595 // force testing of I and swapXY
596 if (0 == i) {
597 num = 0;
598 GrAssert(a.isIdentity());
599 } else if (1 == i) {
600 num = 0;
601 a.setAll(0, GR_Scalar1, 0,
602 GR_Scalar1, 0, 0,
603 0, 0, I()[8]);
604 }
605 for (int j = 0; j < num; ++j) {
606 create_matrix(&b, rand);
607 a.preConcat(b);
608 }
609
610 GrScalar maxStretch = a.getMaxStretch();
611 if (maxStretch > 0) {
612 maxStretch = GrMul(GR_Scalar1 + GR_Scalar1 / 100, maxStretch);
613 }
614 GrPoint origin = a.mapPoint(GrPoint(0,0));
615
616 for (int j = 0; j < 9; ++j) {
617 int mask, origMask = a.fTypeMask;
618 GrScalar old = a[j];
619
620 a.set(j, GR_Scalar1);
621 mask = a.fTypeMask;
622 a.computeTypeMask();
623 GrAssert(mask == a.fTypeMask);
624
625 a.set(j, 0);
626 mask = a.fTypeMask;
627 a.computeTypeMask();
628 GrAssert(mask == a.fTypeMask);
629
630 a.set(j, 10 * GR_Scalar1);
631 mask = a.fTypeMask;
632 a.computeTypeMask();
633 GrAssert(mask == a.fTypeMask);
634
635 a.set(j, old);
636 GrAssert(a.fTypeMask == origMask);
637 }
638
639 for (int j = 0; j < 100; ++j) {
640 GrPoint pt;
641 pt.fX = GrFloatToScalar(rand.nextF(-10, 10));
642 pt.fY = GrFloatToScalar(rand.nextF(-10, 10));
643
644 GrPoint t0, t1, t2;
645 t0 = a.mapPoint(pt); // map to a new point
646 t1 = pt;
647 a.mapPoints(&t1, &t1, 1); // in place
648 a.mapPerspective(&t2, &pt, 1); // full mult
649 GrAssert(t0 == t1 && t1 == t2);
650 if (maxStretch >= 0.f) {
651 GrVec vec;
652 vec.setBetween(t0, origin);
653 GrScalar stretch = vec.length() / pt.distanceToOrigin();
654 GrAssert(stretch <= maxStretch);
655 }
656 }
657 double det = a.determinant();
658 if (fabs(det) > 1e-3 && a.invert(&b)) {
659 GrMatrix c;
660 c.setConcat(a,b);
661 for (int i = 0; i < 9; ++i) {
662 GrScalar diff = GrScalarAbs(c[i] - I()[i]);
663 GrAssert(diff < (5*GR_Scalar1 / 100));
664 }
665 }
666 }
667#endif
668}
669
670///////////////////////////////////////////////////////////////////////////////
671
672int Gr_clz(uint32_t n) {
673 if (0 == n) {
674 return 32;
675 }
676
677 int count = 0;
678 if (0 == (n & 0xFFFF0000)) {
679 count += 16;
680 n <<= 16;
681 }
682 if (0 == (n & 0xFF000000)) {
683 count += 8;
684 n <<= 8;
685 }
686 if (0 == (n & 0xF0000000)) {
687 count += 4;
688 n <<= 4;
689 }
690 if (0 == (n & 0xC0000000)) {
691 count += 2;
692 n <<= 2;
693 }
694 if (0 == (n & 0x80000000)) {
695 count += 1;
696 }
697 return count;
698}
699
700///////////////////////////////////////////////////////////////////////////////
701#include "GrRect.h"
702
703void GrRect::setBounds(const GrPoint pts[], int count) {
704 if (count <= 0) {
705 this->setEmpty();
706 } else {
707 GrScalar L, R, T, B;
708 L = R = pts[0].fX;
709 T = B = pts[0].fY;
710 for (int i = 1; i < count; i++) {
711 GrScalar x = pts[i].fX;
712 GrScalar y = pts[i].fY;
713 if (x < L) {
714 L = x;
715 } else if (x > R) {
716 R = x;
717 }
718 if (y < T) {
719 T = y;
720 } else if (y > B) {
721 B = y;
722 }
723 }
724 this->setLTRB(L, T, R, B);
725 }
726}
727
728
729