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 #pragma once
18 
19 #include "Rect.h"
20 
21 #include <SkMatrix.h>
22 #include <cutils/compiler.h>
23 #include <iomanip>
24 #include <ostream>
25 
26 namespace android {
27 namespace uirenderer {
28 
29 #define SK_MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
30 #define SK_MATRIX_ARGS(m)                                                                      \
31     (m)->get(0), (m)->get(1), (m)->get(2), (m)->get(3), (m)->get(4), (m)->get(5), (m)->get(6), \
32             (m)->get(7), (m)->get(8)
33 
34 #define MATRIX_4_STRING                           \
35     "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
36     " [%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]"
37 #define MATRIX_4_ARGS(m)                                                                           \
38     (m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], (m)->data[1], (m)->data[5],           \
39             (m)->data[9], (m)->data[13], (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
40             (m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15]
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 // Classes
44 ///////////////////////////////////////////////////////////////////////////////
45 
46 class ANDROID_API Matrix4 {
47 public:
48     float data[16];
49 
50     enum Entry {
51         kScaleX = 0,
52         kSkewY = 1,
53         kPerspective0 = 3,
54         kSkewX = 4,
55         kScaleY = 5,
56         kPerspective1 = 7,
57         kScaleZ = 10,
58         kTranslateX = 12,
59         kTranslateY = 13,
60         kTranslateZ = 14,
61         kPerspective2 = 15
62     };
63 
64     // NOTE: The flags from kTypeIdentity to kTypePerspective
65     //       must be kept in sync with the type flags found
66     //       in SkMatrix
67     enum Type {
68         kTypeIdentity = 0,
69         kTypeTranslate = 0x1,
70         kTypeScale = 0x2,
71         kTypeAffine = 0x4,
72         kTypePerspective = 0x8,
73         kTypeRectToRect = 0x10,
74         kTypeUnknown = 0x20,
75     };
76 
77     static const int sGeometryMask = 0xf;
78 
Matrix4()79     Matrix4() { loadIdentity(); }
80 
Matrix4(const float * v)81     explicit Matrix4(const float* v) { load(v); }
82 
Matrix4(const SkMatrix & v)83     Matrix4(const SkMatrix& v) {  // NOLINT, implicit
84         load(v);
85     }
86 
87     float operator[](int index) const { return data[index]; }
88 
89     float& operator[](int index) {
90         mType = kTypeUnknown;
91         return data[index];
92     }
93 
94     Matrix4& operator=(const SkMatrix& v) {
95         load(v);
96         return *this;
97     }
98 
99     friend bool operator==(const Matrix4& a, const Matrix4& b) {
100         return !memcmp(&a.data[0], &b.data[0], 16 * sizeof(float));
101     }
102 
103     friend bool operator!=(const Matrix4& a, const Matrix4& b) { return !(a == b); }
104 
105     void loadIdentity();
106 
107     void load(const float* v);
108     void load(const SkMatrix& v);
109 
110     void loadInverse(const Matrix4& v);
111 
112     void loadTranslate(float x, float y, float z);
113     void loadScale(float sx, float sy, float sz);
114     void loadSkew(float sx, float sy);
115     void loadRotate(float angle);
116     void loadRotate(float angle, float x, float y, float z);
117     void loadMultiply(const Matrix4& u, const Matrix4& v);
118 
119     void loadOrtho(float left, float right, float bottom, float top, float near, float far);
loadOrtho(int width,int height)120     void loadOrtho(int width, int height) { loadOrtho(0, width, height, 0, -1, 1); }
121 
122     uint8_t getType() const;
123 
multiplyInverse(const Matrix4 & v)124     void multiplyInverse(const Matrix4& v) {
125         Matrix4 inv;
126         inv.loadInverse(v);
127         multiply(inv);
128     }
129 
multiply(const Matrix4 & v)130     void multiply(const Matrix4& v) {
131         if (!v.isIdentity()) {
132             Matrix4 u;
133             u.loadMultiply(*this, v);
134             *this = u;
135         }
136     }
137 
138     void multiply(float v);
139 
140     void translate(float x, float y, float z = 0) {
141         if ((getType() & sGeometryMask) <= kTypeTranslate) {
142             data[kTranslateX] += x;
143             data[kTranslateY] += y;
144             data[kTranslateZ] += z;
145             mType |= kTypeUnknown;
146         } else {
147             // Doing a translation will only affect the translate bit of the type
148             // Save the type
149             uint8_t type = mType;
150 
151             Matrix4 u;
152             u.loadTranslate(x, y, z);
153             multiply(u);
154 
155             // Restore the type and fix the translate bit
156             mType = type;
157             if (data[kTranslateX] != 0.0f || data[kTranslateY] != 0.0f) {
158                 mType |= kTypeTranslate;
159             } else {
160                 mType &= ~kTypeTranslate;
161             }
162         }
163     }
164 
scale(float sx,float sy,float sz)165     void scale(float sx, float sy, float sz) {
166         Matrix4 u;
167         u.loadScale(sx, sy, sz);
168         multiply(u);
169     }
170 
skew(float sx,float sy)171     void skew(float sx, float sy) {
172         Matrix4 u;
173         u.loadSkew(sx, sy);
174         multiply(u);
175     }
176 
rotate(float angle,float x,float y,float z)177     void rotate(float angle, float x, float y, float z) {
178         Matrix4 u;
179         u.loadRotate(angle, x, y, z);
180         multiply(u);
181     }
182 
183     /**
184      * If the matrix is identity or translate and/or scale.
185      */
186     bool isSimple() const;
187     bool isPureTranslate() const;
188     bool isIdentity() const;
189     bool isPerspective() const;
190     bool rectToRect() const;
191     bool positiveScale() const;
192 
193     bool changesBounds() const;
194 
195     void copyTo(float* v) const;
196     void copyTo(SkMatrix& v) const;
197 
198     float mapZ(const Vector3& orig) const;
199     void mapPoint3d(Vector3& vec) const;
200     void mapPoint(float& x, float& y) const;  // 2d only
201     void mapRect(Rect& r) const;              // 2d only
202 
203     float getTranslateX() const;
204     float getTranslateY() const;
205 
206     void decomposeScale(float& sx, float& sy) const;
207 
208     void dump(const char* label = nullptr) const;
209 
210     friend std::ostream& operator<<(std::ostream& os, const Matrix4& matrix) {
211         if (matrix.isSimple()) {
212             os << "offset " << matrix.getTranslateX() << "x" << matrix.getTranslateY();
213             if (!matrix.isPureTranslate()) {
214                 os << ", scale " << matrix[kScaleX] << "x" << matrix[kScaleY];
215             }
216         } else {
217             os << "[" << matrix[0];
218             for (int i = 1; i < 16; i++) {
219                 os << ", " << matrix[i];
220             }
221             os << "]";
222         }
223         return os;
224     }
225 
226     static const Matrix4& identity();
227 
invalidateType()228     void invalidateType() { mType = kTypeUnknown; }
229 
230 private:
231     mutable uint8_t mType;
232 
get(int i,int j)233     inline float get(int i, int j) const { return data[i * 4 + j]; }
234 
set(int i,int j,float v)235     inline void set(int i, int j, float v) { data[i * 4 + j] = v; }
236 
237     uint8_t getGeometryType() const;
238 
239 };  // class Matrix4
240 
241 ///////////////////////////////////////////////////////////////////////////////
242 // Types
243 ///////////////////////////////////////////////////////////////////////////////
244 
245 typedef Matrix4 mat4;
246 
247 };  // namespace uirenderer
248 };  // namespace android
249