Compare commits

...

7 Commits

Author SHA1 Message Date
Ben Visness
e210d8729b Add HMM_RotateV2 2023-11-03 11:34:49 -05:00
dev_dwarf
a1c84320f9 Style tweaks to RotateV3Q + axis angle variant 2023-10-31 13:09:20 -06:00
Olivier Perret
8df5da57f5 Clean trailing whitespace in HandmadeMath.h 2023-10-29 18:33:31 +01:00
Olivier Perret
149c18d449 Add HMM_RotateQV3(), for rotating a vec3 by a quaternion 2023-10-29 18:32:09 +01:00
Olivier Perret
98748f702c Provide const versions of operator[] (#166)
This makes it possible use to do something like

const HMM_Vec3 v{1,2,3};
float val = v[1];
2023-10-27 13:15:58 -05:00
Logan Forman
6cf6226c57 remove most references from operators (#164) 2023-08-05 12:57:56 -04:00
Ben Visness
aaa767bf0b Update README.md 2023-02-20 13:29:24 -06:00
6 changed files with 206 additions and 149 deletions

View File

@@ -52,7 +52,7 @@
#define HMM_ACOSF MyACosF #define HMM_ACOSF MyACosF
#define HMM_SQRTF MySqrtF #define HMM_SQRTF MySqrtF
#include "HandmadeMath.h" #include "HandmadeMath.h"
By default, it is assumed that your math functions take radians. To use By default, it is assumed that your math functions take radians. To use
different units, you must define HMM_ANGLE_USER_TO_INTERNAL and 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 HMM_ANGLE_INTERNAL_TO_USER. For example, if you want to use degrees in your
@@ -62,7 +62,7 @@
#define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_TurnToDeg) #define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_TurnToDeg)
============================================================================= =============================================================================
LICENSE LICENSE
This software is in the public domain. Where that dedication is not This software is in the public domain. Where that dedication is not
@@ -162,7 +162,7 @@ extern "C"
&& !defined(HANDMADE_MATH_USE_RADIANS) && !defined(HANDMADE_MATH_USE_RADIANS)
# define HANDMADE_MATH_USE_RADIANS # define HANDMADE_MATH_USE_RADIANS
#endif #endif
#define HMM_PI 3.14159265358979323846 #define HMM_PI 3.14159265358979323846
#define HMM_PI32 3.14159265359f #define HMM_PI32 3.14159265359f
#define HMM_DEG180 180.0 #define HMM_DEG180 180.0
@@ -205,7 +205,7 @@ extern "C"
#if !defined(HMM_ANGLE_INTERNAL_TO_USER) #if !defined(HMM_ANGLE_INTERNAL_TO_USER)
# if defined(HANDMADE_MATH_USE_RADIANS) # 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) # elif defined(HANDMADE_MATH_USE_DEGREES)
# define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_RadToDeg) # define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_RadToDeg)
# elif defined(HANDMADE_MATH_USE_TURNS) # elif defined(HANDMADE_MATH_USE_TURNS)
@@ -244,10 +244,8 @@ typedef union HMM_Vec2
float Elements[2]; float Elements[2];
#ifdef __cplusplus #ifdef __cplusplus
inline float &operator[](const int &Index) inline float &operator[](int Index) { return Elements[Index]; }
{ inline const float& operator[](int Index) const { return Elements[Index]; }
return Elements[Index];
}
#endif #endif
} HMM_Vec2; } HMM_Vec2;
@@ -295,10 +293,8 @@ typedef union HMM_Vec3
float Elements[3]; float Elements[3];
#ifdef __cplusplus #ifdef __cplusplus
inline float &operator[](const int &Index) inline float &operator[](int Index) { return Elements[Index]; }
{ inline const float &operator[](int Index) const { return Elements[Index]; }
return Elements[Index];
}
#endif #endif
} HMM_Vec3; } HMM_Vec3;
@@ -359,10 +355,8 @@ typedef union HMM_Vec4
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
inline float &operator[](const int &Index) inline float &operator[](int Index) { return Elements[Index]; }
{ inline const float &operator[](int Index) const { return Elements[Index]; }
return Elements[Index];
}
#endif #endif
} HMM_Vec4; } HMM_Vec4;
@@ -372,23 +366,19 @@ typedef union HMM_Mat2
HMM_Vec2 Columns[2]; HMM_Vec2 Columns[2];
#ifdef __cplusplus #ifdef __cplusplus
inline HMM_Vec2 &operator[](const int &Index) inline HMM_Vec2 &operator[](int Index) { return Columns[Index]; }
{ inline const HMM_Vec2 &operator[](int Index) const { return Columns[Index]; }
return Columns[Index];
}
#endif #endif
} HMM_Mat2; } HMM_Mat2;
typedef union HMM_Mat3 typedef union HMM_Mat3
{ {
float Elements[3][3]; float Elements[3][3];
HMM_Vec3 Columns[3]; HMM_Vec3 Columns[3];
#ifdef __cplusplus #ifdef __cplusplus
inline HMM_Vec3 &operator[](const int &Index) inline HMM_Vec3 &operator[](int Index) { return Columns[Index]; }
{ inline const HMM_Vec3 &operator[](int Index) const { return Columns[Index]; }
return Columns[Index];
}
#endif #endif
} HMM_Mat3; } HMM_Mat3;
@@ -398,10 +388,8 @@ typedef union HMM_Mat4
HMM_Vec4 Columns[4]; HMM_Vec4 Columns[4];
#ifdef __cplusplus #ifdef __cplusplus
inline HMM_Vec4 &operator[](const int &Index) inline HMM_Vec4 &operator[](int Index) { return Columns[Index]; }
{ inline const HMM_Vec4 &operator[](int Index) const { return Columns[Index]; }
return Columns[Index];
}
#endif #endif
} HMM_Mat4; } HMM_Mat4;
@@ -437,12 +425,12 @@ static inline float HMM_ToRad(float Angle)
{ {
#if defined(HANDMADE_MATH_USE_RADIANS) #if defined(HANDMADE_MATH_USE_RADIANS)
float Result = Angle; float Result = Angle;
#elif defined(HANDMADE_MATH_USE_DEGREES) #elif defined(HANDMADE_MATH_USE_DEGREES)
float Result = Angle * HMM_DegToRad; float Result = Angle * HMM_DegToRad;
#elif defined(HANDMADE_MATH_USE_TURNS) #elif defined(HANDMADE_MATH_USE_TURNS)
float Result = Angle * HMM_TurnToRad; float Result = Angle * HMM_TurnToRad;
#endif #endif
return Result; return Result;
} }
@@ -450,12 +438,12 @@ static inline float HMM_ToDeg(float Angle)
{ {
#if defined(HANDMADE_MATH_USE_RADIANS) #if defined(HANDMADE_MATH_USE_RADIANS)
float Result = Angle * HMM_RadToDeg; float Result = Angle * HMM_RadToDeg;
#elif defined(HANDMADE_MATH_USE_DEGREES) #elif defined(HANDMADE_MATH_USE_DEGREES)
float Result = Angle; float Result = Angle;
#elif defined(HANDMADE_MATH_USE_TURNS) #elif defined(HANDMADE_MATH_USE_TURNS)
float Result = Angle * HMM_TurnToDeg; float Result = Angle * HMM_TurnToDeg;
#endif #endif
return Result; return Result;
} }
@@ -463,12 +451,12 @@ static inline float HMM_ToTurn(float Angle)
{ {
#if defined(HANDMADE_MATH_USE_RADIANS) #if defined(HANDMADE_MATH_USE_RADIANS)
float Result = Angle * HMM_RadToTurn; float Result = Angle * HMM_RadToTurn;
#elif defined(HANDMADE_MATH_USE_DEGREES) #elif defined(HANDMADE_MATH_USE_DEGREES)
float Result = Angle * HMM_DegToTurn; float Result = Angle * HMM_DegToTurn;
#elif defined(HANDMADE_MATH_USE_TURNS) #elif defined(HANDMADE_MATH_USE_TURNS)
float Result = Angle; float Result = Angle;
#endif #endif
return Result; return Result;
} }
@@ -1048,21 +1036,21 @@ static inline HMM_Vec4 HMM_NormV4(HMM_Vec4 A)
*/ */
COVERAGE(HMM_LerpV2, 1) 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); ASSERT_COVERED(HMM_LerpV2);
return HMM_AddV2(HMM_MulV2F(A, 1.0f - Time), HMM_MulV2F(B, Time)); return HMM_AddV2(HMM_MulV2F(A, 1.0f - Time), HMM_MulV2F(B, Time));
} }
COVERAGE(HMM_LerpV3, 1) 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); ASSERT_COVERED(HMM_LerpV3);
return HMM_AddV3(HMM_MulV3F(A, 1.0f - Time), HMM_MulV3F(B, Time)); return HMM_AddV3(HMM_MulV3F(A, 1.0f - Time), HMM_MulV3F(B, Time));
} }
COVERAGE(HMM_LerpV4, 1) 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); ASSERT_COVERED(HMM_LerpV4);
return HMM_AddV4(HMM_MulV4F(A, 1.0f - Time), HMM_MulV4F(B, Time)); return HMM_AddV4(HMM_MulV4F(A, 1.0f - Time), HMM_MulV4F(B, Time));
@@ -1124,7 +1112,7 @@ COVERAGE(HMM_M2D, 1)
static inline HMM_Mat2 HMM_M2D(float Diagonal) static inline HMM_Mat2 HMM_M2D(float Diagonal)
{ {
ASSERT_COVERED(HMM_M2D); ASSERT_COVERED(HMM_M2D);
HMM_Mat2 Result = {0}; HMM_Mat2 Result = {0};
Result.Elements[0][0] = Diagonal; Result.Elements[0][0] = Diagonal;
Result.Elements[1][1] = Diagonal; Result.Elements[1][1] = Diagonal;
@@ -1136,12 +1124,12 @@ COVERAGE(HMM_TransposeM2, 1)
static inline HMM_Mat2 HMM_TransposeM2(HMM_Mat2 Matrix) static inline HMM_Mat2 HMM_TransposeM2(HMM_Mat2 Matrix)
{ {
ASSERT_COVERED(HMM_TransposeM2); ASSERT_COVERED(HMM_TransposeM2);
HMM_Mat2 Result = Matrix; HMM_Mat2 Result = Matrix;
Result.Elements[0][1] = Matrix.Elements[1][0]; Result.Elements[0][1] = Matrix.Elements[1][0];
Result.Elements[1][0] = Matrix.Elements[0][1]; Result.Elements[1][0] = Matrix.Elements[0][1];
return Result; return Result;
} }
@@ -1149,29 +1137,29 @@ COVERAGE(HMM_AddM2, 1)
static inline HMM_Mat2 HMM_AddM2(HMM_Mat2 Left, HMM_Mat2 Right) static inline HMM_Mat2 HMM_AddM2(HMM_Mat2 Left, HMM_Mat2 Right)
{ {
ASSERT_COVERED(HMM_AddM2); ASSERT_COVERED(HMM_AddM2);
HMM_Mat2 Result; HMM_Mat2 Result;
Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0]; 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][1] = Left.Elements[0][1] + Right.Elements[0][1];
Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0]; Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0];
Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1]; Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1];
return Result; return Result;
} }
COVERAGE(HMM_SubM2, 1) COVERAGE(HMM_SubM2, 1)
static inline HMM_Mat2 HMM_SubM2(HMM_Mat2 Left, HMM_Mat2 Right) static inline HMM_Mat2 HMM_SubM2(HMM_Mat2 Left, HMM_Mat2 Right)
{ {
ASSERT_COVERED(HMM_SubM2); ASSERT_COVERED(HMM_SubM2);
HMM_Mat2 Result; HMM_Mat2 Result;
Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0]; 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][1] = Left.Elements[0][1] - Right.Elements[0][1];
Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0]; Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0];
Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1]; Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1];
return Result; return Result;
} }
@@ -1179,7 +1167,7 @@ COVERAGE(HMM_MulM2V2, 1)
static inline HMM_Vec2 HMM_MulM2V2(HMM_Mat2 Matrix, HMM_Vec2 Vector) static inline HMM_Vec2 HMM_MulM2V2(HMM_Mat2 Matrix, HMM_Vec2 Vector)
{ {
ASSERT_COVERED(HMM_MulM2V2); ASSERT_COVERED(HMM_MulM2V2);
HMM_Vec2 Result; HMM_Vec2 Result;
Result.X = Vector.Elements[0] * Matrix.Columns[0].X; Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
@@ -1188,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.X += Vector.Elements[1] * Matrix.Columns[1].X;
Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y; Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y;
return Result; return Result;
} }
COVERAGE(HMM_MulM2, 1) COVERAGE(HMM_MulM2, 1)
static inline HMM_Mat2 HMM_MulM2(HMM_Mat2 Left, HMM_Mat2 Right) static inline HMM_Mat2 HMM_MulM2(HMM_Mat2 Left, HMM_Mat2 Right)
{ {
ASSERT_COVERED(HMM_MulM2); ASSERT_COVERED(HMM_MulM2);
HMM_Mat2 Result; HMM_Mat2 Result;
Result.Columns[0] = HMM_MulM2V2(Left, Right.Columns[0]); Result.Columns[0] = HMM_MulM2V2(Left, Right.Columns[0]);
Result.Columns[1] = HMM_MulM2V2(Left, Right.Columns[1]); Result.Columns[1] = HMM_MulM2V2(Left, Right.Columns[1]);
return Result; return Result;
} }
COVERAGE(HMM_MulM2F, 1) COVERAGE(HMM_MulM2F, 1)
static inline HMM_Mat2 HMM_MulM2F(HMM_Mat2 Matrix, float Scalar) static inline HMM_Mat2 HMM_MulM2F(HMM_Mat2 Matrix, float Scalar)
{ {
ASSERT_COVERED(HMM_MulM2F); ASSERT_COVERED(HMM_MulM2F);
HMM_Mat2 Result; HMM_Mat2 Result;
Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar; Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar; Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar; Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar; Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
return Result; return Result;
} }
@@ -1222,7 +1210,7 @@ COVERAGE(HMM_DivM2F, 1)
static inline HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar) static inline HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar)
{ {
ASSERT_COVERED(HMM_DivM2F); ASSERT_COVERED(HMM_DivM2F);
HMM_Mat2 Result; HMM_Mat2 Result;
Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar; Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
@@ -1234,7 +1222,7 @@ static inline HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar)
} }
COVERAGE(HMM_DeterminantM2, 1) COVERAGE(HMM_DeterminantM2, 1)
static inline float HMM_DeterminantM2(HMM_Mat2 Matrix) static inline float HMM_DeterminantM2(HMM_Mat2 Matrix)
{ {
ASSERT_COVERED(HMM_DeterminantM2); ASSERT_COVERED(HMM_DeterminantM2);
return Matrix.Elements[0][0]*Matrix.Elements[1][1] - Matrix.Elements[0][1]*Matrix.Elements[1][0]; return Matrix.Elements[0][0]*Matrix.Elements[1][1] - Matrix.Elements[0][1]*Matrix.Elements[1][0];
@@ -1242,7 +1230,7 @@ static inline float HMM_DeterminantM2(HMM_Mat2 Matrix)
COVERAGE(HMM_InvGeneralM2, 1) 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); ASSERT_COVERED(HMM_InvGeneralM2);
@@ -1272,7 +1260,7 @@ COVERAGE(HMM_M3D, 1)
static inline HMM_Mat3 HMM_M3D(float Diagonal) static inline HMM_Mat3 HMM_M3D(float Diagonal)
{ {
ASSERT_COVERED(HMM_M3D); ASSERT_COVERED(HMM_M3D);
HMM_Mat3 Result = {0}; HMM_Mat3 Result = {0};
Result.Elements[0][0] = Diagonal; Result.Elements[0][0] = Diagonal;
Result.Elements[1][1] = Diagonal; Result.Elements[1][1] = Diagonal;
@@ -1294,7 +1282,7 @@ static inline HMM_Mat3 HMM_TransposeM3(HMM_Mat3 Matrix)
Result.Elements[1][2] = Matrix.Elements[2][1]; Result.Elements[1][2] = Matrix.Elements[2][1];
Result.Elements[2][1] = Matrix.Elements[1][2]; Result.Elements[2][1] = Matrix.Elements[1][2];
Result.Elements[2][0] = Matrix.Elements[0][2]; Result.Elements[2][0] = Matrix.Elements[0][2];
return Result; return Result;
} }
@@ -1302,9 +1290,9 @@ COVERAGE(HMM_AddM3, 1)
static inline HMM_Mat3 HMM_AddM3(HMM_Mat3 Left, HMM_Mat3 Right) static inline HMM_Mat3 HMM_AddM3(HMM_Mat3 Left, HMM_Mat3 Right)
{ {
ASSERT_COVERED(HMM_AddM3); ASSERT_COVERED(HMM_AddM3);
HMM_Mat3 Result; HMM_Mat3 Result;
Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0]; 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][1] = Left.Elements[0][1] + Right.Elements[0][1];
Result.Elements[0][2] = Left.Elements[0][2] + Right.Elements[0][2]; Result.Elements[0][2] = Left.Elements[0][2] + Right.Elements[0][2];
@@ -1315,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][1] = Left.Elements[2][1] + Right.Elements[2][1];
Result.Elements[2][2] = Left.Elements[2][2] + Right.Elements[2][2]; Result.Elements[2][2] = Left.Elements[2][2] + Right.Elements[2][2];
return Result; return Result;
} }
COVERAGE(HMM_SubM3, 1) COVERAGE(HMM_SubM3, 1)
@@ -1342,7 +1330,7 @@ COVERAGE(HMM_MulM3V3, 1)
static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector) static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector)
{ {
ASSERT_COVERED(HMM_MulM3V3); ASSERT_COVERED(HMM_MulM3V3);
HMM_Vec3 Result; HMM_Vec3 Result;
Result.X = Vector.Elements[0] * Matrix.Columns[0].X; Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
@@ -1356,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.X += Vector.Elements[2] * Matrix.Columns[2].X;
Result.Y += Vector.Elements[2] * Matrix.Columns[2].Y; Result.Y += Vector.Elements[2] * Matrix.Columns[2].Y;
Result.Z += Vector.Elements[2] * Matrix.Columns[2].Z; Result.Z += Vector.Elements[2] * Matrix.Columns[2].Z;
return Result; return Result;
} }
COVERAGE(HMM_MulM3, 1) COVERAGE(HMM_MulM3, 1)
@@ -1370,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[1] = HMM_MulM3V3(Left, Right.Columns[1]);
Result.Columns[2] = HMM_MulM3V3(Left, Right.Columns[2]); Result.Columns[2] = HMM_MulM3V3(Left, Right.Columns[2]);
return Result; return Result;
} }
COVERAGE(HMM_MulM3F, 1) COVERAGE(HMM_MulM3F, 1)
@@ -1390,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][1] = Matrix.Elements[2][1] * Scalar;
Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar; Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar;
return Result; return Result;
} }
COVERAGE(HMM_DivM3, 1) COVERAGE(HMM_DivM3, 1)
@@ -1399,7 +1387,7 @@ static inline HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar)
ASSERT_COVERED(HMM_DivM3); ASSERT_COVERED(HMM_DivM3);
HMM_Mat3 Result; HMM_Mat3 Result;
Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar; Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar; Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar; Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar;
@@ -1410,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][1] = Matrix.Elements[2][1] / Scalar;
Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar; Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar;
return Result; return Result;
} }
COVERAGE(HMM_DeterminantM3, 1) COVERAGE(HMM_DeterminantM3, 1)
static inline float HMM_DeterminantM3(HMM_Mat3 Matrix) static inline float HMM_DeterminantM3(HMM_Mat3 Matrix)
{ {
ASSERT_COVERED(HMM_DeterminantM3); ASSERT_COVERED(HMM_DeterminantM3);
@@ -1427,7 +1415,7 @@ static inline float HMM_DeterminantM3(HMM_Mat3 Matrix)
} }
COVERAGE(HMM_InvGeneralM3, 1) 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); ASSERT_COVERED(HMM_InvGeneralM3);
@@ -1562,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][2] = Left.Elements[3][2] - Right.Elements[3][2];
Result.Elements[3][3] = Left.Elements[3][3] - Right.Elements[3][3]; Result.Elements[3][3] = Left.Elements[3][3] - Right.Elements[3][3];
#endif #endif
return Result; return Result;
} }
@@ -1658,7 +1646,7 @@ static inline HMM_Mat4 HMM_DivM4F(HMM_Mat4 Matrix, float Scalar)
} }
COVERAGE(HMM_DeterminantM4, 1) COVERAGE(HMM_DeterminantM4, 1)
static inline float HMM_DeterminantM4(HMM_Mat4 Matrix) static inline float HMM_DeterminantM4(HMM_Mat4 Matrix)
{ {
ASSERT_COVERED(HMM_DeterminantM4); ASSERT_COVERED(HMM_DeterminantM4);
@@ -1666,14 +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 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 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)); 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); return HMM_DotV3(C01, B32) + HMM_DotV3(C23, B10);
} }
COVERAGE(HMM_InvGeneralM4, 1) COVERAGE(HMM_InvGeneralM4, 1)
// Returns a general-purpose inverse of an HMM_Mat4. Note that special-purpose inverses of many transformations // Returns a general-purpose inverse of an HMM_Mat4. Note that special-purpose inverses of many transformations
// are available and will be more efficient. // are available and will be more efficient.
static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix) static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
{ {
ASSERT_COVERED(HMM_InvGeneralM4); ASSERT_COVERED(HMM_InvGeneralM4);
@@ -1681,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 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 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)); 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)); float InvDeterminant = 1.0f / (HMM_DotV3(C01, B32) + HMM_DotV3(C23, B10));
C01 = HMM_MulV3F(C01, InvDeterminant); C01 = HMM_MulV3F(C01, InvDeterminant);
C23 = HMM_MulV3F(C23, InvDeterminant); C23 = HMM_MulV3F(C23, InvDeterminant);
@@ -1693,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[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[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)); 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); return HMM_TransposeM4(Result);
} }
@@ -1755,7 +1743,7 @@ static inline HMM_Mat4 HMM_Orthographic_LH_NO(float Left, float Right, float Bot
HMM_Mat4 Result = HMM_Orthographic_RH_NO(Left, Right, Bottom, Top, Near, Far); HMM_Mat4 Result = HMM_Orthographic_RH_NO(Left, Right, Bottom, Top, Near, Far);
Result.Elements[2][2] = -Result.Elements[2][2]; Result.Elements[2][2] = -Result.Elements[2][2];
return Result; return Result;
} }
@@ -1769,7 +1757,7 @@ static inline HMM_Mat4 HMM_Orthographic_LH_ZO(float Left, float Right, float Bot
HMM_Mat4 Result = HMM_Orthographic_RH_ZO(Left, Right, Bottom, Top, Near, Far); HMM_Mat4 Result = HMM_Orthographic_RH_ZO(Left, Right, Bottom, Top, Near, Far);
Result.Elements[2][2] = -Result.Elements[2][2]; Result.Elements[2][2] = -Result.Elements[2][2];
return Result; return Result;
} }
@@ -1785,7 +1773,7 @@ static inline HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix)
Result.Elements[1][1] = 1.0f / OrthoMatrix.Elements[1][1]; Result.Elements[1][1] = 1.0f / OrthoMatrix.Elements[1][1];
Result.Elements[2][2] = 1.0f / OrthoMatrix.Elements[2][2]; Result.Elements[2][2] = 1.0f / OrthoMatrix.Elements[2][2];
Result.Elements[3][3] = 1.0f; Result.Elements[3][3] = 1.0f;
Result.Elements[3][0] = -OrthoMatrix.Elements[3][0] * Result.Elements[0][0]; 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][1] = -OrthoMatrix.Elements[3][1] * Result.Elements[1][1];
Result.Elements[3][2] = -OrthoMatrix.Elements[3][2] * Result.Elements[2][2]; Result.Elements[3][2] = -OrthoMatrix.Elements[3][2] * Result.Elements[2][2];
@@ -1809,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[2][2] = (Near + Far) / (Near - Far);
Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far); Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
return Result; return Result;
} }
@@ -1835,25 +1823,25 @@ static inline HMM_Mat4 HMM_Perspective_RH_ZO(float FOV, float AspectRatio, float
COVERAGE(HMM_Perspective_LH_NO, 1) COVERAGE(HMM_Perspective_LH_NO, 1)
static inline HMM_Mat4 HMM_Perspective_LH_NO(float FOV, float AspectRatio, float Near, float Far) static inline HMM_Mat4 HMM_Perspective_LH_NO(float FOV, float AspectRatio, float Near, float Far)
{ {
ASSERT_COVERED(HMM_Perspective_LH_NO); ASSERT_COVERED(HMM_Perspective_LH_NO);
HMM_Mat4 Result = HMM_Perspective_RH_NO(FOV, AspectRatio, Near, Far); HMM_Mat4 Result = HMM_Perspective_RH_NO(FOV, AspectRatio, Near, Far);
Result.Elements[2][2] = -Result.Elements[2][2]; Result.Elements[2][2] = -Result.Elements[2][2];
Result.Elements[2][3] = -Result.Elements[2][3]; Result.Elements[2][3] = -Result.Elements[2][3];
return Result; return Result;
} }
COVERAGE(HMM_Perspective_LH_ZO, 1) COVERAGE(HMM_Perspective_LH_ZO, 1)
static inline HMM_Mat4 HMM_Perspective_LH_ZO(float FOV, float AspectRatio, float Near, float Far) static inline HMM_Mat4 HMM_Perspective_LH_ZO(float FOV, float AspectRatio, float Near, float Far)
{ {
ASSERT_COVERED(HMM_Perspective_LH_ZO); ASSERT_COVERED(HMM_Perspective_LH_ZO);
HMM_Mat4 Result = HMM_Perspective_RH_ZO(FOV, AspectRatio, Near, Far); HMM_Mat4 Result = HMM_Perspective_RH_ZO(FOV, AspectRatio, Near, Far);
Result.Elements[2][2] = -Result.Elements[2][2]; Result.Elements[2][2] = -Result.Elements[2][2];
Result.Elements[2][3] = -Result.Elements[2][3]; Result.Elements[2][3] = -Result.Elements[2][3];
return Result; return Result;
} }
@@ -1974,7 +1962,7 @@ static inline HMM_Mat4 HMM_Scale(HMM_Vec3 Scale)
} }
COVERAGE(HMM_InvScale, 1) 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); ASSERT_COVERED(HMM_InvScale);
@@ -2178,7 +2166,7 @@ static inline HMM_Quat HMM_MulQ(HMM_Quat Left, HMM_Quat Right)
Result.Y += Right.Elements[3] * +Left.Elements[1]; Result.Y += Right.Elements[3] * +Left.Elements[1];
Result.Z += Right.Elements[0] * -Left.Elements[1]; Result.Z += Right.Elements[0] * -Left.Elements[1];
Result.W += Right.Elements[1] * -Left.Elements[1]; Result.W += Right.Elements[1] * -Left.Elements[1];
Result.X += Right.Elements[1] * -Left.Elements[2]; Result.X += Right.Elements[1] * -Left.Elements[2];
Result.Y += Right.Elements[0] * +Left.Elements[2]; Result.Y += Right.Elements[0] * +Left.Elements[2];
Result.Z += Right.Elements[3] * +Left.Elements[2]; Result.Z += Right.Elements[3] * +Left.Elements[2];
@@ -2258,7 +2246,7 @@ COVERAGE(HMM_InvQ, 1)
static inline HMM_Quat HMM_InvQ(HMM_Quat Left) static inline HMM_Quat HMM_InvQ(HMM_Quat Left)
{ {
ASSERT_COVERED(HMM_InvQ); ASSERT_COVERED(HMM_InvQ);
HMM_Quat Result; HMM_Quat Result;
Result.X = -Left.X; Result.X = -Left.X;
Result.Y = -Left.Y; Result.Y = -Left.Y;
@@ -2324,7 +2312,7 @@ static inline HMM_Quat HMM_SLerp(HMM_Quat Left, float Time, HMM_Quat Right)
Cos_Theta = -Cos_Theta; Cos_Theta = -Cos_Theta;
Right = HMM_Q(-Right.X, -Right.Y, -Right.Z, -Right.W); Right = HMM_Q(-Right.X, -Right.Y, -Right.Z, -Right.W);
} }
/* NOTE(lcf): Use Normalized Linear interpolation when vectors are roughly not L.I. */ /* NOTE(lcf): Use Normalized Linear interpolation when vectors are roughly not L.I. */
if (Cos_Theta > 0.9995f) { if (Cos_Theta > 0.9995f) {
Result = HMM_NLerp(Left, Time, Right); Result = HMM_NLerp(Left, Time, Right);
@@ -2336,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_MixQ(Left, MixLeft, Right, MixRight);
Result = HMM_NormQ(Result); Result = HMM_NormQ(Result);
} }
return Result; return Result;
} }
@@ -2516,27 +2504,63 @@ static inline HMM_Quat HMM_M4ToQ_LH(HMM_Mat4 M)
COVERAGE(HMM_QFromAxisAngle_RH, 1) 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); ASSERT_COVERED(HMM_QFromAxisAngle_RH);
HMM_Quat Result; HMM_Quat Result;
HMM_Vec3 AxisNormalized = HMM_NormV3(Axis); 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.XYZ = HMM_MulV3F(AxisNormalized, SineOfRotation);
Result.W = HMM_CosF(AngleOfRotation / 2.0f); Result.W = HMM_CosF(Angle / 2.0f);
return Result; return Result;
} }
COVERAGE(HMM_QFromAxisAngle_LH, 1) 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); 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));
} }
@@ -2636,23 +2660,23 @@ static inline float HMM_Dot(HMM_Vec4 Left, HMM_Vec4 VecTwo)
ASSERT_COVERED(HMM_DotV4CPP); ASSERT_COVERED(HMM_DotV4CPP);
return HMM_DotV4(Left, VecTwo); return HMM_DotV4(Left, VecTwo);
} }
COVERAGE(HMM_LerpV2CPP, 1) 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); ASSERT_COVERED(HMM_LerpV2CPP);
return HMM_LerpV2(Left, Time, Right); return HMM_LerpV2(Left, Time, Right);
} }
COVERAGE(HMM_LerpV3CPP, 1) 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); ASSERT_COVERED(HMM_LerpV3CPP);
return HMM_LerpV3(Left, Time, Right); return HMM_LerpV3(Left, Time, Right);
} }
COVERAGE(HMM_LerpV4CPP, 1) 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); ASSERT_COVERED(HMM_LerpV4CPP);
return HMM_LerpV4(Left, Time, Right); return HMM_LerpV4(Left, Time, Right);

