diff --git a/HandmadeMath.h b/HandmadeMath.h index fc8e00b..2b4d59c 100644 --- a/HandmadeMath.h +++ b/HandmadeMath.h @@ -1,5 +1,5 @@ /* - HandmadeMath.h v1.7.1 + HandmadeMath.h v1.8.0 This is a single header file with a bunch of useful functions for game and graphics math operations. @@ -65,119 +65,6 @@ versions of these functions that are provided by the CRT. ============================================================================= - - Version History: - 0.2 (*) Updated documentation - (*) Better C compliance - (*) Prefix all handmade math functions - (*) Better operator overloading - 0.2a - (*) Prefixed Macros - 0.2b - (*) Disabled warning 4201 on MSVC as it is legal is C11 - (*) Removed the f at the end of HMM_PI to get 64bit precision - 0.3 - (*) Added +=, -=, *=, /= for hmm_vec2, hmm_vec3, hmm_vec4 - 0.4 - (*) SSE Optimized HMM_SqrtF - (*) SSE Optimized HMM_RSqrtF - (*) Removed CRT - 0.5 - (*) Added scalar multiplication and division for vectors - and matrices - (*) Added matrix subtraction and += for hmm_mat4 - (*) Reconciled all headers and implementations - (*) Tidied up, and filled in a few missing operators - 0.5.1 - (*) Ensured column-major order for matrices throughout - (*) Fixed HMM_Translate producing row-major matrices - 0.5.2 - (*) Fixed SSE code in HMM_SqrtF - (*) Fixed SSE code in HMM_RSqrtF - 0.6 - (*) Added Unit testing - (*) Made HMM_Power faster - (*) Fixed possible efficiency problem with HMM_Normalize - (*) RENAMED HMM_LengthSquareRoot to HMM_LengthSquared - (*) RENAMED HMM_RSqrtF to HMM_RSquareRootF - (*) RENAMED HMM_SqrtF to HMM_SquareRootF - (*) REMOVED Inner function (user should use Dot now) - (*) REMOVED HMM_FastInverseSquareRoot function declaration - 0.7 - (*) REMOVED HMM_LengthSquared in HANDMADE_MATH_IMPLEMENTATION (should - use HMM_LengthSquaredVec3, or HANDMADE_MATH_CPP_MODE for function - overloaded version) - (*) REMOVED HMM_Length in HANDMADE_MATH_IMPLEMENTATION (should use - HMM_LengthVec3, HANDMADE_MATH_CPP_MODE for function - overloaded version) - (*) REMOVED HMM_Normalize in HANDMADE_MATH_IMPLEMENTATION (should use - HMM_NormalizeVec3, or HANDMADE_MATH_CPP_MODE for function - overloaded version) - (*) Added HMM_LengthSquaredVec2 - (*) Added HMM_LengthSquaredVec4 - (*) Addd HMM_LengthVec2 - (*) Added HMM_LengthVec4 - (*) Added HMM_NormalizeVec2 - (*) Added HMM_NormalizeVec4 - 1.0 - (*) Lots of testing! - 1.1 - (*) Quaternion support - (*) Added type hmm_quaternion - (*) Added HMM_Quaternion - (*) Added HMM_QuaternionV4 - (*) Added HMM_AddQuaternion - (*) Added HMM_SubtractQuaternion - (*) Added HMM_MultiplyQuaternion - (*) Added HMM_MultiplyQuaternionF - (*) Added HMM_DivideQuaternionF - (*) Added HMM_InverseQuaternion - (*) Added HMM_DotQuaternion - (*) Added HMM_NormalizeQuaternion - (*) Added HMM_Slerp - (*) Added HMM_QuaternionToMat4 - (*) Added HMM_QuaternionFromAxisAngle - 1.1.1 - (*) Resolved compiler warnings on gcc and g++ - 1.1.2 - (*) Fixed invalid HMMDEF's in the function definitions - 1.1.3 - (*) Fixed compile error in C mode - 1.1.4 - (*) Fixed SSE being included on platforms that don't support it - (*) Fixed divide-by-zero errors when normalizing zero vectors. - 1.1.5 - (*) Add Width and Height to HMM_Vec2 - (*) Made it so you can supply your own SqrtF - 1.2.0 - (*) Added equality functions for HMM_Vec2, HMM_Vec3, and HMM_Vec4. - (*) Added HMM_EqualsVec2, HMM_EqualsVec3, and HMM_EqualsVec4 - (*) Added C++ overloaded HMM_Equals for all three - (*) Added C++ == and != operators for all three - (*) SSE'd HMM_MultiplyMat4 (this is _WAY_ faster) - (*) SSE'd HMM_Transpose - 1.3.0 - (*) Remove need to #define HANDMADE_MATH_CPP_MODE - 1.4.0 - (*) Fixed bug when using HandmadeMath in C mode - (*) SSEd all vec4 operations - (*) Removed all zero-ing - 1.5.0 - (*) Changed internal structure for better performance and inlining. - (*) As a result, HANDMADE_MATH_NO_INLINE has been removed and no - longer has any effect. - 1.5.1 - (*) Fixed a bug with uninitialized elements in HMM_LookAt. - 1.6.0 - (*) Added array subscript operators for vector and matrix types in - C++. This is provided as a convenience, but be aware that it may - incur an extra function call in unoptimized builds. - 1.7.0 - (*) Renamed the 'Rows' member of hmm_mat4 to 'Columns'. Since our - matrices are column-major, this should have been named 'Columns' - from the start. 'Rows' is still present, but has been deprecated. - 1.7.1 - (*) Changed operator[] to take a const ref int instead of an int. LICENSE @@ -1129,6 +1016,21 @@ HMM_INLINE hmm_vec4 HMM_NormalizeVec4(hmm_vec4 A) return (Result); } +HMM_INLINE hmm_vec2 HMM_FastNormalizeVec2(hmm_vec2 A) +{ + return HMM_MultiplyVec2f(A, HMM_RSquareRootF(HMM_DotVec2(A, A))); +} + +HMM_INLINE hmm_vec3 HMM_FastNormalizeVec3(hmm_vec3 A) +{ + return HMM_MultiplyVec3f(A, HMM_RSquareRootF(HMM_DotVec3(A, A))); +} + +HMM_INLINE hmm_vec4 HMM_FastNormalizeVec4(hmm_vec4 A) +{ + return HMM_MultiplyVec4f(A, HMM_RSquareRootF(HMM_DotVec4(A, A))); +} + /* * SSE stuff @@ -1512,6 +1414,27 @@ HMM_INLINE hmm_vec4 HMM_Normalize(hmm_vec4 A) return (Result); } +HMM_INLINE hmm_vec2 HMM_FastNormalize(hmm_vec2 A) +{ + hmm_vec2 Result = HMM_FastNormalizeVec2(A); + + return (Result); +} + +HMM_INLINE hmm_vec3 HMM_FastNormalize(hmm_vec3 A) +{ + hmm_vec3 Result = HMM_FastNormalizeVec3(A); + + return (Result); +} + +HMM_INLINE hmm_vec4 HMM_FastNormalize(hmm_vec4 A) +{ + hmm_vec4 Result = HMM_FastNormalizeVec4(A); + + return (Result); +} + HMM_INLINE hmm_quaternion HMM_Normalize(hmm_quaternion A) { hmm_quaternion Result = HMM_NormalizeQuaternion(A); diff --git a/README.md b/README.md index 79f6909..b9dbc52 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ To get started, go download [the latest release](https://github.com/HandmadeMath Version | Changes | ----------------|----------------| +**1.8.0** | Added fast vector normalization routines that use fast inverse square roots. **1.7.1** | Changed operator[] to take a const ref int instead of an int. **1.7.0** | Renamed the 'Rows' member of hmm_mat4 to 'Columns'. Since our matrices are column-major, this should have been named 'Columns' from the start. 'Rows' is still present, but has been deprecated. **1.6.0** | Added array subscript operators for vector and matrix types in C++. This is provided as a convenience, but be aware that it may incur an extra function call in unoptimized builds. diff --git a/test/categories/VectorOps.h b/test/categories/VectorOps.h index 32990aa..27262b1 100644 --- a/test/categories/VectorOps.h +++ b/test/categories/VectorOps.h @@ -134,6 +134,106 @@ TEST(VectorOps, NormalizeZero) #endif } +TEST(VectorOps, FastNormalize) +{ + hmm_vec2 v2 = HMM_Vec2(1.0f, -2.0f); + hmm_vec3 v3 = HMM_Vec3(1.0f, -2.0f, 3.0f); + hmm_vec4 v4 = HMM_Vec4(1.0f, -2.0f, 3.0f, -1.0f); + + { + hmm_vec2 result = HMM_FastNormalizeVec2(v2); + EXPECT_NEAR(HMM_LengthVec2(result), 1.0f, 0.001f); + EXPECT_GT(result.X, 0.0f); + EXPECT_LT(result.Y, 0.0f); + } + { + hmm_vec3 result = HMM_FastNormalizeVec3(v3); + EXPECT_NEAR(HMM_LengthVec3(result), 1.0f, 0.001f); + EXPECT_GT(result.X, 0.0f); + EXPECT_LT(result.Y, 0.0f); + EXPECT_GT(result.Z, 0.0f); + } + { + hmm_vec4 result = HMM_FastNormalizeVec4(v4); + EXPECT_NEAR(HMM_LengthVec4(result), 1.0f, 0.001f); + EXPECT_GT(result.X, 0.0f); + EXPECT_LT(result.Y, 0.0f); + EXPECT_GT(result.Z, 0.0f); + EXPECT_LT(result.W, 0.0f); + } + +#ifdef __cplusplus + { + hmm_vec2 result = HMM_FastNormalize(v2); + EXPECT_NEAR(HMM_LengthVec2(result), 1.0f, 0.001f); + EXPECT_GT(result.X, 0.0f); + EXPECT_LT(result.Y, 0.0f); + } + { + hmm_vec3 result = HMM_FastNormalize(v3); + EXPECT_NEAR(HMM_LengthVec3(result), 1.0f, 0.001f); + EXPECT_GT(result.X, 0.0f); + EXPECT_LT(result.Y, 0.0f); + EXPECT_GT(result.Z, 0.0f); + } + { + hmm_vec4 result = HMM_FastNormalize(v4); + EXPECT_NEAR(HMM_LengthVec4(result), 1.0f, 0.001f); + EXPECT_GT(result.X, 0.0f); + EXPECT_LT(result.Y, 0.0f); + EXPECT_GT(result.Z, 0.0f); + EXPECT_LT(result.W, 0.0f); + } +#endif +} + +TEST(VectorOps, FastNormalizeZero) +{ + hmm_vec2 v2 = HMM_Vec2(0.0f, 0.0f); + hmm_vec3 v3 = HMM_Vec3(0.0f, 0.0f, 0.0f); + hmm_vec4 v4 = HMM_Vec4(0.0f, 0.0f, 0.0f, 0.0f); + + { + hmm_vec2 result = HMM_FastNormalizeVec2(v2); + EXPECT_FLOAT_EQ(result.X, 0.0f); + EXPECT_FLOAT_EQ(result.Y, 0.0f); + } + { + hmm_vec3 result = HMM_FastNormalizeVec3(v3); + EXPECT_FLOAT_EQ(result.X, 0.0f); + EXPECT_FLOAT_EQ(result.Y, 0.0f); + EXPECT_FLOAT_EQ(result.Z, 0.0f); + } + { + hmm_vec4 result = HMM_FastNormalizeVec4(v4); + EXPECT_FLOAT_EQ(result.X, 0.0f); + EXPECT_FLOAT_EQ(result.Y, 0.0f); + EXPECT_FLOAT_EQ(result.Z, 0.0f); + EXPECT_FLOAT_EQ(result.W, 0.0f); + } + +#ifdef __cplusplus + { + hmm_vec2 result = HMM_FastNormalize(v2); + EXPECT_FLOAT_EQ(result.X, 0.0f); + EXPECT_FLOAT_EQ(result.Y, 0.0f); + } + { + hmm_vec3 result = HMM_FastNormalize(v3); + EXPECT_FLOAT_EQ(result.X, 0.0f); + EXPECT_FLOAT_EQ(result.Y, 0.0f); + EXPECT_FLOAT_EQ(result.Z, 0.0f); + } + { + hmm_vec4 result = HMM_FastNormalize(v4); + EXPECT_FLOAT_EQ(result.X, 0.0f); + EXPECT_FLOAT_EQ(result.Y, 0.0f); + EXPECT_FLOAT_EQ(result.Z, 0.0f); + EXPECT_FLOAT_EQ(result.W, 0.0f); + } +#endif +} + TEST(VectorOps, Cross) { hmm_vec3 v1 = HMM_Vec3(1.0f, 2.0f, 3.0f);