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 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