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