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