View File

@@ -24,6 +24,16 @@ A few config options are available. See the header comment in [the source](./Han
## FAQ ## 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?** **What's the license?**
This library is in the public domain. You can do whatever you want with it. This library is in the public domain. You can do whatever you want with it.
@@ -31,7 +41,3 @@ This library is in the public domain. You can do whatever you want with it.
**Where can I contact you to ask questions?** **Where can I contact you to ask questions?**
Feel free to make GitHub issues for any questions, concerns, or problems you encounter. 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.

View File

@@ -155,9 +155,9 @@ INITIALIZER(_HMT_COVERCASE_FUNCNAME_INIT(name)) { \
if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \ if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \
_HMT_CASE_FAIL(); \ _HMT_CASE_FAIL(); \
if ((_msg)[0] == 0) { \ if ((_msg)[0] == 0) { \
printf("Expected %f, got %f", (_expected), actual); \ printf("Expected %f, got %f (error: %.9g)", (_expected), actual, diff); \
} else { \ } else { \
printf("%s: Expected %f, got %f", (_msg), (_expected), actual); \ printf("%s: Expected %f, got %f (error: %.9g)", (_msg), (_expected), actual, diff); \
} \ } \
} \ } \
} }

View File

@@ -129,22 +129,22 @@ TEST(InvMatrix, InvGeneral)
float Det = HMM_DeterminantM4(Matrix); float Det = HMM_DeterminantM4(Matrix);
EXPECT_FLOAT_EQ(Det, -80.0f); EXPECT_FLOAT_EQ(Det, -80.0f);
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]); EXPECT_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]); EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]); EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]); EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]); EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]); EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]); EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]); EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]); EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]); EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]); EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]); EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]); EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]); EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]); EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]); EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.00001f);
#ifdef __cplusplus #ifdef __cplusplus
Inverse = HMM_InvGeneral(Matrix); Inverse = HMM_InvGeneral(Matrix);
@@ -153,22 +153,22 @@ TEST(InvMatrix, InvGeneral)
Det = HMM_Determinant(Matrix); Det = HMM_Determinant(Matrix);
EXPECT_FLOAT_EQ(Det, -80.0f); EXPECT_FLOAT_EQ(Det, -80.0f);
EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]); EXPECT_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]); EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]); EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]); EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]); EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]); EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]); EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]); EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]); EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]); EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]); EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]); EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]); EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]); EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]); EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.00001f);
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]); EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.00001f);
#endif #endif
} }

