matrix operations
This commit is contained in:
parent
48e3b8e26c
commit
ad5ba21b4d
6 changed files with 1433 additions and 613 deletions
|
|
@ -1,433 +1,330 @@
|
|||
/*
|
||||
Crafter®.Math
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
catcrafts.net
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License version 3.0 as published by the Free Software Foundation;
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
export module Crafter.Math:MatrixRowMajor;
|
||||
|
||||
import :Basic;
|
||||
import :Vector;
|
||||
import std;
|
||||
|
||||
namespace Crafter {
|
||||
export template <typename T, std::uint32_t CollumSize, std::uint32_t RowSize, std::uint32_t Repeats>
|
||||
class MatrixRowMajor {
|
||||
public:
|
||||
T m[RowSize][CollumSize*Repeats];
|
||||
|
||||
MatrixRowMajor() = default;
|
||||
|
||||
MatrixRowMajor(
|
||||
float x0, float y0, float z0, float w0,
|
||||
float x1, float y1, float z1, float w1,
|
||||
float x2, float y2, float z2, float w2,
|
||||
float x3, float y3, float z3, float w3
|
||||
) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
m[0][0] = x0;
|
||||
m[0][1] = y0;
|
||||
m[0][2] = z0;
|
||||
m[0][3] = w0;
|
||||
|
||||
m[1][0] = x1;
|
||||
m[1][1] = y1;
|
||||
m[1][2] = z1;
|
||||
m[1][3] = w1;
|
||||
|
||||
m[2][0] = x2;
|
||||
m[2][1] = y2;
|
||||
m[2][2] = z2;
|
||||
m[2][3] = w2;
|
||||
|
||||
m[3][0] = x3;
|
||||
m[3][1] = y3;
|
||||
m[3][2] = z3;
|
||||
m[3][3] = w3;
|
||||
}
|
||||
|
||||
MatrixRowMajor(
|
||||
float x0, float y0, float z0, float w0,
|
||||
float x1, float y1, float z1, float w1,
|
||||
float x2, float y2, float z2, float w2
|
||||
) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
m[0][0] = x0;
|
||||
m[0][1] = y0;
|
||||
m[0][2] = z0;
|
||||
m[0][3] = w0;
|
||||
|
||||
m[1][0] = x1;
|
||||
m[1][1] = y1;
|
||||
m[1][2] = z1;
|
||||
m[1][3] = w1;
|
||||
|
||||
m[2][0] = x2;
|
||||
m[2][1] = y2;
|
||||
m[2][2] = z2;
|
||||
m[2][3] = w2;
|
||||
}
|
||||
|
||||
template <std::uint32_t VAligment>
|
||||
Vector<T, 3, VAligment> operator*(Vector<T, 3, VAligment> b) const requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return Vector<T, 3, VAligment>(
|
||||
b.x * m[0][0] + b.y * m[0][1] + b.z * m[0][2] + m[0][3],
|
||||
b.x * m[1][0] + b.y * m[1][1] + b.z * m[1][2] + m[1][3],
|
||||
b.x * m[2][0] + b.y * m[2][1] + b.z * m[2][2] + m[2][3]
|
||||
);
|
||||
}
|
||||
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> operator*(MatrixRowMajor<T, CollumSize, RowSize, Repeats> b) const requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> result;
|
||||
|
||||
result.m[0][0] = b.m[0][0] * m[0][0] + b.m[0][1] * m[1][0] + b.m[0][2] * m[2][0] + b.m[0][3] * m[3][0];
|
||||
result.m[1][0] = b.m[1][0] * m[0][0] + b.m[1][1] * m[1][0] + b.m[1][2] * m[2][0] + b.m[1][3] * m[3][0];
|
||||
result.m[2][0] = b.m[2][0] * m[0][0] + b.m[2][1] * m[1][0] + b.m[2][2] * m[2][0] + b.m[2][3] * m[3][0];
|
||||
result.m[3][0] = b.m[3][0] * m[0][0] + b.m[3][1] * m[1][0] + b.m[3][2] * m[2][0] + b.m[3][3] * m[3][0];
|
||||
|
||||
result.m[0][1] = b.m[0][0] * m[0][1] + b.m[0][1] * m[1][1] + b.m[0][2] * m[2][1] + b.m[0][3] * m[3][1];
|
||||
result.m[1][1] = b.m[1][0] * m[0][1] + b.m[1][1] * m[1][1] + b.m[1][2] * m[2][1] + b.m[1][3] * m[3][1];
|
||||
result.m[2][1] = b.m[2][0] * m[0][1] + b.m[2][1] * m[1][1] + b.m[2][2] * m[2][1] + b.m[2][3] * m[3][1];
|
||||
result.m[3][1] = b.m[3][0] * m[0][1] + b.m[3][1] * m[1][1] + b.m[3][2] * m[2][1] + b.m[3][3] * m[3][1];
|
||||
|
||||
result.m[0][2] = b.m[0][0] * m[0][2] + b.m[0][1] * m[1][2] + b.m[0][2] * m[2][2] + b.m[0][3] * m[3][2];
|
||||
result.m[1][2] = b.m[1][0] * m[0][2] + b.m[1][1] * m[1][2] + b.m[1][2] * m[2][2] + b.m[1][3] * m[3][2];
|
||||
result.m[2][2] = b.m[2][0] * m[0][2] + b.m[2][1] * m[1][2] + b.m[2][2] * m[2][2] + b.m[2][3] * m[3][2];
|
||||
result.m[3][2] = b.m[3][0] * m[0][2] + b.m[3][1] * m[1][2] + b.m[3][2] * m[2][2] + b.m[3][3] * m[3][2];
|
||||
|
||||
result.m[0][3] = b.m[0][0] * m[0][3] + b.m[0][1] * m[1][3] + b.m[0][2] * m[2][3] + b.m[0][3] * m[3][3];
|
||||
result.m[1][3] = b.m[1][0] * m[0][3] + b.m[1][1] * m[1][3] + b.m[1][2] * m[2][3] + b.m[1][3] * m[3][3];
|
||||
result.m[2][3] = b.m[2][0] * m[0][3] + b.m[2][1] * m[1][3] + b.m[2][2] * m[2][3] + b.m[2][3] * m[3][3];
|
||||
result.m[3][3] = b.m[3][0] * m[0][3] + b.m[3][1] * m[1][3] + b.m[3][2] * m[2][3] + b.m[3][3] * m[3][3];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> operator*(MatrixRowMajor<T, CollumSize, RowSize, Repeats> b) const requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> result;
|
||||
|
||||
// Column 0
|
||||
result.m[0][0] = b.m[0][0]*m[0][0] + b.m[0][1]*m[1][0] + b.m[0][2]*m[2][0];
|
||||
result.m[1][0] = b.m[1][0]*m[0][0] + b.m[1][1]*m[1][0] + b.m[1][2]*m[2][0];
|
||||
result.m[2][0] = b.m[2][0]*m[0][0] + b.m[2][1]*m[1][0] + b.m[2][2]*m[2][0];
|
||||
|
||||
// Column 1
|
||||
result.m[0][1] = b.m[0][0]*m[0][1] + b.m[0][1]*m[1][1] + b.m[0][2]*m[2][1];
|
||||
result.m[1][1] = b.m[1][0]*m[0][1] + b.m[1][1]*m[1][1] + b.m[1][2]*m[2][1];
|
||||
result.m[2][1] = b.m[2][0]*m[0][1] + b.m[2][1]*m[1][1] + b.m[2][2]*m[2][1];
|
||||
|
||||
// Column 2
|
||||
result.m[0][2] = b.m[0][0]*m[0][2] + b.m[0][1]*m[1][2] + b.m[0][2]*m[2][2];
|
||||
result.m[1][2] = b.m[1][0]*m[0][2] + b.m[1][1]*m[1][2] + b.m[1][2]*m[2][2];
|
||||
result.m[2][2] = b.m[2][0]*m[0][2] + b.m[2][1]*m[1][2] + b.m[2][2]*m[2][2];
|
||||
|
||||
// Translation column
|
||||
result.m[0][3] = b.m[0][0]*m[0][3] + b.m[0][1]*m[1][3] + b.m[0][2]*m[2][3] + b.m[0][3];
|
||||
result.m[1][3] = b.m[1][0]*m[0][3] + b.m[1][1]*m[1][3] + b.m[1][2]*m[2][3] + b.m[1][3];
|
||||
result.m[2][3] = b.m[2][0]*m[0][3] + b.m[2][1]*m[1][3] + b.m[2][2]*m[2][3] + b.m[2][3];
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Identity() requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor<T, CollumSize, RowSize, Repeats>(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0
|
||||
);
|
||||
}
|
||||
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Scaling(float x, float y, float z) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor<T, CollumSize, RowSize, Repeats>(
|
||||
x, 0, 0, 0,
|
||||
0, y, 0, 0,
|
||||
0, 0, z, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Scaling(float x, float y, float z) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor<T, CollumSize, RowSize, Repeats>(
|
||||
x, 0, 0, 0,
|
||||
0, y, 0, 0,
|
||||
0, 0, z, 0
|
||||
);
|
||||
}
|
||||
template <std::uint32_t VAligment>
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Scaling(Vector<float, 3, VAligment> vector) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return Scaling(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Translation(float x, float y, float z) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor<T, CollumSize, RowSize, Repeats>(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
x, y, z, 1
|
||||
);
|
||||
}
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Translation(float x, float y, float z) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor<T, CollumSize, RowSize, Repeats>(
|
||||
1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, 1, z
|
||||
);
|
||||
}
|
||||
|
||||
template <std::uint32_t VAligment>
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Translation(Vector<T, 3, VAligment> vector) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return Translation(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Rotation(float Pitch, float Yaw, float Roll) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
float cp = std::cosf(Pitch);
|
||||
float sp = std::sinf(Pitch);
|
||||
|
||||
float cy = std::cosf(Yaw);
|
||||
float sy = std::sinf(Yaw);
|
||||
|
||||
float cr = std::cosf(Roll);
|
||||
float sr = std::sinf(Roll);
|
||||
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> M;
|
||||
M.m[0][0] = cr * cy + sr * sp * sy;
|
||||
M.m[0][1] = sr * cp;
|
||||
M.m[0][2] = sr * sp * cy - cr * sy;
|
||||
M.m[0][3] = 0.0f;
|
||||
|
||||
M.m[1][0] = cr * sp * sy - sr * cy;
|
||||
M.m[1][1] = cr * cp;
|
||||
M.m[1][2] = sr * sy + cr * sp * cy;
|
||||
M.m[1][3] = 0.0f;
|
||||
|
||||
M.m[2][0] = cp * sy;
|
||||
M.m[2][1] = -sp;
|
||||
M.m[2][2] = cp * cy;
|
||||
M.m[2][3] = 0.0f;
|
||||
|
||||
M.m[3][0] = 0.0f;
|
||||
M.m[3][1] = 0.0f;
|
||||
M.m[3][2] = 0.0f;
|
||||
M.m[3][3] = 1.0f;
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Rotation(float Pitch, float Yaw, float Roll) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
float cp = std::cosf(Pitch);
|
||||
float sp = std::sinf(Pitch);
|
||||
|
||||
float cy = std::cosf(Yaw);
|
||||
float sy = std::sinf(Yaw);
|
||||
|
||||
float cr = std::cosf(Roll);
|
||||
float sr = std::sinf(Roll);
|
||||
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> M;
|
||||
M.m[0][0] = cr * cy + sr * sp * sy;
|
||||
M.m[0][1] = sr * cp;
|
||||
M.m[0][2] = sr * sp * cy - cr * sy;
|
||||
M.m[0][3] = 0.0f;
|
||||
|
||||
M.m[1][0] = cr * sp * sy - sr * cy;
|
||||
M.m[1][1] = cr * cp;
|
||||
M.m[1][2] = sr * sy + cr * sp * cy;
|
||||
M.m[1][3] = 0.0f;
|
||||
|
||||
M.m[2][0] = cp * sy;
|
||||
M.m[2][1] = -sp;
|
||||
M.m[2][2] = cp * cy;
|
||||
M.m[2][3] = 0.0f;
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
template <std::uint32_t VAligment>
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> LookAt(Vector<T, 3, VAligment> eyePosition, Vector<T, 3, VAligment> focusPosition, Vector<T, 3, VAligment> upDirection) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> M;
|
||||
|
||||
Vector<T, 3, VAligment> negEyeDirection = eyePosition - focusPosition;
|
||||
return LookTo(eyePosition, negEyeDirection, upDirection);
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
template <std::uint32_t VAligment>
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> LookTo(Vector<T, 3, VAligment> eyePosition, Vector<T, 3, VAligment> eyeDirection, Vector<T, 3, VAligment> upDirection) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
Vector<T, 3, 3> R2 = eyeDirection.Normalize();
|
||||
|
||||
Vector<T, 3, 3> R0 = upDirection.Cross(R2);
|
||||
R0 = R0.Normalize();
|
||||
|
||||
Vector<T, 3, 3> R1 = R2.Cross(R0);
|
||||
|
||||
Vector<T, 3, 3> NegEyePosition = -eyePosition;
|
||||
|
||||
float D0 = R0.Dot(NegEyePosition);
|
||||
float D1 = R1.Dot(NegEyePosition);
|
||||
float D2 = R2.Dot(NegEyePosition);
|
||||
|
||||
MatrixRowMajor<T, CollumSize, RowSize, Repeats> M;
|
||||
M.m[0][0] = R0.v[0];
|
||||
M.m[1][0] = R0.v[1];
|
||||
M.m[2][0] = R0.v[2];
|
||||
M.m[3][0] = D0;
|
||||
|
||||
M.m[0][1] = R1.v[0];
|
||||
M.m[1][1] = R1.v[1];
|
||||
M.m[2][1] = R1.v[2];
|
||||
M.m[3][1] = D1;
|
||||
|
||||
M.m[0][2] = R2.v[0];
|
||||
M.m[1][2] = R2.v[1];
|
||||
M.m[2][2] = R2.v[2];
|
||||
M.m[3][2] = D2;
|
||||
|
||||
M.m[0][3] = 0;
|
||||
M.m[1][3] = 0;
|
||||
M.m[2][3] = 0;
|
||||
M.m[3][3] = 1;
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
template <std::uint32_t VAligment>
|
||||
static MatrixRowMajor<T, CollumSize, RowSize, Repeats> Rotation(Vector<T, 3, VAligment> vector) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return Rotation(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
template <std::uint32_t VAligment>
|
||||
Vector<T, 3, VAligment> TransformNormal(Vector<T, 3, VAligment> V) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
Vector<T, 3, 3> Z = Vector<T, 3, 3>(V.z, V.z, V.z);
|
||||
Vector<T, 3, 3> Y = Vector<T, 3, 3>(V.y, V.y, V.y);
|
||||
Vector<T, 3, 3> X = Vector<T, 3, 3>(V.x, V.x, V.x);
|
||||
|
||||
Vector<T, 3, VAligment> Result = Z * Vector<T, 3, VAligment>(m[2][0], m[2][1], m[2][2]);
|
||||
Result = Y * Vector<T, 3, VAligment>(m[1][0], m[1][1], m[1][2]) + Result;
|
||||
Result = X * Vector<T, 3, VAligment>(m[0][0], m[0][1], m[0][2]) + Result;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// MatrixRowMajor<T, CollumSize, RowSize, Repeats> Inverse() requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
// Vector<float, 4> V0[4], V1[4];
|
||||
// V0[0] = Vector<float, 4>(m[0][2], m[0][2], m[1][2], m[1][2]);
|
||||
// V1[0] = Vector<float, 4>(m[2][3], m[3][3], m[2][3], m[3][3]);
|
||||
// V0[1] = Vector<float, 4>(m[0][0], m[0][0], m[1][0], m[1][0]);
|
||||
// V1[1] = Vector<float, 4>(m[2][1], m[3][1], m[2][1], m[3][1]);
|
||||
// V0[2] = Vector<float, 4>(m[0][2], m[2][2], m[0][0], m[2][0]);
|
||||
// V1[2] = Vector<float, 4>(m[1][3], m[3][3], m[1][1], m[3][1]);
|
||||
|
||||
// Vector<float, 4> D0 = V0[0] * V1[0];
|
||||
// Vector<float, 4> D1 = V0[1] * V1[1];
|
||||
// Vector<float, 4> D2 = V0[2] * V1[2];
|
||||
|
||||
// V0[0] = Vector<float, 4>(m[2][2], m[3][2], m[2][2], m[3][2]);
|
||||
// V1[0] = Vector<float, 4>(m[0][3], m[0][3], m[1][3], m[1][3]);
|
||||
// V0[1] = Vector<float, 4>(m[2][0], m[3][0], m[2][0], m[3][0]);
|
||||
// V1[1] = Vector<float, 4>(m[0][1], m[0][1], m[1][1], m[1][1]);
|
||||
// V0[2] = Vector<float, 4>(m[1][2], m[3][2], m[1][0], m[3][0]);
|
||||
// V1[2] = Vector<float, 4>(m[0][3], m[2][3], m[0][1], m[2][1]);
|
||||
|
||||
// D0 = Vector<float, 4>::NegativeMultiplySubtract(V0[0], V1[0], D0);
|
||||
// D1 = Vector<float, 4>::NegativeMultiplySubtract(V0[1], V1[1], D1);
|
||||
// D2 = Vector<float, 4>::NegativeMultiplySubtract(V0[2], V1[2], D2);
|
||||
|
||||
// V0[0] = Vector<float, 4>(m[1][1], m[2][1], m[0][1], m[1][1]);
|
||||
// V1[0] = Vector<float, 4>(D2.v[1], D0.v[1], D0.v[3], D0.v[0]);
|
||||
// V0[1] = Vector<float, 4>(m[2][0], m[0][0], m[1][0], m[0][0]);
|
||||
// V1[1] = Vector<float, 4>(D0.v[3], D2.v[1], D0.v[1], D0.v[2]);
|
||||
// V0[2] = Vector<float, 4>(m[1][3], m[2][3], m[0][3], m[1][3]);
|
||||
// V1[2] = Vector<float, 4>(D2.v[3], D1.v[1], D1.v[3], D1.v[0]);
|
||||
// V0[3] = Vector<float, 4>(m[2][2], m[0][2], m[1][2], m[0][2]);
|
||||
// V1[3] = Vector<float, 4>(D1.v[3], D2.v[3], D1.v[1], D1.v[2]);
|
||||
|
||||
// Vector<float, 4> C0 = V0[0] * V1[0];
|
||||
// Vector<float, 4> C2 = V0[1] * V1[1];
|
||||
// Vector<float, 4> C4 = V0[2] * V1[2];
|
||||
// Vector<float, 4> C6 = V0[3] * V1[3];
|
||||
|
||||
// V0[0] = Vector<float, 4>(m[2][1], m[3][1], m[1][1], m[2][1]);
|
||||
// V1[0] = Vector<float, 4>(D0.v[3], D0.v[0], D0.v[1], D2.v[0]);
|
||||
// V0[1] = Vector<float, 4>(m[3][0], m[2][0], m[3][0], m[1][0]);
|
||||
// V1[1] = Vector<float, 4>(D0.v[2], D0.v[1], D2.v[0], D0.v[0]);
|
||||
// V0[2] = Vector<float, 4>(m[2][3], m[3][3], m[1][3], m[2][3]);
|
||||
// V1[2] = Vector<float, 4>(D1.v[3], D1.v[0], D1.v[1], D2.v[2]);
|
||||
// V0[3] = XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_Z, XM_SWIZZLE_W, XM_SWIZZLE_Y>(MT.r[2]);
|
||||
// V1[3] = XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_0Y, XM_PERMUTE_1Z, XM_PERMUTE_0X>(D1, D2);
|
||||
|
||||
// C0 = XMVectorNegativeMultiplySubtract(V0[0], V1[0], C0);
|
||||
// C2 = XMVectorNegativeMultiplySubtract(V0[1], V1[1], C2);
|
||||
// C4 = XMVectorNegativeMultiplySubtract(V0[2], V1[2], C4);
|
||||
// C6 = XMVectorNegativeMultiplySubtract(V0[3], V1[3], C6);
|
||||
|
||||
// V0[0] = XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_X>(MT.r[1]);
|
||||
// V1[0] = XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_1Y, XM_PERMUTE_1X, XM_PERMUTE_0Z>(D0, D2);
|
||||
// V0[1] = XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Z>(MT.r[0]);
|
||||
// V1[1] = XMVectorPermute<XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_1X>(D0, D2);
|
||||
// V0[2] = XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_X>(MT.r[3]);
|
||||
// V1[2] = XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_1W, XM_PERMUTE_1Z, XM_PERMUTE_0Z>(D1, D2);
|
||||
// V0[3] = XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Z>(MT.r[2]);
|
||||
// V1[3] = XMVectorPermute<XM_PERMUTE_1W, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_1Z>(D1, D2);
|
||||
|
||||
// XMVECTOR C1 = XMVectorNegativeMultiplySubtract(V0[0], V1[0], C0);
|
||||
// C0 = XMVectorMultiplyAdd(V0[0], V1[0], C0);
|
||||
// XMVECTOR C3 = XMVectorMultiplyAdd(V0[1], V1[1], C2);
|
||||
// C2 = XMVectorNegativeMultiplySubtract(V0[1], V1[1], C2);
|
||||
// XMVECTOR C5 = XMVectorNegativeMultiplySubtract(V0[2], V1[2], C4);
|
||||
// C4 = XMVectorMultiplyAdd(V0[2], V1[2], C4);
|
||||
// XMVECTOR C7 = XMVectorMultiplyAdd(V0[3], V1[3], C6);
|
||||
// C6 = XMVectorNegativeMultiplySubtract(V0[3], V1[3], C6);
|
||||
|
||||
// XMMATRIX R;
|
||||
// R.r[0] = XMVectorSelect(C0, C1, g_XMSelect0101.v);
|
||||
// R.r[1] = XMVectorSelect(C2, C3, g_XMSelect0101.v);
|
||||
// R.r[2] = XMVectorSelect(C4, C5, g_XMSelect0101.v);
|
||||
// R.r[3] = XMVectorSelect(C6, C7, g_XMSelect0101.v);
|
||||
|
||||
// XMVECTOR Determinant = XMVector4Dot(R.r[0], MT.r[0]);
|
||||
// XMVECTOR Reciprocal = XMVectorReciprocal(Determinant);
|
||||
|
||||
// XMMATRIX Result;
|
||||
// Result.r[0] = XMVectorMultiply(R.r[0], Reciprocal);
|
||||
// Result.r[1] = XMVectorMultiply(R.r[1], Reciprocal);
|
||||
// Result.r[2] = XMVectorMultiply(R.r[2], Reciprocal);
|
||||
// Result.r[3] = XMVectorMultiply(R.r[3], Reciprocal);
|
||||
// return Result;
|
||||
// }
|
||||
};
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::formatter<Crafter::MatrixRowMajor<float, 4, 4, 1>> : std::formatter<std::string> {
|
||||
auto format(const Crafter::MatrixRowMajor<float, 4, 4, 1>& obj, format_context& ctx) const {
|
||||
return std::formatter<std::string>::format(std::format("{{{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}}}",
|
||||
obj.m[0][0], obj.m[0][1], obj.m[0][2], obj.m[0][3],
|
||||
obj.m[1][0], obj.m[1][1], obj.m[1][2], obj.m[1][3],
|
||||
obj.m[2][0], obj.m[2][1], obj.m[2][2], obj.m[2][3],
|
||||
obj.m[3][0], obj.m[3][1], obj.m[3][2], obj.m[3][3]
|
||||
), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<Crafter::MatrixRowMajor<float, 4, 3, 1>> : std::formatter<std::string> {
|
||||
auto format(const Crafter::MatrixRowMajor<float, 4, 3, 1>& obj, format_context& ctx) const {
|
||||
return std::formatter<std::string>::format(std::format("{{{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}}}",
|
||||
obj.m[0][0], obj.m[0][1], obj.m[0][2], obj.m[0][3],
|
||||
obj.m[1][0], obj.m[1][1], obj.m[1][2], obj.m[1][3],
|
||||
obj.m[2][0], obj.m[2][1], obj.m[2][2], obj.m[2][3]
|
||||
), ctx);
|
||||
}
|
||||
};
|
||||
/*
|
||||
Crafter®.Math
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
catcrafts.net
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License version 3.0 as published by the Free Software Foundation;
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
export module Crafter.Math:MatrixRowMajor;
|
||||
|
||||
import :Basic;
|
||||
import :VectorF32;
|
||||
import std;
|
||||
|
||||
namespace Crafter {
|
||||
// Row-major matrix whose rows live in optimized SIMD vectors. All
|
||||
// multiplications are expressed as broadcast + fused multiply-add against
|
||||
// these row vectors so the heavy work stays in __m128/__m256/__m512 land.
|
||||
//
|
||||
// CollumSize is the column count; only CollumSize == 4 is implemented (the
|
||||
// matrix gets one SIMD row per row). Repeats is reserved for future
|
||||
// SoA-style batching.
|
||||
export template <typename T, std::uint32_t CollumSize, std::uint32_t RowSize, std::uint32_t Repeats>
|
||||
class MatrixRowMajor {
|
||||
public:
|
||||
// Rows are exposed publicly so users can compose with VectorF32 ops
|
||||
// directly without going through an accessor. Each row is a single
|
||||
// SIMD vector covering all columns.
|
||||
VectorF32<static_cast<std::uint8_t>(CollumSize), 1> rows[RowSize];
|
||||
|
||||
MatrixRowMajor() = default;
|
||||
|
||||
MatrixRowMajor(
|
||||
float x0, float y0, float z0, float w0,
|
||||
float x1, float y1, float z1, float w1,
|
||||
float x2, float y2, float z2, float w2,
|
||||
float x3, float y3, float z3, float w3
|
||||
) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
alignas(16) float r0[4] = { x0, y0, z0, w0 };
|
||||
alignas(16) float r1[4] = { x1, y1, z1, w1 };
|
||||
alignas(16) float r2[4] = { x2, y2, z2, w2 };
|
||||
alignas(16) float r3[4] = { x3, y3, z3, w3 };
|
||||
rows[0] = VectorF32<4, 1>(r0);
|
||||
rows[1] = VectorF32<4, 1>(r1);
|
||||
rows[2] = VectorF32<4, 1>(r2);
|
||||
rows[3] = VectorF32<4, 1>(r3);
|
||||
}
|
||||
|
||||
MatrixRowMajor(
|
||||
float x0, float y0, float z0, float w0,
|
||||
float x1, float y1, float z1, float w1,
|
||||
float x2, float y2, float z2, float w2
|
||||
) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
alignas(16) float r0[4] = { x0, y0, z0, w0 };
|
||||
alignas(16) float r1[4] = { x1, y1, z1, w1 };
|
||||
alignas(16) float r2[4] = { x2, y2, z2, w2 };
|
||||
rows[0] = VectorF32<4, 1>(r0);
|
||||
rows[1] = VectorF32<4, 1>(r1);
|
||||
rows[2] = VectorF32<4, 1>(r2);
|
||||
}
|
||||
|
||||
// Flatten to RowSize*CollumSize contiguous floats (row-major). Replaces
|
||||
// the old `m[i][j]` raw array access for callers that need a packed
|
||||
// float buffer (e.g. GPU upload via memcpy).
|
||||
constexpr void Store(float* dst) const requires(CollumSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
for (std::uint32_t i = 0; i < RowSize; ++i) {
|
||||
rows[i].Store(dst + i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr std::array<float, RowSize * 4> Store() const requires(CollumSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
std::array<float, RowSize * 4> out{};
|
||||
Store(out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
// Affine transform: extend `b` with implicit w=1 (translation) and dot
|
||||
// each row against it. Three row-dots packed into one batched 4-pair
|
||||
// Dot call (lane 3 of the result is the duplicated row 0 and gets
|
||||
// discarded).
|
||||
VectorF32<3, 1> operator*(VectorF32<3, 1> b) const requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
std::array<float, 4> bArr = b.template Store<float>();
|
||||
alignas(16) float bhBuf[4] = { bArr[0], bArr[1], bArr[2], 1.0f };
|
||||
VectorF32<4, 1> bh(bhBuf);
|
||||
|
||||
VectorF32<1, 4> dots = VectorF32<4, 1>::Dot(
|
||||
rows[0], bh, rows[1], bh, rows[2], bh, rows[0], bh);
|
||||
|
||||
std::array<float, 4> dotsArr = dots.template Store<float>();
|
||||
alignas(16) float outBuf[4] = { dotsArr[0], dotsArr[1], dotsArr[2], 0.0f };
|
||||
return VectorF32<3, 1>(outBuf);
|
||||
}
|
||||
|
||||
// Linear transform (no translation): same as the affine version but
|
||||
// with bh.w = 0 so the translation column does not contribute. Useful
|
||||
// for direction vectors and normals.
|
||||
VectorF32<3, 1> TransformNormal(VectorF32<3, 1> b) const requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
std::array<float, 4> bArr = b.template Store<float>();
|
||||
alignas(16) float bhBuf[4] = { bArr[0], bArr[1], bArr[2], 0.0f };
|
||||
VectorF32<4, 1> bh(bhBuf);
|
||||
|
||||
VectorF32<1, 4> dots = VectorF32<4, 1>::Dot(
|
||||
rows[0], bh, rows[1], bh, rows[2], bh, rows[0], bh);
|
||||
|
||||
std::array<float, 4> dotsArr = dots.template Store<float>();
|
||||
alignas(16) float outBuf[4] = { dotsArr[0], dotsArr[1], dotsArr[2], 0.0f };
|
||||
return VectorF32<3, 1>(outBuf);
|
||||
}
|
||||
|
||||
// 4×4 matrix product via broadcast + FMA. Each result row is
|
||||
// b[i][0]·rows[0] + b[i][1]·rows[1] + b[i][2]·rows[2] + b[i][3]·rows[3]
|
||||
// produced with four shuffle-broadcasts and three fused multiply-adds.
|
||||
MatrixRowMajor operator*(MatrixRowMajor b) const requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
MatrixRowMajor result;
|
||||
for (std::uint32_t i = 0; i < 4; ++i) {
|
||||
VectorF32<4, 1> bi = b.rows[i];
|
||||
VectorF32<4, 1> bx = bi.template Shuffle<{{0, 0, 0, 0}}>();
|
||||
VectorF32<4, 1> by = bi.template Shuffle<{{1, 1, 1, 1}}>();
|
||||
VectorF32<4, 1> bz = bi.template Shuffle<{{2, 2, 2, 2}}>();
|
||||
VectorF32<4, 1> bw = bi.template Shuffle<{{3, 3, 3, 3}}>();
|
||||
|
||||
VectorF32<4, 1> row = bx * rows[0];
|
||||
row = VectorF32<4, 1>::MulitplyAdd(by, rows[1], row);
|
||||
row = VectorF32<4, 1>::MulitplyAdd(bz, rows[2], row);
|
||||
row = VectorF32<4, 1>::MulitplyAdd(bw, rows[3], row);
|
||||
result.rows[i] = row;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 4×3 affine product. Same broadcast + FMA pattern, but the implicit
|
||||
// 4th row of both matrices is [0, 0, 0, 1] so the b.w · row3 term
|
||||
// contributes only to the translation slot.
|
||||
MatrixRowMajor operator*(MatrixRowMajor b) const requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
alignas(16) float wRowBuf[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
VectorF32<4, 1> wRow(wRowBuf);
|
||||
|
||||
MatrixRowMajor result;
|
||||
for (std::uint32_t i = 0; i < 3; ++i) {
|
||||
VectorF32<4, 1> bi = b.rows[i];
|
||||
VectorF32<4, 1> bx = bi.template Shuffle<{{0, 0, 0, 0}}>();
|
||||
VectorF32<4, 1> by = bi.template Shuffle<{{1, 1, 1, 1}}>();
|
||||
VectorF32<4, 1> bz = bi.template Shuffle<{{2, 2, 2, 2}}>();
|
||||
VectorF32<4, 1> bw = bi.template Shuffle<{{3, 3, 3, 3}}>();
|
||||
|
||||
VectorF32<4, 1> row = bx * rows[0];
|
||||
row = VectorF32<4, 1>::MulitplyAdd(by, rows[1], row);
|
||||
row = VectorF32<4, 1>::MulitplyAdd(bz, rows[2], row);
|
||||
row = VectorF32<4, 1>::MulitplyAdd(bw, wRow, row);
|
||||
result.rows[i] = row;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static MatrixRowMajor Identity() requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0
|
||||
);
|
||||
}
|
||||
|
||||
static MatrixRowMajor Identity() requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
static MatrixRowMajor Scaling(float x, float y, float z) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor(
|
||||
x, 0, 0, 0,
|
||||
0, y, 0, 0,
|
||||
0, 0, z, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
static MatrixRowMajor Scaling(float x, float y, float z) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor(
|
||||
x, 0, 0, 0,
|
||||
0, y, 0, 0,
|
||||
0, 0, z, 0
|
||||
);
|
||||
}
|
||||
static MatrixRowMajor Scaling(VectorF32<3, 1> vector) requires(CollumSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
std::array<float, 4> a = vector.template Store<float>();
|
||||
return Scaling(a[0], a[1], a[2]);
|
||||
}
|
||||
|
||||
static MatrixRowMajor Translation(float x, float y, float z) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
x, y, z, 1
|
||||
);
|
||||
}
|
||||
static MatrixRowMajor Translation(float x, float y, float z) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return MatrixRowMajor(
|
||||
1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, 1, z
|
||||
);
|
||||
}
|
||||
static MatrixRowMajor Translation(VectorF32<3, 1> vector) requires(CollumSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
std::array<float, 4> a = vector.template Store<float>();
|
||||
return Translation(a[0], a[1], a[2]);
|
||||
}
|
||||
|
||||
// Pitch/yaw/roll Euler rotation. Computes all three sin/cos pairs as a
|
||||
// single batched SinCos on a VectorF32<3, 1>, then assembles the rows.
|
||||
static MatrixRowMajor Rotation(float Pitch, float Yaw, float Roll) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
alignas(16) float angles[4] = { Pitch, Yaw, Roll, 0.0f };
|
||||
VectorF32<3, 1> v(angles);
|
||||
std::tuple<VectorF32<3, 1>, VectorF32<3, 1>> sc = v.SinCos();
|
||||
std::array<float, 4> s = std::get<0>(sc).template Store<float>();
|
||||
std::array<float, 4> c = std::get<1>(sc).template Store<float>();
|
||||
const float sp = s[0], cp = c[0];
|
||||
const float sy = s[1], cy = c[1];
|
||||
const float sr = s[2], cr = c[2];
|
||||
|
||||
return MatrixRowMajor(
|
||||
cr * cy + sr * sp * sy, sr * cp, sr * sp * cy - cr * sy, 0.0f,
|
||||
cr * sp * sy - sr * cy, cr * cp, sr * sy + cr * sp * cy, 0.0f,
|
||||
cp * sy, -sp, cp * cy, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
}
|
||||
|
||||
static MatrixRowMajor Rotation(float Pitch, float Yaw, float Roll) requires(CollumSize == 4 && RowSize == 3 && Repeats == 1 && std::same_as<T, float>) {
|
||||
alignas(16) float angles[4] = { Pitch, Yaw, Roll, 0.0f };
|
||||
VectorF32<3, 1> v(angles);
|
||||
std::tuple<VectorF32<3, 1>, VectorF32<3, 1>> sc = v.SinCos();
|
||||
std::array<float, 4> s = std::get<0>(sc).template Store<float>();
|
||||
std::array<float, 4> c = std::get<1>(sc).template Store<float>();
|
||||
const float sp = s[0], cp = c[0];
|
||||
const float sy = s[1], cy = c[1];
|
||||
const float sr = s[2], cr = c[2];
|
||||
|
||||
return MatrixRowMajor(
|
||||
cr * cy + sr * sp * sy, sr * cp, sr * sp * cy - cr * sy, 0.0f,
|
||||
cr * sp * sy - sr * cy, cr * cp, sr * sy + cr * sp * cy, 0.0f,
|
||||
cp * sy, -sp, cp * cy, 0.0f
|
||||
);
|
||||
}
|
||||
|
||||
static MatrixRowMajor Rotation(VectorF32<3, 1> v) requires(CollumSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
std::array<float, 4> a = v.template Store<float>();
|
||||
return Rotation(a[0], a[1], a[2]);
|
||||
}
|
||||
|
||||
// View matrix: builds the basis from a forward (negated) direction and
|
||||
// an up reference, then dots each basis vector with -eye for the
|
||||
// translation column. The four dots needed are produced by a single
|
||||
// batched 4-pair Dot.
|
||||
static MatrixRowMajor LookTo(VectorF32<3, 1> eyePosition, VectorF32<3, 1> eyeDirection, VectorF32<3, 1> upDirection) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
// R0 = up × R2 is linear in R2, so its normalized direction does
|
||||
// not depend on whether we hand R2 in before or after its own
|
||||
// normalize. Computing R0_raw from the un-normalized R2 lets us
|
||||
// satisfy the 4-input Normalize requirement with one batched call
|
||||
// (duplicating R2 and R0 in the padding slots).
|
||||
VectorF32<3, 1> R0Raw = VectorF32<3, 1>::Cross(upDirection, eyeDirection);
|
||||
auto normalized = VectorF32<3, 1>::Normalize(eyeDirection, R0Raw, eyeDirection, R0Raw);
|
||||
VectorF32<3, 1> R2 = std::get<0>(normalized);
|
||||
VectorF32<3, 1> R0 = std::get<1>(normalized);
|
||||
VectorF32<3, 1> R1 = VectorF32<3, 1>::Cross(R2, R0);
|
||||
VectorF32<3, 1> negEye = -eyePosition;
|
||||
|
||||
VectorF32<1, 4> dots = VectorF32<3, 1>::Dot(
|
||||
R0, negEye, R1, negEye, R2, negEye, R0, negEye);
|
||||
std::array<float, 4> d = dots.template Store<float>();
|
||||
std::array<float, 4> r0a = R0.template Store<float>();
|
||||
std::array<float, 4> r1a = R1.template Store<float>();
|
||||
std::array<float, 4> r2a = R2.template Store<float>();
|
||||
|
||||
return MatrixRowMajor(
|
||||
r0a[0], r1a[0], r2a[0], 0.0f,
|
||||
r0a[1], r1a[1], r2a[1], 0.0f,
|
||||
r0a[2], r1a[2], r2a[2], 0.0f,
|
||||
d[0], d[1], d[2], 1.0f
|
||||
);
|
||||
}
|
||||
|
||||
static MatrixRowMajor LookAt(VectorF32<3, 1> eyePosition, VectorF32<3, 1> focusPosition, VectorF32<3, 1> upDirection) requires(CollumSize == 4 && RowSize == 4 && Repeats == 1 && std::same_as<T, float>) {
|
||||
return LookTo(eyePosition, eyePosition - focusPosition, upDirection);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Pretty printer using Store() so it does not depend on the legacy m[i][j]
|
||||
// access pattern.
|
||||
template <>
|
||||
struct std::formatter<Crafter::MatrixRowMajor<float, 4, 4, 1>> : std::formatter<std::string> {
|
||||
auto format(const Crafter::MatrixRowMajor<float, 4, 4, 1>& obj, format_context& ctx) const {
|
||||
std::array<float, 16> v = obj.Store();
|
||||
return std::formatter<std::string>::format(std::format(
|
||||
"{{{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}}}",
|
||||
v[0], v[1], v[2], v[3],
|
||||
v[4], v[5], v[6], v[7],
|
||||
v[8], v[9], v[10], v[11],
|
||||
v[12], v[13], v[14], v[15]
|
||||
), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<Crafter::MatrixRowMajor<float, 4, 3, 1>> : std::formatter<std::string> {
|
||||
auto format(const Crafter::MatrixRowMajor<float, 4, 3, 1>& obj, format_context& ctx) const {
|
||||
std::array<float, 12> v = obj.Store();
|
||||
return std::formatter<std::string>::format(std::format(
|
||||
"{{{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}}}",
|
||||
v[0], v[1], v[2], v[3],
|
||||
v[4], v[5], v[6], v[7],
|
||||
v[8], v[9], v[10], v[11]
|
||||
), ctx);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue