Compare commits

...

17 Commits
v1.1 ... v1.2.0

Author SHA1 Message Date
strangezak
98fffbd7cc Forgot to update version 2017-07-16 21:29:26 -07:00
Ben Visness
efd9f2f4b7 Matrix Multiply SSE (#65)
* SSEd HMM_MultiplyMat4 and HMM_Transpose. And added HMM_LinearCombineSSE

* Maybe Travis doesn't support SSE?

* Fix compile process so the SSE option is consistently defined

* Fix link error

* Documentation

* Added function prototype for operator ==

* Added != operator for hmm_vec2, hmm_vec3, hmm_vec4

* Add C versions of equality checks

Also made the C++ tests actually run...😳

* Update documentation
2017-07-16 21:19:34 -07:00
Ben Visness
c8ada18370 Update README for 1.1.5 2017-06-21 09:31:20 -05:00
Zak Strange
70ac2b7e5b 1.1.5 (#64)
* Added Width, and Height to hmm_vec2, and fixed SqrtF when compiling without the CRT

* Syntax error

* Test all the vector access methods
2017-06-14 20:49:44 -07:00
Ben Visness
924ee43923 Update history to include @DanielGibson's SSE fixes 2017-06-13 11:39:42 -05:00
Ben Visness
440b885d59 Update version to 1.1.4 2017-06-13 11:26:46 -05:00
Emil Lauridsen
98f535aeec Handle zero-vector normalization. (#63)
* Handle zero-vector normalization.

When normalizing a vectors, we have to check whether vector length is
not zero, to avoid dividing by zero when normalizing zero-vectors.

* Test for normalization of zero vectors
2017-06-13 11:21:55 -05:00
Ben Visness
09524f72ed Merge branch 'sse-testing'
# Conflicts:
#	HandmadeMath.h
2017-06-11 18:54:06 -05:00
Emil Lauridsen
be30046a5a C89 style comments (#62) 2017-06-11 10:32:46 -07:00
Daniel Gibson
ff4513ff33 Make it usable on non-SSE platforms (#60)
* at one place HANDMADE_NO_SSE instead of HANDMADE_MATH_NO_SSE was used
* introduce HANDMADE_MATH__USE_SSE for the SSE #ifdefs throughout code
  - use #ifdef HANDMADE_MATH_NO_SSE at only one place
* only use SSE (#define HANDMADE_MATH__USE_SSE) if the targetplatform
  actually supports it
  => users don't have to #define HANDMADE_MATH_NO_SSE on ARM etc
* at one place HMM_SqrtF instead of HMM_SquareRootF was used
2017-06-09 17:14:24 -07:00
Ben Visness
364569abe9 Fix wrong name for square root function 2017-06-09 10:43:11 -05:00
Ben Visness
a9972e71da Test both with and without SSE 2017-06-09 10:37:38 -05:00
Ben Visness
cf606db217 Test in both C and C++ (#58)
* Switch to custom unit testing that is compatible with C

* Remove Google Test framework

* Attempt to fix missing math functions

* Link against C math library

* Try forcing c99 again

* Include -lm at compile time

* Move -lm argument to the end

* Update README and gitignore
2017-04-07 08:47:54 -05:00
Ben Visness
67b84dece7 Fix invalid HMMDEF's in function definitions (#56)
* Fix invalid HMMDEF's in function definitions

* Update version number and readme
2017-03-29 16:19:25 -07:00
Ben Visness
8e188c4b7c Update CONTRIBUTING.md 2017-03-21 18:14:57 -05:00
Ben Visness
36fbeaeac4 Create CONTRIBUTING.md (#54) 2017-03-21 10:49:56 -07:00
Ben Visness
666f7e3325 Restrict struct warning suppression to clang only (#50)
* Restrict struct warning suppression to clang only

* Update changelist

* Move gcc diagnostic pop inside header section
2017-01-15 09:50:53 -08:00
14 changed files with 2679 additions and 1873 deletions

1
.gitignore vendored
View File

@@ -32,3 +32,4 @@
*.out *.out
*.app *.app
hmm_test hmm_test
hmm_test*

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "externals/googletest"]
path = externals/googletest
url = https://github.com/google/googletest.git

View File

@@ -5,4 +5,8 @@ compiler:
install: install:
- cd test - cd test
- make - make
script: ./hmm_test script:
- ./hmm_test_c
- ./hmm_test_c_no_sse
- ./hmm_test_cpp
- ./hmm_test_cpp_no_sse

51
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,51 @@
# Quick style guide
* Put braces on a new line
* Float literals should have digits both before and after the decimal.
```cpp
// Good
0.0f;
0.5f;
1.0f;
3.14159f;
// Bad
1.f
.0f
```
* Put macros and return types on a separate line from the function definition:
```cpp
HINLINE float
HMM_MyFunction()
{
// ...
}
```
* Explicitly initialize variables to zero:
```cpp
HINLINE float
HMM_MyFunction()
{
float MyFloat = 0.0f;
hmm_vec3 MyVector = {0};
}
```
* Put parentheses around the returned value:
```cpp
HINLINE float
HMM_MyFunction()
{
return (1.0f);
}
```
# Other notes
* If a new function is defined with different names for different datatypes, also add C++ overloaded versions of the functions. For example, if you have `HMM_LengthVec2(hmm_vec2)` and `HMM_LengthVec3(hmm_vec3)`, also provide `HMM_Length(hmm_vec2)` and `HMM_Length(hmm_vec3)`.
It is fine for the overloaded versions to call the C versions.
* Only use operator overloading for analogous operators in C. That means `+` for vector addition is fine, but no using `^` for cross product or `|` for dot product.
* Try to define functions in the same order as the prototypes.
* Don't forget that Handmade Math uses column-major order for matrices!

View File

@@ -1,10 +1,10 @@
/* /*
HandmadeMath.h v1.1 HandmadeMath.h v1.2.0
This is a single header file with a bunch of useful functions for This is a single header file with a bunch of useful functions for
basic game math operations. basic game math operations.
========================================================================== =============================================================================
You MUST You MUST
@@ -18,7 +18,7 @@
All other files should just #include "HandmadeMath.h" without the #define. All other files should just #include "HandmadeMath.h" without the #define.
========================================================================== =============================================================================
For overloaded and operator overloaded versions of the base C functions, For overloaded and operator overloaded versions of the base C functions,
you MUST you MUST
@@ -34,7 +34,7 @@
All other files should just #include "HandmadeMath.h" without the #define. All other files should just #include "HandmadeMath.h" without the #define.
========================================================================== =============================================================================
To disable SSE intrinsics, you MUST To disable SSE intrinsics, you MUST
@@ -54,7 +54,7 @@
#define HANDMADE_MATH_NO_SSE #define HANDMADE_MATH_NO_SSE
#include "HandmadeMath.h" #include "HandmadeMath.h"
========================================================================== =============================================================================
To disable inlining functions, you MUST To disable inlining functions, you MUST
@@ -70,26 +70,28 @@
All other files should just #include "HandmadeMath.h" without the #define. All other files should just #include "HandmadeMath.h" without the #define.
========================================================================== =============================================================================
To Disable the CRT, you MUST To use HandmadeMath without the CRT, you MUST
#define HMM_SINF MySinF #define HMM_SINF MySinF
#define HMM_COSF MyCosF #define HMM_COSF MyCosF
#define HMM_TANF MyTanF #define HMM_TANF MyTanF
#define HMM_SQRTF MySqrtF
#define HMM_EXPF MyExpF #define HMM_EXPF MyExpF
#define HMM_LOGF MyLogF #define HMM_LOGF MyLogF
#define HMM_ACOSF MyACosF #define HMM_ACOSF MyACosF
#define HMM_ATANF MyATanF #define HMM_ATANF MyATanF
#define HMM_ATAN2F MYATan2F #define HMM_ATAN2F MYATan2F
Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F, ExpF and LogF Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F,
in EXACTLY one C or C++ file that includes this header, BEFORE the ExpF, and LogF in EXACTLY one C or C++ file that includes this header,
include, like this: BEFORE the include, like this:
#define HMM_SINF MySinF #define HMM_SINF MySinF
#define HMM_COSF MyCosF #define HMM_COSF MyCosF
#define HMM_TANF MyTanF #define HMM_TANF MyTanF
#define HMM_SQRTF MySqrtF
#define HMM_EXPF MyExpF #define HMM_EXPF MyExpF
#define HMM_LOGF MyLogF #define HMM_LOGF MyLogF
#define HMM_ACOSF MyACosF #define HMM_ACOSF MyACosF
@@ -102,7 +104,7 @@
If you do not define all five of these, HandmadeMath.h will use the If you do not define all five of these, HandmadeMath.h will use the
versions of these functions that are provided by the CRT. versions of these functions that are provided by the CRT.
========================================================================== =============================================================================
Version History: Version History:
0.2 (*) Updated documentation 0.2 (*) Updated documentation
@@ -142,9 +144,15 @@
(*) REMOVED Inner function (user should use Dot now) (*) REMOVED Inner function (user should use Dot now)
(*) REMOVED HMM_FastInverseSquareRoot function declaration (*) REMOVED HMM_FastInverseSquareRoot function declaration
0.7 0.7
(*) REMOVED HMM_LengthSquared in HANDMADE_MATH_IMPLEMENTATION (should use HMM_LengthSquaredVec3, or HANDMADE_MATH_CPP_MODE for function overloaded version) (*) REMOVED HMM_LengthSquared in HANDMADE_MATH_IMPLEMENTATION (should
(*) REMOVED HMM_Length in HANDMADE_MATH_IMPLEMENTATION (should use HMM_LengthVec3, HANDMADE_MATH_CPP_MODE for function overloaded version) use HMM_LengthSquaredVec3, or HANDMADE_MATH_CPP_MODE for function
(*) REMOVED HMM_Normalize in HANDMADE_MATH_IMPLEMENTATION (should use HMM_NormalizeVec3, or HANDMADE_MATH_CPP_MODE for function overloaded version) 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_LengthSquaredVec2
(*) Added HMM_LengthSquaredVec4 (*) Added HMM_LengthSquaredVec4
(*) Addd HMM_LengthVec2 (*) Addd HMM_LengthVec2
@@ -153,7 +161,6 @@
(*) Added HMM_NormalizeVec4 (*) Added HMM_NormalizeVec4
1.0 1.0
(*) Lots of testing! (*) Lots of testing!
1.1 1.1
(*) Quaternion support (*) Quaternion support
(*) Added type hmm_quaternion (*) Added type hmm_quaternion
@@ -170,6 +177,25 @@
(*) Added HMM_Slerp (*) Added HMM_Slerp
(*) Added HMM_QuaternionToMat4 (*) Added HMM_QuaternionToMat4
(*) Added HMM_QuaternionFromAxisAngle (*) 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
LICENSE LICENSE
@@ -193,9 +219,31 @@
Jeroen van Rijn (@J_vanRijn) Jeroen van Rijn (@J_vanRijn)
Kiljacken (@Kiljacken) Kiljacken (@Kiljacken)
Insofaras (@insofaras) Insofaras (@insofaras)
Daniel Gibson (@DanielGibson)
*/ */
#ifndef HANDMADE_NO_SSE
/* 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)
=> only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */
#ifndef HANDMADE_MATH_NO_SSE
# 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 )
# define HANDMADE_MATH__USE_SSE 1
# endif
# else /* not MSVC, probably GCC, clang, icc or something that doesn't support SSE anyway */
# ifdef __SSE__ /* they #define __SSE__ if it's supported */
# define HANDMADE_MATH__USE_SSE 1
# endif /* __SSE__ */
# endif /* not _MSC_VER */
#endif /* #ifndef HANDMADE_MATH_NO_SSE */
#include <stdint.h> // This is for types
#ifdef HANDMADE_MATH__USE_SSE
#include <xmmintrin.h> #include <xmmintrin.h>
#endif #endif
@@ -206,7 +254,8 @@
#pragma warning(disable:4201) #pragma warning(disable:4201)
#endif #endif
#ifdef __GNUC__ #ifdef __clang__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" #pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
#endif #endif
@@ -230,8 +279,8 @@ extern "C"
#endif #endif
#if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \ #if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \
!defined(HMM_EXPF) || !defined(HMM_LOGF) || !defined(HMM_ACOSF) || \ !defined(HMM_SQRTF) || !defined(HMM_EXPF) || !defined(HMM_LOGF) || \
!defined(HMM_ATANF)|| !defined(HMM_ATAN2F) !defined(HMM_ACOSF) || !defined(HMM_ATANF)|| !defined(HMM_ATAN2F)
#include <math.h> #include <math.h>
#endif #endif
@@ -246,6 +295,10 @@ extern "C"
#ifndef HMM_TANF #ifndef HMM_TANF
#define HMM_TANF tanf #define HMM_TANF tanf
#endif #endif
#ifndef HMM_SQRTF
#define HMM_SQRTF sqrtf
#endif
#ifndef HMM_EXPF #ifndef HMM_EXPF
#define HMM_EXPF expf #define HMM_EXPF expf
@@ -292,6 +345,11 @@ typedef union hmm_vec2
{ {
float Left, Right; float Left, Right;
}; };
struct
{
float Width, Height;
};
float Elements[2]; float Elements[2];
} hmm_vec2; } hmm_vec2;
@@ -396,6 +454,11 @@ typedef union hmm_vec4
typedef union hmm_mat4 typedef union hmm_mat4
{ {
float Elements[4][4]; float Elements[4][4];
#ifdef HANDMADE_MATH__USE_SSE
__m128 Rows[4];
#endif
} hmm_mat4; } hmm_mat4;
typedef union hmm_quaternion typedef union hmm_quaternion
@@ -417,6 +480,8 @@ typedef union hmm_quaternion
float Elements[4]; float Elements[4];
} hmm_quaternion; } hmm_quaternion;
typedef int32_t hmm_bool;
typedef hmm_vec2 hmm_v2; typedef hmm_vec2 hmm_v2;
typedef hmm_vec3 hmm_v3; typedef hmm_vec3 hmm_v3;
typedef hmm_vec4 hmm_v4; typedef hmm_vec4 hmm_v4;
@@ -488,10 +553,19 @@ HMMDEF hmm_vec3 HMM_DivideVec3f(hmm_vec3 Left, float Right);
HMMDEF hmm_vec4 HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right); HMMDEF hmm_vec4 HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right);
HMMDEF hmm_vec4 HMM_DivideVec4f(hmm_vec4 Left, float Right); HMMDEF hmm_vec4 HMM_DivideVec4f(hmm_vec4 Left, float Right);
HMMDEF hmm_bool HMM_EqualsVec2(hmm_vec2 Left, hmm_vec2 Right);
HMMDEF hmm_bool HMM_EqualsVec3(hmm_vec3 Left, hmm_vec3 Right);
HMMDEF hmm_bool HMM_EqualsVec4(hmm_vec4 Left, hmm_vec4 Right);
HMMDEF hmm_mat4 HMM_Mat4(void); HMMDEF hmm_mat4 HMM_Mat4(void);
HMMDEF hmm_mat4 HMM_Mat4d(float Diagonal); HMMDEF hmm_mat4 HMM_Mat4d(float Diagonal);
HMMDEF hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right); HMMDEF hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right);
HMMDEF hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right); HMMDEF hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right);
#ifdef HANDMADE_MATH__USE_SSE
HMMDEF __m128 HMM_LinearCombineSSE(__m128 Left, hmm_mat4 Right);
#endif
HMMDEF hmm_mat4 HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right); HMMDEF hmm_mat4 HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right);
HMMDEF hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar); HMMDEF hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar);
HMMDEF hmm_vec4 HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector); HMMDEF hmm_vec4 HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector);
@@ -581,6 +655,10 @@ HMMDEF hmm_mat4 HMM_Divide(hmm_mat4 Left, float Right);
HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, hmm_quaternion Right); HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, hmm_quaternion Right);
HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, float Right); HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, float Right);
HMMDEF hmm_bool HMM_Equals(hmm_vec2 Left, hmm_vec2 Right);
HMMDEF hmm_bool HMM_Equals(hmm_vec3 Left, hmm_vec3 Right);
HMMDEF hmm_bool HMM_Equals(hmm_vec4 Left, hmm_vec4 Right);
HMMDEF hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right); HMMDEF hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right);
HMMDEF hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right); HMMDEF hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right);
HMMDEF hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right); HMMDEF hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right);
@@ -655,8 +733,20 @@ HMMDEF hmm_vec4 &operator/=(hmm_vec4 &Left, float Right);
HMMDEF hmm_mat4 &operator/=(hmm_mat4 &Left, float Right); HMMDEF hmm_mat4 &operator/=(hmm_mat4 &Left, float Right);
HMMDEF hmm_quaternion &operator/=(hmm_quaternion &Left, float Right); HMMDEF hmm_quaternion &operator/=(hmm_quaternion &Left, float Right);
HMMDEF hmm_bool operator==(hmm_vec2 Left, hmm_vec2 Right);
HMMDEF hmm_bool operator==(hmm_vec3 Left, hmm_vec3 Right);
HMMDEF hmm_bool operator==(hmm_vec4 Left, hmm_vec4 Right);
HMMDEF hmm_bool operator!=(hmm_vec2 Left, hmm_vec2 Right);
HMMDEF hmm_bool operator!=(hmm_vec3 Left, hmm_vec3 Right);
HMMDEF hmm_bool operator!=(hmm_vec4 Left, hmm_vec4 Right);
#endif /* HANDMADE_MATH_CPP */ #endif /* HANDMADE_MATH_CPP */
#ifdef __clang__
#pragma GCC diagnostic pop
#endif
#endif /* HANDMADE_MATH_H */ #endif /* HANDMADE_MATH_H */
#ifdef HANDMADE_MATH_IMPLEMENTATION #ifdef HANDMADE_MATH_IMPLEMENTATION
@@ -747,12 +837,12 @@ HMM_SquareRootF(float Value)
{ {
float Result = 0.0f; float Result = 0.0f;
#ifdef HANDMADE_MATH_NO_SSE #ifdef HANDMADE_MATH__USE_SSE
Result = sqrtf(Value);
#else
__m128 In = _mm_set_ss(Value); __m128 In = _mm_set_ss(Value);
__m128 Out = _mm_sqrt_ss(In); __m128 Out = _mm_sqrt_ss(In);
Result = _mm_cvtss_f32(Out); Result = _mm_cvtss_f32(Out);
#else
Result = HMM_SQRTF(Value);
#endif #endif
return(Result); return(Result);
@@ -763,12 +853,12 @@ HMM_RSquareRootF(float Value)
{ {
float Result = 0.0f; float Result = 0.0f;
#ifdef HANDMADE_MATH_NO_SSE #ifdef HANDMADE_MATH__USE_SSE
Result = 1.0f/HMM_SqrtF(Value);
#else
__m128 In = _mm_set_ss(Value); __m128 In = _mm_set_ss(Value);
__m128 Out = _mm_rsqrt_ss(In); __m128 Out = _mm_rsqrt_ss(In);
Result = _mm_cvtss_f32(Out); Result = _mm_cvtss_f32(Out);
#else
Result = 1.0f/HMM_SquareRootF(Value);
#endif #endif
return(Result); return(Result);
@@ -893,8 +983,12 @@ HMM_NormalizeVec2(hmm_vec2 A)
float VectorLength = HMM_LengthVec2(A); float VectorLength = HMM_LengthVec2(A);
Result.X = A.X * (1.0f / VectorLength); /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
Result.Y = A.Y * (1.0f / VectorLength); if (VectorLength != 0.0f)
{
Result.X = A.X * (1.0f / VectorLength);
Result.Y = A.Y * (1.0f / VectorLength);
}
return (Result); return (Result);
} }
@@ -906,9 +1000,13 @@ HMM_NormalizeVec3(hmm_vec3 A)
float VectorLength = HMM_LengthVec3(A); float VectorLength = HMM_LengthVec3(A);
Result.X = A.X * (1.0f / VectorLength); /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
Result.Y = A.Y * (1.0f / VectorLength); if (VectorLength != 0.0f)
Result.Z = A.Z * (1.0f / VectorLength); {
Result.X = A.X * (1.0f / VectorLength);
Result.Y = A.Y * (1.0f / VectorLength);
Result.Z = A.Z * (1.0f / VectorLength);
}
return (Result); return (Result);
} }
@@ -920,10 +1018,14 @@ HMM_NormalizeVec4(hmm_vec4 A)
float VectorLength = HMM_LengthVec4(A); float VectorLength = HMM_LengthVec4(A);
Result.X = A.X * (1.0f / VectorLength); /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
Result.Y = A.Y * (1.0f / VectorLength); if (VectorLength != 0.0f)
Result.Z = A.Z * (1.0f / VectorLength); {
Result.W = A.W * (1.0f / VectorLength); Result.X = A.X * (1.0f / VectorLength);
Result.Y = A.Y * (1.0f / VectorLength);
Result.Z = A.Z * (1.0f / VectorLength);
Result.W = A.W * (1.0f / VectorLength);
}
return (Result); return (Result);
} }
@@ -1269,6 +1371,36 @@ HMM_DivideVec4f(hmm_vec4 Left, float Right)
return (Result); return (Result);
} }
HINLINE hmm_bool
HMM_EqualsVec2(hmm_vec2 Left, hmm_vec2 Right)
{
hmm_bool Result = 0;
Result = (Left.X == Right.X && Left.Y == Right.Y);
return (Result);
}
HINLINE hmm_bool
HMM_EqualsVec3(hmm_vec3 Left, hmm_vec3 Right)
{
hmm_bool Result = 0;
Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z);
return (Result);
}
HINLINE hmm_bool
HMM_EqualsVec4(hmm_vec4 Left, hmm_vec4 Right)
{
hmm_bool Result = 0;
Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W);
return (Result);
}
HINLINE hmm_mat4 HINLINE hmm_mat4
HMM_Mat4(void) HMM_Mat4(void)
{ {
@@ -1326,11 +1458,38 @@ HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right)
return (Result); return (Result);
} }
#ifdef HANDMADE_MATH__USE_SSE
HINLINE __m128
HMM_LinearCombineSSE(__m128 Left, hmm_mat4 Right)
{
__m128 Result = {};
Result = _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x00), Right.Rows[0]);
Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x55), Right.Rows[1]));
Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xaa), Right.Rows[2]));
Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xff), Right.Rows[3]));
return(Result);
}
#endif
HINLINE hmm_mat4 HINLINE hmm_mat4
HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right) HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right)
{ {
hmm_mat4 Result = HMM_Mat4(); hmm_mat4 Result = HMM_Mat4();
#ifdef HANDMADE_MATH__USE_SSE
hmm_mat4 TransposedLeft = HMM_Transpose(Left);
hmm_mat4 TransposedRight = HMM_Transpose(Right);
Result.Rows[0] = HMM_LinearCombineSSE(TransposedLeft.Rows[0], TransposedRight);
Result.Rows[1] = HMM_LinearCombineSSE(TransposedLeft.Rows[1], TransposedRight);
Result.Rows[2] = HMM_LinearCombineSSE(TransposedLeft.Rows[2], TransposedRight);
Result.Rows[3] = HMM_LinearCombineSSE(TransposedLeft.Rows[3], TransposedRight);
Result = HMM_Transpose(Result);
#else
int Columns; int Columns;
for(Columns = 0; Columns < 4; ++Columns) for(Columns = 0; Columns < 4; ++Columns)
{ {
@@ -1347,7 +1506,7 @@ HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right)
Result.Elements[Columns][Rows] = Sum; Result.Elements[Columns][Rows] = Sum;
} }
} }
#endif
return (Result); return (Result);
} }
@@ -1412,6 +1571,11 @@ HMM_Transpose(hmm_mat4 Matrix)
{ {
hmm_mat4 Result = HMM_Mat4(); hmm_mat4 Result = HMM_Mat4();
#ifdef HANDMADE_MATH__USE_SSE
Result = Matrix;
_MM_TRANSPOSE4_PS(Result.Rows[0], Result.Rows[1], Result.Rows[2], Result.Rows[3]);
#else
int Columns; int Columns;
for(Columns = 0; Columns < 4; ++Columns) for(Columns = 0; Columns < 4; ++Columns)
{ {
@@ -1421,7 +1585,8 @@ HMM_Transpose(hmm_mat4 Matrix)
Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows]; Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];
} }
} }
#endif
return (Result); return (Result);
} }
@@ -1538,7 +1703,7 @@ HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up)
} }
HMMDEF hmm_quaternion HINLINE hmm_quaternion
HMM_Quaternion(float X, float Y, float Z, float W) HMM_Quaternion(float X, float Y, float Z, float W)
{ {
hmm_quaternion Result = {0}; hmm_quaternion Result = {0};
@@ -1684,7 +1849,7 @@ HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right)
Result.Z = HMM_Lerp(Left.Z, Time, Right.Z); Result.Z = HMM_Lerp(Left.Z, Time, Right.Z);
Result.W = HMM_Lerp(Left.W, Time, Right.W); Result.W = HMM_Lerp(Left.W, Time, Right.W);
Result = HMM_Normalize(Result); Result = HMM_NormalizeQuaternion(Result);
return(Result); return(Result);
} }
@@ -1769,7 +1934,7 @@ HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation)
#ifdef HANDMADE_MATH_CPP_MODE #ifdef HANDMADE_MATH_CPP_MODE
HMMDEF float HINLINE float
HMM_Length(hmm_vec2 A) HMM_Length(hmm_vec2 A)
{ {
float Result = 0.0f; float Result = 0.0f;
@@ -1779,7 +1944,7 @@ HMM_Length(hmm_vec2 A)
return(Result); return(Result);
} }
HMMDEF float HINLINE float
HMM_Length(hmm_vec3 A) HMM_Length(hmm_vec3 A)
{ {
float Result = 0.0f; float Result = 0.0f;
@@ -1789,7 +1954,7 @@ HMM_Length(hmm_vec3 A)
return(Result); return(Result);
} }
HMMDEF float HINLINE float
HMM_Length(hmm_vec4 A) HMM_Length(hmm_vec4 A)
{ {
float Result = 0.0f; float Result = 0.0f;
@@ -1927,7 +2092,7 @@ HMM_Add(hmm_vec3 Left, hmm_vec3 Right)
return (Result); return (Result);
} }
HMMDEF HINLINE hmm_vec4 HINLINE hmm_vec4
HMM_Add(hmm_vec4 Left, hmm_vec4 Right) HMM_Add(hmm_vec4 Left, hmm_vec4 Right)
{ {
hmm_vec4 Result = {0}; hmm_vec4 Result = {0};
@@ -2179,6 +2344,33 @@ HMM_Divide(hmm_quaternion Left, float Right)
return (Result); return (Result);
} }
HINLINE hmm_bool
HMM_Equals(hmm_vec2 Left, hmm_vec2 Right)
{
hmm_bool Result = 0;
Result = HMM_EqualsVec2(Left, Right);
return (Result);
}
HINLINE hmm_bool
HMM_Equals(hmm_vec3 Left, hmm_vec3 Right)
{
hmm_bool Result = 0;
Result = HMM_EqualsVec3(Left, Right);
return (Result);
}
HINLINE hmm_bool
HMM_Equals(hmm_vec4 Left, hmm_vec4 Right)
{
hmm_bool Result = 0;
Result = HMM_EqualsVec4(Left, Right);
return (Result);
}
HINLINE hmm_vec2 HINLINE hmm_vec2
operator+(hmm_vec2 Left, hmm_vec2 Right) operator+(hmm_vec2 Left, hmm_vec2 Right)
{ {
@@ -2641,6 +2833,43 @@ operator*=(hmm_quaternion &Left, float Right)
return (Left = Left * Right); return (Left = Left * Right);
} }
HINLINE hmm_bool
operator==(hmm_vec2 Left, hmm_vec2 Right)
{
return HMM_EqualsVec2(Left, Right);
}
HINLINE hmm_bool
operator==(hmm_vec3 Left, hmm_vec3 Right)
{
return HMM_EqualsVec3(Left, Right);
}
HINLINE hmm_bool
operator==(hmm_vec4 Left, hmm_vec4 Right)
{
return HMM_EqualsVec4(Left, Right);
}
HINLINE hmm_bool
operator!=(hmm_vec2 Left, hmm_vec2 Right)
{
return !HMM_EqualsVec2(Left, Right);
}
HINLINE hmm_bool
operator!=(hmm_vec3 Left, hmm_vec3 Right)
{
return !HMM_EqualsVec3(Left, Right);
}
HINLINE hmm_bool
operator!=(hmm_vec4 Left, hmm_vec4 Right)
{
return !HMM_EqualsVec4(Left, Right);
}
#endif /* HANDMADE_MATH_CPP_MODE */ #endif /* HANDMADE_MATH_CPP_MODE */
#endif /* HANDMADE_MATH_IMPLEMENTATION */ #endif /* HANDMADE_MATH_IMPLEMENTATION */

View File

@@ -12,6 +12,12 @@ _This library is free and will stay free, but if you would like to support devel
Version | Changes | Version | Changes |
----------------|----------------| ----------------|----------------|
**1.2.0** | Added equality functions for `HMM_Vec2`, `HMM_Vec3`, and `HMM_Vec4`, and SSE'd `HMM_MultiplyMat4` and `HMM_Transpose`.
**1.1.5** | Added `Width` and `Height` to `HMM_Vec2`, and made it so you can supply your own `SqrtF`.
**1.1.4** | Fixed SSE being included on platforms that don't support it, and fixed divide-by-zero errors when normalizing zero vectors.
**1.1.3** | Fixed compile error in C mode
**1.1.2** | Fixed invalid HMMDEF's in the function definitions
**1.1.1** | Resolved compiler warnings on gcc and g++
**1.1** | Quaternions! | **1.1** | Quaternions! |
**1.0** | Lots of testing | **1.0** | Lots of testing |
**0.7** | Added HMM_Vec2, and HMM_Vec4 versions of HMM_LengthSquared, HMM_Length, and HMM_Normalize. | **0.7** | Added HMM_Vec2, and HMM_Vec4 versions of HMM_LengthSquared, HMM_Length, and HMM_Normalize. |
@@ -33,7 +39,7 @@ _This library is free and will stay free, but if you would like to support devel
**What's the license?** **What's the license?**
This library is in the public domain. You can do whatever you want with them. 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?**