View File

@@ -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); HMM_Vec3 axis = HMM_V3(0.0f, 1.0f, 0.0f);
EXPECT_NEAR(result.X, 0.707107f, 0.001f); 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.Y, 0.0f, 0.001f);
EXPECT_NEAR(result.Z, 0.0f, 0.001f); EXPECT_NEAR(result.Z, 1.0f, 0.001f);
EXPECT_NEAR(result.W, 0.707107f, 0.001f);
} }
{ {
HMM_Quat result = HMM_QFromAxisAngle_LH(axis, angle); HMM_Vec3 axis = HMM_V3(1.0f, 0.0f, 0.0f);
EXPECT_NEAR(result.X, -0.707107f, 0.001f); float angle = HMM_AngleTurn(1.0/8);
EXPECT_NEAR(result.Y, 0.0f, 0.001f); HMM_Vec3 result = HMM_RotateV3AxisAngle_RH(HMM_V3(0.0f, 0.0f, 1.0f), axis, angle);
EXPECT_NEAR(result.Z, 0.0f, 0.001f); EXPECT_NEAR(result.X, 0.0f, 0.001f);
EXPECT_NEAR(result.W, 0.707107f, 0.001f); EXPECT_NEAR(result.Y, -0.707170f, 0.001f);
EXPECT_NEAR(result.Z, 0.707170f, 0.001f);
} }
} }

View File

@@ -63,7 +63,8 @@ TEST(Transformations, LookAt)
{ {
const float abs_error = 0.001f; 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][0], 0.169031f, abs_error);
EXPECT_NEAR(result.Elements[0][1], 0.897085f, 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); 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);
}
}