Compare commits

..

25 Commits

Author SHA1 Message Date
Ben Visness
142ba3cd9d Align backslashes for great aesthetics (very important) 2025-02-24 17:45:35 -06:00
Ben Visness
8c2ac269ba Redo test scripts 2025-02-23 20:33:06 -06:00
Ben Visness
736ebaaf23 Test and fix _Generic 2025-02-23 20:33:06 -06:00
Ben Visness
bdc7dd2a51 Merge pull request #172 from jonasgf/whitespace
Remove trailing whitespace and extra newlines at end of file
2024-05-28 09:46:45 -05:00
Ben Visness
b4ce44823b Merge pull request #171 from jonasgf/missing-braces
Ignore missing braces warning for all GCC versions
2024-05-28 09:46:22 -05:00
Jonas
2901e70ca3 Remove trailing whitespace and extra newlines at end of file 2024-04-27 22:56:11 +02:00
Jonas
21b4a0d209 Ignore missing braces warning for all GCC versions 2024-04-27 22:46:15 +02:00
Ben Visness
43836aa3a6 Merge pull request #170 from B-Y-P/master
Add HMM_QFromNormPair() and HMM_QFromVecPair()
2024-04-11 11:08:32 -05:00
BYP
bdc04881de Add HMM_QFromNormPair() and HMM_QFromVecPair() 2024-04-08 21:21:54 -04:00
Ben Visness
322826bcee Merge pull request #169 from Jack-Punter/neon_support
Neon support
2023-12-15 20:14:20 -06:00
jack punter
4e1e97522d Address Ben's changes 2023-12-14 21:39:50 +00:00
Jack Punter
6603c796cc Update test Makefile to use NO_SIMD over NO_SSE 2023-12-12 01:53:43 +00:00
Jack Punter
623215b228 NEON Quaternion Multiply 2023-12-12 01:47:01 +00:00
Jack Punter
fcc510f767 Fix scalar 2023-12-12 01:42:37 +00:00
Jack Punter
133a595b6f Better Neon tranpose
vld can de-interleave up to 4-float element structures in one go into multiple registers. This allows us to load each column of the matrix and put each element into a corresponding vector, essentially doing the entire transpose in 1 instruction

Fixed it
2023-12-12 01:42:37 +00:00
Jack Punter
5f20d693c9 Add Neon implementations for all but Quaternion multiply 2023-12-11 22:57:19 +00:00
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
Ben Visness
422bc588e9 Fix inverse perspective 2023-02-20 13:03:46 -06:00
Ben Visness
beb837a3c6 Tweak docs, add tests, find bugs 2023-02-02 19:18:24 -06:00
16 changed files with 1007 additions and 637 deletions

View File

@@ -6,8 +6,8 @@
both C and C++. both C and C++.
============================================================================= =============================================================================
CONFIG CONFIG
=============================================================================
By default, all angles in Handmade Math are specified in radians. However, it 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 can be configured to use degrees or turns instead. Use one of the following
@@ -24,11 +24,13 @@
HMM_AngleDeg(degrees) HMM_AngleDeg(degrees)
HMM_AngleTurn(turns) HMM_AngleTurn(turns)
The definitions of these functions change depending on the default unit.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Handmade Math ships with SSE (SIMD) implementations of several common Handmade Math ships with SSE (SIMD) implementations of several common
operations. To disable the use of SSE intrinsics, you must operations. To disable the use of SSE intrinsics, you must define
define HANDMADE_MATH_NO_SSE before including this file: HANDMADE_MATH_NO_SSE before including this file:
#define HANDMADE_MATH_NO_SSE #define HANDMADE_MATH_NO_SSE
#include "HandmadeMath.h" #include "HandmadeMath.h"
@@ -103,10 +105,15 @@
# define ASSERT_COVERED(a) # define ASSERT_COVERED(a)
#endif #endif
#ifdef HANDMADE_MATH_NO_SSE
# warning "HANDMADE_MATH_NO_SSE is deprecated, use HANDMADE_MATH_NO_SIMD instead"
# define HANDMADE_MATH_NO_SIMD
#endif
/* let's figure out if SSE is really available (unless disabled anyway) /* let's figure out if SSE is really available (unless disabled anyway)
(it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support) (it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support)
=> only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */ => only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */
#ifndef HANDMADE_MATH_NO_SSE #ifndef HANDMADE_MATH_NO_SIMD
# ifdef _MSC_VER /* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */ # ifdef _MSC_VER /* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */
# if defined(_M_AMD64) || ( defined(_M_IX86_FP) && _M_IX86_FP >= 1 ) # if defined(_M_AMD64) || ( defined(_M_IX86_FP) && _M_IX86_FP >= 1 )
# define HANDMADE_MATH__USE_SSE 1 # define HANDMADE_MATH__USE_SSE 1
@@ -116,7 +123,10 @@
# define HANDMADE_MATH__USE_SSE 1 # define HANDMADE_MATH__USE_SSE 1
# endif /* __SSE__ */ # endif /* __SSE__ */
# endif /* not _MSC_VER */ # endif /* not _MSC_VER */
#endif /* #ifndef HANDMADE_MATH_NO_SSE */ # ifdef __ARM_NEON
# define HANDMADE_MATH__USE_NEON 1
# endif /* NEON Supported */
#endif /* #ifndef HANDMADE_MATH_NO_SIMD */
#if (!defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) #if (!defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
# define HANDMADE_MATH__USE_C11_GENERICS 1 # define HANDMADE_MATH__USE_C11_GENERICS 1
@@ -126,6 +136,10 @@
# include <xmmintrin.h> # include <xmmintrin.h>
#endif #endif
#ifdef HANDMADE_MATH__USE_NEON
# include <arm_neon.h>
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable:4201) #pragma warning(disable:4201)
#endif #endif
@@ -133,9 +147,7 @@
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wfloat-equal" # pragma GCC diagnostic ignored "-Wfloat-equal"
# if (defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) || defined(__clang__) # pragma GCC diagnostic ignored "-Wmissing-braces"
# pragma GCC diagnostic ignored "-Wmissing-braces"
# endif
# ifdef __clang__ # ifdef __clang__
# pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" # pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
@@ -242,10 +254,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;
@@ -293,10 +303,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;
@@ -356,11 +364,13 @@ typedef union HMM_Vec4
__m128 SSE; __m128 SSE;
#endif #endif
#ifdef HANDMADE_MATH__USE_NEON
float32x4_t NEON;
#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;
@@ -370,10 +380,8 @@ 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;
@@ -383,10 +391,8 @@ typedef union HMM_Mat3
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;
@@ -396,10 +402,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;
@@ -424,6 +428,9 @@ typedef union HMM_Quat
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
__m128 SSE; __m128 SSE;
#endif #endif
#ifdef HANDMADE_MATH__USE_NEON
float32x4_t NEON;
#endif
} HMM_Quat; } HMM_Quat;
typedef signed int HMM_Bool; typedef signed int HMM_Bool;
@@ -513,6 +520,10 @@ static inline float HMM_SqrtF(float Float)
__m128 In = _mm_set_ss(Float); __m128 In = _mm_set_ss(Float);
__m128 Out = _mm_sqrt_ss(In); __m128 Out = _mm_sqrt_ss(In);
Result = _mm_cvtss_f32(Out); Result = _mm_cvtss_f32(Out);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t In = vdupq_n_f32(Float);
float32x4_t Out = vsqrtq_f32(In);
Result = vgetq_lane_f32(Out, 0);
#else #else
Result = HMM_SQRTF(Float); Result = HMM_SQRTF(Float);
#endif #endif
@@ -603,6 +614,9 @@ static inline HMM_Vec4 HMM_V4(float X, float Y, float Z, float W)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_setr_ps(X, Y, Z, W); Result.SSE = _mm_setr_ps(X, Y, Z, W);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t v = {X, Y, Z, W};
Result.NEON = v;
#else #else
Result.X = X; Result.X = X;
Result.Y = Y; Result.Y = Y;
@@ -622,6 +636,9 @@ static inline HMM_Vec4 HMM_V4V(HMM_Vec3 Vector, float W)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_setr_ps(Vector.X, Vector.Y, Vector.Z, W); Result.SSE = _mm_setr_ps(Vector.X, Vector.Y, Vector.Z, W);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t v = {Vector.X, Vector.Y, Vector.Z, W};
Result.NEON = v;
#else #else
Result.XYZ = Vector; Result.XYZ = Vector;
Result.W = W; Result.W = W;
@@ -669,6 +686,8 @@ static inline HMM_Vec4 HMM_AddV4(HMM_Vec4 Left, HMM_Vec4 Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_add_ps(Left.SSE, Right.SSE); Result.SSE = _mm_add_ps(Left.SSE, Right.SSE);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vaddq_f32(Left.NEON, Right.NEON);
#else #else
Result.X = Left.X + Right.X; Result.X = Left.X + Right.X;
Result.Y = Left.Y + Right.Y; Result.Y = Left.Y + Right.Y;
@@ -713,6 +732,8 @@ static inline HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE); Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vsubq_f32(Left.NEON, Right.NEON);
#else #else
Result.X = Left.X - Right.X; Result.X = Left.X - Right.X;
Result.Y = Left.Y - Right.Y; Result.Y = Left.Y - Right.Y;
@@ -782,6 +803,8 @@ static inline HMM_Vec4 HMM_MulV4(HMM_Vec4 Left, HMM_Vec4 Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_mul_ps(Left.SSE, Right.SSE); Result.SSE = _mm_mul_ps(Left.SSE, Right.SSE);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vmulq_f32(Left.NEON, Right.NEON);
#else #else
Result.X = Left.X * Right.X; Result.X = Left.X * Right.X;
Result.Y = Left.Y * Right.Y; Result.Y = Left.Y * Right.Y;
@@ -802,6 +825,8 @@ static inline HMM_Vec4 HMM_MulV4F(HMM_Vec4 Left, float Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
__m128 Scalar = _mm_set1_ps(Right); __m128 Scalar = _mm_set1_ps(Right);
Result.SSE = _mm_mul_ps(Left.SSE, Scalar); Result.SSE = _mm_mul_ps(Left.SSE, Scalar);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vmulq_n_f32(Left.NEON, Right);
#else #else
Result.X = Left.X * Right; Result.X = Left.X * Right;
Result.Y = Left.Y * Right; Result.Y = Left.Y * Right;
@@ -871,6 +896,8 @@ static inline HMM_Vec4 HMM_DivV4(HMM_Vec4 Left, HMM_Vec4 Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_div_ps(Left.SSE, Right.SSE); Result.SSE = _mm_div_ps(Left.SSE, Right.SSE);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vdivq_f32(Left.NEON, Right.NEON);
#else #else
Result.X = Left.X / Right.X; Result.X = Left.X / Right.X;
Result.Y = Left.Y / Right.Y; Result.Y = Left.Y / Right.Y;
@@ -891,6 +918,9 @@ static inline HMM_Vec4 HMM_DivV4F(HMM_Vec4 Left, float Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
__m128 Scalar = _mm_set1_ps(Right); __m128 Scalar = _mm_set1_ps(Right);
Result.SSE = _mm_div_ps(Left.SSE, Scalar); Result.SSE = _mm_div_ps(Left.SSE, Scalar);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t Scalar = vdupq_n_f32(Right);
Result.NEON = vdivq_f32(Left.NEON, Scalar);
#else #else
Result.X = Left.X / Right; Result.X = Left.X / Right;
Result.Y = Left.Y / Right; Result.Y = Left.Y / Right;
@@ -953,6 +983,11 @@ static inline float HMM_DotV4(HMM_Vec4 Left, HMM_Vec4 Right)
SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3)); SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3));
SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
_mm_store_ss(&Result, SSEResultOne); _mm_store_ss(&Result, SSEResultOne);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t NEONMultiplyResult = vmulq_f32(Left.NEON, Right.NEON);
float32x4_t NEONHalfAdd = vpaddq_f32(NEONMultiplyResult, NEONMultiplyResult);
float32x4_t NEONFullAdd = vpaddq_f32(NEONHalfAdd, NEONHalfAdd);
Result = vgetq_lane_f32(NEONFullAdd, 0);
#else #else
Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W)); Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W));
#endif #endif
@@ -1081,6 +1116,11 @@ static inline HMM_Vec4 HMM_LinearCombineV4M4(HMM_Vec4 Left, HMM_Mat4 Right)
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x55), Right.Columns[1].SSE)); Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x55), Right.Columns[1].SSE));
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xaa), Right.Columns[2].SSE)); Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xaa), Right.Columns[2].SSE));
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xff), Right.Columns[3].SSE)); Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xff), Right.Columns[3].SSE));
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vmulq_laneq_f32(Right.Columns[0].NEON, Left.NEON, 0);
Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[1].NEON, Left.NEON, 1);
Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[2].NEON, Left.NEON, 2);
Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[3].NEON, Left.NEON, 3);
#else #else
Result.X = Left.Elements[0] * Right.Columns[0].X; Result.X = Left.Elements[0] * Right.Columns[0].X;
Result.Y = Left.Elements[0] * Right.Columns[0].Y; Result.Y = Left.Elements[0] * Right.Columns[0].Y;
@@ -1391,10 +1431,10 @@ static inline HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar)
return Result; return Result;
} }
COVERAGE(HMM_DivM3, 1) COVERAGE(HMM_DivM3F, 1)
static inline HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar) static inline HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar)
{ {
ASSERT_COVERED(HMM_DivM3); ASSERT_COVERED(HMM_DivM3F);
HMM_Mat3 Result; HMM_Mat3 Result;
@@ -1475,22 +1515,33 @@ static inline HMM_Mat4 HMM_TransposeM4(HMM_Mat4 Matrix)
{ {
ASSERT_COVERED(HMM_TransposeM4); ASSERT_COVERED(HMM_TransposeM4);
HMM_Mat4 Result = Matrix; HMM_Mat4 Result;
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result = Matrix;
_MM_TRANSPOSE4_PS(Result.Columns[0].SSE, Result.Columns[1].SSE, Result.Columns[2].SSE, Result.Columns[3].SSE); _MM_TRANSPOSE4_PS(Result.Columns[0].SSE, Result.Columns[1].SSE, Result.Columns[2].SSE, Result.Columns[3].SSE);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4x4_t Transposed = vld4q_f32((float*)Matrix.Columns);
Result.Columns[0].NEON = Transposed.val[0];
Result.Columns[1].NEON = Transposed.val[1];
Result.Columns[2].NEON = Transposed.val[2];
Result.Columns[3].NEON = Transposed.val[3];
#else #else
Result.Elements[0][0] = Matrix.Elements[0][0];
Result.Elements[0][1] = Matrix.Elements[1][0]; Result.Elements[0][1] = Matrix.Elements[1][0];
Result.Elements[0][2] = Matrix.Elements[2][0]; Result.Elements[0][2] = Matrix.Elements[2][0];
Result.Elements[0][3] = Matrix.Elements[3][0]; Result.Elements[0][3] = Matrix.Elements[3][0];
Result.Elements[1][0] = Matrix.Elements[0][1]; Result.Elements[1][0] = Matrix.Elements[0][1];
Result.Elements[1][1] = Matrix.Elements[1][1];
Result.Elements[1][2] = Matrix.Elements[2][1]; Result.Elements[1][2] = Matrix.Elements[2][1];
Result.Elements[1][3] = Matrix.Elements[3][1]; Result.Elements[1][3] = Matrix.Elements[3][1];
Result.Elements[2][1] = Matrix.Elements[1][2];
Result.Elements[2][0] = Matrix.Elements[0][2]; Result.Elements[2][0] = Matrix.Elements[0][2];
Result.Elements[2][1] = Matrix.Elements[1][2];
Result.Elements[2][2] = Matrix.Elements[2][2];
Result.Elements[2][3] = Matrix.Elements[3][2]; Result.Elements[2][3] = Matrix.Elements[3][2];
Result.Elements[3][0] = Matrix.Elements[0][3];
Result.Elements[3][1] = Matrix.Elements[1][3]; Result.Elements[3][1] = Matrix.Elements[1][3];
Result.Elements[3][2] = Matrix.Elements[2][3]; Result.Elements[3][2] = Matrix.Elements[2][3];
Result.Elements[3][0] = Matrix.Elements[0][3]; Result.Elements[3][3] = Matrix.Elements[3][3];
#endif #endif
return Result; return Result;
@@ -1503,29 +1554,10 @@ static inline HMM_Mat4 HMM_AddM4(HMM_Mat4 Left, HMM_Mat4 Right)
HMM_Mat4 Result; HMM_Mat4 Result;
#ifdef HANDMADE_MATH__USE_SSE Result.Columns[0] = HMM_AddV4(Left.Columns[0], Right.Columns[0]);
Result.Columns[0].SSE = _mm_add_ps(Left.Columns[0].SSE, Right.Columns[0].SSE); Result.Columns[1] = HMM_AddV4(Left.Columns[1], Right.Columns[1]);
Result.Columns[1].SSE = _mm_add_ps(Left.Columns[1].SSE, Right.Columns[1].SSE); Result.Columns[2] = HMM_AddV4(Left.Columns[2], Right.Columns[2]);
Result.Columns[2].SSE = _mm_add_ps(Left.Columns[2].SSE, Right.Columns[2].SSE); Result.Columns[3] = HMM_AddV4(Left.Columns[3], Right.Columns[3]);
Result.Columns[3].SSE = _mm_add_ps(Left.Columns[3].SSE, Right.Columns[3].SSE);
#else
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];
Result.Elements[0][3] = Left.Elements[0][3] + Right.Elements[0][3];
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][2] = Left.Elements[1][2] + Right.Elements[1][2];
Result.Elements[1][3] = Left.Elements[1][3] + Right.Elements[1][3];
Result.Elements[2][0] = Left.Elements[2][0] + Right.Elements[2][0];
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][3] = Left.Elements[2][3] + Right.Elements[2][3];
Result.Elements[3][0] = Left.Elements[3][0] + Right.Elements[3][0];
Result.Elements[3][1] = Left.Elements[3][1] + Right.Elements[3][1];
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; return Result;
} }
@@ -1537,29 +1569,10 @@ static inline HMM_Mat4 HMM_SubM4(HMM_Mat4 Left, HMM_Mat4 Right)
HMM_Mat4 Result; HMM_Mat4 Result;
#ifdef HANDMADE_MATH__USE_SSE Result.Columns[0] = HMM_SubV4(Left.Columns[0], Right.Columns[0]);
Result.Columns[0].SSE = _mm_sub_ps(Left.Columns[0].SSE, Right.Columns[0].SSE); Result.Columns[1] = HMM_SubV4(Left.Columns[1], Right.Columns[1]);
Result.Columns[1].SSE = _mm_sub_ps(Left.Columns[1].SSE, Right.Columns[1].SSE); Result.Columns[2] = HMM_SubV4(Left.Columns[2], Right.Columns[2]);
Result.Columns[2].SSE = _mm_sub_ps(Left.Columns[2].SSE, Right.Columns[2].SSE); Result.Columns[3] = HMM_SubV4(Left.Columns[3], Right.Columns[3]);
Result.Columns[3].SSE = _mm_sub_ps(Left.Columns[3].SSE, Right.Columns[3].SSE);
#else
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];
Result.Elements[0][3] = Left.Elements[0][3] - Right.Elements[0][3];
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][2] = Left.Elements[1][2] - Right.Elements[1][2];
Result.Elements[1][3] = Left.Elements[1][3] - Right.Elements[1][3];
Result.Elements[2][0] = Left.Elements[2][0] - Right.Elements[2][0];
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][3] = Left.Elements[2][3] - Right.Elements[2][3];
Result.Elements[3][0] = Left.Elements[3][0] - Right.Elements[3][0];
Result.Elements[3][1] = Left.Elements[3][1] - Right.Elements[3][1];
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; return Result;
} }
@@ -1585,12 +1598,18 @@ static inline HMM_Mat4 HMM_MulM4F(HMM_Mat4 Matrix, float Scalar)
HMM_Mat4 Result; HMM_Mat4 Result;
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
__m128 SSEScalar = _mm_set1_ps(Scalar); __m128 SSEScalar = _mm_set1_ps(Scalar);
Result.Columns[0].SSE = _mm_mul_ps(Matrix.Columns[0].SSE, SSEScalar); Result.Columns[0].SSE = _mm_mul_ps(Matrix.Columns[0].SSE, SSEScalar);
Result.Columns[1].SSE = _mm_mul_ps(Matrix.Columns[1].SSE, SSEScalar); Result.Columns[1].SSE = _mm_mul_ps(Matrix.Columns[1].SSE, SSEScalar);
Result.Columns[2].SSE = _mm_mul_ps(Matrix.Columns[2].SSE, SSEScalar); Result.Columns[2].SSE = _mm_mul_ps(Matrix.Columns[2].SSE, SSEScalar);
Result.Columns[3].SSE = _mm_mul_ps(Matrix.Columns[3].SSE, SSEScalar); Result.Columns[3].SSE = _mm_mul_ps(Matrix.Columns[3].SSE, SSEScalar);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.Columns[0].NEON = vmulq_n_f32(Matrix.Columns[0].NEON, Scalar);
Result.Columns[1].NEON = vmulq_n_f32(Matrix.Columns[1].NEON, Scalar);
Result.Columns[2].NEON = vmulq_n_f32(Matrix.Columns[2].NEON, Scalar);
Result.Columns[3].NEON = vmulq_n_f32(Matrix.Columns[3].NEON, Scalar);
#else #else
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;
@@ -1633,6 +1652,12 @@ static inline HMM_Mat4 HMM_DivM4F(HMM_Mat4 Matrix, float Scalar)
Result.Columns[1].SSE = _mm_div_ps(Matrix.Columns[1].SSE, SSEScalar); Result.Columns[1].SSE = _mm_div_ps(Matrix.Columns[1].SSE, SSEScalar);
Result.Columns[2].SSE = _mm_div_ps(Matrix.Columns[2].SSE, SSEScalar); Result.Columns[2].SSE = _mm_div_ps(Matrix.Columns[2].SSE, SSEScalar);
Result.Columns[3].SSE = _mm_div_ps(Matrix.Columns[3].SSE, SSEScalar); Result.Columns[3].SSE = _mm_div_ps(Matrix.Columns[3].SSE, SSEScalar);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t NEONScalar = vdupq_n_f32(Scalar);
Result.Columns[0].NEON = vdivq_f32(Matrix.Columns[0].NEON, NEONScalar);
Result.Columns[1].NEON = vdivq_f32(Matrix.Columns[1].NEON, NEONScalar);
Result.Columns[2].NEON = vdivq_f32(Matrix.Columns[2].NEON, NEONScalar);
Result.Columns[3].NEON = vdivq_f32(Matrix.Columns[3].NEON, NEONScalar);
#else #else
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;
@@ -1669,6 +1694,8 @@ static inline float HMM_DeterminantM4(HMM_Mat4 Matrix)
} }
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
// 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);
@@ -1698,6 +1725,9 @@ static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
*/ */
COVERAGE(HMM_Orthographic_RH_NO, 1) 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) 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); ASSERT_COVERED(HMM_Orthographic_RH_NO);
@@ -1706,18 +1736,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[0][0] = 2.0f / (Right - Left);
Result.Elements[1][1] = 2.0f / (Top - Bottom); 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][3] = 1.0f;
Result.Elements[3][0] = (Left + Right) / (Left - Right); Result.Elements[3][0] = (Left + Right) / (Left - Right);
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
Result.Elements[3][2] = (Near + Far) / (Near - Far);
Result.Elements[2][2] = 2.0f / (Near - Far);
Result.Elements[3][2] = (Far + Near) / (Near - Far);
return Result; return Result;
} }
COVERAGE(HMM_Orthographic_RH_ZO, 1) 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) 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); ASSERT_COVERED(HMM_Orthographic_RH_ZO);
@@ -1726,18 +1758,20 @@ static inline HMM_Mat4 HMM_Orthographic_RH_ZO(float Left, float Right, float Bot
Result.Elements[0][0] = 2.0f / (Right - Left); Result.Elements[0][0] = 2.0f / (Right - Left);
Result.Elements[1][1] = 2.0f / (Top - Bottom); 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][3] = 1.0f;
Result.Elements[3][0] = (Left + Right) / (Left - Right); Result.Elements[3][0] = (Left + Right) / (Left - Right);
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
Result.Elements[2][2] = 1.0f / (Near - Far);
Result.Elements[3][2] = (Near) / (Near - Far); Result.Elements[3][2] = (Near) / (Near - Far);
return Result; return Result;
} }
COVERAGE(HMM_Orthographic_LH_NO, 1) 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) 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); ASSERT_COVERED(HMM_Orthographic_LH_NO);
@@ -1749,6 +1783,9 @@ static inline HMM_Mat4 HMM_Orthographic_LH_NO(float Left, float Right, float Bot
} }
COVERAGE(HMM_Orthographic_LH_ZO, 1) 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) 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); ASSERT_COVERED(HMM_Orthographic_LH_ZO);
@@ -1760,6 +1797,8 @@ static inline HMM_Mat4 HMM_Orthographic_LH_ZO(float Left, float Right, float Bot
} }
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) static inline HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix)
{ {
ASSERT_COVERED(HMM_InvOrthographic); ASSERT_COVERED(HMM_InvOrthographic);
@@ -1841,10 +1880,10 @@ static inline HMM_Mat4 HMM_Perspective_LH_ZO(float FOV, float AspectRatio, float
return Result; return Result;
} }
COVERAGE(HMM_InvPerspective, 1) COVERAGE(HMM_InvPerspective_RH, 1)
static inline HMM_Mat4 HMM_InvPerspective(HMM_Mat4 PerspectiveMatrix) static inline HMM_Mat4 HMM_InvPerspective_RH(HMM_Mat4 PerspectiveMatrix)
{ {
ASSERT_COVERED(HMM_InvPerspective); ASSERT_COVERED(HMM_InvPerspective_RH);
HMM_Mat4 Result = {0}; HMM_Mat4 Result = {0};
Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0]; Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0];
@@ -1858,6 +1897,23 @@ static inline HMM_Mat4 HMM_InvPerspective(HMM_Mat4 PerspectiveMatrix)
return Result; 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) COVERAGE(HMM_Translate, 1)
static inline HMM_Mat4 HMM_Translate(HMM_Vec3 Translation) static inline HMM_Mat4 HMM_Translate(HMM_Vec3 Translation)
{ {
@@ -2044,6 +2100,9 @@ static inline HMM_Quat HMM_Q(float X, float Y, float Z, float W)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_setr_ps(X, Y, Z, W); Result.SSE = _mm_setr_ps(X, Y, Z, W);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t v = { X, Y, Z, W };
Result.NEON = v;
#else #else
Result.X = X; Result.X = X;
Result.Y = Y; Result.Y = Y;
@@ -2063,6 +2122,8 @@ static inline HMM_Quat HMM_QV4(HMM_Vec4 Vector)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = Vector.SSE; Result.SSE = Vector.SSE;
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = Vector.NEON;
#else #else
Result.X = Vector.X; Result.X = Vector.X;
Result.Y = Vector.Y; Result.Y = Vector.Y;
@@ -2082,6 +2143,8 @@ static inline HMM_Quat HMM_AddQ(HMM_Quat Left, HMM_Quat Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_add_ps(Left.SSE, Right.SSE); Result.SSE = _mm_add_ps(Left.SSE, Right.SSE);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vaddq_f32(Left.NEON, Right.NEON);
#else #else
Result.X = Left.X + Right.X; Result.X = Left.X + Right.X;
@@ -2102,6 +2165,8 @@ static inline HMM_Quat HMM_SubQ(HMM_Quat Left, HMM_Quat Right)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE); Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vsubq_f32(Left.NEON, Right.NEON);
#else #else
Result.X = Left.X - Right.X; Result.X = Left.X - Right.X;
Result.Y = Left.Y - Right.Y; Result.Y = Left.Y - Right.Y;
@@ -2135,6 +2200,19 @@ static inline HMM_Quat HMM_MulQ(HMM_Quat Left, HMM_Quat Right)
SSEResultOne = _mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(3, 3, 3, 3)); SSEResultOne = _mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(3, 3, 3, 3));
SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(3, 2, 1, 0)); SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(3, 2, 1, 0));
Result.SSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne)); Result.SSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t Right1032 = vrev64q_f32(Right.NEON);
float32x4_t Right3210 = vcombine_f32(vget_high_f32(Right1032), vget_low_f32(Right1032));
float32x4_t Right2301 = vrev64q_f32(Right3210);
float32x4_t FirstSign = {1.0f, -1.0f, 1.0f, -1.0f};
Result.NEON = vmulq_f32(Right3210, vmulq_f32(vdupq_laneq_f32(Left.NEON, 0), FirstSign));
float32x4_t SecondSign = {1.0f, 1.0f, -1.0f, -1.0f};
Result.NEON = vfmaq_f32(Result.NEON, Right2301, vmulq_f32(vdupq_laneq_f32(Left.NEON, 1), SecondSign));
float32x4_t ThirdSign = {-1.0f, 1.0f, 1.0f, -1.0f};
Result.NEON = vfmaq_f32(Result.NEON, Right1032, vmulq_f32(vdupq_laneq_f32(Left.NEON, 2), ThirdSign));
Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.NEON, Left.NEON, 3);
#else #else
Result.X = Right.Elements[3] * +Left.Elements[0]; Result.X = Right.Elements[3] * +Left.Elements[0];
Result.Y = Right.Elements[2] * -Left.Elements[0]; Result.Y = Right.Elements[2] * -Left.Elements[0];
@@ -2170,6 +2248,8 @@ static inline HMM_Quat HMM_MulQF(HMM_Quat Left, float Multiplicative)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
__m128 Scalar = _mm_set1_ps(Multiplicative); __m128 Scalar = _mm_set1_ps(Multiplicative);
Result.SSE = _mm_mul_ps(Left.SSE, Scalar); Result.SSE = _mm_mul_ps(Left.SSE, Scalar);
#elif defined(HANDMADE_MATH__USE_NEON)
Result.NEON = vmulq_n_f32(Left.NEON, Multiplicative);
#else #else
Result.X = Left.X * Multiplicative; Result.X = Left.X * Multiplicative;
Result.Y = Left.Y * Multiplicative; Result.Y = Left.Y * Multiplicative;
@@ -2190,6 +2270,9 @@ static inline HMM_Quat HMM_DivQF(HMM_Quat Left, float Divnd)
#ifdef HANDMADE_MATH__USE_SSE #ifdef HANDMADE_MATH__USE_SSE
__m128 Scalar = _mm_set1_ps(Divnd); __m128 Scalar = _mm_set1_ps(Divnd);
Result.SSE = _mm_div_ps(Left.SSE, Scalar); Result.SSE = _mm_div_ps(Left.SSE, Scalar);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t Scalar = vdupq_n_f32(Divnd);
Result.NEON = vdivq_f32(Left.NEON, Scalar);
#else #else
Result.X = Left.X / Divnd; Result.X = Left.X / Divnd;
Result.Y = Left.Y / Divnd; Result.Y = Left.Y / Divnd;
@@ -2214,6 +2297,11 @@ static inline float HMM_DotQ(HMM_Quat Left, HMM_Quat Right)
SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3)); SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3));
SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
_mm_store_ss(&Result, SSEResultOne); _mm_store_ss(&Result, SSEResultOne);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t NEONMultiplyResult = vmulq_f32(Left.NEON, Right.NEON);
float32x4_t NEONHalfAdd = vpaddq_f32(NEONMultiplyResult, NEONMultiplyResult);
float32x4_t NEONFullAdd = vpaddq_f32(NEONHalfAdd, NEONHalfAdd);
Result = vgetq_lane_f32(NEONFullAdd, 0);
#else #else
Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W)); Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W));
#endif #endif
@@ -2257,6 +2345,10 @@ static inline HMM_Quat _HMM_MixQ(HMM_Quat Left, float MixLeft, HMM_Quat Right, f
__m128 SSEResultOne = _mm_mul_ps(Left.SSE, ScalarLeft); __m128 SSEResultOne = _mm_mul_ps(Left.SSE, ScalarLeft);
__m128 SSEResultTwo = _mm_mul_ps(Right.SSE, ScalarRight); __m128 SSEResultTwo = _mm_mul_ps(Right.SSE, ScalarRight);
Result.SSE = _mm_add_ps(SSEResultOne, SSEResultTwo); Result.SSE = _mm_add_ps(SSEResultOne, SSEResultTwo);
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t ScaledLeft = vmulq_n_f32(Left.NEON, MixLeft);
float32x4_t ScaledRight = vmulq_n_f32(Right.NEON, MixRight);
Result.NEON = vaddq_f32(ScaledLeft, ScaledRight);
#else #else
Result.X = Left.X*MixLeft + Right.X*MixRight; Result.X = Left.X*MixLeft + Right.X*MixRight;
Result.Y = Left.Y*MixLeft + Right.Y*MixRight; Result.Y = Left.Y*MixLeft + Right.Y*MixRight;
@@ -2483,27 +2575,84 @@ 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_QFromNormPair, 1)
static inline HMM_Quat HMM_QFromNormPair(HMM_Vec3 Left, HMM_Vec3 Right)
{
ASSERT_COVERED(HMM_QFromNormPair);
HMM_Quat Result;
Result.XYZ = HMM_Cross(Left, Right);
Result.W = 1.0f + HMM_DotV3(Left, Right);
return HMM_NormQ(Result);
}
COVERAGE(HMM_QFromVecPair, 1)
static inline HMM_Quat HMM_QFromVecPair(HMM_Vec3 Left, HMM_Vec3 Right)
{
ASSERT_COVERED(HMM_QFromVecPair);
return HMM_QFromNormPair(HMM_NormV3(Left), HMM_NormV3(Right));
}
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));
} }
@@ -3638,6 +3787,9 @@ static inline HMM_Vec4 operator-(HMM_Vec4 In)
HMM_Vec4 Result; HMM_Vec4 Result;
#if HANDMADE_MATH__USE_SSE #if HANDMADE_MATH__USE_SSE
Result.SSE = _mm_xor_ps(In.SSE, _mm_set1_ps(-0.0f)); Result.SSE = _mm_xor_ps(In.SSE, _mm_set1_ps(-0.0f));
#elif defined(HANDMADE_MATH__USE_NEON)
float32x4_t Zero = vdupq_n_f32(0.0f);
Result.NEON = vsubq_f32(Zero, In.NEON);
#else #else
Result.X = -In.X; Result.X = -In.X;
Result.Y = -In.Y; Result.Y = -In.Y;
@@ -3651,124 +3803,131 @@ static inline HMM_Vec4 operator-(HMM_Vec4 In)
#endif /* __cplusplus*/ #endif /* __cplusplus*/
#ifdef HANDMADE_MATH__USE_C11_GENERICS #ifdef HANDMADE_MATH__USE_C11_GENERICS
void __hmm_invalid_generic();
#define HMM_Add(A, B) _Generic((A), \ #define HMM_Add(A, B) _Generic((A), \
HMM_Vec2: HMM_AddV2, \ HMM_Vec2: HMM_AddV2, \
HMM_Vec3: HMM_AddV3, \ HMM_Vec3: HMM_AddV3, \
HMM_Vec4: HMM_AddV4, \ HMM_Vec4: HMM_AddV4, \
HMM_Mat2: HMM_AddM2, \ HMM_Mat2: HMM_AddM2, \
HMM_Mat3: HMM_AddM3, \ HMM_Mat3: HMM_AddM3, \
HMM_Mat4: HMM_AddM4, \ HMM_Mat4: HMM_AddM4, \
HMM_Quat: HMM_AddQ \ HMM_Quat: HMM_AddQ \
)(A, B) )(A, B)
#define HMM_Sub(A, B) _Generic((A), \ #define HMM_Sub(A, B) _Generic((A), \
HMM_Vec2: HMM_SubV2, \ HMM_Vec2: HMM_SubV2, \
HMM_Vec3: HMM_SubV3, \ HMM_Vec3: HMM_SubV3, \
HMM_Vec4: HMM_SubV4, \ HMM_Vec4: HMM_SubV4, \
HMM_Mat2: HMM_SubM2, \ HMM_Mat2: HMM_SubM2, \
HMM_Mat3: HMM_SubM3, \ HMM_Mat3: HMM_SubM3, \
HMM_Mat4: HMM_SubM4, \ HMM_Mat4: HMM_SubM4, \
HMM_Quat: HMM_SubQ \ HMM_Quat: HMM_SubQ \
)(A, B) )(A, B)
#define HMM_Mul(A, B) _Generic((B), \ #define HMM_Mul(A, B) _Generic((B), \
float: _Generic((A), \ float: _Generic((A), \
HMM_Vec2: HMM_MulV2F, \ HMM_Vec2: HMM_MulV2F, \
HMM_Vec3: HMM_MulV3F, \ HMM_Vec3: HMM_MulV3F, \
HMM_Vec4: HMM_MulV4F, \ HMM_Vec4: HMM_MulV4F, \
HMM_Mat2: HMM_MulM2F, \ HMM_Mat2: HMM_MulM2F, \
HMM_Mat3: HMM_MulM3F, \ HMM_Mat3: HMM_MulM3F, \
HMM_Mat4: HMM_MulM4F, \ HMM_Mat4: HMM_MulM4F, \
HMM_Quat: HMM_MulQF \ HMM_Quat: HMM_MulQF, \
), \ default: __hmm_invalid_generic \
HMM_Mat2: HMM_MulM2, \ ), \
HMM_Mat3: HMM_MulM3, \ HMM_Vec2: _Generic((A), \
HMM_Mat4: HMM_MulM4, \ HMM_Vec2: HMM_MulV2, \
HMM_Quat: HMM_MulQ, \
default: _Generic((A), \
HMM_Vec2: HMM_MulV2, \
HMM_Vec3: HMM_MulV3, \
HMM_Vec4: HMM_MulV4, \
HMM_Mat2: HMM_MulM2V2, \ HMM_Mat2: HMM_MulM2V2, \
default: __hmm_invalid_generic \
), \
HMM_Vec3: _Generic((A), \
HMM_Vec3: HMM_MulV3, \
HMM_Mat3: HMM_MulM3V3, \ HMM_Mat3: HMM_MulM3V3, \
HMM_Mat4: HMM_MulM4V4 \ default: __hmm_invalid_generic \
) \ ), \
HMM_Vec4: _Generic((A), \
HMM_Vec4: HMM_MulV4, \
HMM_Mat4: HMM_MulM4V4, \
default: __hmm_invalid_generic \
), \
HMM_Mat2: HMM_MulM2, \
HMM_Mat3: HMM_MulM3, \
HMM_Mat4: HMM_MulM4, \
HMM_Quat: HMM_MulQ \
)(A, B) )(A, B)
#define HMM_Div(A, B) _Generic((B), \ #define HMM_Div(A, B) _Generic((B), \
float: _Generic((A), \ float: _Generic((A), \
HMM_Mat2: HMM_DivM2F, \
HMM_Mat3: HMM_DivM3F, \
HMM_Mat4: HMM_DivM4F, \
HMM_Vec2: HMM_DivV2F, \ HMM_Vec2: HMM_DivV2F, \
HMM_Vec3: HMM_DivV3F, \ HMM_Vec3: HMM_DivV3F, \
HMM_Vec4: HMM_DivV4F, \ HMM_Vec4: HMM_DivV4F, \
HMM_Quat: HMM_DivQF \ HMM_Mat2: HMM_DivM2F, \
), \ HMM_Mat3: HMM_DivM3F, \
HMM_Mat2: HMM_DivM2, \ HMM_Mat4: HMM_DivM4F, \
HMM_Mat3: HMM_DivM3, \ HMM_Quat: HMM_DivQF \
HMM_Mat4: HMM_DivM4, \ ), \
HMM_Quat: HMM_DivQ, \ HMM_Vec2: HMM_DivV2, \
default: _Generic((A), \ HMM_Vec3: HMM_DivV3, \
HMM_Vec2: HMM_DivV2, \ HMM_Vec4: HMM_DivV4 \
HMM_Vec3: HMM_DivV3, \
HMM_Vec4: HMM_DivV4 \
) \
)(A, B) )(A, B)
#define HMM_Len(A) _Generic((A), \ #define HMM_Len(A) _Generic((A), \
HMM_Vec2: HMM_LenV2, \ HMM_Vec2: HMM_LenV2, \
HMM_Vec3: HMM_LenV3, \ HMM_Vec3: HMM_LenV3, \
HMM_Vec4: HMM_LenV4 \ HMM_Vec4: HMM_LenV4 \
)(A) )(A)
#define HMM_LenSqr(A) _Generic((A), \ #define HMM_LenSqr(A) _Generic((A), \
HMM_Vec2: HMM_LenSqrV2, \ HMM_Vec2: HMM_LenSqrV2, \
HMM_Vec3: HMM_LenSqrV3, \ HMM_Vec3: HMM_LenSqrV3, \
HMM_Vec4: HMM_LenSqrV4 \ HMM_Vec4: HMM_LenSqrV4 \
)(A) )(A)
#define HMM_Norm(A) _Generic((A), \ #define HMM_Norm(A) _Generic((A), \
HMM_Vec2: HMM_NormV2, \ HMM_Vec2: HMM_NormV2, \
HMM_Vec3: HMM_NormV3, \ HMM_Vec3: HMM_NormV3, \
HMM_Vec4: HMM_NormV4 \ HMM_Vec4: HMM_NormV4, \
HMM_Quat: HMM_NormQ \
)(A) )(A)
#define HMM_Dot(A, B) _Generic((A), \ #define HMM_Dot(A, B) _Generic((A), \
HMM_Vec2: HMM_DotV2, \ HMM_Vec2: HMM_DotV2, \
HMM_Vec3: HMM_DotV3, \ HMM_Vec3: HMM_DotV3, \
HMM_Vec4: HMM_DotV4 \ HMM_Vec4: HMM_DotV4, \
HMM_Quat: HMM_DotQ \
)(A, B) )(A, B)
#define HMM_Lerp(A, T, B) _Generic((A), \ #define HMM_Lerp(A, T, B) _Generic((A), \
float: HMM_Lerp, \ float: HMM_Lerp, \
HMM_Vec2: HMM_LerpV2, \ HMM_Vec2: HMM_LerpV2, \
HMM_Vec3: HMM_LerpV3, \ HMM_Vec3: HMM_LerpV3, \
HMM_Vec4: HMM_LerpV4 \ HMM_Vec4: HMM_LerpV4 \
)(A, T, B) )(A, T, B)
#define HMM_Eq(A, B) _Generic((A), \ #define HMM_Eq(A, B) _Generic((A), \
HMM_Vec2: HMM_EqV2, \ HMM_Vec2: HMM_EqV2, \
HMM_Vec3: HMM_EqV3, \ HMM_Vec3: HMM_EqV3, \
HMM_Vec4: HMM_EqV4 \ HMM_Vec4: HMM_EqV4 \
)(A, B) )(A, B)
#define HMM_Transpose(M) _Generic((M), \ #define HMM_Transpose(M) _Generic((M), \
HMM_Mat2: HMM_TransposeM2, \ HMM_Mat2: HMM_TransposeM2, \
HMM_Mat3: HMM_TransposeM3, \ HMM_Mat3: HMM_TransposeM3, \
HMM_Mat4: HMM_TransposeM4 \ HMM_Mat4: HMM_TransposeM4 \
)(M) )(M)
#define HMM_Determinant(M) _Generic((M), \ #define HMM_Determinant(M) _Generic((M), \
HMM_Mat2: HMM_DeterminantM2, \ HMM_Mat2: HMM_DeterminantM2, \
HMM_Mat3: HMM_DeterminantM3, \ HMM_Mat3: HMM_DeterminantM3, \
HMM_Mat4: HMM_DeterminantM4 \ HMM_Mat4: HMM_DeterminantM4 \
)(M) )(M)
#define HMM_InvGeneral(M) _Generic((M), \ #define HMM_InvGeneral(M) _Generic((M), \
HMM_Mat2: HMM_InvGeneralM2, \ HMM_Mat2: HMM_InvGeneralM2, \
HMM_Mat3: HMM_InvGeneralM3, \ HMM_Mat3: HMM_InvGeneralM3, \
HMM_Mat4: HMM_InvGeneralM4 \ HMM_Mat4: HMM_InvGeneralM4 \
)(M) )(M)
#endif #endif
@@ -3778,6 +3937,3 @@ static inline HMM_Vec4 operator-(HMM_Vec4 In)
#endif #endif
#endif /* HANDMADE_MATH_H */ #endif /* HANDMADE_MATH_H */

