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