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