View File

@@ -1,36 +1,43 @@
# Handmade Math # 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). 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: Here's what sets Handmade Math apart:
- **A simple single-header library.** Just `#include "HandmadeMath.h"`. - **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 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`. - **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. - **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 ## 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. A few config options are available. See the header comment in [the source](./HandmadeMath.h) for details.
## 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.
**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

@@ -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(); \ _HMT_CASE_START(); \
float actual = (_actual); \ float actual = (_actual); \
float diff = actual - (_expected); \ float diff = actual - (_expected); \
if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \ if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \
_HMT_CASE_FAIL(); \ _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(); \ _HMT_CASE_START(); \
float actual = (_actual); \ float actual = (_actual); \
float diff = actual - (_expected); \ float diff = actual - (_expected); \
if (diff < -(_epsilon) || (_epsilon) < diff) { \ if (diff < -(_epsilon) || (_epsilon) < diff) { \
_HMT_CASE_FAIL(); \ _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) { \ #define HMT_EXPECT_LT(_actual, _expected) { \
_HMT_CASE_START(); \ _HMT_CASE_START(); \
@@ -192,7 +202,46 @@ INITIALIZER(_HMT_COVERCASE_FUNCNAME_INIT(name)) { \
#define EXPECT_TRUE(_actual) HMT_EXPECT_TRUE(_actual) #define EXPECT_TRUE(_actual) HMT_EXPECT_TRUE(_actual)
#define EXPECT_FALSE(_actual) HMT_EXPECT_FALSE(_actual) #define EXPECT_FALSE(_actual) HMT_EXPECT_FALSE(_actual)
#define EXPECT_FLOAT_EQ(_actual, _expected) HMT_EXPECT_FLOAT_EQ(_actual, _expected) #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_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_LT(_actual, _expected) HMT_EXPECT_LT(_actual, _expected)
#define EXPECT_GT(_actual, _expected) HMT_EXPECT_GT(_actual, _expected) #define EXPECT_GT(_actual, _expected) HMT_EXPECT_GT(_actual, _expected)
#endif // HMT_SAFE_MACROS #endif // HMT_SAFE_MACROS

View File

@@ -2,77 +2,123 @@ BUILD_DIR=./build
CXXFLAGS+=-g -Wall -Wextra -pthread -Wno-missing-braces -Wno-missing-field-initializers -Wfloat-equal CXXFLAGS+=-g -Wall -Wextra -pthread -Wno-missing-braces -Wno-missing-field-initializers -Wfloat-equal
all: c c_no_sse cpp cpp_no_sse build_c_without_coverage build_cpp_without_coverage .PHONY: all all_c all_cpp
all: all_c all_cpp
build_all: build_c build_c_no_sse build_cpp build_cpp_no_sse all_c: c99 c99_no_simd c11 c17
all_cpp: cpp98 cpp98_no_simd cpp03 cpp11 cpp14 cpp17 cpp20
.PHONY: clean
clean: clean:
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)
c: build_c .PHONY: c99
$(BUILD_DIR)/hmm_test_c c99:
@echo "\nCompiling as C99"
build_c: HandmadeMath.c test_impl
@echo "\nCompiling in C mode"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR)\ cd $(BUILD_DIR)\
&& $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \ && $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \
-c ../HandmadeMath.c ../hmm_test.c \ ../HandmadeMath.c ../hmm_test.c \
-lm \ -lm -o hmm_test_c99 \
&& $(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm && ./hmm_test_c99
c_no_sse: build_c_no_sse .PHONY: c99_no_simd
$(BUILD_DIR)/hmm_test_c_no_sse c99_no_simd:
@echo "\nCompiling as C99 (no SIMD)"
build_c_no_sse: HandmadeMath.c test_impl
@echo "\nCompiling in C mode (no SSE)"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \ cd $(BUILD_DIR) \
&& $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \ && $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \
-DHANDMADE_MATH_NO_SSE \ -DHANDMADE_MATH_NO_SIMD \
-c ../HandmadeMath.c ../hmm_test.c \ ../HandmadeMath.c ../hmm_test.c \
-lm \ -lm -o hmm_test_c99_no_simd \
&& $(CC) -ohmm_test_c_no_sse HandmadeMath.o hmm_test.o -lm && ./hmm_test_c99_no_simd
cpp: build_cpp .PHONY: c11
$(BUILD_DIR)/hmm_test_cpp c11:
@echo "\nCompiling as C11"
build_cpp: HandmadeMath.cpp test_impl
@echo "\nCompiling in C++ mode"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp \
-DHANDMADE_MATH_CPP_MODE \
../HandmadeMath.cpp ../hmm_test.cpp
cpp_no_sse: build_cpp_no_sse
$(BUILD_DIR)/hmm_test_cpp_no_sse
build_cpp_no_sse: HandmadeMath.cpp test_impl
@echo "\nCompiling in C++ mode (no SSE)"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp_no_sse \
-DHANDMADE_MATH_CPP_MODE -DHANDMADE_MATH_NO_SSE \
../HandmadeMath.cpp ../hmm_test.cpp
test_impl: hmm_test.cpp hmm_test.c
build_c_without_coverage: HandmadeMath.c test_impl
@echo "\nCompiling in C mode"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR)\ cd $(BUILD_DIR)\
&& $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \ && $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c11 \
-DWITHOUT_COVERAGE \ ../HandmadeMath.c ../hmm_test.c \
-c ../HandmadeMath.c ../hmm_test.c \ -lm -o hmm_test_c11 \
-lm \ && ./hmm_test_c11
&& $(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm
build_cpp_without_coverage: HandmadeMath.cpp test_impl .PHONY: c17
@echo "\nCompiling in C++ mode (no SSE)" c17:
@echo "\nCompiling as C17"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR)\
&& $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c17 \
../HandmadeMath.c ../hmm_test.c \
-lm -o hmm_test_c17 \
&& ./hmm_test_c17
.PHONY: cpp98
cpp98:
@echo "\nCompiling as C++98"
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \ cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp_no_sse \ && $(CXX) $(CPPFLAGS) $(CXXFLAGS) -std=c++98 \
-DHANDMADE_MATH_CPP_MODE -DWITHOUT_COVERAGE \ ../HandmadeMath.cpp ../hmm_test.cpp \
../HandmadeMath.cpp ../hmm_test.cpp -lm -o hmm_test_cpp98 \
&& ./hmm_test_cpp98
.PHONY: cpp98_no_simd
cpp98_no_simd:
@echo "\nCompiling as C++98 (no SIMD)"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -std=c++98 \
-DHANDMADE_MATH_NO_SIMD \
../HandmadeMath.cpp ../hmm_test.cpp \
-lm -o hmm_test_cpp98 \
&& ./hmm_test_cpp98
.PHONY: cpp03
cpp03:
@echo "\nCompiling as C++03"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -std=c++03 \
../HandmadeMath.cpp ../hmm_test.cpp \
-lm -o hmm_test_cpp03 \
&& ./hmm_test_cpp03
.PHONY: cpp11
cpp11:
@echo "\nCompiling as C++11"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -std=c++11 \
../HandmadeMath.cpp ../hmm_test.cpp \
-lm -o hmm_test_cpp11 \
&& ./hmm_test_cpp11
.PHONY: cpp14
cpp14:
@echo "\nCompiling as C++14"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -std=c++14 \
../HandmadeMath.cpp ../hmm_test.cpp \
-lm -o hmm_test_cpp14 \
&& ./hmm_test_cpp14
.PHONY: cpp17
cpp17:
@echo "\nCompiling as C++17"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -std=c++17 \
../HandmadeMath.cpp ../hmm_test.cpp \
-lm -o hmm_test_cpp17 \
&& ./hmm_test_cpp17
.PHONY: cpp20
cpp20:
@echo "\nCompiling as C++20"
mkdir -p $(BUILD_DIR)
cd $(BUILD_DIR) \
&& $(CXX) $(CPPFLAGS) $(CXXFLAGS) -std=c++20 \
../HandmadeMath.cpp ../hmm_test.cpp \
-lm -o hmm_test_cpp20 \
&& ./hmm_test_cpp20

View File

@@ -10,12 +10,14 @@ TEST(Addition, Vec2)
EXPECT_FLOAT_EQ(result.X, 4.0f); EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f); EXPECT_FLOAT_EQ(result.Y, 6.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Add(v2_1, v2_2); HMM_Vec2 result = HMM_Add(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 4.0f); EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f); EXPECT_FLOAT_EQ(result.Y, 6.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec2 result = v2_1 + v2_2; HMM_Vec2 result = v2_1 + v2_2;
EXPECT_FLOAT_EQ(result.X, 4.0f); EXPECT_FLOAT_EQ(result.X, 4.0f);
@@ -39,13 +41,15 @@ TEST(Addition, Vec3)
EXPECT_FLOAT_EQ(result.Y, 7.0f); EXPECT_FLOAT_EQ(result.Y, 7.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f); EXPECT_FLOAT_EQ(result.Z, 9.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Add(v3_1, v3_2); HMM_Vec3 result = HMM_Add(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 5.0f); EXPECT_FLOAT_EQ(result.X, 5.0f);
EXPECT_FLOAT_EQ(result.Y, 7.0f); EXPECT_FLOAT_EQ(result.Y, 7.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f); EXPECT_FLOAT_EQ(result.Z, 9.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec3 result = v3_1 + v3_2; HMM_Vec3 result = v3_1 + v3_2;
EXPECT_FLOAT_EQ(result.X, 5.0f); EXPECT_FLOAT_EQ(result.X, 5.0f);
@@ -72,7 +76,7 @@ TEST(Addition, Vec4)
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f); EXPECT_FLOAT_EQ(result.W, 12.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Add(v4_1, v4_2); HMM_Vec4 result = HMM_Add(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 6.0f); EXPECT_FLOAT_EQ(result.X, 6.0f);
@@ -80,6 +84,8 @@ TEST(Addition, Vec4)
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f); EXPECT_FLOAT_EQ(result.W, 12.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec4 result = v4_1 + v4_2; HMM_Vec4 result = v4_1 + v4_2;
EXPECT_FLOAT_EQ(result.X, 6.0f); EXPECT_FLOAT_EQ(result.X, 6.0f);
@@ -125,7 +131,7 @@ TEST(Addition, Mat2)
EXPECT_FLOAT_EQ(result.Elements[1][1], 12.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 12.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat2 result = HMM_Add(a, b); HMM_Mat2 result = HMM_Add(a, b);
EXPECT_FLOAT_EQ(result.Elements[0][0], 6.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 6.0f);
@@ -133,6 +139,8 @@ TEST(Addition, Mat2)
EXPECT_FLOAT_EQ(result.Elements[1][0], 10.0f); EXPECT_FLOAT_EQ(result.Elements[1][0], 10.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 12.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 12.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat2 result = a + b; HMM_Mat2 result = a + b;
EXPECT_FLOAT_EQ(result.Elements[0][0], 6.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 6.0f);
@@ -182,7 +190,7 @@ TEST(Addition, Mat3)
EXPECT_FLOAT_EQ(result.Elements[2][2], 27.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 27.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat3 result = HMM_Add(a, b); HMM_Mat3 result = HMM_Add(a, b);
EXPECT_FLOAT_EQ(result.Elements[0][0], 11.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 11.0f);
@@ -195,6 +203,8 @@ TEST(Addition, Mat3)
EXPECT_FLOAT_EQ(result.Elements[2][1], 25.0f); EXPECT_FLOAT_EQ(result.Elements[2][1], 25.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 27.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 27.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat3 result = a + b; HMM_Mat3 result = a + b;
EXPECT_FLOAT_EQ(result.Elements[0][0], 11.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 11.0f);
@@ -257,7 +267,7 @@ TEST(Addition, Mat4)
} }
} }
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat4 result = HMM_Add(m4_1, m4_2); HMM_Mat4 result = HMM_Add(m4_1, m4_2);
float Expected = 18.0f; float Expected = 18.0f;
@@ -270,6 +280,8 @@ TEST(Addition, Mat4)
} }
} }
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat4 result = m4_1 + m4_2; HMM_Mat4 result = m4_1 + m4_2;
float Expected = 18.0f; float Expected = 18.0f;
@@ -308,7 +320,7 @@ TEST(Addition, Quaternion)
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f); EXPECT_FLOAT_EQ(result.W, 12.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Quat result = HMM_Add(q1, q2); HMM_Quat result = HMM_Add(q1, q2);
EXPECT_FLOAT_EQ(result.X, 6.0f); EXPECT_FLOAT_EQ(result.X, 6.0f);
@@ -316,6 +328,8 @@ TEST(Addition, Quaternion)
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f); EXPECT_FLOAT_EQ(result.W, 12.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Quat result = q1 + q2; HMM_Quat result = q1 + q2;
EXPECT_FLOAT_EQ(result.X, 6.0f); EXPECT_FLOAT_EQ(result.X, 6.0f);

View File

@@ -10,12 +10,14 @@ TEST(Division, Vec2Vec2)
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f); EXPECT_FLOAT_EQ(result.Y, 0.75f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Div(v2_1, v2_2); HMM_Vec2 result = HMM_Div(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f); EXPECT_FLOAT_EQ(result.Y, 0.75f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec2 result = v2_1 / v2_2; HMM_Vec2 result = v2_1 / v2_2;
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -38,12 +40,14 @@ TEST(Division, Vec2Scalar)
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f); EXPECT_FLOAT_EQ(result.Y, 1.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Div(v2, s); HMM_Vec2 result = HMM_Div(v2, s);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f); EXPECT_FLOAT_EQ(result.Y, 1.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec2 result = v2 / s; HMM_Vec2 result = v2 / s;
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -67,13 +71,15 @@ TEST(Division, Vec3Vec3)
EXPECT_FLOAT_EQ(result.Y, 0.75f); EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Div(v3_1, v3_2); HMM_Vec3 result = HMM_Div(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.75f); EXPECT_FLOAT_EQ(result.Y, 0.75f);
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec3 result = v3_1 / v3_2; HMM_Vec3 result = v3_1 / v3_2;
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -99,13 +105,15 @@ TEST(Division, Vec3Scalar)
EXPECT_FLOAT_EQ(result.Y, 1.0f); EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f); EXPECT_FLOAT_EQ(result.Z, 1.5f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Div(v3, s); HMM_Vec3 result = HMM_Div(v3, s);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 1.0f); EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 1.5f); EXPECT_FLOAT_EQ(result.Z, 1.5f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec3 result = v3 / s; HMM_Vec3 result = v3 / s;
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -132,7 +140,7 @@ TEST(Division, Vec4Vec4)
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 0.25f); EXPECT_FLOAT_EQ(result.W, 0.25f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Div(v4_1, v4_2); HMM_Vec4 result = HMM_Div(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -140,6 +148,8 @@ TEST(Division, Vec4Vec4)
EXPECT_FLOAT_EQ(result.Z, 10.0f); EXPECT_FLOAT_EQ(result.Z, 10.0f);
EXPECT_FLOAT_EQ(result.W, 0.25f); EXPECT_FLOAT_EQ(result.W, 0.25f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec4 result = v4_1 / v4_2; HMM_Vec4 result = v4_1 / v4_2;
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -168,7 +178,7 @@ TEST(Division, Vec4Scalar)
EXPECT_FLOAT_EQ(result.Z, 1.5f); EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f); EXPECT_FLOAT_EQ(result.W, 2.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Div(v4, s); HMM_Vec4 result = HMM_Div(v4, s);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -176,6 +186,8 @@ TEST(Division, Vec4Scalar)
EXPECT_FLOAT_EQ(result.Z, 1.5f); EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f); EXPECT_FLOAT_EQ(result.W, 2.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec4 result = v4 / s; HMM_Vec4 result = v4 / s;
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -212,7 +224,7 @@ TEST(Division, Mat2Scalar)
EXPECT_FLOAT_EQ(result.Elements[1][1], 8.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 8.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat2 result = HMM_Div(m, s); HMM_Mat2 result = HMM_Div(m, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f);
@@ -220,7 +232,9 @@ TEST(Division, Mat2Scalar)
EXPECT_FLOAT_EQ(result.Elements[1][0], 6.0f); EXPECT_FLOAT_EQ(result.Elements[1][0], 6.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 8.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 8.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat2 result = m / s; HMM_Mat2 result = m / s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f);
@@ -257,7 +271,7 @@ TEST(Division, Mat3Scalar)
EXPECT_FLOAT_EQ(result.Elements[2][2], 18.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 18.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat3 result = HMM_Div(m, s); HMM_Mat3 result = HMM_Div(m, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f);
@@ -270,7 +284,9 @@ TEST(Division, Mat3Scalar)
EXPECT_FLOAT_EQ(result.Elements[2][1], 16.0f); EXPECT_FLOAT_EQ(result.Elements[2][1], 16.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 18.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 18.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat3 result = m / s; HMM_Mat3 result = m / s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 2.0f);
@@ -322,7 +338,7 @@ TEST(Division, Mat4Scalar)
EXPECT_FLOAT_EQ(result.Elements[3][2], 7.5f); EXPECT_FLOAT_EQ(result.Elements[3][2], 7.5f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 8.0f); EXPECT_FLOAT_EQ(result.Elements[3][3], 8.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat4 result = HMM_Div(m4, s); HMM_Mat4 result = HMM_Div(m4, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 0.5f); EXPECT_FLOAT_EQ(result.Elements[0][0], 0.5f);
@@ -342,6 +358,8 @@ TEST(Division, Mat4Scalar)
EXPECT_FLOAT_EQ(result.Elements[3][2], 7.5f); EXPECT_FLOAT_EQ(result.Elements[3][2], 7.5f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 8.0f); EXPECT_FLOAT_EQ(result.Elements[3][3], 8.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat4 result = m4 / s; HMM_Mat4 result = m4 / s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 0.5f); EXPECT_FLOAT_EQ(result.Elements[0][0], 0.5f);
@@ -394,7 +412,7 @@ TEST(Division, QuaternionScalar)
EXPECT_FLOAT_EQ(result.Z, 1.5f); EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f); EXPECT_FLOAT_EQ(result.W, 2.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Quat result = HMM_Div(q, f); HMM_Quat result = HMM_Div(q, f);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -402,6 +420,8 @@ TEST(Division, QuaternionScalar)
EXPECT_FLOAT_EQ(result.Z, 1.5f); EXPECT_FLOAT_EQ(result.Z, 1.5f);
EXPECT_FLOAT_EQ(result.W, 2.0f); EXPECT_FLOAT_EQ(result.W, 2.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Quat result = q / f; HMM_Quat result = q / f;
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);

View File

@@ -9,10 +9,12 @@ TEST(Equality, Vec2)
EXPECT_TRUE(HMM_EqV2(a, b)); EXPECT_TRUE(HMM_EqV2(a, b));
EXPECT_FALSE(HMM_EqV2(a, c)); EXPECT_FALSE(HMM_EqV2(a, c));
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_TRUE(HMM_Eq(a, b)); EXPECT_TRUE(HMM_Eq(a, b));
EXPECT_FALSE(HMM_Eq(a, c)); EXPECT_FALSE(HMM_Eq(a, c));
#endif
#ifdef __cplusplus
EXPECT_TRUE(a == b); EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c); EXPECT_FALSE(a == c);
@@ -30,10 +32,12 @@ TEST(Equality, Vec3)
EXPECT_TRUE(HMM_EqV3(a, b)); EXPECT_TRUE(HMM_EqV3(a, b));
EXPECT_FALSE(HMM_EqV3(a, c)); EXPECT_FALSE(HMM_EqV3(a, c));
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_TRUE(HMM_Eq(a, b)); EXPECT_TRUE(HMM_Eq(a, b));
EXPECT_FALSE(HMM_Eq(a, c)); EXPECT_FALSE(HMM_Eq(a, c));
#endif
#ifdef __cplusplus
EXPECT_TRUE(a == b); EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c); EXPECT_FALSE(a == c);
@@ -51,10 +55,12 @@ TEST(Equality, Vec4)
EXPECT_TRUE(HMM_EqV4(a, b)); EXPECT_TRUE(HMM_EqV4(a, b));
EXPECT_FALSE(HMM_EqV4(a, c)); EXPECT_FALSE(HMM_EqV4(a, c));
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_TRUE(HMM_Eq(a, b)); EXPECT_TRUE(HMM_Eq(a, b));
EXPECT_FALSE(HMM_Eq(a, c)); EXPECT_FALSE(HMM_Eq(a, c));
#endif
#ifdef __cplusplus
EXPECT_TRUE(a == b); EXPECT_TRUE(a == b);
EXPECT_FALSE(a == c); EXPECT_FALSE(a == c);

View File

@@ -19,7 +19,7 @@ TEST(InvMatrix, Transpose)
EXPECT_FLOAT_EQ(result.Elements[1][0], Expect.Elements[1][0]); 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][1], Expect.Elements[1][1]);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat2 result = HMM_Transpose(Matrix); HMM_Mat2 result = HMM_Transpose(Matrix);
EXPECT_FLOAT_EQ(result.Elements[0][0], Expect.Elements[0][0]); EXPECT_FLOAT_EQ(result.Elements[0][0], Expect.Elements[0][0]);
@@ -54,7 +54,7 @@ TEST(InvMatrix, Transpose)
EXPECT_FLOAT_EQ(result.Elements[2][1], Expect.Elements[2][1]); 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][2], Expect.Elements[2][2]);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat3 result = HMM_Transpose(Matrix); HMM_Mat3 result = HMM_Transpose(Matrix);
EXPECT_FLOAT_EQ(result.Elements[0][0], Expect.Elements[0][0]); EXPECT_FLOAT_EQ(result.Elements[0][0], Expect.Elements[0][0]);
@@ -94,7 +94,7 @@ TEST(InvMatrix, Transpose)
EXPECT_FLOAT_EQ(result.Elements[2][1], Expect.Elements[2][1]); 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][2], Expect.Elements[2][2]);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat4 result = HMM_Transpose(Matrix); HMM_Mat4 result = HMM_Transpose(Matrix);
EXPECT_FLOAT_EQ(result.Elements[0][0], Expect.Elements[0][0]); EXPECT_FLOAT_EQ(result.Elements[0][0], Expect.Elements[0][0]);
@@ -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
} }
@@ -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 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 Inverse = HMM_InvOrthographic(Matrix);
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse); EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.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]);
} }
{ {
HMM_Mat4 Matrix = HMM_Perspective_RH_NO(HMM_AngleDeg(120), 16.0/9.0, 10, 10000); HMM_Mat4 Matrix = HMM_Orthographic_RH_ZO(-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 Inverse = HMM_InvPerspective(Matrix); EXPECT_M4_EQ(HMM_MulM4(Matrix, Inverse), HMM_M4D(1.0f));
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_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 Eye = {10.0f, 10.0f, 10.0f};
HMM_Vec3 Center = {100.0f, 200.0f, 30.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 Expect = HMM_M4D(1.0f);
HMM_Mat4 Inverse = HMM_InvLookAt(Matrix); HMM_Mat4 Inverse = HMM_InvLookAt(Matrix);
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse); HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
EXPECT_M4_NEAR(Result, Expect, 0.001f);
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);
} }
{
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_Vec3 Axis = {1.0f, -1.0f, 0.5f};
HMM_Mat4 Matrix = HMM_Rotate_RH(HMM_AngleDeg(30), HMM_NormV3(Axis)); HMM_Mat4 Matrix = HMM_Rotate_RH(HMM_AngleDeg(30), HMM_NormV3(Axis));
HMM_Mat4 Expect = HMM_M4D(1.0f); HMM_Mat4 Expect = HMM_M4D(1.0f);
HMM_Mat4 Inverse = HMM_InvRotate(Matrix); HMM_Mat4 Inverse = HMM_InvRotate(Matrix);
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse); HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
EXPECT_M4_NEAR(Result, Expect, 0.001f);
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);
} }
{ {
HMM_Vec3 Scale = {1.0f, -1.0f, 0.5f}; HMM_Vec3 Axis = {1.0f, -1.0f, 0.5f};
HMM_Mat4 Matrix = HMM_Scale(Scale); HMM_Mat4 Matrix = HMM_Rotate_LH(HMM_AngleDeg(30), HMM_NormV3(Axis));
HMM_Mat4 Expect = HMM_M4D(1.0f); 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); HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
EXPECT_M4_NEAR(Result, Expect, 0.001f);
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_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);
}

View File

@@ -10,12 +10,14 @@ TEST(Multiplication, Vec2Vec2)
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f); EXPECT_FLOAT_EQ(result.Y, 8.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Mul(v2_1, v2_2); HMM_Vec2 result = HMM_Mul(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 8.0f); EXPECT_FLOAT_EQ(result.Y, 8.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec2 result = v2_1 * v2_2; HMM_Vec2 result = v2_1 * v2_2;
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
@@ -38,12 +40,14 @@ TEST(Multiplication, Vec2Scalar)
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f); EXPECT_FLOAT_EQ(result.Y, 6.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Mul(v2, s); HMM_Vec2 result = HMM_Mul(v2, s);
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f); EXPECT_FLOAT_EQ(result.Y, 6.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec2 result = v2 * s; HMM_Vec2 result = v2 * s;
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
@@ -72,13 +76,15 @@ TEST(Multiplication, Vec3Vec3)
EXPECT_FLOAT_EQ(result.Y, 10.0f); EXPECT_FLOAT_EQ(result.Y, 10.0f);
EXPECT_FLOAT_EQ(result.Z, 18.0f); EXPECT_FLOAT_EQ(result.Z, 18.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Mul(v3_1, v3_2); HMM_Vec3 result = HMM_Mul(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, 4.0f); EXPECT_FLOAT_EQ(result.X, 4.0f);
EXPECT_FLOAT_EQ(result.Y, 10.0f); EXPECT_FLOAT_EQ(result.Y, 10.0f);
EXPECT_FLOAT_EQ(result.Z, 18.0f); EXPECT_FLOAT_EQ(result.Z, 18.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec3 result = v3_1 * v3_2; HMM_Vec3 result = v3_1 * v3_2;
EXPECT_FLOAT_EQ(result.X, 4.0f); EXPECT_FLOAT_EQ(result.X, 4.0f);
@@ -104,13 +110,15 @@ TEST(Multiplication, Vec3Scalar)
EXPECT_FLOAT_EQ(result.Y, 6.0f); EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f); EXPECT_FLOAT_EQ(result.Z, 9.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Mul(v3, s); HMM_Vec3 result = HMM_Mul(v3, s);
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f); EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, 9.0f); EXPECT_FLOAT_EQ(result.Z, 9.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec3 result = v3 * s; HMM_Vec3 result = v3 * s;
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
@@ -143,7 +151,7 @@ TEST(Multiplication, Vec4Vec4)
EXPECT_FLOAT_EQ(result.Z, 21.0f); EXPECT_FLOAT_EQ(result.Z, 21.0f);
EXPECT_FLOAT_EQ(result.W, 32.0f); EXPECT_FLOAT_EQ(result.W, 32.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Mul(v4_1, v4_2); HMM_Vec4 result = HMM_Mul(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, 5.0f); EXPECT_FLOAT_EQ(result.X, 5.0f);
@@ -151,6 +159,8 @@ TEST(Multiplication, Vec4Vec4)
EXPECT_FLOAT_EQ(result.Z, 21.0f); EXPECT_FLOAT_EQ(result.Z, 21.0f);
EXPECT_FLOAT_EQ(result.W, 32.0f); EXPECT_FLOAT_EQ(result.W, 32.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec4 result = v4_1 * v4_2; HMM_Vec4 result = v4_1 * v4_2;
EXPECT_FLOAT_EQ(result.X, 5.0f); EXPECT_FLOAT_EQ(result.X, 5.0f);
@@ -179,7 +189,7 @@ TEST(Multiplication, Vec4Scalar)
EXPECT_FLOAT_EQ(result.Z, 9.0f); EXPECT_FLOAT_EQ(result.Z, 9.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f); EXPECT_FLOAT_EQ(result.W, 12.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Mul(v4, s); HMM_Vec4 result = HMM_Mul(v4, s);
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
@@ -187,6 +197,8 @@ TEST(Multiplication, Vec4Scalar)
EXPECT_FLOAT_EQ(result.Z, 9.0f); EXPECT_FLOAT_EQ(result.Z, 9.0f);
EXPECT_FLOAT_EQ(result.W, 12.0f); EXPECT_FLOAT_EQ(result.W, 12.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec4 result = v4 * s; HMM_Vec4 result = v4 * s;
EXPECT_FLOAT_EQ(result.X, 3.0f); EXPECT_FLOAT_EQ(result.X, 3.0f);
@@ -234,7 +246,7 @@ TEST(Multiplication, Mat2Mat2) {
EXPECT_FLOAT_EQ(result.Elements[1][1], 46.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 46.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat2 result = HMM_Mul(a,b); HMM_Mat2 result = HMM_Mul(a,b);
EXPECT_FLOAT_EQ(result.Elements[0][0], 23.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 23.0f);
@@ -242,7 +254,9 @@ TEST(Multiplication, Mat2Mat2) {
EXPECT_FLOAT_EQ(result.Elements[1][0], 31.0f); EXPECT_FLOAT_EQ(result.Elements[1][0], 31.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 46.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 46.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat2 result = a * b; HMM_Mat2 result = a * b;
EXPECT_FLOAT_EQ(result.Elements[0][0], 23.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 23.0f);
@@ -271,7 +285,7 @@ TEST(Multiplication, Mat2Scalar) {
EXPECT_FLOAT_EQ(result.Elements[1][0], 30.0f); EXPECT_FLOAT_EQ(result.Elements[1][0], 30.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 40.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 40.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat2 result = HMM_Mul(m, s); HMM_Mat2 result = HMM_Mul(m, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f);
@@ -279,6 +293,8 @@ TEST(Multiplication, Mat2Scalar) {
EXPECT_FLOAT_EQ(result.Elements[1][0], 30.0f); EXPECT_FLOAT_EQ(result.Elements[1][0], 30.0f);
EXPECT_FLOAT_EQ(result.Elements[1][1], 40.0f); EXPECT_FLOAT_EQ(result.Elements[1][1], 40.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat2 result = m * s; HMM_Mat2 result = m * s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f);
@@ -322,13 +338,15 @@ TEST(Multiplication, Mat2Vec2) {
EXPECT_FLOAT_EQ(result.Elements[1], 34.0f); EXPECT_FLOAT_EQ(result.Elements[1], 34.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Mul(m, v); HMM_Vec2 result = HMM_Mul(m, v);
EXPECT_FLOAT_EQ(result.Elements[0], 23.0f); EXPECT_FLOAT_EQ(result.Elements[0], 23.0f);
EXPECT_FLOAT_EQ(result.Elements[1], 34.0f); EXPECT_FLOAT_EQ(result.Elements[1], 34.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec2 result = m * v; HMM_Vec2 result = m * v;
EXPECT_FLOAT_EQ(result.Elements[0], 23.0f); EXPECT_FLOAT_EQ(result.Elements[0], 23.0f);
@@ -368,7 +386,7 @@ TEST(Multiplication, Mat3Mat3)
EXPECT_FLOAT_EQ(result.Elements[2][2], 312.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 312.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat3 result = HMM_Mul(a,b); HMM_Mat3 result = HMM_Mul(a,b);
EXPECT_FLOAT_EQ(result.Elements[0][0], 138.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 138.0f);
@@ -381,7 +399,9 @@ TEST(Multiplication, Mat3Mat3)
EXPECT_FLOAT_EQ(result.Elements[2][1], 261.0f); EXPECT_FLOAT_EQ(result.Elements[2][1], 261.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 312.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 312.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat3 result = a * b; HMM_Mat3 result = a * b;
EXPECT_FLOAT_EQ(result.Elements[0][0], 138.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 138.0f);
@@ -420,7 +440,7 @@ TEST(Multiplication, Mat3Scalar) {
EXPECT_FLOAT_EQ(result.Elements[2][1], 80.0f); EXPECT_FLOAT_EQ(result.Elements[2][1], 80.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 90.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 90.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat3 result = HMM_Mul(m, s); HMM_Mat3 result = HMM_Mul(m, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f);
@@ -433,6 +453,8 @@ TEST(Multiplication, Mat3Scalar) {
EXPECT_FLOAT_EQ(result.Elements[2][1], 80.0f); EXPECT_FLOAT_EQ(result.Elements[2][1], 80.0f);
EXPECT_FLOAT_EQ(result.Elements[2][2], 90.0f); EXPECT_FLOAT_EQ(result.Elements[2][2], 90.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat3 result = m * s; HMM_Mat3 result = m * s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 10.0f);
@@ -491,14 +513,15 @@ TEST(Multiplication, Mat3Vec3) {
EXPECT_FLOAT_EQ(result.Elements[1], 171.0f); EXPECT_FLOAT_EQ(result.Elements[1], 171.0f);
EXPECT_FLOAT_EQ(result.Elements[2], 204.0f); EXPECT_FLOAT_EQ(result.Elements[2], 204.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Mul(m, v); HMM_Vec3 result = HMM_Mul(m, v);
EXPECT_FLOAT_EQ(result.Elements[0], 138.0f); EXPECT_FLOAT_EQ(result.Elements[0], 138.0f);
EXPECT_FLOAT_EQ(result.Elements[1], 171.0f); EXPECT_FLOAT_EQ(result.Elements[1], 171.0f);
EXPECT_FLOAT_EQ(result.Elements[2], 204.0f); EXPECT_FLOAT_EQ(result.Elements[2], 204.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec3 result = m * v; HMM_Vec3 result = m * v;
EXPECT_FLOAT_EQ(result.Elements[0], 138.0f); EXPECT_FLOAT_EQ(result.Elements[0], 138.0f);
@@ -552,7 +575,7 @@ TEST(Multiplication, Mat4Mat4)
EXPECT_FLOAT_EQ(result.Elements[3][2], 1118.0f); EXPECT_FLOAT_EQ(result.Elements[3][2], 1118.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 1240.0f); EXPECT_FLOAT_EQ(result.Elements[3][3], 1240.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat4 result = HMM_Mul(m4_1, m4_2); HMM_Mat4 result = HMM_Mul(m4_1, m4_2);
EXPECT_FLOAT_EQ(result.Elements[0][0], 538.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 538.0f);
@@ -572,6 +595,8 @@ TEST(Multiplication, Mat4Mat4)
EXPECT_FLOAT_EQ(result.Elements[3][2], 1118.0f); EXPECT_FLOAT_EQ(result.Elements[3][2], 1118.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 1240.0f); EXPECT_FLOAT_EQ(result.Elements[3][3], 1240.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat4 result = m4_1 * m4_2; HMM_Mat4 result = m4_1 * m4_2;
EXPECT_FLOAT_EQ(result.Elements[0][0], 538.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 538.0f);
@@ -634,7 +659,7 @@ TEST(Multiplication, Mat4Scalar)
EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f); EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f); EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat4 result = HMM_Mul(m4, s); HMM_Mat4 result = HMM_Mul(m4, s);
EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f);
@@ -654,6 +679,8 @@ TEST(Multiplication, Mat4Scalar)
EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f); EXPECT_FLOAT_EQ(result.Elements[3][2], 45.0f);
EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f); EXPECT_FLOAT_EQ(result.Elements[3][3], 48.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat4 result = m4 * s; HMM_Mat4 result = m4 * s;
EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f); EXPECT_FLOAT_EQ(result.Elements[0][0], 3.0f);
@@ -737,7 +764,7 @@ TEST(Multiplication, Mat4Vec4)
EXPECT_FLOAT_EQ(result.Z, 110.0f); EXPECT_FLOAT_EQ(result.Z, 110.0f);
EXPECT_FLOAT_EQ(result.W, 120.0f); EXPECT_FLOAT_EQ(result.W, 120.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Mul(m4, v4); HMM_Vec4 result = HMM_Mul(m4, v4);
EXPECT_FLOAT_EQ(result.X, 90.0f); EXPECT_FLOAT_EQ(result.X, 90.0f);
@@ -745,6 +772,8 @@ TEST(Multiplication, Mat4Vec4)
EXPECT_FLOAT_EQ(result.Z, 110.0f); EXPECT_FLOAT_EQ(result.Z, 110.0f);
EXPECT_FLOAT_EQ(result.W, 120.0f); EXPECT_FLOAT_EQ(result.W, 120.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec4 result = m4 * v4; HMM_Vec4 result = m4 * v4;
EXPECT_FLOAT_EQ(result.X, 90.0f); EXPECT_FLOAT_EQ(result.X, 90.0f);
@@ -769,7 +798,7 @@ TEST(Multiplication, QuaternionQuaternion)
EXPECT_FLOAT_EQ(result.Z, 48.0f); EXPECT_FLOAT_EQ(result.Z, 48.0f);
EXPECT_FLOAT_EQ(result.W, -6.0f); EXPECT_FLOAT_EQ(result.W, -6.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Quat result = HMM_Mul(q1, q2); HMM_Quat result = HMM_Mul(q1, q2);
EXPECT_FLOAT_EQ(result.X, 24.0f); EXPECT_FLOAT_EQ(result.X, 24.0f);
@@ -777,6 +806,8 @@ TEST(Multiplication, QuaternionQuaternion)
EXPECT_FLOAT_EQ(result.Z, 48.0f); EXPECT_FLOAT_EQ(result.Z, 48.0f);
EXPECT_FLOAT_EQ(result.W, -6.0f); EXPECT_FLOAT_EQ(result.W, -6.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Quat result = q1 * q2; HMM_Quat result = q1 * q2;
EXPECT_FLOAT_EQ(result.X, 24.0f); EXPECT_FLOAT_EQ(result.X, 24.0f);
@@ -803,7 +834,7 @@ TEST(Multiplication, QuaternionScalar)
EXPECT_FLOAT_EQ(result.Z, 6.0f); EXPECT_FLOAT_EQ(result.Z, 6.0f);
EXPECT_FLOAT_EQ(result.W, 8.0f); EXPECT_FLOAT_EQ(result.W, 8.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Quat result = HMM_Mul(q, f); HMM_Quat result = HMM_Mul(q, f);
EXPECT_FLOAT_EQ(result.X, 2.0f); EXPECT_FLOAT_EQ(result.X, 2.0f);
@@ -811,6 +842,8 @@ TEST(Multiplication, QuaternionScalar)
EXPECT_FLOAT_EQ(result.Z, 6.0f); EXPECT_FLOAT_EQ(result.Z, 6.0f);
EXPECT_FLOAT_EQ(result.W, 8.0f); EXPECT_FLOAT_EQ(result.W, 8.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Quat result = q * f; HMM_Quat result = q * f;
EXPECT_FLOAT_EQ(result.X, 2.0f); EXPECT_FLOAT_EQ(result.X, 2.0f);

View File

@@ -2,67 +2,84 @@
TEST(Projection, Orthographic) 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); // Near and far distances correspond to negative Z, hence the Z coordinates here are negative.
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0); HMM_Vec4 minCorner = HMM_V4(-8.0f, 5.0f, -1.0f, 1.0);
HMM_Vec4 projected = HMM_MulM4V4(projection, original); HMM_Vec4 maxCorner = HMM_V4(12.0f, 10.0f, -100.0f, 1.0);
EXPECT_FLOAT_EQ(projected.X, 0.5f); // Z from -1 to 1 (GL convention)
EXPECT_FLOAT_EQ(projected.Y, 1.0f); {
EXPECT_FLOAT_EQ(projected.Z, -1.0f); HMM_Mat4 projection = HMM_Orthographic_RH_NO(ORTHO_BOUNDS);
EXPECT_FLOAT_EQ(projected.W, 1.0f); 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 */ // Z from 0 to 1 (DX convention)
projection = HMM_Orthographic_RH_ZO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f); {
projected = HMM_MulM4V4(projection, original); HMM_Mat4 projection = HMM_Orthographic_RH_ZO(ORTHO_BOUNDS);
EXPECT_FLOAT_EQ(projected.Z, 0.0f); 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));
}
} }
// Left-handed
{ {
HMM_Mat4 projection = HMM_Orthographic_LH_NO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f); // Near and far distances correspond to positive Z, hence the Z coordinates here are positive.
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0); HMM_Vec4 minCorner = HMM_V4(-8.0f, 5.0f, 1.0f, 1.0);
HMM_Vec4 projected = HMM_MulM4V4(projection, original); HMM_Vec4 maxCorner = HMM_V4(12.0f, 10.0f, 100.0f, 1.0);
EXPECT_FLOAT_EQ(projected.X, 0.5f); // Z from -1 to 1 (GL convention)
EXPECT_FLOAT_EQ(projected.Y, 1.0f); {
EXPECT_FLOAT_EQ(projected.Z, -1.0f); HMM_Mat4 projection = HMM_Orthographic_LH_NO(ORTHO_BOUNDS);
EXPECT_FLOAT_EQ(projected.W, 1.0f); 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 */ // Z from 0 to 1 (DX convention)
projection = HMM_Orthographic_LH_ZO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f); {
projected = HMM_MulM4V4(projection, original); HMM_Mat4 projection = HMM_Orthographic_LH_ZO(ORTHO_BOUNDS);
EXPECT_FLOAT_EQ(projected.Z, 0.0f); 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) TEST(Projection, Perspective)
{ {
// Right-handed
{ {
HMM_Mat4 projection = HMM_Perspective_RH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f); // Z from -1 to 1 (GL convention)
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0f); {
HMM_Vec4 projected = HMM_MulM4V4(projection, original); HMM_Mat4 projection = HMM_Perspective_RH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
EXPECT_FLOAT_EQ(projected.X, 2.5f); HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0f);
EXPECT_FLOAT_EQ(projected.Y, 5.0f); EXPECT_V4_EQ(HMM_MulM4V4(projection, original), HMM_V4(2.5f, 5.0f, -1.0f, 1.0f));
EXPECT_FLOAT_EQ(projected.Z, -1.0f); }
EXPECT_FLOAT_EQ(projected.W, 1.0f);
/* ZO */ // Z from 0 to 1 (DX convention)
projection = HMM_Perspective_RH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f); {
projected = HMM_MulM4V4(projection, original); HMM_Mat4 projection = HMM_Perspective_RH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
EXPECT_FLOAT_EQ(projected.Z, 0.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); // Z from -1 to 1 (GL convention)
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0f); {
HMM_Vec4 projected = HMM_MulM4V4(projection, original); HMM_Mat4 projection = HMM_Perspective_LH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
EXPECT_FLOAT_EQ(projected.X, 2.5f); HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0f);
EXPECT_FLOAT_EQ(projected.Y, 5.0f); EXPECT_V4_EQ(HMM_MulM4V4(projection, original), HMM_V4(2.5f, 5.0f, -1.0f, 1.0f));
EXPECT_FLOAT_EQ(projected.Z, -1.0f); }
EXPECT_FLOAT_EQ(projected.W, 1.0f);
/* ZO */ // Z from 0 to 1 (DX convention)
projection = HMM_Perspective_LH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f); {
projected = HMM_MulM4V4(projection, original); HMM_Mat4 projection = HMM_Perspective_LH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
EXPECT_FLOAT_EQ(projected.Z, 0.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));
}
} }
} }

View File

@@ -22,7 +22,7 @@ TEST(QuaternionOps, Dot)
float result = HMM_DotQ(q1, q2); float result = HMM_DotQ(q1, q2);
EXPECT_FLOAT_EQ(result, 70.0f); EXPECT_FLOAT_EQ(result, 70.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
float result = HMM_Dot(q1, q2); float result = HMM_Dot(q1, q2);
EXPECT_FLOAT_EQ(result, 70.0f); EXPECT_FLOAT_EQ(result, 70.0f);
@@ -41,7 +41,7 @@ TEST(QuaternionOps, Normalize)
EXPECT_NEAR(result.Z, 0.5477225575f, 0.001f); EXPECT_NEAR(result.Z, 0.5477225575f, 0.001f);
EXPECT_NEAR(result.W, 0.7302967433f, 0.001f); EXPECT_NEAR(result.W, 0.7302967433f, 0.001f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Quat result = HMM_Norm(q); HMM_Quat result = HMM_Norm(q);
EXPECT_NEAR(result.X, 0.1825741858f, 0.001f); EXPECT_NEAR(result.X, 0.1825741858f, 0.001f);
@@ -97,7 +97,7 @@ TEST(QuaternionOps, SLerp)
EXPECT_NEAR(result.Z, -0.40824830f, 0.001f); EXPECT_NEAR(result.Z, -0.40824830f, 0.001f);
EXPECT_NEAR(result.W, 0.70710676f, 0.001f); EXPECT_NEAR(result.W, 0.70710676f, 0.001f);
} }
{ {
HMM_Quat result = HMM_SLerp(from, 1.0f, to); HMM_Quat result = HMM_SLerp(from, 1.0f, to);
EXPECT_NEAR(result.X, 0.5f, 0.001f); EXPECT_NEAR(result.X, 0.5f, 0.001f);
EXPECT_NEAR(result.Y, 0.5f, 0.001f); EXPECT_NEAR(result.Y, 0.5f, 0.001f);
@@ -254,23 +254,44 @@ 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);
}
}
TEST(QuaternionOps, QuatFromPairs)
{
{
HMM_Vec3 n1 = HMM_V3(0.0f, 1.0f, 0.0f);
HMM_Vec3 n2 = HMM_V3(0.0f, 0.0f, 1.0f);
HMM_Quat q = HMM_QFromNormPair(n1, n2);
HMM_Vec3 result = HMM_RotateV3Q(n1, q);
EXPECT_NEAR(result.X, n2.X, 0.001f);
EXPECT_NEAR(result.Y, n2.Y, 0.001f);
EXPECT_NEAR(result.Z, n2.Z, 0.001f);
}
{
HMM_Vec3 v1 = HMM_V3(2.0f, 2.0f, 2.0f);
HMM_Vec3 v2 = HMM_V3(3.0f, 0.0f, 0.0f);
HMM_Quat q = HMM_QFromVecPair(v1, v2);
HMM_Vec3 result = HMM_RotateV3Q(HMM_V3(0.0f, 1.0f, 0.0f), q);
EXPECT_NEAR(result.X, 0.577350, 0.001f);
EXPECT_NEAR(result.Y, 0.788675, 0.001f);
EXPECT_NEAR(result.Z, -0.211325, 0.001f);
} }
} }

View File

@@ -10,12 +10,14 @@ TEST(Subtraction, Vec2)
EXPECT_FLOAT_EQ(result.X, -2.0f); EXPECT_FLOAT_EQ(result.X, -2.0f);
EXPECT_FLOAT_EQ(result.Y, -2.0f); EXPECT_FLOAT_EQ(result.Y, -2.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Sub(v2_1, v2_2); HMM_Vec2 result = HMM_Sub(v2_1, v2_2);
EXPECT_FLOAT_EQ(result.X, -2.0f); EXPECT_FLOAT_EQ(result.X, -2.0f);
EXPECT_FLOAT_EQ(result.Y, -2.0f); EXPECT_FLOAT_EQ(result.Y, -2.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec2 result = v2_1 - v2_2; HMM_Vec2 result = v2_1 - v2_2;
EXPECT_FLOAT_EQ(result.X, -2.0f); EXPECT_FLOAT_EQ(result.X, -2.0f);
@@ -39,13 +41,15 @@ TEST(Subtraction, Vec3)
EXPECT_FLOAT_EQ(result.Y, -3.0f); EXPECT_FLOAT_EQ(result.Y, -3.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f); EXPECT_FLOAT_EQ(result.Z, -3.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Sub(v3_1, v3_2); HMM_Vec3 result = HMM_Sub(v3_1, v3_2);
EXPECT_FLOAT_EQ(result.X, -3.0f); EXPECT_FLOAT_EQ(result.X, -3.0f);
EXPECT_FLOAT_EQ(result.Y, -3.0f); EXPECT_FLOAT_EQ(result.Y, -3.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f); EXPECT_FLOAT_EQ(result.Z, -3.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec3 result = v3_1 - v3_2; HMM_Vec3 result = v3_1 - v3_2;
EXPECT_FLOAT_EQ(result.X, -3.0f); EXPECT_FLOAT_EQ(result.X, -3.0f);
@@ -72,7 +76,7 @@ TEST(Subtraction, Vec4)
EXPECT_FLOAT_EQ(result.Z, -4.0f); EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f); EXPECT_FLOAT_EQ(result.W, -4.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Sub(v4_1, v4_2); HMM_Vec4 result = HMM_Sub(v4_1, v4_2);
EXPECT_FLOAT_EQ(result.X, -4.0f); EXPECT_FLOAT_EQ(result.X, -4.0f);
@@ -80,6 +84,8 @@ TEST(Subtraction, Vec4)
EXPECT_FLOAT_EQ(result.Z, -4.0f); EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f); EXPECT_FLOAT_EQ(result.W, -4.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Vec4 result = v4_1 - v4_2; HMM_Vec4 result = v4_1 - v4_2;
EXPECT_FLOAT_EQ(result.X, -4.0f); EXPECT_FLOAT_EQ(result.X, -4.0f);
@@ -124,7 +130,7 @@ TEST(Subtraction, Mat2)
EXPECT_FLOAT_EQ(result.Elements[1][0], 4.0); EXPECT_FLOAT_EQ(result.Elements[1][0], 4.0);
EXPECT_FLOAT_EQ(result.Elements[1][1], 4.0); EXPECT_FLOAT_EQ(result.Elements[1][1], 4.0);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat2 result = HMM_Sub(b,a); HMM_Mat2 result = HMM_Sub(b,a);
EXPECT_FLOAT_EQ(result.Elements[0][0], 4.0); EXPECT_FLOAT_EQ(result.Elements[0][0], 4.0);
@@ -132,7 +138,8 @@ TEST(Subtraction, Mat2)
EXPECT_FLOAT_EQ(result.Elements[1][0], 4.0); EXPECT_FLOAT_EQ(result.Elements[1][0], 4.0);
EXPECT_FLOAT_EQ(result.Elements[1][1], 4.0); EXPECT_FLOAT_EQ(result.Elements[1][1], 4.0);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat2 result = b - a; HMM_Mat2 result = b - a;
EXPECT_FLOAT_EQ(result.Elements[0][0], 4.0); EXPECT_FLOAT_EQ(result.Elements[0][0], 4.0);
@@ -183,7 +190,7 @@ TEST(Subtraction, Mat3)
EXPECT_FLOAT_EQ(result.Elements[2][1], 9.0); EXPECT_FLOAT_EQ(result.Elements[2][1], 9.0);
EXPECT_FLOAT_EQ(result.Elements[2][2], 9.0); EXPECT_FLOAT_EQ(result.Elements[2][2], 9.0);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat3 result = HMM_Sub(b,a); HMM_Mat3 result = HMM_Sub(b,a);
EXPECT_FLOAT_EQ(result.Elements[0][0], 9.0); EXPECT_FLOAT_EQ(result.Elements[0][0], 9.0);
@@ -196,7 +203,9 @@ TEST(Subtraction, Mat3)
EXPECT_FLOAT_EQ(result.Elements[2][1], 9.0); EXPECT_FLOAT_EQ(result.Elements[2][1], 9.0);
EXPECT_FLOAT_EQ(result.Elements[2][2], 9.0); EXPECT_FLOAT_EQ(result.Elements[2][2], 9.0);
} }
#endif
#ifdef __cplusplus
b -= a; b -= a;
EXPECT_FLOAT_EQ(b.Elements[0][0], 9.0); EXPECT_FLOAT_EQ(b.Elements[0][0], 9.0);
EXPECT_FLOAT_EQ(b.Elements[0][1], 9.0); EXPECT_FLOAT_EQ(b.Elements[0][1], 9.0);
@@ -245,7 +254,7 @@ TEST(Subtraction, Mat4)
} }
} }
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Mat4 result = HMM_Sub(m4_1, m4_2); HMM_Mat4 result = HMM_Sub(m4_1, m4_2);
for (int Column = 0; Column < 4; ++Column) for (int Column = 0; Column < 4; ++Column)
@@ -256,6 +265,8 @@ TEST(Subtraction, Mat4)
} }
} }
} }
#endif
#ifdef __cplusplus
{ {
HMM_Mat4 result = m4_1 - m4_2; HMM_Mat4 result = m4_1 - m4_2;
for (int Column = 0; Column < 4; ++Column) for (int Column = 0; Column < 4; ++Column)
@@ -290,7 +301,7 @@ TEST(Subtraction, Quaternion)
EXPECT_FLOAT_EQ(result.Z, -4.0f); EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f); EXPECT_FLOAT_EQ(result.W, -4.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Quat result = HMM_Sub(q1, q2); HMM_Quat result = HMM_Sub(q1, q2);
EXPECT_FLOAT_EQ(result.X, -4.0f); EXPECT_FLOAT_EQ(result.X, -4.0f);
@@ -298,6 +309,8 @@ TEST(Subtraction, Quaternion)
EXPECT_FLOAT_EQ(result.Z, -4.0f); EXPECT_FLOAT_EQ(result.Z, -4.0f);
EXPECT_FLOAT_EQ(result.W, -4.0f); EXPECT_FLOAT_EQ(result.W, -4.0f);
} }
#endif
#ifdef __cplusplus
{ {
HMM_Quat result = q1 - q2; HMM_Quat result = q1 - q2;
EXPECT_FLOAT_EQ(result.X, -4.0f); EXPECT_FLOAT_EQ(result.X, -4.0f);

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);
}
}

View File

@@ -10,7 +10,7 @@ TEST(VectorOps, LengthSquared)
EXPECT_FLOAT_EQ(HMM_LenSqrV3(v3), 14.0f); EXPECT_FLOAT_EQ(HMM_LenSqrV3(v3), 14.0f);
EXPECT_FLOAT_EQ(HMM_LenSqrV4(v4), 15.0f); EXPECT_FLOAT_EQ(HMM_LenSqrV4(v4), 15.0f);
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_FLOAT_EQ(HMM_LenSqr(v2), 5.0f); EXPECT_FLOAT_EQ(HMM_LenSqr(v2), 5.0f);
EXPECT_FLOAT_EQ(HMM_LenSqr(v3), 14.0f); EXPECT_FLOAT_EQ(HMM_LenSqr(v3), 14.0f);
EXPECT_FLOAT_EQ(HMM_LenSqr(v4), 15.0f); EXPECT_FLOAT_EQ(HMM_LenSqr(v4), 15.0f);
@@ -27,7 +27,7 @@ TEST(VectorOps, Length)
EXPECT_FLOAT_EQ(HMM_LenV3(v3), 7.0f); EXPECT_FLOAT_EQ(HMM_LenV3(v3), 7.0f);
EXPECT_FLOAT_EQ(HMM_LenV4(v4), 13.892444f); EXPECT_FLOAT_EQ(HMM_LenV4(v4), 13.892444f);
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_FLOAT_EQ(HMM_Len(v2), 9.0553856f); EXPECT_FLOAT_EQ(HMM_Len(v2), 9.0553856f);
EXPECT_FLOAT_EQ(HMM_Len(v3), 7.0f); EXPECT_FLOAT_EQ(HMM_Len(v3), 7.0f);
EXPECT_FLOAT_EQ(HMM_Len(v4), 13.892444f); EXPECT_FLOAT_EQ(HMM_Len(v4), 13.892444f);
@@ -62,7 +62,7 @@ TEST(VectorOps, Normalize)
EXPECT_LT(result.W, 0.0f); EXPECT_LT(result.W, 0.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Norm(v2); HMM_Vec2 result = HMM_Norm(v2);
EXPECT_NEAR(HMM_LenV2(result), 1.0f, 0.001f); EXPECT_NEAR(HMM_LenV2(result), 1.0f, 0.001f);
@@ -112,7 +112,7 @@ TEST(VectorOps, NormalizeZero)
EXPECT_FLOAT_EQ(result.W, 0.0f); EXPECT_FLOAT_EQ(result.W, 0.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Norm(v2); HMM_Vec2 result = HMM_Norm(v2);
EXPECT_FLOAT_EQ(result.X, 0.0f); EXPECT_FLOAT_EQ(result.X, 0.0f);
@@ -152,7 +152,7 @@ TEST(VectorOps, DotVec2)
HMM_Vec2 v2 = HMM_V2(3.0f, 4.0f); HMM_Vec2 v2 = HMM_V2(3.0f, 4.0f);
EXPECT_FLOAT_EQ(HMM_DotV2(v1, v2), 11.0f); EXPECT_FLOAT_EQ(HMM_DotV2(v1, v2), 11.0f);
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 11.0f); EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 11.0f);
#endif #endif
} }
@@ -163,7 +163,7 @@ TEST(VectorOps, DotVec3)
HMM_Vec3 v2 = HMM_V3(4.0f, 5.0f, 6.0f); HMM_Vec3 v2 = HMM_V3(4.0f, 5.0f, 6.0f);
EXPECT_FLOAT_EQ(HMM_DotV3(v1, v2), 32.0f); EXPECT_FLOAT_EQ(HMM_DotV3(v1, v2), 32.0f);
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 32.0f); EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 32.0f);
#endif #endif
} }
@@ -174,7 +174,7 @@ TEST(VectorOps, DotVec4)
HMM_Vec4 v2 = HMM_V4(5.0f, 6.0f, 7.0f, 8.0f); HMM_Vec4 v2 = HMM_V4(5.0f, 6.0f, 7.0f, 8.0f);
EXPECT_FLOAT_EQ(HMM_DotV4(v1, v2), 70.0f); EXPECT_FLOAT_EQ(HMM_DotV4(v1, v2), 70.0f);
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 70.0f); EXPECT_FLOAT_EQ(HMM_Dot(v1, v2), 70.0f);
#endif #endif
} }
@@ -189,7 +189,7 @@ TEST(VectorOps, LerpV2)
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
EXPECT_FLOAT_EQ(result.Y, 0.5f); EXPECT_FLOAT_EQ(result.Y, 0.5f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec2 result = HMM_Lerp(v1, 0.5, v2); HMM_Vec2 result = HMM_Lerp(v1, 0.5, v2);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -209,7 +209,7 @@ TEST(VectorOps, LerpV3)
EXPECT_FLOAT_EQ(result.Y, 1.0f); EXPECT_FLOAT_EQ(result.Y, 1.0f);
EXPECT_FLOAT_EQ(result.Z, 0.5f); EXPECT_FLOAT_EQ(result.Z, 0.5f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec3 result = HMM_Lerp(v1, 0.5, v2); HMM_Vec3 result = HMM_Lerp(v1, 0.5, v2);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);
@@ -231,7 +231,7 @@ TEST(VectorOps, LerpV4)
EXPECT_FLOAT_EQ(result.Z, 0.5f); EXPECT_FLOAT_EQ(result.Z, 0.5f);
EXPECT_FLOAT_EQ(result.W, 1.0f); EXPECT_FLOAT_EQ(result.W, 1.0f);
} }
#ifdef __cplusplus #if HANDMADE_MATH__USE_C11_GENERICS || defined(__cplusplus)
{ {
HMM_Vec4 result = HMM_Lerp(v1, 0.5, v2); HMM_Vec4 result = HMM_Lerp(v1, 0.5, v2);
EXPECT_FLOAT_EQ(result.X, 0.5f); EXPECT_FLOAT_EQ(result.X, 0.5f);

View File

@@ -3,16 +3,25 @@
if not exist "build" mkdir build if not exist "build" mkdir build
pushd build pushd build
clang-cl /Fehmm_test_c.exe ..\HandmadeMath.c ..\hmm_test.c clang-cl /std:c11 /Fehmm_test_c11.exe ..\HandmadeMath.c ..\hmm_test.c || exit /b 1
hmm_test_c hmm_test_c11 || exit /b 1
clang-cl /Fehmm_test_c_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.c ..\hmm_test.c clang-cl /std:c11 /Fehmm_test_c11_no_simd.exe /DHANDMADE_MATH_NO_SIMD ..\HandmadeMath.c ..\hmm_test.c || exit /b 1
hmm_test_c_no_sse hmm_test_c11_no_simd || exit /b 1
clang-cl /Fehmm_test_cpp.exe ..\HandmadeMath.cpp ..\hmm_test.cpp clang-cl /std:c17 /Fehmm_test_c17.exe ..\HandmadeMath.c ..\hmm_test.c || exit /b 1
hmm_test_cpp hmm_test_c17 || exit /b 1
clang-cl /Fehmm_test_cpp_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.cpp ..\hmm_test.cpp clang-cl /std:c++14 /Fehmm_test_cpp14.exe ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp_no_sse hmm_test_cpp14 || exit /b 1
clang-cl /std:c++14 /Fehmm_test_cpp14_no_simd.exe /DHANDMADE_MATH_NO_SIMD ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp14_no_simd || exit /b 1
clang-cl /std:c++17 /Fehmm_test_cpp17.exe ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp17 || exit /b 1
clang-cl /std:c++20 /Fehmm_test_cpp20.exe ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp20 || exit /b 1
popd popd

View File

@@ -1,27 +1,32 @@
@echo off @echo off
if "%1%"=="travis" ( where /q cl
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\Tools\VsDevCmd.bat" -host_arch=amd64 -arch=amd64 if ERRORLEVEL 1 (
) else ( for /f "delims=" %%a in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -find VC\Auxiliary\Build\vcvarsall.bat') do (%%a x64)
where /q cl
if ERRORLEVEL 1 (
for /f "delims=" %%a in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -find VC\Auxiliary\Build\vcvarsall.bat') do (%%a x64)
)
) )
if not exist "build" mkdir build if not exist "build" mkdir build
pushd build pushd build
cl /Fehmm_test_c.exe ..\HandmadeMath.c ..\hmm_test.c cl /std:c11 /Fehmm_test_c11.exe ..\HandmadeMath.c ..\hmm_test.c || exit /b 1
hmm_test_c hmm_test_c11 || exit /b 1
cl /Fehmm_test_c_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.c ..\hmm_test.c cl /std:c11 /Fehmm_test_c11_no_simd.exe /DHANDMADE_MATH_NO_SIMD ..\HandmadeMath.c ..\hmm_test.c || exit /b 1
hmm_test_c_no_sse hmm_test_c11_no_simd || exit /b 1
cl /Fehmm_test_cpp.exe ..\HandmadeMath.cpp ..\hmm_test.cpp cl /std:c17 /Fehmm_test_c17.exe ..\HandmadeMath.c ..\hmm_test.c || exit /b 1
hmm_test_cpp hmm_test_c17 || exit /b 1
cl /Fehmm_test_cpp_no_sse.exe /DHANDMADE_MATH_NO_SSE ..\HandmadeMath.cpp ..\hmm_test.cpp cl /std:c++14 /Fehmm_test_cpp14.exe ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp_no_sse hmm_test_cpp14 || exit /b 1
cl /std:c++14 /Fehmm_test_cpp14_no_simd.exe /DHANDMADE_MATH_NO_SIMD ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp14_no_simd || exit /b 1
cl /std:c++17 /Fehmm_test_cpp17.exe ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp17 || exit /b 1
cl /std:c++20 /Fehmm_test_cpp20.exe ..\HandmadeMath.cpp ..\hmm_test.cpp || exit /b 1
hmm_test_cpp20 || exit /b 1
popd popd