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