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 /
    228             (v.data[kScaleX] * ((double) v.data[kScaleY]  * v.data[kPerspective2] -
    229                     (double) v.data[kTranslateY] * v.data[kPerspective1]) +
    230              v.data[kSkewX] * ((double) v.data[kTranslateY] * v.data[kPerspective0] -
    231                      (double) v.data[kSkewY] * v.data[kPerspective2]) +
    232              v.data[kTranslateX] * ((double) v.data[kSkewY] * v.data[kPerspective1] -
    233                      (double) v.data[kScaleY] * v.data[kPerspective0]));
    234 
    235     data[kScaleX] = (v.data[kScaleY] * v.data[kPerspective2] -
    236             v.data[kTranslateY] * v.data[kPerspective1]) * scale;
    237     data[kSkewX] = (v.data[kTranslateX] * v.data[kPerspective1] -
    238             v.data[kSkewX]  * v.data[kPerspective2]) * scale;
    239     data[kTranslateX] = (v.data[kSkewX] * v.data[kTranslateY] -
    240             v.data[kTranslateX] * v.data[kScaleY]) * scale;
    241 
    242     data[kSkewY] = (v.data[kTranslateY] * v.data[kPerspective0] -
    243             v.data[kSkewY]  * v.data[kPerspective2]) * scale;
    244     data[kScaleY] = (v.data[kScaleX] * v.data[kPerspective2] -
    245             v.data[kTranslateX] * v.data[kPerspective0]) * scale;
    246     data[kTranslateY] = (v.data[kTranslateX] * v.data[kSkewY] -
    247             v.data[kScaleX] * v.data[kTranslateY]) * scale;
    248 
    249     data[kPerspective0] = (v.data[kSkewY] * v.data[kPerspective1] -
    250             v.data[kScaleY] * v.data[kPerspective0]) * scale;
    251     data[kPerspective1] = (v.data[kSkewX] * v.data[kPerspective0] -
    252             v.data[kScaleX] * v.data[kPerspective1]) * scale;
    253     data[kPerspective2] = (v.data[kScaleX] * v.data[kScaleY] -
    254             v.data[kSkewX] * v.data[kSkewY]) * scale;
    255 
    256     mType = kTypeUnknown;
    257 }
    258 
    259 void Matrix4::copyTo(float* v) const {
    260     memcpy(v, data, sizeof(data));
    261 }
    262 
    263 float Matrix4::getTranslateX() const {
    264     return data[kTranslateX];
    265 }
    266 
    267 float Matrix4::getTranslateY() const {
    268     return data[kTranslateY];
    269 }
    270 
    271 void Matrix4::multiply(float v) {
    272     for (int i = 0; i < 16; i++) {
    273         data[i] *= v;
    274     }
    275     mType = kTypeUnknown;
    276 }
    277 
    278 void Matrix4::loadTranslate(float x, float y, float z) {
    279     loadIdentity();
    280 
    281     data[kTranslateX] = x;
    282     data[kTranslateY] = y;
    283     data[kTranslateZ] = z;
    284 
    285     mType = kTypeTranslate | kTypeRectToRect;
    286 }
    287 
    288 void Matrix4::loadScale(float sx, float sy, float sz) {
    289     loadIdentity();
    290 
    291     data[kScaleX] = sx;
    292     data[kScaleY] = sy;
    293     data[kScaleZ] = sz;
    294 
    295     mType = kTypeScale | kTypeRectToRect;
    296 }
    297 
    298 void Matrix4::loadSkew(float sx, float sy) {
    299     loadIdentity();
    300 
    301     data[kScaleX]       = 1.0f;
    302     data[kSkewX]        = sx;
    303     data[kTranslateX]   = 0.0f;
    304 
    305     data[kSkewY]        = sy;
    306     data[kScaleY]       = 1.0f;
    307     data[kTranslateY]   = 0.0f;
    308 
    309     data[kPerspective0] = 0.0f;
    310     data[kPerspective1] = 0.0f;
    311     data[kPerspective2] = 1.0f;
    312 
    313     mType = kTypeUnknown;
    314 }
    315 
    316 void Matrix4::loadRotate(float angle) {
    317     angle *= float(M_PI / 180.0f);
    318     float c = cosf(angle);
    319     float s = sinf(angle);
    320 
    321     loadIdentity();
    322 
    323     data[kScaleX]     = c;
    324     data[kSkewX]      = -s;
    325 
    326     data[kSkewY]      = s;
    327     data[kScaleY]     = c;
    328 
    329     mType = kTypeUnknown;
    330 }
    331 
    332 void Matrix4::loadRotate(float angle, float x, float y, float z) {
    333     data[kPerspective0]  = 0.0f;
    334     data[kPerspective1]  = 0.0f;
    335     data[11]             = 0.0f;
    336     data[kTranslateX]    = 0.0f;
    337     data[kTranslateY]    = 0.0f;
    338     data[kTranslateZ]    = 0.0f;
    339     data[kPerspective2]  = 1.0f;
    340 
    341     angle *= float(M_PI / 180.0f);
    342     float c = cosf(angle);
    343     float s = sinf(angle);
    344 
    345     const float length = sqrtf(x * x + y * y + z * z);
    346     float recipLen = 1.0f / length;
    347     x *= recipLen;
    348     y *= recipLen;
    349     z *= recipLen;
    350 
    351     const float nc = 1.0f - c;
    352     const float xy = x * y;
    353     const float yz = y * z;
    354     const float zx = z * x;
    355     const float xs = x * s;
    356     const float ys = y * s;
    357     const float zs = z * s;
    358 
    359     data[kScaleX] = x * x * nc +  c;
    360     data[kSkewX]  =    xy * nc - zs;
    361     data[8]       =    zx * nc + ys;
    362     data[kSkewY]  =    xy * nc + zs;
    363     data[kScaleY] = y * y * nc +  c;
    364     data[9]       =    yz * nc - xs;
    365     data[2]       =    zx * nc - ys;
    366     data[6]       =    yz * nc + xs;
    367     data[kScaleZ] = z * z * nc +  c;
    368 
    369     mType = kTypeUnknown;
    370 }
    371 
    372 void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
    373     for (int i = 0 ; i < 4 ; i++) {
    374         float x = 0;
    375         float y = 0;
    376         float z = 0;
    377         float w = 0;
    378 
    379         for (int j = 0 ; j < 4 ; j++) {
    380             const float e = v.get(i, j);
    381             x += u.get(j, 0) * e;
    382             y += u.get(j, 1) * e;
    383             z += u.get(j, 2) * e;
    384             w += u.get(j, 3) * e;
    385         }
    386 
    387         set(i, 0, x);
    388         set(i, 1, y);
    389         set(i, 2, z);
    390         set(i, 3, w);
    391     }
    392 
    393     mType = kTypeUnknown;
    394 }
    395 
    396 void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) {
    397     loadIdentity();
    398 
    399     data[kScaleX] = 2.0f / (right - left);
    400     data[kScaleY] = 2.0f / (top - bottom);
    401     data[kScaleZ] = -2.0f / (far - near);
    402     data[kTranslateX] = -(right + left) / (right - left);
    403     data[kTranslateY] = -(top + bottom) / (top - bottom);
    404     data[kTranslateZ] = -(far + near) / (far - near);
    405 
    406     mType = kTypeTranslate | kTypeScale | kTypeRectToRect;
    407 }
    408 
    409 float Matrix4::mapZ(const Vector3& orig) const {
    410     // duplicates logic for mapPoint3d's z coordinate
    411     return orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ];
    412 }
    413 
    414 void Matrix4::mapPoint3d(Vector3& vec) const {
    415     //TODO: optimize simple case
    416     const Vector3 orig(vec);
    417     vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX];
    418     vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY];
    419     vec.z = orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ];
    420 }
    421 
    422 #define MUL_ADD_STORE(a, b, c) ((a) = (a) * (b) + (c))
    423 
    424 void Matrix4::mapPoint(float& x, float& y) const {
    425     if (isSimple()) {
    426         MUL_ADD_STORE(x, data[kScaleX], data[kTranslateX]);
    427         MUL_ADD_STORE(y, data[kScaleY], data[kTranslateY]);
    428         return;
    429     }
    430 
    431     float dx = x * data[kScaleX] + y * data[kSkewX] + data[kTranslateX];
    432     float dy = x * data[kSkewY] + y * data[kScaleY] + data[kTranslateY];
    433     float dz = x * data[kPerspective0] + y * data[kPerspective1] + data[kPerspective2];
    434     if (dz) dz = 1.0f / dz;
    435 
    436     x = dx * dz;
    437     y = dy * dz;
    438 }
    439 
    440 /**
    441  * Set the contents of the rect to be the bounding rect around each of the corners, mapped by the
    442  * matrix.
    443  *
    444  * NOTE: an empty rect to an arbitrary matrix isn't guaranteed to have an empty output, since that's
    445  * important for conservative bounds estimation (e.g. rotate45Matrix.mapRect of Rect(0, 10) should
    446  * result in non-empty.
    447  */
    448 void Matrix4::mapRect(Rect& r) const {
    449     if (isIdentity()) return;
    450 
    451     if (isSimple()) {
    452         MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
    453         MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
    454         MUL_ADD_STORE(r.top, data[kScaleY], data[kTranslateY]);
    455         MUL_ADD_STORE(r.bottom, data[kScaleY], data[kTranslateY]);
    456 
    457         if (r.left > r.right) {
    458             float x = r.left;
    459             r.left = r.right;
    460             r.right = x;
    461         }
    462 
    463         if (r.top > r.bottom) {
    464             float y = r.top;
    465             r.top = r.bottom;
    466             r.bottom = y;
    467         }
    468 
    469         return;
    470     }
    471 
    472     float vertices[] = {
    473         r.left, r.top,
    474         r.right, r.top,
    475         r.right, r.bottom,
    476         r.left, r.bottom
    477     };
    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) r.left = x;
    502         else if (x > r.right) r.right = x;
    503         if (y < r.top) r.top = y;
    504         else if (y > r.bottom) r.bottom = y;
    505     }
    506 }
    507 
    508 void Matrix4::decomposeScale(float& sx, float& sy) const {
    509     float len;
    510     len = data[mat4::kScaleX] * data[mat4::kScaleX] + data[mat4::kSkewX] * data[mat4::kSkewX];
    511     sx = copysignf(sqrtf(len), data[mat4::kScaleX]);
    512     len = data[mat4::kScaleY] * data[mat4::kScaleY] + data[mat4::kSkewY] * data[mat4::kSkewY];
    513     sy = copysignf(sqrtf(len), data[mat4::kScaleY]);
    514 }
    515 
    516 void Matrix4::dump(const char* label) const {
    517     ALOGD("%s[simple=%d, type=0x%x", label ? label : "Matrix4", isSimple(), getType());
    518     ALOGD("  %f %f %f %f", data[kScaleX], data[kSkewX], data[8], data[kTranslateX]);
    519     ALOGD("  %f %f %f %f", data[kSkewY], data[kScaleY], data[9], data[kTranslateY]);
    520     ALOGD("  %f %f %f %f", data[2], data[6], data[kScaleZ], data[kTranslateZ]);
    521     ALOGD("  %f %f %f %f", data[kPerspective0], data[kPerspective1], data[11], data[kPerspective2]);
    522     ALOGD("]");
    523 }
    524 
    525 }; // namespace uirenderer
    526 }; // namespace android
    527