• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
identity()40  const Matrix4& Matrix4::identity() {
41      static Matrix4 sIdentity;
42      return sIdentity;
43  }
44  
loadIdentity()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  
isZero(float f)69  static bool isZero(float f) {
70      return fabs(f) <= EPSILON;
71  }
72  
getType() const73  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  
getGeometryType() const116  uint8_t Matrix4::getGeometryType() const {
117      return getType() & sGeometryMask;
118  }
119  
rectToRect() const120  bool Matrix4::rectToRect() const {
121      return getType() & kTypeRectToRect;
122  }
123  
positiveScale() const124  bool Matrix4::positiveScale() const {
125      return (data[kScaleX] > 0.0f && data[kScaleY] > 0.0f);
126  }
127  
changesBounds() const128  bool Matrix4::changesBounds() const {
129      return getType() & (kTypeScale | kTypeAffine | kTypePerspective);
130  }
131  
isPureTranslate() const132  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  
isSimple() const138  bool Matrix4::isSimple() const {
139      return getGeometryType() <= (kTypeScale | kTypeTranslate) && (data[kTranslateZ] == 0.0f);
140  }
141  
isIdentity() const142  bool Matrix4::isIdentity() const {
143      return getGeometryType() == kTypeIdentity;
144  }
145  
isPerspective() const146  bool Matrix4::isPerspective() const {
147      return getType() & kTypePerspective;
148  }
149  
load(const float * v)150  void Matrix4::load(const float* v) {
151      memcpy(data, v, sizeof(data));
152      mType = kTypeUnknown;
153  }
154  
load(const SkMatrix & v)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  
copyTo(SkMatrix & v) const182  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  
loadInverse(const Matrix4 & v)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  
copyTo(float * v) const259  void Matrix4::copyTo(float* v) const {
260      memcpy(v, data, sizeof(data));
261  }
262  
getTranslateX() const263  float Matrix4::getTranslateX() const {
264      return data[kTranslateX];
265  }
266  
getTranslateY() const267  float Matrix4::getTranslateY() const {
268      return data[kTranslateY];
269  }
270  
multiply(float v)271  void Matrix4::multiply(float v) {
272      for (int i = 0; i < 16; i++) {
273          data[i] *= v;
274      }
275      mType = kTypeUnknown;
276  }
277  
loadTranslate(float x,float y,float z)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  
loadScale(float sx,float sy,float sz)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  
loadSkew(float sx,float sy)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  
loadRotate(float angle)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  
loadRotate(float angle,float x,float y,float z)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  
loadMultiply(const Matrix4 & u,const Matrix4 & v)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  
loadOrtho(float left,float right,float bottom,float top,float near,float far)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  
mapZ(const Vector3 & orig) const409  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  
mapPoint3d(Vector3 & vec) const414  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  
mapPoint(float & x,float & y) const424  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   */
mapRect(Rect & r) const448  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  
decomposeScale(float & sx,float & sy) const508  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  
dump(const char * label) const516  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