1 /* 2 * Copyright (C) 2010 The Android Open Source Project 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 #define LOG_TAG "OpenGLRenderer" 18 19 #include <math.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include <utils/Log.h> 24 25 #include <SkMatrix.h> 26 27 #include "Matrix.h" 28 29 namespace android { 30 namespace uirenderer { 31 32 /////////////////////////////////////////////////////////////////////////////// 33 // Defines 34 /////////////////////////////////////////////////////////////////////////////// 35 36 static const float EPSILON = 0.0000001f; 37 38 /////////////////////////////////////////////////////////////////////////////// 39 // Matrix 40 /////////////////////////////////////////////////////////////////////////////// 41 42 const Matrix4& Matrix4::identity() { 43 static Matrix4 sIdentity; 44 return sIdentity; 45 } 46 47 void Matrix4::loadIdentity() { 48 data[kScaleX] = 1.0f; 49 data[kSkewY] = 0.0f; 50 data[2] = 0.0f; 51 data[kPerspective0] = 0.0f; 52 53 data[kSkewX] = 0.0f; 54 data[kScaleY] = 1.0f; 55 data[6] = 0.0f; 56 data[kPerspective1] = 0.0f; 57 58 data[8] = 0.0f; 59 data[9] = 0.0f; 60 data[kScaleZ] = 1.0f; 61 data[11] = 0.0f; 62 63 data[kTranslateX] = 0.0f; 64 data[kTranslateY] = 0.0f; 65 data[kTranslateZ] = 0.0f; 66 data[kPerspective2] = 1.0f; 67 68 mType = kTypeIdentity | kTypeRectToRect; 69 } 70 71 static bool isZero(float f) { 72 return fabs(f) <= EPSILON; 73 } 74 75 uint8_t Matrix4::getType() const { 76 if (mType & kTypeUnknown) { 77 mType = kTypeIdentity; 78 79 if (data[kPerspective0] != 0.0f || data[kPerspective1] != 0.0f || 80 data[kPerspective2] != 1.0f) { 81 mType |= kTypePerspective; 82 } 83 84 if (data[kTranslateX] != 0.0f || data[kTranslateY] != 0.0f) { 85 mType |= kTypeTranslate; 86 } 87 88 float m00 = data[kScaleX]; 89 float m01 = data[kSkewX]; 90 float m10 = data[kSkewY]; 91 float m11 = data[kScaleY]; 92 float m32 = data[kTranslateZ]; 93 94 if (m01 != 0.0f || m10 != 0.0f || m32 != 0.0f) { 95 mType |= kTypeAffine; 96 } 97 98 if (m00 != 1.0f || m11 != 1.0f) { 99 mType |= kTypeScale; 100 } 101 102 // The following section determines whether the matrix will preserve 103 // rectangles. For instance, a rectangle transformed by a pure 104 // translation matrix will result in a rectangle. A rectangle 105 // transformed by a 45 degrees rotation matrix is not a rectangle. 106 // If the matrix has a perspective component then we already know 107 // it doesn't preserve rectangles. 108 if (!(mType & kTypePerspective)) { 109 if ((isZero(m00) && isZero(m11) && !isZero(m01) && !isZero(m10)) || 110 (isZero(m01) && isZero(m10) && !isZero(m00) && !isZero(m11))) { 111 mType |= kTypeRectToRect; 112 } 113 } 114 } 115 return mType; 116 } 117 118 uint8_t Matrix4::getGeometryType() const { 119 return getType() & sGeometryMask; 120 } 121 122 bool Matrix4::rectToRect() const { 123 return getType() & kTypeRectToRect; 124 } 125 126 bool Matrix4::positiveScale() const { 127 return (data[kScaleX] > 0.0f && data[kScaleY] > 0.0f); 128 } 129 130 bool Matrix4::changesBounds() const { 131 return getType() & (kTypeScale | kTypeAffine | kTypePerspective); 132 } 133 134 bool Matrix4::isPureTranslate() const { 135 // NOTE: temporary hack to workaround ignoreTransform behavior with Z values 136 // TODO: separate this into isPure2dTranslate vs isPure3dTranslate 137 return getGeometryType() <= kTypeTranslate && (data[kTranslateZ] == 0.0f); 138 } 139 140 bool Matrix4::isSimple() const { 141 return getGeometryType() <= (kTypeScale | kTypeTranslate) && (data[kTranslateZ] == 0.0f); 142 } 143 144 bool Matrix4::isIdentity() const { 145 return getGeometryType() == kTypeIdentity; 146 } 147 148 bool Matrix4::isPerspective() const { 149 return getType() & kTypePerspective; 150 } 151 152 void Matrix4::load(const float* v) { 153 memcpy(data, v, sizeof(data)); 154 mType = kTypeUnknown; 155 } 156 157 void Matrix4::load(const Matrix4& v) { 158 *this = v; 159 } 160 161 void Matrix4::load(const SkMatrix& v) { 162 memset(data, 0, sizeof(data)); 163 164 data[kScaleX] = v[SkMatrix::kMScaleX]; 165 data[kSkewX] = v[SkMatrix::kMSkewX]; 166 data[kTranslateX] = v[SkMatrix::kMTransX]; 167 168 data[kSkewY] = v[SkMatrix::kMSkewY]; 169 data[kScaleY] = v[SkMatrix::kMScaleY]; 170 data[kTranslateY] = v[SkMatrix::kMTransY]; 171 172 data[kPerspective0] = v[SkMatrix::kMPersp0]; 173 data[kPerspective1] = v[SkMatrix::kMPersp1]; 174 data[kPerspective2] = v[SkMatrix::kMPersp2]; 175 176 data[kScaleZ] = 1.0f; 177 178 // NOTE: The flags are compatible between SkMatrix and this class. 179 // However, SkMatrix::getType() does not return the flag 180 // kRectStaysRect. The return value is masked with 0xF 181 // so we need the extra rectStaysRect() check 182 mType = v.getType(); 183 if (v.rectStaysRect()) { 184 mType |= kTypeRectToRect; 185 } 186 } 187 188 void Matrix4::copyTo(SkMatrix& v) const { 189 v.reset(); 190 191 v.set(SkMatrix::kMScaleX, data[kScaleX]); 192 v.set(SkMatrix::kMSkewX, data[kSkewX]); 193 v.set(SkMatrix::kMTransX, data[kTranslateX]); 194 195 v.set(SkMatrix::kMSkewY, data[kSkewY]); 196 v.set(SkMatrix::kMScaleY, data[kScaleY]); 197 v.set(SkMatrix::kMTransY, data[kTranslateY]); 198 199 v.set(SkMatrix::kMPersp0, data[kPerspective0]); 200 v.set(SkMatrix::kMPersp1, data[kPerspective1]); 201 v.set(SkMatrix::kMPersp2, data[kPerspective2]); 202 } 203 204 void Matrix4::loadInverse(const Matrix4& v) { 205 // Fast case for common translation matrices 206 if (v.isPureTranslate()) { 207 // Reset the matrix 208 // Unnamed fields are never written to except by 209 // loadIdentity(), they don't need to be reset 210 data[kScaleX] = 1.0f; 211 data[kSkewX] = 0.0f; 212 213 data[kScaleY] = 1.0f; 214 data[kSkewY] = 0.0f; 215 216 data[kScaleZ] = 1.0f; 217 218 data[kPerspective0] = 0.0f; 219 data[kPerspective1] = 0.0f; 220 data[kPerspective2] = 1.0f; 221 222 // No need to deal with kTranslateZ because isPureTranslate() 223 // only returns true when the kTranslateZ component is 0 224 data[kTranslateX] = -v.data[kTranslateX]; 225 data[kTranslateY] = -v.data[kTranslateY]; 226 data[kTranslateZ] = 0.0f; 227 228 // A "pure translate" matrix can be identity or translation 229 mType = v.getType(); 230 return; 231 } 232 233 double scale = 1.0 / 234 (v.data[kScaleX] * ((double) v.data[kScaleY] * v.data[kPerspective2] - 235 (double) v.data[kTranslateY] * v.data[kPerspective1]) + 236 v.data[kSkewX] * ((double) v.data[kTranslateY] * v.data[kPerspective0] - 237 (double) v.data[kSkewY] * v.data[kPerspective2]) + 238 v.data[kTranslateX] * ((double) v.data[kSkewY] * v.data[kPerspective1] - 239 (double) v.data[kScaleY] * v.data[kPerspective0])); 240 241 data[kScaleX] = (v.data[kScaleY] * v.data[kPerspective2] - 242 v.data[kTranslateY] * v.data[kPerspective1]) * scale; 243 data[kSkewX] = (v.data[kTranslateX] * v.data[kPerspective1] - 244 v.data[kSkewX] * v.data[kPerspective2]) * scale; 245 data[kTranslateX] = (v.data[kSkewX] * v.data[kTranslateY] - 246 v.data[kTranslateX] * v.data[kScaleY]) * scale; 247 248 data[kSkewY] = (v.data[kTranslateY] * v.data[kPerspective0] - 249 v.data[kSkewY] * v.data[kPerspective2]) * scale; 250 data[kScaleY] = (v.data[kScaleX] * v.data[kPerspective2] - 251 v.data[kTranslateX] * v.data[kPerspective0]) * scale; 252 data[kTranslateY] = (v.data[kTranslateX] * v.data[kSkewY] - 253 v.data[kScaleX] * v.data[kTranslateY]) * scale; 254 255 data[kPerspective0] = (v.data[kSkewY] * v.data[kPerspective1] - 256 v.data[kScaleY] * v.data[kPerspective0]) * scale; 257 data[kPerspective1] = (v.data[kSkewX] * v.data[kPerspective0] - 258 v.data[kScaleX] * v.data[kPerspective1]) * scale; 259 data[kPerspective2] = (v.data[kScaleX] * v.data[kScaleY] - 260 v.data[kSkewX] * v.data[kSkewY]) * scale; 261 262 mType = kTypeUnknown; 263 } 264 265 void Matrix4::copyTo(float* v) const { 266 memcpy(v, data, sizeof(data)); 267 } 268 269 float Matrix4::getTranslateX() const { 270 return data[kTranslateX]; 271 } 272 273 float Matrix4::getTranslateY() const { 274 return data[kTranslateY]; 275 } 276 277 void Matrix4::multiply(float v) { 278 for (int i = 0; i < 16; i++) { 279 data[i] *= v; 280 } 281 mType = kTypeUnknown; 282 } 283 284 void Matrix4::loadTranslate(float x, float y, float z) { 285 loadIdentity(); 286 287 data[kTranslateX] = x; 288 data[kTranslateY] = y; 289 data[kTranslateZ] = z; 290 291 mType = kTypeTranslate | kTypeRectToRect; 292 } 293 294 void Matrix4::loadScale(float sx, float sy, float sz) { 295 loadIdentity(); 296 297 data[kScaleX] = sx; 298 data[kScaleY] = sy; 299 data[kScaleZ] = sz; 300 301 mType = kTypeScale | kTypeRectToRect; 302 } 303 304 void Matrix4::loadSkew(float sx, float sy) { 305 loadIdentity(); 306 307 data[kScaleX] = 1.0f; 308 data[kSkewX] = sx; 309 data[kTranslateX] = 0.0f; 310 311 data[kSkewY] = sy; 312 data[kScaleY] = 1.0f; 313 data[kTranslateY] = 0.0f; 314 315 data[kPerspective0] = 0.0f; 316 data[kPerspective1] = 0.0f; 317 data[kPerspective2] = 1.0f; 318 319 mType = kTypeUnknown; 320 } 321 322 void Matrix4::loadRotate(float angle) { 323 angle *= float(M_PI / 180.0f); 324 float c = cosf(angle); 325 float s = sinf(angle); 326 327 loadIdentity(); 328 329 data[kScaleX] = c; 330 data[kSkewX] = -s; 331 332 data[kSkewY] = s; 333 data[kScaleY] = c; 334 335 mType = kTypeUnknown; 336 } 337 338 void Matrix4::loadRotate(float angle, float x, float y, float z) { 339 data[kPerspective0] = 0.0f; 340 data[kPerspective1] = 0.0f; 341 data[11] = 0.0f; 342 data[kTranslateX] = 0.0f; 343 data[kTranslateY] = 0.0f; 344 data[kTranslateZ] = 0.0f; 345 data[kPerspective2] = 1.0f; 346 347 angle *= float(M_PI / 180.0f); 348 float c = cosf(angle); 349 float s = sinf(angle); 350 351 const float length = sqrtf(x * x + y * y + z * z); 352 float recipLen = 1.0f / length; 353 x *= recipLen; 354 y *= recipLen; 355 z *= recipLen; 356 357 const float nc = 1.0f - c; 358 const float xy = x * y; 359 const float yz = y * z; 360 const float zx = z * x; 361 const float xs = x * s; 362 const float ys = y * s; 363 const float zs = z * s; 364 365 data[kScaleX] = x * x * nc + c; 366 data[kSkewX] = xy * nc - zs; 367 data[8] = zx * nc + ys; 368 data[kSkewY] = xy * nc + zs; 369 data[kScaleY] = y * y * nc + c; 370 data[9] = yz * nc - xs; 371 data[2] = zx * nc - ys; 372 data[6] = yz * nc + xs; 373 data[kScaleZ] = z * z * nc + c; 374 375 mType = kTypeUnknown; 376 } 377 378 void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) { 379 for (int i = 0 ; i < 4 ; i++) { 380 float x = 0; 381 float y = 0; 382 float z = 0; 383 float w = 0; 384 385 for (int j = 0 ; j < 4 ; j++) { 386 const float e = v.get(i, j); 387 x += u.get(j, 0) * e; 388 y += u.get(j, 1) * e; 389 z += u.get(j, 2) * e; 390 w += u.get(j, 3) * e; 391 } 392 393 set(i, 0, x); 394 set(i, 1, y); 395 set(i, 2, z); 396 set(i, 3, w); 397 } 398 399 mType = kTypeUnknown; 400 } 401 402 void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) { 403 loadIdentity(); 404 405 data[kScaleX] = 2.0f / (right - left); 406 data[kScaleY] = 2.0f / (top - bottom); 407 data[kScaleZ] = -2.0f / (far - near); 408 data[kTranslateX] = -(right + left) / (right - left); 409 data[kTranslateY] = -(top + bottom) / (top - bottom); 410 data[kTranslateZ] = -(far + near) / (far - near); 411 412 mType = kTypeTranslate | kTypeScale | kTypeRectToRect; 413 } 414 415 float Matrix4::mapZ(const Vector3& orig) const { 416 // duplicates logic for mapPoint3d's z coordinate 417 return orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ]; 418 } 419 420 void Matrix4::mapPoint3d(Vector3& vec) const { 421 //TODO: optimize simple case 422 const Vector3 orig(vec); 423 vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX]; 424 vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY]; 425 vec.z = orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ]; 426 } 427 428 #define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c) 429 430 void Matrix4::mapPoint(float& x, float& y) const { 431 if (isSimple()) { 432 MUL_ADD_STORE(x, data[kScaleX], data[kTranslateX]); 433 MUL_ADD_STORE(y, data[kScaleY], data[kTranslateY]); 434 return; 435 } 436 437 float dx = x * data[kScaleX] + y * data[kSkewX] + data[kTranslateX]; 438 float dy = x * data[kSkewY] + y * data[kScaleY] + data[kTranslateY]; 439 float dz = x * data[kPerspective0] + y * data[kPerspective1] + data[kPerspective2]; 440 if (dz) dz = 1.0f / dz; 441 442 x = dx * dz; 443 y = dy * dz; 444 } 445 446 void Matrix4::mapRect(Rect& r) const { 447 if (isIdentity()) return; 448 449 if (isSimple()) { 450 MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]); 451 MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]); 452 MUL_ADD_STORE(r.top, data[kScaleY], data[kTranslateY]); 453 MUL_ADD_STORE(r.bottom, data[kScaleY], data[kTranslateY]); 454 455 if (r.left > r.right) { 456 float x = r.left; 457 r.left = r.right; 458 r.right = x; 459 } 460 461 if (r.top > r.bottom) { 462 float y = r.top; 463 r.top = r.bottom; 464 r.bottom = y; 465 } 466 467 return; 468 } 469 470 float vertices[] = { 471 r.left, r.top, 472 r.right, r.top, 473 r.right, r.bottom, 474 r.left, r.bottom 475 }; 476 477 float x, y, z; 478 479 for (int i = 0; i < 8; i+= 2) { 480 float px = vertices[i]; 481 float py = vertices[i + 1]; 482 483 x = px * data[kScaleX] + py * data[kSkewX] + data[kTranslateX]; 484 y = px * data[kSkewY] + py * data[kScaleY] + data[kTranslateY]; 485 z = px * data[kPerspective0] + py * data[kPerspective1] + data[kPerspective2]; 486 if (z) z = 1.0f / z; 487 488 vertices[i] = x * z; 489 vertices[i + 1] = y * z; 490 } 491 492 r.left = r.right = vertices[0]; 493 r.top = r.bottom = vertices[1]; 494 495 for (int i = 2; i < 8; i += 2) { 496 x = vertices[i]; 497 y = vertices[i + 1]; 498 499 if (x < r.left) r.left = x; 500 else if (x > r.right) r.right = x; 501 if (y < r.top) r.top = y; 502 else if (y > r.bottom) r.bottom = y; 503 } 504 } 505 506 void Matrix4::decomposeScale(float& sx, float& sy) const { 507 float len; 508 len = data[mat4::kScaleX] * data[mat4::kScaleX] + data[mat4::kSkewX] * data[mat4::kSkewX]; 509 sx = copysignf(sqrtf(len), data[mat4::kScaleX]); 510 len = data[mat4::kScaleY] * data[mat4::kScaleY] + data[mat4::kSkewY] * data[mat4::kSkewY]; 511 sy = copysignf(sqrtf(len), data[mat4::kScaleY]); 512 } 513 514 void Matrix4::dump(const char* label) const { 515 ALOGD("%s[simple=%d, type=0x%x", label ? label : "Matrix4", isSimple(), getType()); 516 ALOGD(" %f %f %f %f", data[kScaleX], data[kSkewX], data[8], data[kTranslateX]); 517 ALOGD(" %f %f %f %f", data[kSkewY], data[kScaleY], data[9], data[kTranslateY]); 518 ALOGD(" %f %f %f %f", data[2], data[6], data[kScaleZ], data[kTranslateZ]); 519 ALOGD(" %f %f %f %f", data[kPerspective0], data[kPerspective1], data[11], data[kPerspective2]); 520 ALOGD("]"); 521 } 522 523 }; // namespace uirenderer 524 }; // namespace android 525