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