mirror of
https://github.com/HandmadeMath/HandmadeMath.git
synced 2025-12-28 15:44:33 +00:00
Compare commits
9 Commits
v2.0.0-rc2
...
rotate-vec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e210d8729b | ||
|
|
a1c84320f9 | ||
|
|
8df5da57f5 | ||
|
|
149c18d449 | ||
|
|
98748f702c | ||
|
|
6cf6226c57 | ||
|
|
aaa767bf0b | ||
|
|
422bc588e9 | ||
|
|
beb837a3c6 |
275
HandmadeMath.h
275
HandmadeMath.h
@@ -6,8 +6,8 @@
|
||||
both C and C++.
|
||||
|
||||
=============================================================================
|
||||
|
||||
CONFIG
|
||||
=============================================================================
|
||||
|
||||
By default, all angles in Handmade Math are specified in radians. However, it
|
||||
can be configured to use degrees or turns instead. Use one of the following
|
||||
@@ -24,11 +24,13 @@
|
||||
HMM_AngleDeg(degrees)
|
||||
HMM_AngleTurn(turns)
|
||||
|
||||
The definitions of these functions change depending on the default unit.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Handmade Math ships with SSE (SIMD) implementations of several common
|
||||
operations. To disable the use of SSE intrinsics, you must
|
||||
define HANDMADE_MATH_NO_SSE before including this file:
|
||||
operations. To disable the use of SSE intrinsics, you must define
|
||||
HANDMADE_MATH_NO_SSE before including this file:
|
||||
|
||||
#define HANDMADE_MATH_NO_SSE
|
||||
#include "HandmadeMath.h"
|
||||
@@ -50,7 +52,7 @@
|
||||
#define HMM_ACOSF MyACosF
|
||||
#define HMM_SQRTF MySqrtF
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
|
||||
By default, it is assumed that your math functions take radians. To use
|
||||
different units, you must define HMM_ANGLE_USER_TO_INTERNAL and
|
||||
HMM_ANGLE_INTERNAL_TO_USER. For example, if you want to use degrees in your
|
||||
@@ -60,7 +62,7 @@
|
||||
#define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_TurnToDeg)
|
||||
|
||||
=============================================================================
|
||||
|
||||
|
||||
LICENSE
|
||||
|
||||
This software is in the public domain. Where that dedication is not
|
||||
@@ -160,7 +162,7 @@ extern "C"
|
||||
&& !defined(HANDMADE_MATH_USE_RADIANS)
|
||||
# define HANDMADE_MATH_USE_RADIANS
|
||||
#endif
|
||||
|
||||
|
||||
#define HMM_PI 3.14159265358979323846
|
||||
#define HMM_PI32 3.14159265359f
|
||||
#define HMM_DEG180 180.0
|
||||
@@ -203,7 +205,7 @@ extern "C"
|
||||
|
||||
#if !defined(HMM_ANGLE_INTERNAL_TO_USER)
|
||||
# if defined(HANDMADE_MATH_USE_RADIANS)
|
||||
# define HMM_ANGLE_INTERNAL_TO_USER(a) (a)
|
||||
# define HMM_ANGLE_INTERNAL_TO_USER(a) (a)
|
||||
# elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
# define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_RadToDeg)
|
||||
# elif defined(HANDMADE_MATH_USE_TURNS)
|
||||
@@ -242,10 +244,8 @@ typedef union HMM_Vec2
|
||||
float Elements[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline float &operator[](const int &Index)
|
||||
{
|
||||
return Elements[Index];
|
||||
}
|
||||
inline float &operator[](int Index) { return Elements[Index]; }
|
||||
inline const float& operator[](int Index) const { return Elements[Index]; }
|
||||
#endif
|
||||
} HMM_Vec2;
|
||||
|
||||
@@ -293,10 +293,8 @@ typedef union HMM_Vec3
|
||||
float Elements[3];
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline float &operator[](const int &Index)
|
||||
{
|
||||
return Elements[Index];
|
||||
}
|
||||
inline float &operator[](int Index) { return Elements[Index]; }
|
||||
inline const float &operator[](int Index) const { return Elements[Index]; }
|
||||
#endif
|
||||
} HMM_Vec3;
|
||||
|
||||
@@ -357,10 +355,8 @@ typedef union HMM_Vec4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline float &operator[](const int &Index)
|
||||
{
|
||||
return Elements[Index];
|
||||
}
|
||||
inline float &operator[](int Index) { return Elements[Index]; }
|
||||
inline const float &operator[](int Index) const { return Elements[Index]; }
|
||||
#endif
|
||||
} HMM_Vec4;
|
||||
|
||||
@@ -370,23 +366,19 @@ typedef union HMM_Mat2
|
||||
HMM_Vec2 Columns[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline HMM_Vec2 &operator[](const int &Index)
|
||||
{
|
||||
return Columns[Index];
|
||||
}
|
||||
inline HMM_Vec2 &operator[](int Index) { return Columns[Index]; }
|
||||
inline const HMM_Vec2 &operator[](int Index) const { return Columns[Index]; }
|
||||
#endif
|
||||
} HMM_Mat2;
|
||||
|
||||
|
||||
typedef union HMM_Mat3
|
||||
{
|
||||
float Elements[3][3];
|
||||
HMM_Vec3 Columns[3];
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline HMM_Vec3 &operator[](const int &Index)
|
||||
{
|
||||
return Columns[Index];
|
||||
}
|
||||
inline HMM_Vec3 &operator[](int Index) { return Columns[Index]; }
|
||||
inline const HMM_Vec3 &operator[](int Index) const { return Columns[Index]; }
|
||||
#endif
|
||||
} HMM_Mat3;
|
||||
|
||||
@@ -396,10 +388,8 @@ typedef union HMM_Mat4
|
||||
HMM_Vec4 Columns[4];
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline HMM_Vec4 &operator[](const int &Index)
|
||||
{
|
||||
return Columns[Index];
|
||||
}
|
||||
inline HMM_Vec4 &operator[](int Index) { return Columns[Index]; }
|
||||
inline const HMM_Vec4 &operator[](int Index) const { return Columns[Index]; }
|
||||
#endif
|
||||
} HMM_Mat4;
|
||||
|
||||
@@ -435,12 +425,12 @@ static inline float HMM_ToRad(float Angle)
|
||||
{
|
||||
#if defined(HANDMADE_MATH_USE_RADIANS)
|
||||
float Result = Angle;
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
float Result = Angle * HMM_DegToRad;
|
||||
#elif defined(HANDMADE_MATH_USE_TURNS)
|
||||
float Result = Angle * HMM_TurnToRad;
|
||||
#endif
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -448,12 +438,12 @@ static inline float HMM_ToDeg(float Angle)
|
||||
{
|
||||
#if defined(HANDMADE_MATH_USE_RADIANS)
|
||||
float Result = Angle * HMM_RadToDeg;
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
float Result = Angle;
|
||||
#elif defined(HANDMADE_MATH_USE_TURNS)
|
||||
float Result = Angle * HMM_TurnToDeg;
|
||||
#endif
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -461,12 +451,12 @@ static inline float HMM_ToTurn(float Angle)
|
||||
{
|
||||
#if defined(HANDMADE_MATH_USE_RADIANS)
|
||||
float Result = Angle * HMM_RadToTurn;
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
float Result = Angle * HMM_DegToTurn;
|
||||
#elif defined(HANDMADE_MATH_USE_TURNS)
|
||||
float Result = Angle;
|
||||
#endif
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1046,21 +1036,21 @@ static inline HMM_Vec4 HMM_NormV4(HMM_Vec4 A)
|
||||
*/
|
||||
|
||||
COVERAGE(HMM_LerpV2, 1)
|
||||
static inline HMM_Vec2 HMM_LerpV2(HMM_Vec2 A, float Time, HMM_Vec2 B)
|
||||
static inline HMM_Vec2 HMM_LerpV2(HMM_Vec2 A, float Time, HMM_Vec2 B)
|
||||
{
|
||||
ASSERT_COVERED(HMM_LerpV2);
|
||||
return HMM_AddV2(HMM_MulV2F(A, 1.0f - Time), HMM_MulV2F(B, Time));
|
||||
}
|
||||
|
||||
COVERAGE(HMM_LerpV3, 1)
|
||||
static inline HMM_Vec3 HMM_LerpV3(HMM_Vec3 A, float Time, HMM_Vec3 B)
|
||||
static inline HMM_Vec3 HMM_LerpV3(HMM_Vec3 A, float Time, HMM_Vec3 B)
|
||||
{
|
||||
ASSERT_COVERED(HMM_LerpV3);
|
||||
return HMM_AddV3(HMM_MulV3F(A, 1.0f - Time), HMM_MulV3F(B, Time));
|
||||
}
|
||||
|
||||
COVERAGE(HMM_LerpV4, 1)
|
||||
static inline HMM_Vec4 HMM_LerpV4(HMM_Vec4 A, float Time, HMM_Vec4 B)
|
||||
static inline HMM_Vec4 HMM_LerpV4(HMM_Vec4 A, float Time, HMM_Vec4 B)
|
||||
{
|
||||
ASSERT_COVERED(HMM_LerpV4);
|
||||
return HMM_AddV4(HMM_MulV4F(A, 1.0f - Time), HMM_MulV4F(B, Time));
|
||||
@@ -1122,7 +1112,7 @@ COVERAGE(HMM_M2D, 1)
|
||||
static inline HMM_Mat2 HMM_M2D(float Diagonal)
|
||||
{
|
||||
ASSERT_COVERED(HMM_M2D);
|
||||
|
||||
|
||||
HMM_Mat2 Result = {0};
|
||||
Result.Elements[0][0] = Diagonal;
|
||||
Result.Elements[1][1] = Diagonal;
|
||||
@@ -1134,12 +1124,12 @@ COVERAGE(HMM_TransposeM2, 1)
|
||||
static inline HMM_Mat2 HMM_TransposeM2(HMM_Mat2 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_TransposeM2);
|
||||
|
||||
|
||||
HMM_Mat2 Result = Matrix;
|
||||
|
||||
Result.Elements[0][1] = Matrix.Elements[1][0];
|
||||
Result.Elements[1][0] = Matrix.Elements[0][1];
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1147,29 +1137,29 @@ COVERAGE(HMM_AddM2, 1)
|
||||
static inline HMM_Mat2 HMM_AddM2(HMM_Mat2 Left, HMM_Mat2 Right)
|
||||
{
|
||||
ASSERT_COVERED(HMM_AddM2);
|
||||
|
||||
|
||||
HMM_Mat2 Result;
|
||||
|
||||
Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1];
|
||||
|
||||
return Result;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_SubM2, 1)
|
||||
static inline HMM_Mat2 HMM_SubM2(HMM_Mat2 Left, HMM_Mat2 Right)
|
||||
{
|
||||
ASSERT_COVERED(HMM_SubM2);
|
||||
|
||||
|
||||
HMM_Mat2 Result;
|
||||
|
||||
Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1];
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1177,7 +1167,7 @@ COVERAGE(HMM_MulM2V2, 1)
|
||||
static inline HMM_Vec2 HMM_MulM2V2(HMM_Mat2 Matrix, HMM_Vec2 Vector)
|
||||
{
|
||||
ASSERT_COVERED(HMM_MulM2V2);
|
||||
|
||||
|
||||
HMM_Vec2 Result;
|
||||
|
||||
Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
|
||||
@@ -1186,33 +1176,33 @@ static inline HMM_Vec2 HMM_MulM2V2(HMM_Mat2 Matrix, HMM_Vec2 Vector)
|
||||
Result.X += Vector.Elements[1] * Matrix.Columns[1].X;
|
||||
Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y;
|
||||
|
||||
return Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_MulM2, 1)
|
||||
static inline HMM_Mat2 HMM_MulM2(HMM_Mat2 Left, HMM_Mat2 Right)
|
||||
{
|
||||
ASSERT_COVERED(HMM_MulM2);
|
||||
|
||||
|
||||
HMM_Mat2 Result;
|
||||
Result.Columns[0] = HMM_MulM2V2(Left, Right.Columns[0]);
|
||||
Result.Columns[1] = HMM_MulM2V2(Left, Right.Columns[1]);
|
||||
|
||||
return Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_MulM2F, 1)
|
||||
static inline HMM_Mat2 HMM_MulM2F(HMM_Mat2 Matrix, float Scalar)
|
||||
{
|
||||
ASSERT_COVERED(HMM_MulM2F);
|
||||
|
||||
|
||||
HMM_Mat2 Result;
|
||||
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
|
||||
Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
|
||||
Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1220,7 +1210,7 @@ COVERAGE(HMM_DivM2F, 1)
|
||||
static inline HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar)
|
||||
{
|
||||
ASSERT_COVERED(HMM_DivM2F);
|
||||
|
||||
|
||||
HMM_Mat2 Result;
|
||||
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
|
||||
@@ -1232,7 +1222,7 @@ static inline HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar)
|
||||
}
|
||||
|
||||
COVERAGE(HMM_DeterminantM2, 1)
|
||||
static inline float HMM_DeterminantM2(HMM_Mat2 Matrix)
|
||||
static inline float HMM_DeterminantM2(HMM_Mat2 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_DeterminantM2);
|
||||
return Matrix.Elements[0][0]*Matrix.Elements[1][1] - Matrix.Elements[0][1]*Matrix.Elements[1][0];
|
||||
@@ -1240,7 +1230,7 @@ static inline float HMM_DeterminantM2(HMM_Mat2 Matrix)
|
||||
|
||||
|
||||
COVERAGE(HMM_InvGeneralM2, 1)
|
||||
static inline HMM_Mat2 HMM_InvGeneralM2(HMM_Mat2 Matrix)
|
||||
static inline HMM_Mat2 HMM_InvGeneralM2(HMM_Mat2 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvGeneralM2);
|
||||
|
||||
@@ -1270,7 +1260,7 @@ COVERAGE(HMM_M3D, 1)
|
||||
static inline HMM_Mat3 HMM_M3D(float Diagonal)
|
||||
{
|
||||
ASSERT_COVERED(HMM_M3D);
|
||||
|
||||
|
||||
HMM_Mat3 Result = {0};
|
||||
Result.Elements[0][0] = Diagonal;
|
||||
Result.Elements[1][1] = Diagonal;
|
||||
@@ -1292,7 +1282,7 @@ static inline HMM_Mat3 HMM_TransposeM3(HMM_Mat3 Matrix)
|
||||
Result.Elements[1][2] = Matrix.Elements[2][1];
|
||||
Result.Elements[2][1] = Matrix.Elements[1][2];
|
||||
Result.Elements[2][0] = Matrix.Elements[0][2];
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1300,9 +1290,9 @@ COVERAGE(HMM_AddM3, 1)
|
||||
static inline HMM_Mat3 HMM_AddM3(HMM_Mat3 Left, HMM_Mat3 Right)
|
||||
{
|
||||
ASSERT_COVERED(HMM_AddM3);
|
||||
|
||||
|
||||
HMM_Mat3 Result;
|
||||
|
||||
|
||||
Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1];
|
||||
Result.Elements[0][2] = Left.Elements[0][2] + Right.Elements[0][2];
|
||||
@@ -1313,7 +1303,7 @@ static inline HMM_Mat3 HMM_AddM3(HMM_Mat3 Left, HMM_Mat3 Right)
|
||||
Result.Elements[2][1] = Left.Elements[2][1] + Right.Elements[2][1];
|
||||
Result.Elements[2][2] = Left.Elements[2][2] + Right.Elements[2][2];
|
||||
|
||||
return Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_SubM3, 1)
|
||||
@@ -1340,7 +1330,7 @@ COVERAGE(HMM_MulM3V3, 1)
|
||||
static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector)
|
||||
{
|
||||
ASSERT_COVERED(HMM_MulM3V3);
|
||||
|
||||
|
||||
HMM_Vec3 Result;
|
||||
|
||||
Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
|
||||
@@ -1354,8 +1344,8 @@ static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector)
|
||||
Result.X += Vector.Elements[2] * Matrix.Columns[2].X;
|
||||
Result.Y += Vector.Elements[2] * Matrix.Columns[2].Y;
|
||||
Result.Z += Vector.Elements[2] * Matrix.Columns[2].Z;
|
||||
|
||||
return Result;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_MulM3, 1)
|
||||
@@ -1368,7 +1358,7 @@ static inline HMM_Mat3 HMM_MulM3(HMM_Mat3 Left, HMM_Mat3 Right)
|
||||
Result.Columns[1] = HMM_MulM3V3(Left, Right.Columns[1]);
|
||||
Result.Columns[2] = HMM_MulM3V3(Left, Right.Columns[2]);
|
||||
|
||||
return Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_MulM3F, 1)
|
||||
@@ -1388,7 +1378,7 @@ static inline HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar)
|
||||
Result.Elements[2][1] = Matrix.Elements[2][1] * Scalar;
|
||||
Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar;
|
||||
|
||||
return Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_DivM3, 1)
|
||||
@@ -1397,7 +1387,7 @@ static inline HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar)
|
||||
ASSERT_COVERED(HMM_DivM3);
|
||||
|
||||
HMM_Mat3 Result;
|
||||
|
||||
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
|
||||
Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar;
|
||||
@@ -1408,11 +1398,11 @@ static inline HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar)
|
||||
Result.Elements[2][1] = Matrix.Elements[2][1] / Scalar;
|
||||
Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar;
|
||||
|
||||
return Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_DeterminantM3, 1)
|
||||
static inline float HMM_DeterminantM3(HMM_Mat3 Matrix)
|
||||
static inline float HMM_DeterminantM3(HMM_Mat3 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_DeterminantM3);
|
||||
|
||||
@@ -1425,7 +1415,7 @@ static inline float HMM_DeterminantM3(HMM_Mat3 Matrix)
|
||||
}
|
||||
|
||||
COVERAGE(HMM_InvGeneralM3, 1)
|
||||
static inline HMM_Mat3 HMM_InvGeneralM3(HMM_Mat3 Matrix)
|
||||
static inline HMM_Mat3 HMM_InvGeneralM3(HMM_Mat3 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvGeneralM3);
|
||||
|
||||
@@ -1560,7 +1550,7 @@ static inline HMM_Mat4 HMM_SubM4(HMM_Mat4 Left, HMM_Mat4 Right)
|
||||
Result.Elements[3][2] = Left.Elements[3][2] - Right.Elements[3][2];
|
||||
Result.Elements[3][3] = Left.Elements[3][3] - Right.Elements[3][3];
|
||||
#endif
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1656,7 +1646,7 @@ static inline HMM_Mat4 HMM_DivM4F(HMM_Mat4 Matrix, float Scalar)
|
||||
}
|
||||
|
||||
COVERAGE(HMM_DeterminantM4, 1)
|
||||
static inline float HMM_DeterminantM4(HMM_Mat4 Matrix)
|
||||
static inline float HMM_DeterminantM4(HMM_Mat4 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_DeterminantM4);
|
||||
|
||||
@@ -1664,12 +1654,14 @@ static inline float HMM_DeterminantM4(HMM_Mat4 Matrix)
|
||||
HMM_Vec3 C23 = HMM_Cross(Matrix.Columns[2].XYZ, Matrix.Columns[3].XYZ);
|
||||
HMM_Vec3 B10 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[0].XYZ, Matrix.Columns[1].W), HMM_MulV3F(Matrix.Columns[1].XYZ, Matrix.Columns[0].W));
|
||||
HMM_Vec3 B32 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[2].XYZ, Matrix.Columns[3].W), HMM_MulV3F(Matrix.Columns[3].XYZ, Matrix.Columns[2].W));
|
||||
|
||||
|
||||
return HMM_DotV3(C01, B32) + HMM_DotV3(C23, B10);
|
||||
}
|
||||
|
||||
COVERAGE(HMM_InvGeneralM4, 1)
|
||||
static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
|
||||
// Returns a general-purpose inverse of an HMM_Mat4. Note that special-purpose inverses of many transformations
|
||||
// are available and will be more efficient.
|
||||
static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvGeneralM4);
|
||||
|
||||
@@ -1677,7 +1669,7 @@ static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
|
||||
HMM_Vec3 C23 = HMM_Cross(Matrix.Columns[2].XYZ, Matrix.Columns[3].XYZ);
|
||||
HMM_Vec3 B10 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[0].XYZ, Matrix.Columns[1].W), HMM_MulV3F(Matrix.Columns[1].XYZ, Matrix.Columns[0].W));
|
||||
HMM_Vec3 B32 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[2].XYZ, Matrix.Columns[3].W), HMM_MulV3F(Matrix.Columns[3].XYZ, Matrix.Columns[2].W));
|
||||
|
||||
|
||||
float InvDeterminant = 1.0f / (HMM_DotV3(C01, B32) + HMM_DotV3(C23, B10));
|
||||
C01 = HMM_MulV3F(C01, InvDeterminant);
|
||||
C23 = HMM_MulV3F(C23, InvDeterminant);
|
||||
@@ -1689,7 +1681,7 @@ static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
|
||||
Result.Columns[1] = HMM_V4V(HMM_SubV3(HMM_Cross(B32, Matrix.Columns[0].XYZ), HMM_MulV3F(C23, Matrix.Columns[0].W)), +HMM_DotV3(Matrix.Columns[0].XYZ, C23));
|
||||
Result.Columns[2] = HMM_V4V(HMM_AddV3(HMM_Cross(Matrix.Columns[3].XYZ, B10), HMM_MulV3F(C01, Matrix.Columns[3].W)), -HMM_DotV3(Matrix.Columns[3].XYZ, C01));
|
||||
Result.Columns[3] = HMM_V4V(HMM_SubV3(HMM_Cross(B10, Matrix.Columns[2].XYZ), HMM_MulV3F(C01, Matrix.Columns[2].W)), +HMM_DotV3(Matrix.Columns[2].XYZ, C01));
|
||||
|
||||
|
||||
return HMM_TransposeM4(Result);
|
||||
}
|
||||
|
||||
@@ -1698,6 +1690,9 @@ static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
|
||||
*/
|
||||
|
||||
COVERAGE(HMM_Orthographic_RH_NO, 1)
|
||||
// Produces a right-handed orthographic projection matrix with Z ranging from -1 to 1 (the GL convention).
|
||||
// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
|
||||
// Near and Far specify the distances to the near and far clipping planes.
|
||||
static inline HMM_Mat4 HMM_Orthographic_RH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_RH_NO);
|
||||
@@ -1706,18 +1701,20 @@ static inline HMM_Mat4 HMM_Orthographic_RH_NO(float Left, float Right, float Bot
|
||||
|
||||
Result.Elements[0][0] = 2.0f / (Right - Left);
|
||||
Result.Elements[1][1] = 2.0f / (Top - Bottom);
|
||||
Result.Elements[2][2] = 2.0f / (Near - Far);
|
||||
Result.Elements[3][3] = 1.0f;
|
||||
|
||||
Result.Elements[3][0] = (Left + Right) / (Left - Right);
|
||||
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
|
||||
|
||||
Result.Elements[2][2] = 2.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Far + Near) / (Near - Far);
|
||||
Result.Elements[3][2] = (Near + Far) / (Near - Far);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_RH_ZO, 1)
|
||||
// Produces a right-handed orthographic projection matrix with Z ranging from 0 to 1 (the DirectX convention).
|
||||
// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
|
||||
// Near and Far specify the distances to the near and far clipping planes.
|
||||
static inline HMM_Mat4 HMM_Orthographic_RH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_RH_ZO);
|
||||
@@ -1726,40 +1723,47 @@ static inline HMM_Mat4 HMM_Orthographic_RH_ZO(float Left, float Right, float Bot
|
||||
|
||||
Result.Elements[0][0] = 2.0f / (Right - Left);
|
||||
Result.Elements[1][1] = 2.0f / (Top - Bottom);
|
||||
Result.Elements[2][2] = 1.0f / (Near - Far);
|
||||
Result.Elements[3][3] = 1.0f;
|
||||
|
||||
Result.Elements[3][0] = (Left + Right) / (Left - Right);
|
||||
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
|
||||
|
||||
Result.Elements[2][2] = 1.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Near) / (Near - Far);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_LH_NO, 1)
|
||||
// Produces a left-handed orthographic projection matrix with Z ranging from -1 to 1 (the GL convention).
|
||||
// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
|
||||
// Near and Far specify the distances to the near and far clipping planes.
|
||||
static inline HMM_Mat4 HMM_Orthographic_LH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_LH_NO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_RH_NO(Left, Right, Bottom, Top, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_LH_ZO, 1)
|
||||
// Produces a left-handed orthographic projection matrix with Z ranging from 0 to 1 (the DirectX convention).
|
||||
// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
|
||||
// Near and Far specify the distances to the near and far clipping planes.
|
||||
static inline HMM_Mat4 HMM_Orthographic_LH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_LH_ZO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_RH_ZO(Left, Right, Bottom, Top, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_InvOrthographic, 1)
|
||||
COVERAGE(HMM_InvOrthographic, 1)
|
||||
// Returns an inverse for the given orthographic projection matrix. Works for all orthographic
|
||||
// projection matrices, regardless of handedness or NDC convention.
|
||||
static inline HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvOrthographic);
|
||||
@@ -1769,7 +1773,7 @@ static inline HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix)
|
||||
Result.Elements[1][1] = 1.0f / OrthoMatrix.Elements[1][1];
|
||||
Result.Elements[2][2] = 1.0f / OrthoMatrix.Elements[2][2];
|
||||
Result.Elements[3][3] = 1.0f;
|
||||
|
||||
|
||||
Result.Elements[3][0] = -OrthoMatrix.Elements[3][0] * Result.Elements[0][0];
|
||||
Result.Elements[3][1] = -OrthoMatrix.Elements[3][1] * Result.Elements[1][1];
|
||||
Result.Elements[3][2] = -OrthoMatrix.Elements[3][2] * Result.Elements[2][2];
|
||||
@@ -1793,7 +1797,7 @@ static inline HMM_Mat4 HMM_Perspective_RH_NO(float FOV, float AspectRatio, float
|
||||
|
||||
Result.Elements[2][2] = (Near + Far) / (Near - Far);
|
||||
Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1819,32 +1823,32 @@ static inline HMM_Mat4 HMM_Perspective_RH_ZO(float FOV, float AspectRatio, float
|
||||
|
||||
COVERAGE(HMM_Perspective_LH_NO, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_LH_NO(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_LH_NO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Perspective_RH_NO(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
Result.Elements[2][3] = -Result.Elements[2][3];
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_LH_ZO, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_LH_ZO(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_LH_ZO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Perspective_RH_ZO(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
Result.Elements[2][3] = -Result.Elements[2][3];
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_InvPerspective, 1)
|
||||
static inline HMM_Mat4 HMM_InvPerspective(HMM_Mat4 PerspectiveMatrix)
|
||||
COVERAGE(HMM_InvPerspective_RH, 1)
|
||||
static inline HMM_Mat4 HMM_InvPerspective_RH(HMM_Mat4 PerspectiveMatrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvPerspective);
|
||||
ASSERT_COVERED(HMM_InvPerspective_RH);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0];
|
||||
@@ -1858,6 +1862,23 @@ static inline HMM_Mat4 HMM_InvPerspective(HMM_Mat4 PerspectiveMatrix)
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_InvPerspective_LH, 1)
|
||||
static inline HMM_Mat4 HMM_InvPerspective_LH(HMM_Mat4 PerspectiveMatrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvPerspective_LH);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0];
|
||||
Result.Elements[1][1] = 1.0f / PerspectiveMatrix.Elements[1][1];
|
||||
Result.Elements[2][2] = 0.0f;
|
||||
|
||||
Result.Elements[2][3] = 1.0f / PerspectiveMatrix.Elements[3][2];
|
||||
Result.Elements[3][3] = PerspectiveMatrix.Elements[2][2] * -Result.Elements[2][3];
|
||||
Result.Elements[3][2] = PerspectiveMatrix.Elements[2][3];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Translate, 1)
|
||||
static inline HMM_Mat4 HMM_Translate(HMM_Vec3 Translation)
|
||||
{
|
||||
@@ -1941,7 +1962,7 @@ static inline HMM_Mat4 HMM_Scale(HMM_Vec3 Scale)
|
||||
}
|
||||
|
||||
COVERAGE(HMM_InvScale, 1)
|
||||
static inline HMM_Mat4 HMM_InvScale(HMM_Mat4 ScaleMatrix)
|
||||
static inline HMM_Mat4 HMM_InvScale(HMM_Mat4 ScaleMatrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvScale);
|
||||
|
||||
@@ -2145,7 +2166,7 @@ static inline HMM_Quat HMM_MulQ(HMM_Quat Left, HMM_Quat Right)
|
||||
Result.Y += Right.Elements[3] * +Left.Elements[1];
|
||||
Result.Z += Right.Elements[0] * -Left.Elements[1];
|
||||
Result.W += Right.Elements[1] * -Left.Elements[1];
|
||||
|
||||
|
||||
Result.X += Right.Elements[1] * -Left.Elements[2];
|
||||
Result.Y += Right.Elements[0] * +Left.Elements[2];
|
||||
Result.Z += Right.Elements[3] * +Left.Elements[2];
|
||||
@@ -2225,7 +2246,7 @@ COVERAGE(HMM_InvQ, 1)
|
||||
static inline HMM_Quat HMM_InvQ(HMM_Quat Left)
|
||||
{
|
||||
ASSERT_COVERED(HMM_InvQ);
|
||||
|
||||
|
||||
HMM_Quat Result;
|
||||
Result.X = -Left.X;
|
||||
Result.Y = -Left.Y;
|
||||
@@ -2291,7 +2312,7 @@ static inline HMM_Quat HMM_SLerp(HMM_Quat Left, float Time, HMM_Quat Right)
|
||||
Cos_Theta = -Cos_Theta;
|
||||
Right = HMM_Q(-Right.X, -Right.Y, -Right.Z, -Right.W);
|
||||
}
|
||||
|
||||
|
||||
/* NOTE(lcf): Use Normalized Linear interpolation when vectors are roughly not L.I. */
|
||||
if (Cos_Theta > 0.9995f) {
|
||||
Result = HMM_NLerp(Left, Time, Right);
|
||||
@@ -2303,7 +2324,7 @@ static inline HMM_Quat HMM_SLerp(HMM_Quat Left, float Time, HMM_Quat Right)
|
||||
Result = _HMM_MixQ(Left, MixLeft, Right, MixRight);
|
||||
Result = HMM_NormQ(Result);
|
||||
}
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -2483,27 +2504,63 @@ static inline HMM_Quat HMM_M4ToQ_LH(HMM_Mat4 M)
|
||||
|
||||
|
||||
COVERAGE(HMM_QFromAxisAngle_RH, 1)
|
||||
static inline HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float AngleOfRotation)
|
||||
static inline HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float Angle)
|
||||
{
|
||||
ASSERT_COVERED(HMM_QFromAxisAngle_RH);
|
||||
|
||||
HMM_Quat Result;
|
||||
|
||||
HMM_Vec3 AxisNormalized = HMM_NormV3(Axis);
|
||||
float SineOfRotation = HMM_SinF(AngleOfRotation / 2.0f);
|
||||
float SineOfRotation = HMM_SinF(Angle / 2.0f);
|
||||
|
||||
Result.XYZ = HMM_MulV3F(AxisNormalized, SineOfRotation);
|
||||
Result.W = HMM_CosF(AngleOfRotation / 2.0f);
|
||||
Result.W = HMM_CosF(Angle / 2.0f);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_QFromAxisAngle_LH, 1)
|
||||
static inline HMM_Quat HMM_QFromAxisAngle_LH(HMM_Vec3 Axis, float AngleOfRotation)
|
||||
static inline HMM_Quat HMM_QFromAxisAngle_LH(HMM_Vec3 Axis, float Angle)
|
||||
{
|
||||
ASSERT_COVERED(HMM_QFromAxisAngle_LH);
|
||||
|
||||
return HMM_QFromAxisAngle_RH(Axis, -AngleOfRotation);
|
||||
return HMM_QFromAxisAngle_RH(Axis, -Angle);
|
||||
}
|
||||
|
||||
COVERAGE(HMM_RotateV2, 1)
|
||||
static inline HMM_Vec2 HMM_RotateV2(HMM_Vec2 V, float Angle)
|
||||
{
|
||||
ASSERT_COVERED(HMM_RotateV2)
|
||||
|
||||
float sinA = HMM_SinF(Angle);
|
||||
float cosA = HMM_CosF(Angle);
|
||||
|
||||
return HMM_V2(V.X * cosA - V.Y * sinA, V.X * sinA + V.Y * cosA);
|
||||
}
|
||||
|
||||
// implementation from
|
||||
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
|
||||
COVERAGE(HMM_RotateV3Q, 1)
|
||||
static inline HMM_Vec3 HMM_RotateV3Q(HMM_Vec3 V, HMM_Quat Q)
|
||||
{
|
||||
ASSERT_COVERED(HMM_RotateV3Q);
|
||||
|
||||
HMM_Vec3 t = HMM_MulV3F(HMM_Cross(Q.XYZ, V), 2);
|
||||
return HMM_AddV3(V, HMM_AddV3(HMM_MulV3F(t, Q.W), HMM_Cross(Q.XYZ, t)));
|
||||
}
|
||||
|
||||
COVERAGE(HMM_RotateV3AxisAngle_LH, 1)
|
||||
static inline HMM_Vec3 HMM_RotateV3AxisAngle_LH(HMM_Vec3 V, HMM_Vec3 Axis, float Angle) {
|
||||
ASSERT_COVERED(HMM_RotateV3AxisAngle_LH);
|
||||
|
||||
return HMM_RotateV3Q(V, HMM_QFromAxisAngle_LH(Axis, Angle));
|
||||
}
|
||||
|
||||
COVERAGE(HMM_RotateV3AxisAngle_RH, 1)
|
||||
static inline HMM_Vec3 HMM_RotateV3AxisAngle_RH(HMM_Vec3 V, HMM_Vec3 Axis, float Angle) {
|
||||
ASSERT_COVERED(HMM_RotateV3AxisAngle_RH);
|
||||
|
||||
return HMM_RotateV3Q(V, HMM_QFromAxisAngle_RH(Axis, Angle));
|
||||
}
|
||||
|
||||
|
||||
@@ -2603,23 +2660,23 @@ static inline float HMM_Dot(HMM_Vec4 Left, HMM_Vec4 VecTwo)
|
||||
ASSERT_COVERED(HMM_DotV4CPP);
|
||||
return HMM_DotV4(Left, VecTwo);
|
||||
}
|
||||
|
||||
|
||||
COVERAGE(HMM_LerpV2CPP, 1)
|
||||
static inline HMM_Vec2 HMM_Lerp(HMM_Vec2 Left, float Time, HMM_Vec2 Right)
|
||||
static inline HMM_Vec2 HMM_Lerp(HMM_Vec2 Left, float Time, HMM_Vec2 Right)
|
||||
{
|
||||
ASSERT_COVERED(HMM_LerpV2CPP);
|
||||
return HMM_LerpV2(Left, Time, Right);
|
||||
}
|
||||
|
||||
COVERAGE(HMM_LerpV3CPP, 1)
|
||||
static inline HMM_Vec3 HMM_Lerp(HMM_Vec3 Left, float Time, HMM_Vec3 Right)
|
||||
static inline HMM_Vec3 HMM_Lerp(HMM_Vec3 Left, float Time, HMM_Vec3 Right)
|
||||
{
|
||||
ASSERT_COVERED(HMM_LerpV3CPP);
|
||||
return HMM_LerpV3(Left, Time, Right);
|
||||
}
|
||||
|
||||
COVERAGE(HMM_LerpV4CPP, 1)
|
||||
static inline HMM_Vec4 HMM_Lerp(HMM_Vec4 Left, float Time, HMM_Vec4 Right)
|
||||
static inline HMM_Vec4 HMM_Lerp(HMM_Vec4 Left, float Time, HMM_Vec4 Right)
|
||||
{
|
||||
ASSERT_COVERED(HMM_LerpV4CPP);
|
||||
return HMM_LerpV4(Left, Time, Right);
|
||||
|
||||
23
README.md
23
README.md
@@ -1,36 +1,43 @@
|
||||
# Handmade Math
|
||||
|
||||
A single-file, cross-platform, public domain game math library for both C and C++. Supports vectors, matrices, quaternions, and all the utilities you'd expect.
|
||||
A single-file, cross-platform, public domain graphics math library for both C and C++. Supports vectors, matrices, quaternions, and all the utilities you'd expect.
|
||||
|
||||
To get started, go download [the latest release](https://github.com/HandmadeMath/HandmadeMath/releases).
|
||||
|
||||
> If you are upgrading to version 2 of Handmade Math, save yourself some time and use our [automatic update tool](./update).
|
||||
> If you are upgrading to Handmade Math 2.0, save yourself some time and use our [automatic update tool](./update).
|
||||
|
||||
Here's what sets Handmade Math apart:
|
||||
|
||||
- **A simple single-header library.** Just `#include "HandmadeMath.h"`.
|
||||
- **Supports both C and C++.** While libraries like GLM only support C++, Handmade Math supports both C and C++, with convenient overloads wherever possible. For example, C++ codebases get operator overloading, and C11 codebases get `_Generic` versions of common operations.
|
||||
- **Supports all graphics APIs.** Handmade Math has left- and right-handed versions of each operation, as well as support for zero-to-one and negative-one-to-one NDC conventions.
|
||||
- **Swizzling, sort of.** Handmade Math's vector types use unions to provide several ways of accessing the same underlying data. For example, the components of an `HMM_Vec3` can be accessed as `XYZ`, `RGB`, or `UVW` - or subsets can be accessed like `.XY` and `.YZ`.
|
||||
- **Your choice of angle unit.** While Handmade Math uses radians by default, you can configure it to use degrees or [turns](https://www.computerenhance.com/p/turns-are-better-than-radians) instead.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Simply `#include "HandmadeMath.h"`. All functions are `static inline`, so no need for an "implementation" file as with some other single-header libraries.
|
||||
Simply `#include "HandmadeMath.h"`. All functions are `static inline`, so there is no need for an "implementation" file as with some other single-header libraries.
|
||||
|
||||
A few config options are available. See the header comment in [the source](./HandmadeMath.h) for details.
|
||||
|
||||
|
||||
## FAQ
|
||||
|
||||
**What conventions does HMM use, e.g. row vs. column major, handedness, etc.?**
|
||||
|
||||
Handmade Math's matrices are column-major, i.e. data is stored by columns, then rows. It also assumes column vectors, i.e. vectors are written vertically and matrix-vector multiplication is `M * V` instead of `V * M`. For more information, see [this issue](https://github.com/HandmadeMath/HandmadeMath/issues/124#issuecomment-775737253).
|
||||
|
||||
For other properties, we provide variants for each common convention. Functions that care about handedness have left-handed (`LH`) and right-handed (`RH`) variants. Projection functions have zero-to-one (`ZO`) and negative-one-to-one (`NO`) variants for different NDC conventions.
|
||||
|
||||
**What if I don't want the `HMM_` prefix?**
|
||||
|
||||
Do a find and replace in the library source.
|
||||
|
||||
**What's the license?**
|
||||
|
||||
This library is in the public domain. You can do whatever you want with it.
|
||||
|
||||
**Where can I contact you to ask questions?**
|
||||
|
||||
Feel free to make Github issues for any questions, concerns, or problems you encounter.
|
||||
|
||||
**What if I don't want the `HMM_` prefix?**
|
||||
|
||||
Do a find and replace in the library source.
|
||||
Feel free to make GitHub issues for any questions, concerns, or problems you encounter.
|
||||
|
||||
@@ -148,25 +148,35 @@ INITIALIZER(_HMT_COVERCASE_FUNCNAME_INIT(name)) { \
|
||||
} \
|
||||
} \
|
||||
|
||||
#define HMT_EXPECT_FLOAT_EQ(_actual, _expected) { \
|
||||
#define HMT_EXPECT_FLOAT_EQ_MSG(_actual, _expected, _msg) { \
|
||||
_HMT_CASE_START(); \
|
||||
float actual = (_actual); \
|
||||
float diff = actual - (_expected); \
|
||||
if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \
|
||||
_HMT_CASE_FAIL(); \
|
||||
printf("Expected %f, got %f", (_expected), actual); \
|
||||
if ((_msg)[0] == 0) { \
|
||||
printf("Expected %f, got %f (error: %.9g)", (_expected), actual, diff); \
|
||||
} else { \
|
||||
printf("%s: Expected %f, got %f (error: %.9g)", (_msg), (_expected), actual, diff); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#define HMT_EXPECT_FLOAT_EQ(_actual, _expected) HMT_EXPECT_FLOAT_EQ_MSG(_actual, _expected, "");
|
||||
|
||||
#define HMT_EXPECT_NEAR(_actual, _expected, _epsilon) { \
|
||||
#define HMT_EXPECT_NEAR_MSG(_actual, _expected, _epsilon, _msg) { \
|
||||
_HMT_CASE_START(); \
|
||||
float actual = (_actual); \
|
||||
float diff = actual - (_expected); \
|
||||
if (diff < -(_epsilon) || (_epsilon) < diff) { \
|
||||
_HMT_CASE_FAIL(); \
|
||||
printf("Expected %f, got %f", (_expected), actual); \
|
||||
if ((_msg)[0] == 0) { \
|
||||
printf("Expected %f, got %f", (_expected), actual); \
|
||||
} else { \
|
||||
printf("%s: Expected %f, got %f", (_msg), (_expected), actual); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#define HMT_EXPECT_NEAR(_actual, _expected, _epsilon) HMT_EXPECT_NEAR_MSG(_actual, _expected, _epsilon, "");
|
||||
|
||||
#define HMT_EXPECT_LT(_actual, _expected) { \
|
||||
_HMT_CASE_START(); \
|
||||
@@ -192,7 +202,46 @@ INITIALIZER(_HMT_COVERCASE_FUNCNAME_INIT(name)) { \
|
||||
#define EXPECT_TRUE(_actual) HMT_EXPECT_TRUE(_actual)
|
||||
#define EXPECT_FALSE(_actual) HMT_EXPECT_FALSE(_actual)
|
||||
#define EXPECT_FLOAT_EQ(_actual, _expected) HMT_EXPECT_FLOAT_EQ(_actual, _expected)
|
||||
#define EXPECT_V4_EQ(_actual, _expected) \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.X, _expected.X, "incorrect X"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Y, _expected.Y, "incorrect Y"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Z, _expected.Z, "incorrect Z"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.W, _expected.W, "incorrect W");
|
||||
#define EXPECT_M4_EQ(_actual, _expected) \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[0][0], _expected.Elements[0][0], "incorrect [0][0]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[0][1], _expected.Elements[0][1], "incorrect [0][1]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[0][2], _expected.Elements[0][2], "incorrect [0][2]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[0][3], _expected.Elements[0][3], "incorrect [0][3]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[1][0], _expected.Elements[1][0], "incorrect [1][0]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[1][1], _expected.Elements[1][1], "incorrect [1][1]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[1][2], _expected.Elements[1][2], "incorrect [1][2]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[1][3], _expected.Elements[1][3], "incorrect [1][3]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[2][0], _expected.Elements[2][0], "incorrect [2][0]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[2][1], _expected.Elements[2][1], "incorrect [2][1]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[2][2], _expected.Elements[2][2], "incorrect [2][2]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[2][3], _expected.Elements[2][3], "incorrect [2][3]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[3][0], _expected.Elements[3][0], "incorrect [3][0]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[3][1], _expected.Elements[3][1], "incorrect [3][1]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[3][2], _expected.Elements[3][2], "incorrect [3][2]"); \
|
||||
HMT_EXPECT_FLOAT_EQ_MSG(_actual.Elements[3][3], _expected.Elements[3][3], "incorrect [3][3]");
|
||||
#define EXPECT_NEAR(_actual, _expected, _epsilon) HMT_EXPECT_NEAR(_actual, _expected, _epsilon)
|
||||
#define EXPECT_M4_NEAR(_actual, _expected, _epsilon) \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[0][0], _expected.Elements[0][0], _epsilon, "incorrect [0][0]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[0][1], _expected.Elements[0][1], _epsilon, "incorrect [0][1]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[0][2], _expected.Elements[0][2], _epsilon, "incorrect [0][2]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[0][3], _expected.Elements[0][3], _epsilon, "incorrect [0][3]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[1][0], _expected.Elements[1][0], _epsilon, "incorrect [1][0]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[1][1], _expected.Elements[1][1], _epsilon, "incorrect [1][1]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[1][2], _expected.Elements[1][2], _epsilon, "incorrect [1][2]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[1][3], _expected.Elements[1][3], _epsilon, "incorrect [1][3]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[2][0], _expected.Elements[2][0], _epsilon, "incorrect [2][0]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[2][1], _expected.Elements[2][1], _epsilon, "incorrect [2][1]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[2][2], _expected.Elements[2][2], _epsilon, "incorrect [2][2]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[2][3], _expected.Elements[2][3], _epsilon, "incorrect [2][3]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[3][0], _expected.Elements[3][0], _epsilon, "incorrect [3][0]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[3][1], _expected.Elements[3][1], _epsilon, "incorrect [3][1]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[3][2], _expected.Elements[3][2], _epsilon, "incorrect [3][2]"); \
|
||||
HMT_EXPECT_NEAR_MSG(_actual.Elements[3][3], _expected.Elements[3][3], _epsilon, "incorrect [3][3]");
|
||||
#define EXPECT_LT(_actual, _expected) HMT_EXPECT_LT(_actual, _expected)
|
||||
#define EXPECT_GT(_actual, _expected) HMT_EXPECT_GT(_actual, _expected)
|
||||
#endif // HMT_SAFE_MACROS
|
||||
|
||||
@@ -129,22 +129,22 @@ TEST(InvMatrix, InvGeneral)
|
||||
float Det = HMM_DeterminantM4(Matrix);
|
||||
EXPECT_FLOAT_EQ(Det, -80.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
EXPECT_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.00001f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
Inverse = HMM_InvGeneral(Matrix);
|
||||
@@ -153,22 +153,22 @@ TEST(InvMatrix, InvGeneral)
|
||||
Det = HMM_Determinant(Matrix);
|
||||
EXPECT_FLOAT_EQ(Det, -80.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
EXPECT_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.00001f);
|
||||
EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.00001f);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -246,60 +246,56 @@ TEST(InvMatrix, InvGeneral)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InvMatrix, Mat4Inverses)
|
||||
TEST(InvMatrix, InvOrthographic)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_RH_NO(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvOrthographic(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Perspective_RH_NO(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvPerspective(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_RH_ZO(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Inverse = HMM_InvOrthographic(Matrix);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_LH_NO(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Inverse = HMM_InvOrthographic(Matrix);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_LH_ZO(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Inverse = HMM_InvOrthographic(Matrix);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InvMatrix, InvPerspective)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Perspective_RH_NO(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Inverse = HMM_InvPerspective_RH(Matrix);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Perspective_RH_ZO(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Inverse = HMM_InvPerspective_RH(Matrix);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Perspective_LH_NO(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Inverse = HMM_InvPerspective_LH(Matrix);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Perspective_LH_ZO(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Inverse = HMM_InvPerspective_LH(Matrix);
|
||||
EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InvMatrix, InvLookAt)
|
||||
{
|
||||
{
|
||||
HMM_Vec3 Eye = {10.0f, 10.0f, 10.0f};
|
||||
HMM_Vec3 Center = {100.0f, 200.0f, 30.0f};
|
||||
@@ -308,106 +304,56 @@ TEST(InvMatrix, Mat4Inverses)
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvLookAt(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.001f);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.001f);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.001f);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.001f);
|
||||
EXPECT_M4_NEAR(Result, Expect, 0.001f);
|
||||
}
|
||||
{
|
||||
HMM_Vec3 Eye = {10.0f, 10.0f, 10.0f};
|
||||
HMM_Vec3 Center = {100.0f, 200.0f, 30.0f};
|
||||
HMM_Vec3 Up = {0.0f, 0.0f, 1.0f};
|
||||
HMM_Mat4 Matrix = HMM_LookAt_LH(Eye, Center, Up);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvLookAt(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
EXPECT_M4_NEAR(Result, Expect, 0.001f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InvMatrix, InvRotate)
|
||||
{
|
||||
{
|
||||
HMM_Vec3 Axis = {1.0f, -1.0f, 0.5f};
|
||||
HMM_Mat4 Matrix = HMM_Rotate_RH(HMM_AngleDeg(30), HMM_NormV3(Axis));
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvRotate(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.001f);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.001f);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.001f);
|
||||
|
||||
EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.001f);
|
||||
EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.001f);
|
||||
EXPECT_M4_NEAR(Result, Expect, 0.001f);
|
||||
}
|
||||
{
|
||||
HMM_Vec3 Scale = {1.0f, -1.0f, 0.5f};
|
||||
HMM_Mat4 Matrix = HMM_Scale(Scale);
|
||||
HMM_Vec3 Axis = {1.0f, -1.0f, 0.5f};
|
||||
HMM_Mat4 Matrix = HMM_Rotate_LH(HMM_AngleDeg(30), HMM_NormV3(Axis));
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvScale(Matrix);
|
||||
HMM_Mat4 Inverse = HMM_InvRotate(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
EXPECT_M4_NEAR(Result, Expect, 0.001f);
|
||||
}
|
||||
{
|
||||
HMM_Vec3 Move = {1.0f, -1.0f, 0.5f};
|
||||
HMM_Mat4 Matrix = HMM_Translate(Move);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvTranslate(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]);
|
||||
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InvMatrix, InvScale)
|
||||
{
|
||||
HMM_Vec3 Scale = {1.0f, -1.0f, 0.5f};
|
||||
HMM_Mat4 Matrix = HMM_Scale(Scale);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvScale(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
EXPECT_M4_EQ(Result, Expect);
|
||||
}
|
||||
|
||||
TEST(InvMatrix, InvTranslate)
|
||||
{
|
||||
HMM_Vec3 Move = {1.0f, -1.0f, 0.5f};
|
||||
HMM_Mat4 Matrix = HMM_Translate(Move);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvTranslate(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
EXPECT_M4_EQ(Result, Expect);
|
||||
}
|
||||
|
||||
@@ -2,67 +2,84 @@
|
||||
|
||||
TEST(Projection, Orthographic)
|
||||
{
|
||||
#define ORTHO_BOUNDS -8.0f, 12.0f, 5.0f, 10.0f, 1.0f, 100.0f
|
||||
|
||||
// Right-handed
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_RH_NO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, 10.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
// Near and far distances correspond to negative Z, hence the Z coordinates here are negative.
|
||||
HMM_Vec4 minCorner = HMM_V4(-8.0f, 5.0f, -1.0f, 1.0);
|
||||
HMM_Vec4 maxCorner = HMM_V4(12.0f, 10.0f, -100.0f, 1.0);
|
||||
|
||||
EXPECT_FLOAT_EQ(projected.X, 0.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
// Z from -1 to 1 (GL convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_RH_NO(ORTHO_BOUNDS);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, minCorner), HMM_V4(-1.0f, -1.0f, -1.0f, 1.0f));
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, maxCorner), HMM_V4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Orthographic_RH_ZO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
// Z from 0 to 1 (DX convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_RH_ZO(ORTHO_BOUNDS);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, minCorner), HMM_V4(-1.0f, -1.0f, 0.0f, 1.0f));
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, maxCorner), HMM_V4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_LH_NO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
|
||||
EXPECT_FLOAT_EQ(projected.X, 0.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Orthographic_LH_ZO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
// Left-handed
|
||||
{
|
||||
// Near and far distances correspond to positive Z, hence the Z coordinates here are positive.
|
||||
HMM_Vec4 minCorner = HMM_V4(-8.0f, 5.0f, 1.0f, 1.0);
|
||||
HMM_Vec4 maxCorner = HMM_V4(12.0f, 10.0f, 100.0f, 1.0);
|
||||
|
||||
// Z from -1 to 1 (GL convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_LH_NO(ORTHO_BOUNDS);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, minCorner), HMM_V4(-1.0f, -1.0f, -1.0f, 1.0f));
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, maxCorner), HMM_V4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
// Z from 0 to 1 (DX convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_LH_ZO(ORTHO_BOUNDS);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, minCorner), HMM_V4(-1.0f, -1.0f, 0.0f, 1.0f));
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, maxCorner), HMM_V4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Projection, Perspective)
|
||||
{
|
||||
// Right-handed
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_RH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
// Z from -1 to 1 (GL convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_RH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0f);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, original), HMM_V4(2.5f, 5.0f, -1.0f, 1.0f));
|
||||
}
|
||||
|
||||
/* ZO */
|
||||
projection = HMM_Perspective_RH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
// Z from 0 to 1 (DX convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_RH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0f);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, original), HMM_V4(2.5f, 5.0f, 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Left-handed
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_LH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* ZO */
|
||||
projection = HMM_Perspective_LH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
// Z from -1 to 1 (GL convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_LH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0f);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, original), HMM_V4(2.5f, 5.0f, -1.0f, 1.0f));
|
||||
}
|
||||
|
||||
// Z from 0 to 1 (DX convention)
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_LH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0f);
|
||||
EXPECT_V4_EQ(HMM_MulM4V4(projection, original), HMM_V4(2.5f, 5.0f, 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,23 +254,22 @@ TEST(QuaternionOps, Mat4ToQuat)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(QuaternionOps, FromAxisAngle)
|
||||
TEST(QuaternionOps, RotateVectorAxisAngle)
|
||||
{
|
||||
HMM_Vec3 axis = HMM_V3(1.0f, 0.0f, 0.0f);
|
||||
float angle = HMM_PI32 / 2.0f;
|
||||
|
||||
{
|
||||
HMM_Quat result = HMM_QFromAxisAngle_RH(axis, angle);
|
||||
EXPECT_NEAR(result.X, 0.707107f, 0.001f);
|
||||
HMM_Vec3 axis = HMM_V3(0.0f, 1.0f, 0.0f);
|
||||
float angle = HMM_AngleTurn(1.0/4);
|
||||
HMM_Vec3 result = HMM_RotateV3AxisAngle_LH(HMM_V3(1.0f, 0.0f, 0.0f), axis, angle);
|
||||
EXPECT_NEAR(result.X, 0.0f, 0.001f);
|
||||
EXPECT_NEAR(result.Y, 0.0f, 0.001f);
|
||||
EXPECT_NEAR(result.Z, 0.0f, 0.001f);
|
||||
EXPECT_NEAR(result.W, 0.707107f, 0.001f);
|
||||
EXPECT_NEAR(result.Z, 1.0f, 0.001f);
|
||||
}
|
||||
{
|
||||
HMM_Quat result = HMM_QFromAxisAngle_LH(axis, angle);
|
||||
EXPECT_NEAR(result.X, -0.707107f, 0.001f);
|
||||
EXPECT_NEAR(result.Y, 0.0f, 0.001f);
|
||||
EXPECT_NEAR(result.Z, 0.0f, 0.001f);
|
||||
EXPECT_NEAR(result.W, 0.707107f, 0.001f);
|
||||
HMM_Vec3 axis = HMM_V3(1.0f, 0.0f, 0.0f);
|
||||
float angle = HMM_AngleTurn(1.0/8);
|
||||
HMM_Vec3 result = HMM_RotateV3AxisAngle_RH(HMM_V3(0.0f, 0.0f, 1.0f), axis, angle);
|
||||
EXPECT_NEAR(result.X, 0.0f, 0.001f);
|
||||
EXPECT_NEAR(result.Y, -0.707170f, 0.001f);
|
||||
EXPECT_NEAR(result.Z, 0.707170f, 0.001f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ TEST(Transformations, LookAt)
|
||||
{
|
||||
const float abs_error = 0.001f;
|
||||
|
||||
{ HMM_Mat4 result = HMM_LookAt_RH(HMM_V3(1.0f, 0.0f, 0.0f), HMM_V3(0.0f, 2.0f, 1.0f), HMM_V3(2.0f, 1.0f, 1.0f));
|
||||
{
|
||||
HMM_Mat4 result = HMM_LookAt_RH(HMM_V3(1.0f, 0.0f, 0.0f), HMM_V3(0.0f, 2.0f, 1.0f), HMM_V3(2.0f, 1.0f, 1.0f));
|
||||
|
||||
EXPECT_NEAR(result.Elements[0][0], 0.169031f, abs_error);
|
||||
EXPECT_NEAR(result.Elements[0][1], 0.897085f, abs_error);
|
||||
@@ -103,3 +104,30 @@ TEST(Transformations, LookAt)
|
||||
EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Transformations, RotateV2)
|
||||
{
|
||||
HMM_Vec2 v2 = HMM_V2(1, 2);
|
||||
|
||||
float epsilon = 0.000001f;
|
||||
{
|
||||
HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(90));
|
||||
EXPECT_NEAR(res.X, -2.0f, epsilon);
|
||||
EXPECT_NEAR(res.Y, 1.0f, epsilon);
|
||||
}
|
||||
{
|
||||
HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(180));
|
||||
EXPECT_NEAR(res.X, -1.0f, epsilon);
|
||||
EXPECT_NEAR(res.Y, -2.0f, epsilon);
|
||||
}
|
||||
{
|
||||
HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(270));
|
||||
EXPECT_NEAR(res.X, 2.0f, epsilon);
|
||||
EXPECT_NEAR(res.Y, -1.0f, epsilon);
|
||||
}
|
||||
{
|
||||
HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(360));
|
||||
EXPECT_NEAR(res.X, 1.0f, epsilon);
|
||||
EXPECT_NEAR(res.Y, 2.0f, epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user