1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "wm_math.h"
17 #include <cstdlib>
18
19 namespace OHOS::Rosen {
20 namespace TransformHelper {
21 const Matrix3 Matrix3::Identity = { {
22 { 1, 0, 0 },
23 { 0, 1, 0 },
24 { 0, 0, 1 },
25 } };
26 const Matrix4 Matrix4::Identity = { {
27 { 1, 0, 0, 0 },
28 { 0, 1, 0, 0 },
29 { 0, 0, 1, 0 },
30 { 0, 0, 0, 1 },
31 } };
32
operator *(const Matrix3 & left,const Matrix3 & right)33 Matrix3 operator*(const Matrix3& left, const Matrix3& right)
34 {
35 return { {
36 // row 0
37 { left.mat_[0][0] * right.mat_[0][0] + left.mat_[0][1] * right.mat_[1][0] + left.mat_[0][2] * right.mat_[2][0],
38 left.mat_[0][0] * right.mat_[0][1] + left.mat_[0][1] * right.mat_[1][1] + left.mat_[0][2] * right.mat_[2][1],
39 left.mat_[0][0] * right.mat_[0][2] + left.mat_[0][1] * right.mat_[1][2] + left.mat_[0][2] * right.mat_[2][2] },
40
41 // row 1
42 { left.mat_[1][0] * right.mat_[0][0] + left.mat_[1][1] * right.mat_[1][0] + left.mat_[1][2] * right.mat_[2][0],
43 left.mat_[1][0] * right.mat_[0][1] + left.mat_[1][1] * right.mat_[1][1] + left.mat_[1][2] * right.mat_[2][1],
44 left.mat_[1][0] * right.mat_[0][2] + left.mat_[1][1] * right.mat_[1][2] + left.mat_[1][2] * right.mat_[2][2] },
45
46 // row 2
47 { left.mat_[2][0] * right.mat_[0][0] + left.mat_[2][1] * right.mat_[1][0] + left.mat_[2][2] * right.mat_[2][0],
48 left.mat_[2][0] * right.mat_[0][1] + left.mat_[2][1] * right.mat_[1][1] + left.mat_[2][2] * right.mat_[2][1],
49 left.mat_[2][0] * right.mat_[0][2] + left.mat_[2][1] * right.mat_[1][2] + left.mat_[2][2] * right.mat_[2][2] }
50 } };
51 }
52
operator *=(const Matrix3 & right)53 Matrix3& Matrix3::operator*=(const Matrix3& right)
54 {
55 *this = *this * right;
56 return *this;
57 }
58
operator *(const Matrix4 & left,const Matrix4 & right)59 Matrix4 operator*(const Matrix4& left, const Matrix4& right)
60 {
61 return { {
62 // row 0
63 { left.mat_[0][0] * right.mat_[0][0] + left.mat_[0][1] * right.mat_[1][0] +
64 left.mat_[0][2] * right.mat_[2][0] + left.mat_[0][3] * right.mat_[3][0],
65 left.mat_[0][0] * right.mat_[0][1] + left.mat_[0][1] * right.mat_[1][1] +
66 left.mat_[0][2] * right.mat_[2][1] + left.mat_[0][3] * right.mat_[3][1],
67 left.mat_[0][0] * right.mat_[0][2] + left.mat_[0][1] * right.mat_[1][2] +
68 left.mat_[0][2] * right.mat_[2][2] + left.mat_[0][3] * right.mat_[3][2],
69 left.mat_[0][0] * right.mat_[0][3] + left.mat_[0][1] * right.mat_[1][3] +
70 left.mat_[0][2] * right.mat_[2][3] + left.mat_[0][3] * right.mat_[3][3] },
71
72 // row 1
73 { left.mat_[1][0] * right.mat_[0][0] + left.mat_[1][1] * right.mat_[1][0] +
74 left.mat_[1][2] * right.mat_[2][0] + left.mat_[1][3] * right.mat_[3][0],
75 left.mat_[1][0] * right.mat_[0][1] + left.mat_[1][1] * right.mat_[1][1] +
76 left.mat_[1][2] * right.mat_[2][1] + left.mat_[1][3] * right.mat_[3][1],
77 left.mat_[1][0] * right.mat_[0][2] + left.mat_[1][1] * right.mat_[1][2] +
78 left.mat_[1][2] * right.mat_[2][2] + left.mat_[1][3] * right.mat_[3][2],
79 left.mat_[1][0] * right.mat_[0][3] + left.mat_[1][1] * right.mat_[1][3] +
80 left.mat_[1][2] * right.mat_[2][3] + left.mat_[1][3] * right.mat_[3][3] },
81
82 // row 2
83 { left.mat_[2][0] * right.mat_[0][0] + left.mat_[2][1] * right.mat_[1][0] +
84 left.mat_[2][2] * right.mat_[2][0] + left.mat_[2][3] * right.mat_[3][0],
85 left.mat_[2][0] * right.mat_[0][1] + left.mat_[2][1] * right.mat_[1][1] +
86 left.mat_[2][2] * right.mat_[2][1] + left.mat_[2][3] * right.mat_[3][1],
87 left.mat_[2][0] * right.mat_[0][2] + left.mat_[2][1] * right.mat_[1][2] +
88 left.mat_[2][2] * right.mat_[2][2] + left.mat_[2][3] * right.mat_[3][2],
89 left.mat_[2][0] * right.mat_[0][3] + left.mat_[2][1] * right.mat_[1][3] +
90 left.mat_[2][2] * right.mat_[2][3] + left.mat_[2][3] * right.mat_[3][3] },
91
92 // row 3
93 { left.mat_[3][0] * right.mat_[0][0] + left.mat_[3][1] * right.mat_[1][0] +
94 left.mat_[3][2] * right.mat_[2][0] + left.mat_[3][3] * right.mat_[3][0],
95 left.mat_[3][0] * right.mat_[0][1] + left.mat_[3][1] * right.mat_[1][1] +
96 left.mat_[3][2] * right.mat_[2][1] + left.mat_[3][3] * right.mat_[3][1],
97 left.mat_[3][0] * right.mat_[0][2] + left.mat_[3][1] * right.mat_[1][2] +
98 left.mat_[3][2] * right.mat_[2][2] + left.mat_[3][3] * right.mat_[3][2],
99 left.mat_[3][0] * right.mat_[0][3] + left.mat_[3][1] * right.mat_[1][3] +
100 left.mat_[3][2] * right.mat_[2][3] + left.mat_[3][3] * right.mat_[3][3] }
101 } };
102 }
103
operator *=(const Matrix4 & right)104 Matrix4& Matrix4::operator*=(const Matrix4& right)
105 {
106 *this = *this * right;
107 return *this;
108 }
109
SwapRow(int row1,int row2)110 void Matrix4::SwapRow(int row1, int row2)
111 {
112 float *p = mat_[row1];
113 float *q = mat_[row2];
114 float tmp = p[0];
115 p[0] = q[0];
116 q[0] = tmp;
117
118 tmp = p[1];
119 p[1] = q[1];
120 q[1] = tmp;
121
122 tmp = p[2]; // 2: row2
123 p[2] = q[2]; // 2: row2
124 q[2] = tmp; // 2: row2
125
126 tmp = p[3]; // 3: row3
127 p[3] = q[3]; // 3: row3
128 q[3] = tmp; // 3: row3
129 }
130
Invert()131 void Matrix4::Invert()
132 {
133 // Inverse matrix with Gauss-Jordan method
134 Matrix4 tmp = Matrix4::Identity;
135 int i, j, k;
136 for (k = 0; k < MAT_SIZE; k++) {
137 float t = mat_[k][k];
138 if (t < MathHelper::POS_ZERO && t > MathHelper::NAG_ZERO) {
139 for (i = k + 1; i < MAT_SIZE; i++) {
140 if (mat_[i][k] < MathHelper::NAG_ZERO || mat_[i][k] > MathHelper::POS_ZERO) {
141 SwapRow(k, i);
142 tmp.SwapRow(k, i);
143 break;
144 }
145 }
146 t = mat_[k][k];
147 }
148 for (j = 0; j <= k; j++) {
149 tmp.mat_[k][j] /= t;
150 }
151 for (; j < MAT_SIZE; j++) {
152 mat_[k][j] /= t;
153 tmp.mat_[k][j] /= t;
154 }
155 for (i = 0; i < MAT_SIZE; i++) {
156 if (i == k) {
157 continue;
158 }
159 float u = mat_[i][k];
160 for (j = 0; j <= k; j++) {
161 tmp.mat_[i][j] -= tmp.mat_[k][j] * u;
162 }
163 for (; j < MAT_SIZE; j++) {
164 mat_[i][j] -= mat_[k][j] * u;
165 tmp.mat_[i][j] -= tmp.mat_[k][j] * u;
166 }
167 }
168 }
169 *this = tmp;
170 }
171
GetScale() const172 Vector3 Matrix4::GetScale() const
173 {
174 Vector3 retVal;
175 retVal.x_ = Vector3(mat_[0][0], mat_[0][1], mat_[0][2]).Length(); // 2: column2
176 retVal.y_ = Vector3(mat_[1][0], mat_[1][1], mat_[1][2]).Length(); // 2: column2
177 retVal.z_ = Vector3(mat_[2][0], mat_[2][1], mat_[2][2]).Length(); // 2: row2
178 return retVal;
179 }
180
GetTranslation() const181 Vector3 Matrix4::GetTranslation() const
182 {
183 return Vector3(mat_[3][0], mat_[3][1], mat_[3][2]); // 3: row3, 2: column2
184 }
185
186 // Create a scale matrix with x and y scales
CreateScale(float xScale,float yScale)187 Matrix3 CreateScale(float xScale, float yScale)
188 {
189 return { {
190 { xScale, 0.0f, 0.0f },
191 { 0.0f, yScale, 0.0f },
192 { 0.0f, 0.0f, 1.0f },
193 } };
194 }
195
196 // Create a rotation matrix about the Z axis
197 // theta is in radians
CreateRotation(float theta)198 Matrix3 CreateRotation(float theta)
199 {
200 return { {
201 { std::cos(theta), std::sin(theta), 0.0f },
202 { -std::sin(theta), std::cos(theta), 0.0f },
203 { 0.0f, 0.0f, 1.0f },
204 } };
205 }
206
207 // Create a translation matrix (on the xy-plane)
CreateTranslation(const Vector2 & trans)208 Matrix3 CreateTranslation(const Vector2& trans)
209 {
210 return { {
211 { 1.0f, 0.0f, 0.0f },
212 { 0.0f, 1.0f, 0.0f },
213 { trans.x_, trans.y_, 1.0f },
214 } };
215 }
216
217 // Create a scale matrix with x, y, and z scales
CreateScale(float xScale,float yScale,float zScale)218 Matrix4 CreateScale(float xScale, float yScale, float zScale)
219 {
220 return { {
221 { xScale, 0.0f, 0.0f, 0.0f },
222 { 0.0f, yScale, 0.0f, 0.0f },
223 { 0.0f, 0.0f, zScale, 0.0f },
224 { 0.0f, 0.0f, 0.0f, 1.0f },
225 } };
226 }
227
228 // Create a rotation matrix about X axis
229 // theta is in radians
CreateRotationX(float theta)230 Matrix4 CreateRotationX(float theta)
231 {
232 return { {
233 { 1.0f, 0.0f, 0.0f, 0.0f },
234 { 0.0f, std::cos(theta), std::sin(theta), 0.0f },
235 { 0.0f, -std::sin(theta), std::cos(theta), 0.0f },
236 { 0.0f, 0.0f, 0.0f, 1.0f },
237 } };
238 }
239
240 // Create a rotation matrix about Y axis
241 // theta is in radians
CreateRotationY(float theta)242 Matrix4 CreateRotationY(float theta)
243 {
244 return { {
245 { std::cos(theta), 0.0f, -std::sin(theta), 0.0f },
246 { 0.0f, 1.0f, 0.0f, 0.0f },
247 { std::sin(theta), 0.0f, std::cos(theta), 0.0f },
248 { 0.0f, 0.0f, 0.0f, 1.0f },
249 } };
250 }
251
252 // Create a rotation matrix about Z axis
253 // theta is in radians
CreateRotationZ(float theta)254 Matrix4 CreateRotationZ(float theta)
255 {
256 return { {
257 { std::cos(theta), std::sin(theta), 0.0f, 0.0f },
258 { -std::sin(theta), std::cos(theta), 0.0f, 0.0f },
259 { 0.0f, 0.0f, 1.0f, 0.0f },
260 { 0.0f, 0.0f, 0.0f, 1.0f },
261 } };
262 }
263
264 // Create a 3D translation matrix
CreateTranslation(const Vector3 & trans)265 Matrix4 CreateTranslation(const Vector3& trans)
266 {
267 return { {
268 { 1.0f, 0.0f, 0.0f, 0.0f },
269 { 0.0f, 1.0f, 0.0f, 0.0f },
270 { 0.0f, 0.0f, 1.0f, 0.0f },
271 { trans.x_, trans.y_, trans.z_, 1.0f },
272 } };
273 }
274
CreateLookAt(const Vector3 & eye,const Vector3 & target,const Vector3 & up)275 Matrix4 CreateLookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
276 {
277 Vector3 zaxis = Vector3::Normalize(target - eye);
278 Vector3 xaxis = Vector3::Normalize(Vector3::Cross(up, zaxis));
279 Vector3 yaxis = Vector3::Normalize(Vector3::Cross(zaxis, xaxis));
280 Vector3 trans;
281 trans.x_ = -Vector3::Dot(xaxis, eye);
282 trans.y_ = -Vector3::Dot(yaxis, eye);
283 trans.z_ = -Vector3::Dot(zaxis, eye);
284
285 return { {
286 { xaxis.x_, yaxis.x_, zaxis.x_, 0.0f },
287 { xaxis.y_, yaxis.y_, zaxis.y_, 0.0f },
288 { xaxis.z_, yaxis.z_, zaxis.z_, 0.0f },
289 { trans.x_, trans.y_, trans.z_, 1.0f }
290 } };
291 }
292
CreatePerspective(const Vector3 & camera)293 Matrix4 CreatePerspective(const Vector3& camera)
294 {
295 return { {
296 { std::abs(camera.z_), 0.0f, 0.0f, 0.0f },
297 { 0.0f, std::abs(camera.z_), 0.0f, 0.0f },
298 { camera.x_, camera.y_, 0.0f, 1.0f },
299 { 0.0f, 0.0f, 1.0f, 0.0f },
300 } };
301 }
302
303 // Transform a Vector2 in xy-plane by matrix3
Transform(const Vector2 & vec,const Matrix3 & mat)304 Vector2 Transform(const Vector2& vec, const Matrix3& mat)
305 {
306 Vector2 retVal;
307 retVal.x_ = vec.x_ * mat.mat_[0][0] + vec.y_ * mat.mat_[1][0] + mat.mat_[2][0]; // 2: row2
308 retVal.y_ = vec.x_ * mat.mat_[0][1] + vec.y_ * mat.mat_[1][1] + mat.mat_[2][1]; // 2: row2
309 return retVal;
310 }
311
312 // Transform a Vector3 in 3D world by matrix4
Transform(const Vector3 & vec,const Matrix4 & mat)313 Vector3 Transform(const Vector3& vec, const Matrix4& mat)
314 {
315 Vector3 retVal;
316 retVal.x_ = vec.x_ * mat.mat_[0][0] + vec.y_ * mat.mat_[1][0] +
317 vec.z_ * mat.mat_[2][0] + mat.mat_[3][0]; // 2: row2, 3: row3
318 retVal.y_ = vec.x_ * mat.mat_[0][1] + vec.y_ * mat.mat_[1][1] +
319 vec.z_ * mat.mat_[2][1] + mat.mat_[3][1]; // 2: row2, 3: row3
320 retVal.z_ = vec.x_ * mat.mat_[0][2] + vec.y_ * mat.mat_[1][2] + // 2: row2
321 vec.z_ * mat.mat_[2][2] + mat.mat_[3][2]; // 2: row2, 3: row3
322 return retVal;
323 }
324
325 // Transform the vector and renormalize the w component
TransformWithPerspDiv(const Vector3 & vec,const Matrix4 & mat,float w)326 Vector3 TransformWithPerspDiv(const Vector3& vec, const Matrix4& mat, float w)
327 {
328 Vector3 retVal;
329 retVal.x_ = vec.x_ * mat.mat_[0][0] + vec.y_ * mat.mat_[1][0] +
330 vec.z_ * mat.mat_[2][0] + w * mat.mat_[3][0]; // 2: row2, 3: row3
331 retVal.y_ = vec.x_ * mat.mat_[0][1] + vec.y_ * mat.mat_[1][1] +
332 vec.z_ * mat.mat_[2][1] + w * mat.mat_[3][1]; // 2: row2, 3: row3
333 retVal.z_ = vec.x_ * mat.mat_[0][2] + vec.y_ * mat.mat_[1][2] +
334 vec.z_ * mat.mat_[2][2] + w * mat.mat_[3][2]; // 2: row2, 3: row3
335 float transformedW = vec.x_ * mat.mat_[0][3] + vec.y_ * mat.mat_[1][3] +
336 vec.z_ * mat.mat_[2][3] + w * mat.mat_[3][3]; // 2: row2, 3: row3
337 if (!MathHelper::NearZero(transformedW)) {
338 transformedW = 1.0f / transformedW;
339 retVal *= transformedW;
340 }
341 return retVal;
342 }
343
344 // Given a screen point, unprojects it into origin position at screen,
345 // based on the current transform matrix
GetOriginScreenPoint(const Vector2 & p,const Matrix4 & mat)346 Vector2 GetOriginScreenPoint(const Vector2& p, const Matrix4& mat)
347 {
348 Matrix4 invertMat = mat;
349 invertMat.Invert();
350 // Get start point
351 Vector3 screenPoint(p.x_, p.y_, 0.1f);
352 Vector3 start = TransformWithPerspDiv(screenPoint, invertMat);
353 // Get end point
354 screenPoint.z_ = 0.9f;
355 Vector3 end = TransformWithPerspDiv(screenPoint, invertMat);
356 // Get the intersection point of line start-end and xy plane
357 float t = end.z_ / (end.z_ - start.z_);
358 return Vector2(t * start.x_ + (1 - t) * end.x_, t * start.y_ + (1 - t) * end.y_);
359 }
360 } // namespace TransformHelper
361 } // namespace OHOS::Rosen
362