* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "wm_math.h"
#include <cstdlib>
namespace OHOS::Rosen {
namespace TransformHelper {
const Matrix3 Matrix3::Identity = { {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 },
} };
const Matrix4 Matrix4::Identity = { {
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 },
} };
Matrix3 operator*(const Matrix3& left, const Matrix3& right)
{
return { {
{ left.mat_[0][0] * right.mat_[0][0] + left.mat_[0][1] * right.mat_[1][0] + left.mat_[0][2] * right.mat_[2][0],
left.mat_[0][0] * right.mat_[0][1] + left.mat_[0][1] * right.mat_[1][1] + left.mat_[0][2] * right.mat_[2][1],
left.mat_[0][0] * right.mat_[0][2] + left.mat_[0][1] * right.mat_[1][2] + left.mat_[0][2] * right.mat_[2][2] },
{ left.mat_[1][0] * right.mat_[0][0] + left.mat_[1][1] * right.mat_[1][0] + left.mat_[1][2] * right.mat_[2][0],
left.mat_[1][0] * right.mat_[0][1] + left.mat_[1][1] * right.mat_[1][1] + left.mat_[1][2] * right.mat_[2][1],
left.mat_[1][0] * right.mat_[0][2] + left.mat_[1][1] * right.mat_[1][2] + left.mat_[1][2] * right.mat_[2][2] },
{ left.mat_[2][0] * right.mat_[0][0] + left.mat_[2][1] * right.mat_[1][0] + left.mat_[2][2] * right.mat_[2][0],
left.mat_[2][0] * right.mat_[0][1] + left.mat_[2][1] * right.mat_[1][1] + left.mat_[2][2] * right.mat_[2][1],
left.mat_[2][0] * right.mat_[0][2] + left.mat_[2][1] * right.mat_[1][2] + left.mat_[2][2] * right.mat_[2][2] }
} };
}
Matrix3& Matrix3::operator*=(const Matrix3& right)
{
*this = *this * right;
return *this;
}
Matrix4 operator*(const Matrix4& left, const Matrix4& right)
{
return { {
{ left.mat_[0][0] * right.mat_[0][0] + left.mat_[0][1] * right.mat_[1][0] +
left.mat_[0][2] * right.mat_[2][0] + left.mat_[0][3] * right.mat_[3][0],
left.mat_[0][0] * right.mat_[0][1] + left.mat_[0][1] * right.mat_[1][1] +
left.mat_[0][2] * right.mat_[2][1] + left.mat_[0][3] * right.mat_[3][1],
left.mat_[0][0] * right.mat_[0][2] + left.mat_[0][1] * right.mat_[1][2] +
left.mat_[0][2] * right.mat_[2][2] + left.mat_[0][3] * right.mat_[3][2],
left.mat_[0][0] * right.mat_[0][3] + left.mat_[0][1] * right.mat_[1][3] +
left.mat_[0][2] * right.mat_[2][3] + left.mat_[0][3] * right.mat_[3][3] },
{ left.mat_[1][0] * right.mat_[0][0] + left.mat_[1][1] * right.mat_[1][0] +
left.mat_[1][2] * right.mat_[2][0] + left.mat_[1][3] * right.mat_[3][0],
left.mat_[1][0] * right.mat_[0][1] + left.mat_[1][1] * right.mat_[1][1] +
left.mat_[1][2] * right.mat_[2][1] + left.mat_[1][3] * right.mat_[3][1],
left.mat_[1][0] * right.mat_[0][2] + left.mat_[1][1] * right.mat_[1][2] +
left.mat_[1][2] * right.mat_[2][2] + left.mat_[1][3] * right.mat_[3][2],
left.mat_[1][0] * right.mat_[0][3] + left.mat_[1][1] * right.mat_[1][3] +
left.mat_[1][2] * right.mat_[2][3] + left.mat_[1][3] * right.mat_[3][3] },
{ left.mat_[2][0] * right.mat_[0][0] + left.mat_[2][1] * right.mat_[1][0] +
left.mat_[2][2] * right.mat_[2][0] + left.mat_[2][3] * right.mat_[3][0],
left.mat_[2][0] * right.mat_[0][1] + left.mat_[2][1] * right.mat_[1][1] +
left.mat_[2][2] * right.mat_[2][1] + left.mat_[2][3] * right.mat_[3][1],
left.mat_[2][0] * right.mat_[0][2] + left.mat_[2][1] * right.mat_[1][2] +
left.mat_[2][2] * right.mat_[2][2] + left.mat_[2][3] * right.mat_[3][2],
left.mat_[2][0] * right.mat_[0][3] + left.mat_[2][1] * right.mat_[1][3] +
left.mat_[2][2] * right.mat_[2][3] + left.mat_[2][3] * right.mat_[3][3] },
{ left.mat_[3][0] * right.mat_[0][0] + left.mat_[3][1] * right.mat_[1][0] +
left.mat_[3][2] * right.mat_[2][0] + left.mat_[3][3] * right.mat_[3][0],
left.mat_[3][0] * right.mat_[0][1] + left.mat_[3][1] * right.mat_[1][1] +
left.mat_[3][2] * right.mat_[2][1] + left.mat_[3][3] * right.mat_[3][1],
left.mat_[3][0] * right.mat_[0][2] + left.mat_[3][1] * right.mat_[1][2] +
left.mat_[3][2] * right.mat_[2][2] + left.mat_[3][3] * right.mat_[3][2],
left.mat_[3][0] * right.mat_[0][3] + left.mat_[3][1] * right.mat_[1][3] +
left.mat_[3][2] * right.mat_[2][3] + left.mat_[3][3] * right.mat_[3][3] }
} };
}
Matrix4& Matrix4::operator*=(const Matrix4& right)
{
*this = *this * right;
return *this;
}
void Matrix4::SwapRow(int row1, int row2)
{
float *p = mat_[row1];
float *q = mat_[row2];
float tmp = p[0];
p[0] = q[0];
q[0] = tmp;
tmp = p[1];
p[1] = q[1];
q[1] = tmp;
tmp = p[2];
p[2] = q[2];
q[2] = tmp;
tmp = p[3];
p[3] = q[3];
q[3] = tmp;
}
void Matrix4::Invert()
{
Matrix4 tmp = Matrix4::Identity;
int i, j, k;
for (k = 0; k < MAT_SIZE; k++) {
float t = mat_[k][k];
if (t < MathHelper::POS_ZERO && t > MathHelper::NAG_ZERO) {
for (i = k + 1; i < MAT_SIZE; i++) {
if (mat_[i][k] < MathHelper::NAG_ZERO || mat_[i][k] > MathHelper::POS_ZERO) {
SwapRow(k, i);
tmp.SwapRow(k, i);
break;
}
}
t = mat_[k][k];
}
for (j = 0; j <= k; j++) {
tmp.mat_[k][j] /= t;
}
for (; j < MAT_SIZE; j++) {
mat_[k][j] /= t;
tmp.mat_[k][j] /= t;
}
for (i = 0; i < MAT_SIZE; i++) {
if (i == k) {
continue;
}
float u = mat_[i][k];
for (j = 0; j <= k; j++) {
tmp.mat_[i][j] -= tmp.mat_[k][j] * u;
}
for (; j < MAT_SIZE; j++) {
mat_[i][j] -= mat_[k][j] * u;
tmp.mat_[i][j] -= tmp.mat_[k][j] * u;
}
}
}
*this = tmp;
}
Vector3 Matrix4::GetScale() const
{
Vector3 retVal;
retVal.x_ = Vector3(mat_[0][0], mat_[0][1], mat_[0][2]).Length();
retVal.y_ = Vector3(mat_[1][0], mat_[1][1], mat_[1][2]).Length();
retVal.z_ = Vector3(mat_[2][0], mat_[2][1], mat_[2][2]).Length();
return retVal;
}
Vector3 Matrix4::GetTranslation() const
{
return Vector3(mat_[3][0], mat_[3][1], mat_[3][2]);
}
Matrix3 CreateScale(float xScale, float yScale)
{
return { {
{ xScale, 0.0f, 0.0f },
{ 0.0f, yScale, 0.0f },
{ 0.0f, 0.0f, 1.0f },
} };
}
Matrix3 CreateRotation(float theta)
{
return { {
{ std::cos(theta), std::sin(theta), 0.0f },
{ -std::sin(theta), std::cos(theta), 0.0f },
{ 0.0f, 0.0f, 1.0f },
} };
}
Matrix3 CreateTranslation(const Vector2& trans)
{
return { {
{ 1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ trans.x_, trans.y_, 1.0f },
} };
}
Matrix4 CreateScale(float xScale, float yScale, float zScale)
{
return { {
{ xScale, 0.0f, 0.0f, 0.0f },
{ 0.0f, yScale, 0.0f, 0.0f },
{ 0.0f, 0.0f, zScale, 0.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f },
} };
}
Matrix4 CreateRotationX(float theta)
{
return { {
{ 1.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, std::cos(theta), std::sin(theta), 0.0f },
{ 0.0f, -std::sin(theta), std::cos(theta), 0.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f },
} };
}
Matrix4 CreateRotationY(float theta)
{
return { {
{ std::cos(theta), 0.0f, -std::sin(theta), 0.0f },
{ 0.0f, 1.0f, 0.0f, 0.0f },
{ std::sin(theta), 0.0f, std::cos(theta), 0.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f },
} };
}
Matrix4 CreateRotationZ(float theta)
{
return { {
{ std::cos(theta), std::sin(theta), 0.0f, 0.0f },
{ -std::sin(theta), std::cos(theta), 0.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f },
} };
}
Matrix4 CreateTranslation(const Vector3& trans)
{
return { {
{ 1.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f, 0.0f },
{ trans.x_, trans.y_, trans.z_, 1.0f },
} };
}
Matrix4 CreateLookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
{
Vector3 zaxis = Vector3::Normalize(target - eye);
Vector3 xaxis = Vector3::Normalize(Vector3::Cross(up, zaxis));
Vector3 yaxis = Vector3::Normalize(Vector3::Cross(zaxis, xaxis));
Vector3 trans;
trans.x_ = -Vector3::Dot(xaxis, eye);
trans.y_ = -Vector3::Dot(yaxis, eye);
trans.z_ = -Vector3::Dot(zaxis, eye);
return { {
{ xaxis.x_, yaxis.x_, zaxis.x_, 0.0f },
{ xaxis.y_, yaxis.y_, zaxis.y_, 0.0f },
{ xaxis.z_, yaxis.z_, zaxis.z_, 0.0f },
{ trans.x_, trans.y_, trans.z_, 1.0f }
} };
}
Matrix4 CreatePerspective(const Vector3& camera)
{
return { {
{ std::abs(camera.z_), 0.0f, 0.0f, 0.0f },
{ 0.0f, std::abs(camera.z_), 0.0f, 0.0f },
{ camera.x_, camera.y_, 0.0f, 1.0f },
{ 0.0f, 0.0f, 1.0f, 0.0f },
} };
}
Vector2 Transform(const Vector2& vec, const Matrix3& mat)
{
Vector2 retVal;
retVal.x_ = vec.x_ * mat.mat_[0][0] + vec.y_ * mat.mat_[1][0] + mat.mat_[2][0];
retVal.y_ = vec.x_ * mat.mat_[0][1] + vec.y_ * mat.mat_[1][1] + mat.mat_[2][1];
return retVal;
}
Vector3 Transform(const Vector3& vec, const Matrix4& mat)
{
Vector3 retVal;
retVal.x_ = vec.x_ * mat.mat_[0][0] + vec.y_ * mat.mat_[1][0] +
vec.z_ * mat.mat_[2][0] + mat.mat_[3][0];
retVal.y_ = vec.x_ * mat.mat_[0][1] + vec.y_ * mat.mat_[1][1] +
vec.z_ * mat.mat_[2][1] + mat.mat_[3][1];
retVal.z_ = vec.x_ * mat.mat_[0][2] + vec.y_ * mat.mat_[1][2] +
vec.z_ * mat.mat_[2][2] + mat.mat_[3][2];
return retVal;
}
Vector3 TransformWithPerspDiv(const Vector3& vec, const Matrix4& mat, float w)
{
Vector3 retVal;
retVal.x_ = vec.x_ * mat.mat_[0][0] + vec.y_ * mat.mat_[1][0] +
vec.z_ * mat.mat_[2][0] + w * mat.mat_[3][0];
retVal.y_ = vec.x_ * mat.mat_[0][1] + vec.y_ * mat.mat_[1][1] +
vec.z_ * mat.mat_[2][1] + w * mat.mat_[3][1];
retVal.z_ = vec.x_ * mat.mat_[0][2] + vec.y_ * mat.mat_[1][2] +
vec.z_ * mat.mat_[2][2] + w * mat.mat_[3][2];
float transformedW = vec.x_ * mat.mat_[0][3] + vec.y_ * mat.mat_[1][3] +
vec.z_ * mat.mat_[2][3] + w * mat.mat_[3][3];
if (!MathHelper::NearZero(transformedW)) {
transformedW = 1.0f / transformedW;
retVal *= transformedW;
}
return retVal;
}
Vector2 GetOriginScreenPoint(const Vector2& p, const Matrix4& mat)
{
Matrix4 invertMat = mat;
invertMat.Invert();
Vector3 screenPoint(p.x_, p.y_, 0.1f);
Vector3 start = TransformWithPerspDiv(screenPoint, invertMat);
screenPoint.z_ = 0.9f;
Vector3 end = TransformWithPerspDiv(screenPoint, invertMat);
float t = end.z_ / (end.z_ - start.z_);
return Vector2(t * start.x_ + (1 - t) * end.x_, t * start.y_ + (1 - t) * end.y_);
}
}
}