Submodule externals/googletest deleted from ed9d1e1ff9

4
test/HandmadeMath.c Normal file
View File

@@ -0,0 +1,4 @@
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_INLINE
#include "../HandmadeMath.h"

View File

@@ -1,5 +1,2 @@
#include "HandmadeMath.c"
#define HANDMADE_MATH_IMPLEMENTATION // C++ compilers complain when compiling a .c file...
#define HANDMADE_MATH_CPP_MODE
#define HANDMADE_MATH_NO_INLINE
#include "../HandmadeMath.h"

94
test/HandmadeTest.h Normal file
View File

@@ -0,0 +1,94 @@
#ifndef HANDMADETEST_H
#define HANDMADETEST_H
#include <float.h>
#include <stdio.h>
int hmt_count_tests = 0;
int hmt_count_failedtests = 0;
int hmt_count_failures = 0;
#define RESET "\033[0m"
#define RED "\033[31m"
#define GREEN "\033[32m"
#define CATEGORY_BEGIN(name) { \
int count_categorytests = 0; \
int count_categoryfailedtests = 0; \
int count_categoryfailures = 0; \
printf("\n" #name ":\n");
#define CATEGORY_END(name) \
hmt_count_tests += count_categorytests; \
hmt_count_failedtests += count_categoryfailedtests; \
hmt_count_failures += count_categoryfailures; \
printf("%d/%d tests passed, %d failures\n", count_categorytests - count_categoryfailedtests, count_categorytests, count_categoryfailures); \
}
#define TEST_BEGIN(name) { \
int count_testfailures = 0; \
count_categorytests++; \
printf(" " #name ":");
#define TEST_END() \
count_categoryfailures += count_testfailures; \
if (count_testfailures > 0) { \
count_categoryfailedtests++; \
printf("\n"); \
} else { \
printf(GREEN " [PASS]\n" RESET); \
} \
}
#define CASE_FAIL() \
count_testfailures++; \
printf("\n - " RED "[FAIL] (%d) " RESET, __LINE__)
/*
* Asserts and expects
*/
#define EXPECT_TRUE(_actual) do { \
if (!(_actual)) { \
CASE_FAIL(); \
printf("Expected true but got something false"); \
} \
} while (0)
#define EXPECT_FALSE(_actual) do { \
if (_actual) { \
CASE_FAIL(); \
printf("Expected false but got something true"); \
} \
} while (0)
#define EXPECT_FLOAT_EQ(_actual, _expected) do { \
float actual = (_actual); \
float diff = actual - (_expected); \
if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \
CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \
} \
} while (0)
#define EXPECT_NEAR(_actual, _expected, _epsilon) do { \
float actual = (_actual); \
float diff = actual - (_expected); \
if (diff < -(_epsilon) || (_epsilon) < diff) { \
CASE_FAIL(); \
printf("Expected %f, got %f", (_expected), actual); \
} \
} while (0)
#define EXPECT_LT(_actual, _expected) do { \
if ((_actual) >= (_expected)) { \
CASE_FAIL(); \
printf("Expected %f to be less than %f", (_actual), (_expected)); \
} \
} while (0)
#define EXPECT_GT(_actual, _expected) do { \
if ((_actual) <= (_expected)) { \
CASE_FAIL(); \
printf("Expected %f to be greater than %f", (_actual), (_expected)); \
} \
} while (0)
#endif

View File

@@ -1,81 +1,37 @@
# A sample Makefile for building Google Test and using it in user ROOT_DIR=..
# tests. Please tweak it to suit your environment and project. You
# may want to move it to your project's root directory.
#
# SYNOPSIS:
#
# make [all] - makes everything.
# make TARGET - makes the given target.
# make clean - removes all files generated by make.
# Please tweak the following variable definitions as needed by your CXXFLAGS+=-g -Wall -Wextra -pthread -Wno-missing-braces -Wno-missing-field-initializers
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.
# Points to the root of Google Test, relative to where this file is. all: c c_no_sse cpp cpp_no_sse
# Remember to tweak this if you move this file.
GTEST_DIR = ../externals/googletest/googletest
# Where to find user code. clean:
USER_DIR = .. rm -f hmm_test_c hmm_test_cpp hmm_test_c_no_sse hmm_test_cpp_no_sse *.o
# Flags passed to the preprocessor. c: $(ROOT_DIR)/test/HandmadeMath.c test_impl
# Set Google Test's header directory as a system directory, such that @echo "\nCompiling in C mode"
# the compiler doesn't generate warnings in Google Test headers. $(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \
CPPFLAGS += -isystem $(GTEST_DIR)/include -c $(ROOT_DIR)/test/HandmadeMath.c $(ROOT_DIR)/test/hmm_test.c \
-lm
$(CC) -ohmm_test_c HandmadeMath.o hmm_test.o -lm
# Flags passed to the C++ compiler. c_no_sse: $(ROOT_DIR)/test/HandmadeMath.c test_impl
CXXFLAGS += -g -Wall -Wextra -pthread -Wno-missing-braces -Wno-missing-field-initializers @echo "\nCompiling in C mode (no SSE)"
$(CC) $(CPPFLAGS) $(CXXFLAGS) -std=c99 \
-DHANDMADE_MATH_NO_SSE \
-c $(ROOT_DIR)/test/HandmadeMath.c $(ROOT_DIR)/test/hmm_test.c \
-lm
$(CC) -ohmm_test_c_no_sse HandmadeMath.o hmm_test.o -lm
# All tests produced by this Makefile. Remember to add new tests you cpp: $(ROOT_DIR)/test/HandmadeMath.cpp test_impl
# created to the list. @echo "\nCompiling in C++ mode"
TESTS = hmm_test $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp \
-DHANDMADE_MATH_CPP_MODE \
$(ROOT_DIR)/test/HandmadeMath.cpp $(ROOT_DIR)/test/hmm_test.cpp
# All Google Test headers. Usually you shouldn't change this cpp_no_sse: $(ROOT_DIR)/test/HandmadeMath.cpp test_impl
# definition. @echo "\nCompiling in C++ mode (no SSE)"
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -ohmm_test_cpp_no_sse \
$(GTEST_DIR)/include/gtest/internal/*.h -DHANDMADE_MATH_CPP_MODE -DHANDMADE_MATH_NO_SSE \
$(ROOT_DIR)/test/HandmadeMath.cpp $(ROOT_DIR)/test/hmm_test.cpp
# House-keeping build targets. test_impl: $(ROOT_DIR)/test/hmm_test.cpp $(ROOT_DIR)/test/hmm_test.c
all : $(TESTS)
clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o
# Builds gtest.a and gtest_main.a.
# Usually you shouldn't tweak such internal variables, indicated by a
# trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc
gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $@ $^
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $@ $^
# Builds a sample test. A test should link with either gtest.a or
# gtest_main.a, depending on whether it defines its own main()
# function.
HandmadeMath.o : $(USER_DIR)/test/HandmadeMath.cpp $(USER_DIR)/HandmadeMath.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/test/HandmadeMath.cpp
hmm_test.o : $(USER_DIR)/test/hmm_test.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/test/hmm_test.cpp
hmm_test : HandmadeMath.o hmm_test.o gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@

11
test/README.md Normal file
View File

@@ -0,0 +1,11 @@
# Testing
You can compile and run the tests yourself by running:
```
make
./hmm_test_c
./hmm_test_c_no_sse
./hmm_test_cpp
./hmm_test_cpp_no_sse
```

2202
test/hmm_test.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff