Add HandmadeMath.
Add simple morphing code.
diff --git a/examples/skinning/HandmadeMath.h b/examples/skinning/HandmadeMath.h
new file mode 100644
index 0000000..b0c6f5c
--- /dev/null
+++ b/examples/skinning/HandmadeMath.h
@@ -0,0 +1,2507 @@
+/*
+ HandmadeMath.h v1.7.0
+
+ This is a single header file with a bunch of useful functions for game and
+ graphics math operations.
+
+ =============================================================================
+
+ You MUST
+
+ #define HANDMADE_MATH_IMPLEMENTATION
+
+ in EXACTLY one C or C++ file that includes this header, BEFORE the
+ include, like this:
+
+ #define HANDMADE_MATH_IMPLEMENTATION
+ #include "HandmadeMath.h"
+
+ All other files should just #include "HandmadeMath.h" without the #define.
+
+ =============================================================================
+
+ To disable SSE intrinsics, you MUST
+
+ #define HANDMADE_MATH_NO_SSE
+
+ in EXACTLY one C or C++ file that includes this header, BEFORE the
+ include, like this:
+
+ #define HANDMADE_MATH_IMPLEMENTATION
+ #define HANDMADE_MATH_NO_SSE
+ #include "HandmadeMath.h"
+
+ =============================================================================
+
+ To use HandmadeMath without the CRT, you MUST
+
+ #define HMM_SINF MySinF
+ #define HMM_COSF MyCosF
+ #define HMM_TANF MyTanF
+ #define HMM_SQRTF MySqrtF
+ #define HMM_EXPF MyExpF
+ #define HMM_LOGF MyLogF
+ #define HMM_ACOSF MyACosF
+ #define HMM_ATANF MyATanF
+ #define HMM_ATAN2F MYATan2F
+
+ Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F,
+ ExpF, and LogF in EXACTLY one C or C++ file that includes this header,
+ BEFORE the include, like this:
+
+ #define HMM_SINF MySinF
+ #define HMM_COSF MyCosF
+ #define HMM_TANF MyTanF
+ #define HMM_SQRTF MySqrtF
+ #define HMM_EXPF MyExpF
+ #define HMM_LOGF MyLogF
+ #define HMM_ACOSF MyACosF
+ #define HMM_ATANF MyATanF
+ #define HMM_ATAN2F MyATan2F
+ #define HANDMADE_MATH_IMPLEMENTATION
+ #include "HandmadeMath.h"
+
+ If you do not define all of these, HandmadeMath.h will use the
+ 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.
+
+
+ LICENSE
+
+ This software is in the public domain. Where that dedication is not
+ recognized, you are granted a perpetual, irrevocable license to copy,
+ distribute, and modify this file as you see fit.
+
+ CREDITS
+
+ Written by Zakary Strange (zak@strangedev.net && @strangezak)
+
+ Functionality:
+ Matt Mascarenhas (@miblo_)
+ Aleph
+ FieryDrake (@fierydrake)
+ Gingerbill (@TheGingerBill)
+ Ben Visness (@bvisness)
+ Trinton Bullard (@Peliex_Dev)
+
+ Fixes:
+ Jeroen van Rijn (@J_vanRijn)
+ Kiljacken (@Kiljacken)
+ Insofaras (@insofaras)
+ Daniel Gibson (@DanielGibson)
+*/
+
+
+/* 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>
+#endif
+
+#ifndef HANDMADE_MATH_H
+#define HANDMADE_MATH_H
+
+#ifdef _MSC_VER
+#pragma warning(disable:4201)
+#endif
+
+#ifdef __clang__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define HMM_INLINE static inline
+#define HMM_EXTERN extern
+
+#if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \
+ !defined(HMM_SQRTF) || !defined(HMM_EXPF) || !defined(HMM_LOGF) || \
+ !defined(HMM_ACOSF) || !defined(HMM_ATANF)|| !defined(HMM_ATAN2F)
+#include <math.h>
+#endif
+
+#ifndef HMM_SINF
+#define HMM_SINF sinf
+#endif
+
+#ifndef HMM_COSF
+#define HMM_COSF cosf
+#endif
+
+#ifndef HMM_TANF
+#define HMM_TANF tanf
+#endif
+
+#ifndef HMM_SQRTF
+#define HMM_SQRTF sqrtf
+#endif
+
+#ifndef HMM_EXPF
+#define HMM_EXPF expf
+#endif
+
+#ifndef HMM_LOGF
+#define HMM_LOGF logf
+#endif
+
+#ifndef HMM_ACOSF
+#define HMM_ACOSF acosf
+#endif
+
+#ifndef HMM_ATANF
+#define HMM_ATANF atanf
+#endif
+
+#ifndef HMM_ATAN2F
+#define HMM_ATAN2F atan2f
+#endif
+
+#define HMM_PI32 3.14159265359f
+#define HMM_PI 3.14159265358979323846
+
+#define HMM_MIN(a, b) (a) > (b) ? (b) : (a)
+#define HMM_MAX(a, b) (a) < (b) ? (b) : (a)
+#define HMM_ABS(a) ((a) > 0 ? (a) : -(a))
+#define HMM_MOD(a, m) ((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m))
+#define HMM_SQUARE(x) ((x) * (x))
+
+typedef union hmm_vec2
+{
+ struct
+ {
+ float X, Y;
+ };
+
+ struct
+ {
+ float U, V;
+ };
+
+ struct
+ {
+ float Left, Right;
+ };
+
+ struct
+ {
+ float Width, Height;
+ };
+
+ float Elements[2];
+
+#ifdef __cplusplus
+ inline float &operator[](int Index)
+ {
+ return Elements[Index];
+ }
+#endif
+} hmm_vec2;
+
+typedef union hmm_vec3
+{
+ struct
+ {
+ float X, Y, Z;
+ };
+
+ struct
+ {
+ float U, V, W;
+ };
+
+ struct
+ {
+ float R, G, B;
+ };
+
+ struct
+ {
+ hmm_vec2 XY;
+ float Ignored0_;
+ };
+
+ struct
+ {
+ float Ignored1_;
+ hmm_vec2 YZ;
+ };
+
+ struct
+ {
+ hmm_vec2 UV;
+ float Ignored2_;
+ };
+
+ struct
+ {
+ float Ignored3_;
+ hmm_vec2 VW;
+ };
+
+ float Elements[3];
+
+#ifdef __cplusplus
+ inline float &operator[](int Index)
+ {
+ return Elements[Index];
+ }
+#endif
+} hmm_vec3;
+
+typedef union hmm_vec4
+{
+ struct
+ {
+ union
+ {
+ hmm_vec3 XYZ;
+ struct
+ {
+ float X, Y, Z;
+ };
+ };
+
+ float W;
+ };
+ struct
+ {
+ union
+ {
+ hmm_vec3 RGB;
+ struct
+ {
+ float R, G, B;
+ };
+ };
+
+ float A;
+ };
+
+ struct
+ {
+ hmm_vec2 XY;
+ float Ignored0_;
+ float Ignored1_;
+ };
+
+ struct
+ {
+ float Ignored2_;
+ hmm_vec2 YZ;
+ float Ignored3_;
+ };
+
+ struct
+ {
+ float Ignored4_;
+ float Ignored5_;
+ hmm_vec2 ZW;
+ };
+
+ float Elements[4];
+
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 InternalElementsSSE;
+#endif
+
+#ifdef __cplusplus
+ inline float &operator[](int Index)
+ {
+ return Elements[Index];
+ }
+#endif
+} hmm_vec4;
+
+typedef union hmm_mat4
+{
+ float Elements[4][4];
+
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 Columns[4];
+
+ // DEPRECATED. Our matrices are column-major, so this was named
+ // incorrectly. Use Columns instead.
+ __m128 Rows[4];
+#endif
+
+#ifdef __cplusplus
+ inline hmm_vec4 operator[](const int Index)
+ {
+ float* col = Elements[Index];
+
+ hmm_vec4 result;
+ result.Elements[0] = col[0];
+ result.Elements[1] = col[1];
+ result.Elements[2] = col[2];
+ result.Elements[3] = col[3];
+
+ return result;
+ }
+#endif
+} hmm_mat4;
+
+typedef union hmm_quaternion
+{
+ struct
+ {
+ union
+ {
+ hmm_vec3 XYZ;
+ struct
+ {
+ float X, Y, Z;
+ };
+ };
+
+ float W;
+ };
+
+ float Elements[4];
+} hmm_quaternion;
+
+typedef int32_t hmm_bool;
+
+typedef hmm_vec2 hmm_v2;
+typedef hmm_vec3 hmm_v3;
+typedef hmm_vec4 hmm_v4;
+typedef hmm_mat4 hmm_m4;
+
+
+/*
+ * Floating-point math functions
+ */
+
+HMM_INLINE float HMM_SinF(float Radians)
+{
+ float Result = HMM_SINF(Radians);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_CosF(float Radians)
+{
+ float Result = HMM_COSF(Radians);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_TanF(float Radians)
+{
+ float Result = HMM_TANF(Radians);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_ACosF(float Radians)
+{
+ float Result = HMM_ACOSF(Radians);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_ATanF(float Radians)
+{
+ float Result = HMM_ATANF(Radians);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_ATan2F(float Left, float Right)
+{
+ float Result = HMM_ATAN2F(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_ExpF(float Float)
+{
+ float Result = HMM_EXPF(Float);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LogF(float Float)
+{
+ float Result = HMM_LOGF(Float);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_SquareRootF(float Float)
+{
+ float Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 In = _mm_set_ss(Float);
+ __m128 Out = _mm_sqrt_ss(In);
+ Result = _mm_cvtss_f32(Out);
+#else
+ Result = HMM_SQRTF(Float);
+#endif
+
+ return(Result);
+}
+
+HMM_INLINE float HMM_RSquareRootF(float Float)
+{
+ float Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 In = _mm_set_ss(Float);
+ __m128 Out = _mm_rsqrt_ss(In);
+ Result = _mm_cvtss_f32(Out);
+#else
+ Result = 1.0f/HMM_SquareRootF(Float);
+#endif
+
+ return(Result);
+}
+
+HMM_EXTERN float HMM_Power(float Base, int Exponent);
+
+HMM_INLINE float HMM_PowerF(float Base, float Exponent)
+{
+ float Result = HMM_EXPF(Exponent * HMM_LOGF(Base));
+
+ return (Result);
+}
+
+
+/*
+ * Utility functions
+ */
+HMM_INLINE float HMM_ToRadians(float Degrees)
+{
+ float Result = Degrees * (HMM_PI32 / 180.0f);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Lerp(float A, float Time, float B)
+{
+ float Result = (1.0f - Time) * A + Time * B;
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Clamp(float Min, float Value, float Max)
+{
+ float Result = Value;
+
+ if(Result < Min)
+ {
+ Result = Min;
+ }
+ else if(Result > Max)
+ {
+ Result = Max;
+ }
+
+ return (Result);
+}
+
+
+/*
+ * Vector initialization
+ */
+
+HMM_INLINE hmm_vec2 HMM_Vec2(float X, float Y)
+{
+ hmm_vec2 Result;
+
+ Result.X = X;
+ Result.Y = Y;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Vec2i(int X, int Y)
+{
+ hmm_vec2 Result;
+
+ Result.X = (float)X;
+ Result.Y = (float)Y;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Vec3(float X, float Y, float Z)
+{
+ hmm_vec3 Result;
+
+ Result.X = X;
+ Result.Y = Y;
+ Result.Z = Z;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Vec3i(int X, int Y, int Z)
+{
+ hmm_vec3 Result;
+
+ Result.X = (float)X;
+ Result.Y = (float)Y;
+ Result.Z = (float)Z;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Vec4(float X, float Y, float Z, float W)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = _mm_setr_ps(X, Y, Z, W);
+#else
+ Result.X = X;
+ Result.Y = Y;
+ Result.Z = Z;
+ Result.W = W;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Vec4i(int X, int Y, int Z, int W)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = _mm_setr_ps((float)X, (float)Y, (float)Z, (float)W);
+#else
+ Result.X = (float)X;
+ Result.Y = (float)Y;
+ Result.Z = (float)Z;
+ Result.W = (float)W;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Vec4v(hmm_vec3 Vector, float W)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = _mm_setr_ps(Vector.X, Vector.Y, Vector.Z, W);
+#else
+ Result.XYZ = Vector;
+ Result.W = W;
+#endif
+
+ return (Result);
+}
+
+
+/*
+ * Binary vector operations
+ */
+
+HMM_INLINE hmm_vec2 HMM_AddVec2(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result;
+
+ Result.X = Left.X + Right.X;
+ Result.Y = Left.Y + Right.Y;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_AddVec3(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result;
+
+ Result.X = Left.X + Right.X;
+ Result.Y = Left.Y + Right.Y;
+ Result.Z = Left.Z + Right.Z;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_AddVec4(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = _mm_add_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);
+#else
+ Result.X = Left.X + Right.X;
+ Result.Y = Left.Y + Right.Y;
+ Result.Z = Left.Z + Right.Z;
+ Result.W = Left.W + Right.W;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_SubtractVec2(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result;
+
+ Result.X = Left.X - Right.X;
+ Result.Y = Left.Y - Right.Y;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_SubtractVec3(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result;
+
+ Result.X = Left.X - Right.X;
+ Result.Y = Left.Y - Right.Y;
+ Result.Z = Left.Z - Right.Z;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_SubtractVec4(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = _mm_sub_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);
+#else
+ Result.X = Left.X - Right.X;
+ Result.Y = Left.Y - Right.Y;
+ Result.Z = Left.Z - Right.Z;
+ Result.W = Left.W - Right.W;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_MultiplyVec2(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result;
+
+ Result.X = Left.X * Right.X;
+ Result.Y = Left.Y * Right.Y;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_MultiplyVec2f(hmm_vec2 Left, float Right)
+{
+ hmm_vec2 Result;
+
+ Result.X = Left.X * Right;
+ Result.Y = Left.Y * Right;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_MultiplyVec3(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result;
+
+ Result.X = Left.X * Right.X;
+ Result.Y = Left.Y * Right.Y;
+ Result.Z = Left.Z * Right.Z;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_MultiplyVec3f(hmm_vec3 Left, float Right)
+{
+ hmm_vec3 Result;
+
+ Result.X = Left.X * Right;
+ Result.Y = Left.Y * Right;
+ Result.Z = Left.Z * Right;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_MultiplyVec4(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);
+#else
+ Result.X = Left.X * Right.X;
+ Result.Y = Left.Y * Right.Y;
+ Result.Z = Left.Z * Right.Z;
+ Result.W = Left.W * Right.W;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_MultiplyVec4f(hmm_vec4 Left, float Right)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 Scalar = _mm_set1_ps(Right);
+ Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Scalar);
+#else
+ Result.X = Left.X * Right;
+ Result.Y = Left.Y * Right;
+ Result.Z = Left.Z * Right;
+ Result.W = Left.W * Right;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result;
+
+ Result.X = Left.X / Right.X;
+ Result.Y = Left.Y / Right.Y;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_DivideVec2f(hmm_vec2 Left, float Right)
+{
+ hmm_vec2 Result;
+
+ Result.X = Left.X / Right;
+ Result.Y = Left.Y / Right;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result;
+
+ Result.X = Left.X / Right.X;
+ Result.Y = Left.Y / Right.Y;
+ Result.Z = Left.Z / Right.Z;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_DivideVec3f(hmm_vec3 Left, float Right)
+{
+ hmm_vec3 Result;
+
+ Result.X = Left.X / Right;
+ Result.Y = Left.Y / Right;
+ Result.Z = Left.Z / Right;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Right.InternalElementsSSE);
+#else
+ Result.X = Left.X / Right.X;
+ Result.Y = Left.Y / Right.Y;
+ Result.Z = Left.Z / Right.Z;
+ Result.W = Left.W / Right.W;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_DivideVec4f(hmm_vec4 Left, float Right)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 Scalar = _mm_set1_ps(Right);
+ Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Scalar);
+#else
+ Result.X = Left.X / Right;
+ Result.Y = Left.Y / Right;
+ Result.Z = Left.Z / Right;
+ Result.W = Left.W / Right;
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_bool HMM_EqualsVec2(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_bool HMM_EqualsVec3(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_bool HMM_EqualsVec4(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_DotVec2(hmm_vec2 VecOne, hmm_vec2 VecTwo)
+{
+ float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_DotVec3(hmm_vec3 VecOne, hmm_vec3 VecTwo)
+{
+ float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_DotVec4(hmm_vec4 VecOne, hmm_vec4 VecTwo)
+{
+ float Result;
+
+ // NOTE(zak): IN the future if we wanna check what version SSE is support
+ // we can use _mm_dp_ps (4.3) but for now we will use the old way.
+ // Or a r = _mm_mul_ps(v1, v2), r = _mm_hadd_ps(r, r), r = _mm_hadd_ps(r, r) for SSE3
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 SSEResultOne = _mm_mul_ps(VecOne.InternalElementsSSE, VecTwo.InternalElementsSSE);
+ __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1));
+ SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
+ SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3));
+ SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
+ _mm_store_ss(&Result, SSEResultOne);
+#else
+ Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z) + (VecOne.W * VecTwo.W);
+#endif
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Cross(hmm_vec3 VecOne, hmm_vec3 VecTwo)
+{
+ hmm_vec3 Result;
+
+ Result.X = (VecOne.Y * VecTwo.Z) - (VecOne.Z * VecTwo.Y);
+ Result.Y = (VecOne.Z * VecTwo.X) - (VecOne.X * VecTwo.Z);
+ Result.Z = (VecOne.X * VecTwo.Y) - (VecOne.Y * VecTwo.X);
+
+ return (Result);
+}
+
+
+/*
+ * Unary vector operations
+ */
+
+HMM_INLINE float HMM_LengthSquaredVec2(hmm_vec2 A)
+{
+ float Result = HMM_DotVec2(A, A);
+
+ return(Result);
+}
+
+HMM_INLINE float HMM_LengthSquaredVec3(hmm_vec3 A)
+{
+ float Result = HMM_DotVec3(A, A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LengthSquaredVec4(hmm_vec4 A)
+{
+ float Result = HMM_DotVec4(A, A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LengthVec2(hmm_vec2 A)
+{
+ float Result = HMM_SquareRootF(HMM_LengthSquaredVec2(A));
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LengthVec3(hmm_vec3 A)
+{
+ float Result = HMM_SquareRootF(HMM_LengthSquaredVec3(A));
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LengthVec4(hmm_vec4 A)
+{
+ float Result = HMM_SquareRootF(HMM_LengthSquaredVec4(A));
+
+ return(Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_NormalizeVec2(hmm_vec2 A)
+{
+ hmm_vec2 Result = {0};
+
+ float VectorLength = HMM_LengthVec2(A);
+
+ /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
+ if (VectorLength != 0.0f)
+ {
+ Result.X = A.X * (1.0f / VectorLength);
+ Result.Y = A.Y * (1.0f / VectorLength);
+ }
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_NormalizeVec3(hmm_vec3 A)
+{
+ hmm_vec3 Result = {0};
+
+ float VectorLength = HMM_LengthVec3(A);
+
+ /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
+ if (VectorLength != 0.0f)
+ {
+ Result.X = A.X * (1.0f / VectorLength);
+ Result.Y = A.Y * (1.0f / VectorLength);
+ Result.Z = A.Z * (1.0f / VectorLength);
+ }
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_NormalizeVec4(hmm_vec4 A)
+{
+ hmm_vec4 Result = {0};
+
+ float VectorLength = HMM_LengthVec4(A);
+
+ /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
+ if (VectorLength != 0.0f)
+ {
+ float Multiplier = 1.0f / VectorLength;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ __m128 SSEMultiplier = _mm_set1_ps(Multiplier);
+ Result.InternalElementsSSE = _mm_mul_ps(A.InternalElementsSSE, SSEMultiplier);
+#else
+ Result.X = A.X * Multiplier;
+ Result.Y = A.Y * Multiplier;
+ Result.Z = A.Z * Multiplier;
+ Result.W = A.W * Multiplier;
+#endif
+ }
+
+ return (Result);
+}
+
+
+/*
+ * SSE stuff
+ */
+
+#ifdef HANDMADE_MATH__USE_SSE
+HMM_INLINE __m128 HMM_LinearCombineSSE(__m128 Left, hmm_mat4 Right)
+{
+ __m128 Result;
+ Result = _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x00), Right.Columns[0]);
+ Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x55), Right.Columns[1]));
+ Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xaa), Right.Columns[2]));
+ Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xff), Right.Columns[3]));
+
+ return (Result);
+}
+#endif
+
+
+/*
+ * Matrix functions
+ */
+
+HMM_INLINE hmm_mat4 HMM_Mat4(void)
+{
+ hmm_mat4 Result = {0};
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Mat4d(float Diagonal)
+{
+ hmm_mat4 Result = HMM_Mat4();
+
+ Result.Elements[0][0] = Diagonal;
+ Result.Elements[1][1] = Diagonal;
+ Result.Elements[2][2] = Diagonal;
+ Result.Elements[3][3] = Diagonal;
+
+ return (Result);
+}
+
+#ifdef HANDMADE_MATH__USE_SSE
+HMM_INLINE hmm_mat4 HMM_Transpose(hmm_mat4 Matrix)
+{
+ hmm_mat4 Result = Matrix;
+
+ _MM_TRANSPOSE4_PS(Result.Columns[0], Result.Columns[1], Result.Columns[2], Result.Columns[3]);
+
+ return (Result);
+}
+#else
+HMM_EXTERN hmm_mat4 HMM_Transpose(hmm_mat4 Matrix);
+#endif
+
+#ifdef HANDMADE_MATH__USE_SSE
+HMM_INLINE hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result;
+
+ Result.Columns[0] = _mm_add_ps(Left.Columns[0], Right.Columns[0]);
+ Result.Columns[1] = _mm_add_ps(Left.Columns[1], Right.Columns[1]);
+ Result.Columns[2] = _mm_add_ps(Left.Columns[2], Right.Columns[2]);
+ Result.Columns[3] = _mm_add_ps(Left.Columns[3], Right.Columns[3]);
+
+ return (Result);
+}
+#else
+HMM_EXTERN hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right);
+#endif
+
+#ifdef HANDMADE_MATH__USE_SSE
+HMM_INLINE hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result;
+
+ Result.Columns[0] = _mm_sub_ps(Left.Columns[0], Right.Columns[0]);
+ Result.Columns[1] = _mm_sub_ps(Left.Columns[1], Right.Columns[1]);
+ Result.Columns[2] = _mm_sub_ps(Left.Columns[2], Right.Columns[2]);
+ Result.Columns[3] = _mm_sub_ps(Left.Columns[3], Right.Columns[3]);
+
+ return (Result);
+}
+#else
+HMM_EXTERN hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right);
+#endif
+
+HMM_EXTERN hmm_mat4 HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right);
+
+#ifdef HANDMADE_MATH__USE_SSE
+HMM_INLINE hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar)
+{
+ hmm_mat4 Result;
+
+ __m128 SSEScalar = _mm_set1_ps(Scalar);
+ Result.Columns[0] = _mm_mul_ps(Matrix.Columns[0], SSEScalar);
+ Result.Columns[1] = _mm_mul_ps(Matrix.Columns[1], SSEScalar);
+ Result.Columns[2] = _mm_mul_ps(Matrix.Columns[2], SSEScalar);
+ Result.Columns[3] = _mm_mul_ps(Matrix.Columns[3], SSEScalar);
+
+ return (Result);
+}
+#else
+HMM_EXTERN hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar);
+#endif
+
+HMM_EXTERN hmm_vec4 HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector);
+
+#ifdef HANDMADE_MATH__USE_SSE
+HMM_INLINE hmm_mat4 HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar)
+{
+ hmm_mat4 Result;
+
+ __m128 SSEScalar = _mm_set1_ps(Scalar);
+ Result.Columns[0] = _mm_div_ps(Matrix.Columns[0], SSEScalar);
+ Result.Columns[1] = _mm_div_ps(Matrix.Columns[1], SSEScalar);
+ Result.Columns[2] = _mm_div_ps(Matrix.Columns[2], SSEScalar);
+ Result.Columns[3] = _mm_div_ps(Matrix.Columns[3], SSEScalar);
+
+ return (Result);
+}
+#else
+HMM_EXTERN hmm_mat4 HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar);
+#endif
+
+
+/*
+ * Common graphics transformations
+ */
+
+HMM_INLINE hmm_mat4 HMM_Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far)
+{
+ hmm_mat4 Result = HMM_Mat4();
+
+ Result.Elements[0][0] = 2.0f / (Right - Left);
+ Result.Elements[1][1] = 2.0f / (Top - Bottom);
+ Result.Elements[2][2] = 2.0f / (Near - Far);
+ Result.Elements[3][3] = 1.0f;
+
+ Result.Elements[3][0] = (Left + Right) / (Left - Right);
+ Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
+ Result.Elements[3][2] = (Far + Near) / (Near - Far);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Perspective(float FOV, float AspectRatio, float Near, float Far)
+{
+ hmm_mat4 Result = HMM_Mat4();
+
+ float TanThetaOver2 = HMM_TanF(FOV * (HMM_PI32 / 360.0f));
+
+ Result.Elements[0][0] = 1.0f / TanThetaOver2;
+ Result.Elements[1][1] = AspectRatio / TanThetaOver2;
+ Result.Elements[2][3] = -1.0f;
+ Result.Elements[2][2] = (Near + Far) / (Near - Far);
+ Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
+ Result.Elements[3][3] = 0.0f;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Translate(hmm_vec3 Translation)
+{
+ hmm_mat4 Result = HMM_Mat4d(1.0f);
+
+ Result.Elements[3][0] = Translation.X;
+ Result.Elements[3][1] = Translation.Y;
+ Result.Elements[3][2] = Translation.Z;
+
+ return (Result);
+}
+
+HMM_EXTERN hmm_mat4 HMM_Rotate(float Angle, hmm_vec3 Axis);
+
+HMM_INLINE hmm_mat4 HMM_Scale(hmm_vec3 Scale)
+{
+ hmm_mat4 Result = HMM_Mat4d(1.0f);
+
+ Result.Elements[0][0] = Scale.X;
+ Result.Elements[1][1] = Scale.Y;
+ Result.Elements[2][2] = Scale.Z;
+
+ return (Result);
+}
+
+HMM_EXTERN hmm_mat4 HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up);
+
+
+/*
+ * Quaternion operations
+ */
+
+HMM_INLINE hmm_quaternion HMM_Quaternion(float X, float Y, float Z, float W)
+{
+ hmm_quaternion Result;
+
+ Result.X = X;
+ Result.Y = Y;
+ Result.Z = Z;
+ Result.W = W;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_QuaternionV4(hmm_vec4 Vector)
+{
+ hmm_quaternion Result;
+
+ Result.X = Vector.X;
+ Result.Y = Vector.Y;
+ Result.Z = Vector.Z;
+ Result.W = Vector.W;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_AddQuaternion(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result;
+
+ Result.X = Left.X + Right.X;
+ Result.Y = Left.Y + Right.Y;
+ Result.Z = Left.Z + Right.Z;
+ Result.W = Left.W + Right.W;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_SubtractQuaternion(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result;
+
+ Result.X = Left.X - Right.X;
+ Result.Y = Left.Y - Right.Y;
+ Result.Z = Left.Z - Right.Z;
+ Result.W = Left.W - Right.W;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_MultiplyQuaternion(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result;
+
+ Result.X = (Left.X * Right.W) + (Left.Y * Right.Z) - (Left.Z * Right.Y) + (Left.W * Right.X);
+ Result.Y = (-Left.X * Right.Z) + (Left.Y * Right.W) + (Left.Z * Right.X) + (Left.W * Right.Y);
+ Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X) + (Left.Z * Right.W) + (Left.W * Right.Z);
+ Result.W = (-Left.X * Right.X) - (Left.Y * Right.Y) - (Left.Z * Right.Z) + (Left.W * Right.W);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_MultiplyQuaternionF(hmm_quaternion Left, float Multiplicative)
+{
+ hmm_quaternion Result;
+
+ Result.X = Left.X * Multiplicative;
+ Result.Y = Left.Y * Multiplicative;
+ Result.Z = Left.Z * Multiplicative;
+ Result.W = Left.W * Multiplicative;
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_DivideQuaternionF(hmm_quaternion Left, float Dividend)
+{
+ hmm_quaternion Result;
+
+ Result.X = Left.X / Dividend;
+ Result.Y = Left.Y / Dividend;
+ Result.Z = Left.Z / Dividend;
+ Result.W = Left.W / Dividend;
+
+ return (Result);
+}
+
+HMM_EXTERN hmm_quaternion HMM_InverseQuaternion(hmm_quaternion Left);
+
+HMM_INLINE float HMM_DotQuaternion(hmm_quaternion Left, hmm_quaternion Right)
+{
+ float Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_NormalizeQuaternion(hmm_quaternion Left)
+{
+ hmm_quaternion Result;
+
+ float Length = HMM_SquareRootF(HMM_DotQuaternion(Left, Left));
+ Result = HMM_DivideQuaternionF(Left, Length);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right)
+{
+ hmm_quaternion Result;
+
+ Result.X = HMM_Lerp(Left.X, Time, Right.X);
+ Result.Y = HMM_Lerp(Left.Y, Time, Right.Y);
+ Result.Z = HMM_Lerp(Left.Z, Time, Right.Z);
+ Result.W = HMM_Lerp(Left.W, Time, Right.W);
+
+ Result = HMM_NormalizeQuaternion(Result);
+
+ return (Result);
+}
+
+HMM_EXTERN hmm_quaternion HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right);
+HMM_EXTERN hmm_mat4 HMM_QuaternionToMat4(hmm_quaternion Left);
+HMM_EXTERN hmm_quaternion HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+HMM_INLINE float HMM_Length(hmm_vec2 A)
+{
+ float Result = HMM_LengthVec2(A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Length(hmm_vec3 A)
+{
+ float Result = HMM_LengthVec3(A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Length(hmm_vec4 A)
+{
+ float Result = HMM_LengthVec4(A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LengthSquared(hmm_vec2 A)
+{
+ float Result = HMM_LengthSquaredVec2(A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LengthSquared(hmm_vec3 A)
+{
+ float Result = HMM_LengthSquaredVec3(A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_LengthSquared(hmm_vec4 A)
+{
+ float Result = HMM_LengthSquaredVec4(A);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Normalize(hmm_vec2 A)
+{
+ hmm_vec2 Result = HMM_NormalizeVec2(A);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Normalize(hmm_vec3 A)
+{
+ hmm_vec3 Result = HMM_NormalizeVec3(A);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Normalize(hmm_vec4 A)
+{
+ hmm_vec4 Result = HMM_NormalizeVec4(A);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_Normalize(hmm_quaternion A)
+{
+ hmm_quaternion Result = HMM_NormalizeQuaternion(A);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Dot(hmm_vec2 VecOne, hmm_vec2 VecTwo)
+{
+ float Result = HMM_DotVec2(VecOne, VecTwo);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Dot(hmm_vec3 VecOne, hmm_vec3 VecTwo)
+{
+ float Result = HMM_DotVec3(VecOne, VecTwo);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Dot(hmm_vec4 VecOne, hmm_vec4 VecTwo)
+{
+ float Result = HMM_DotVec4(VecOne, VecTwo);
+
+ return (Result);
+}
+
+HMM_INLINE float HMM_Dot(hmm_quaternion QuatOne, hmm_quaternion QuatTwo)
+{
+ float Result = HMM_DotQuaternion(QuatOne, QuatTwo);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Add(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_AddVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Add(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_AddVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Add(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_AddVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Add(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result = HMM_AddMat4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_Add(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result = HMM_AddQuaternion(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Subtract(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_SubtractVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Subtract(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_SubtractVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Subtract(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_SubtractVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Subtract(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result = HMM_SubtractMat4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_Subtract(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result = HMM_SubtractQuaternion(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Multiply(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_MultiplyVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Multiply(hmm_vec2 Left, float Right)
+{
+ hmm_vec2 Result = HMM_MultiplyVec2f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Multiply(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_MultiplyVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Multiply(hmm_vec3 Left, float Right)
+{
+ hmm_vec3 Result = HMM_MultiplyVec3f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Multiply(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_MultiplyVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Multiply(hmm_vec4 Left, float Right)
+{
+ hmm_vec4 Result = HMM_MultiplyVec4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Multiply(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result = HMM_MultiplyMat4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Multiply(hmm_mat4 Left, float Right)
+{
+ hmm_mat4 Result = HMM_MultiplyMat4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Multiply(hmm_mat4 Matrix, hmm_vec4 Vector)
+{
+ hmm_vec4 Result = HMM_MultiplyMat4ByVec4(Matrix, Vector);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_Multiply(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result = HMM_MultiplyQuaternion(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_Multiply(hmm_quaternion Left, float Right)
+{
+ hmm_quaternion Result = HMM_MultiplyQuaternionF(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Divide(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_DivideVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 HMM_Divide(hmm_vec2 Left, float Right)
+{
+ hmm_vec2 Result = HMM_DivideVec2f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Divide(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_DivideVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 HMM_Divide(hmm_vec3 Left, float Right)
+{
+ hmm_vec3 Result = HMM_DivideVec3f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Divide(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_DivideVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 HMM_Divide(hmm_vec4 Left, float Right)
+{
+ hmm_vec4 Result = HMM_DivideVec4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 HMM_Divide(hmm_mat4 Left, float Right)
+{
+ hmm_mat4 Result = HMM_DivideMat4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion HMM_Divide(hmm_quaternion Left, float Right)
+{
+ hmm_quaternion Result = HMM_DivideQuaternionF(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_bool HMM_Equals(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_bool Result = HMM_EqualsVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_bool HMM_Equals(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_bool Result = HMM_EqualsVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_bool HMM_Equals(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_bool Result = HMM_EqualsVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_AddVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_AddVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_AddVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 operator+(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result = HMM_AddMat4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion operator+(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result = HMM_AddQuaternion(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 operator-(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_SubtractVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 operator-(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_SubtractVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator-(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_SubtractVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 operator-(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result = HMM_SubtractMat4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion operator-(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result = HMM_SubtractQuaternion(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_MultiplyVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_MultiplyVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_MultiplyVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result = HMM_MultiplyMat4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result = HMM_MultiplyQuaternion(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, float Right)
+{
+ hmm_vec2 Result = HMM_MultiplyVec2f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, float Right)
+{
+ hmm_vec3 Result = HMM_MultiplyVec3f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, float Right)
+{
+ hmm_vec4 Result = HMM_MultiplyVec4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, float Right)
+{
+ hmm_mat4 Result = HMM_MultiplyMat4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, float Right)
+{
+ hmm_quaternion Result = HMM_MultiplyQuaternionF(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 operator*(float Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_MultiplyVec2f(Right, Left);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 operator*(float Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_MultiplyVec3f(Right, Left);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator*(float Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_MultiplyVec4f(Right, Left);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 operator*(float Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result = HMM_MultiplyMat4f(Right, Left);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion operator*(float Left, hmm_quaternion Right)
+{
+ hmm_quaternion Result = HMM_MultiplyQuaternionF(Right, Left);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator*(hmm_mat4 Matrix, hmm_vec4 Vector)
+{
+ hmm_vec4 Result = HMM_MultiplyMat4ByVec4(Matrix, Vector);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right)
+{
+ hmm_vec2 Result = HMM_DivideVec2(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right)
+{
+ hmm_vec3 Result = HMM_DivideVec3(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right)
+{
+ hmm_vec4 Result = HMM_DivideVec4(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, float Right)
+{
+ hmm_vec2 Result = HMM_DivideVec2f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, float Right)
+{
+ hmm_vec3 Result = HMM_DivideVec3f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, float Right)
+{
+ hmm_vec4 Result = HMM_DivideVec4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_mat4 operator/(hmm_mat4 Left, float Right)
+{
+ hmm_mat4 Result = HMM_DivideMat4f(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_quaternion operator/(hmm_quaternion Left, float Right)
+{
+ hmm_quaternion Result = HMM_DivideQuaternionF(Left, Right);
+
+ return (Result);
+}
+
+HMM_INLINE hmm_vec2 &operator+=(hmm_vec2 &Left, hmm_vec2 Right)
+{
+ return (Left = Left + Right);
+}
+
+HMM_INLINE hmm_vec3 &operator+=(hmm_vec3 &Left, hmm_vec3 Right)
+{
+ return (Left = Left + Right);
+}
+
+HMM_INLINE hmm_vec4 &operator+=(hmm_vec4 &Left, hmm_vec4 Right)
+{
+ return (Left = Left + Right);
+}
+
+HMM_INLINE hmm_mat4 &operator+=(hmm_mat4 &Left, hmm_mat4 Right)
+{
+ return (Left = Left + Right);
+}
+
+HMM_INLINE hmm_quaternion &operator+=(hmm_quaternion &Left, hmm_quaternion Right)
+{
+ return (Left = Left + Right);
+}
+
+HMM_INLINE hmm_vec2 &operator-=(hmm_vec2 &Left, hmm_vec2 Right)
+{
+ return (Left = Left - Right);
+}
+
+HMM_INLINE hmm_vec3 &operator-=(hmm_vec3 &Left, hmm_vec3 Right)
+{
+ return (Left = Left - Right);
+}
+
+HMM_INLINE hmm_vec4 &operator-=(hmm_vec4 &Left, hmm_vec4 Right)
+{
+ return (Left = Left - Right);
+}
+
+HMM_INLINE hmm_mat4 &operator-=(hmm_mat4 &Left, hmm_mat4 Right)
+{
+ return (Left = Left - Right);
+}
+
+HMM_INLINE hmm_quaternion &operator-=(hmm_quaternion &Left, hmm_quaternion Right)
+{
+ return (Left = Left - Right);
+}
+
+HMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, hmm_vec2 Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, hmm_vec3 Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, hmm_vec4 Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, float Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, float Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, float Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_mat4 &operator*=(hmm_mat4 &Left, float Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_quaternion &operator*=(hmm_quaternion &Left, float Right)
+{
+ return (Left = Left * Right);
+}
+
+HMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, float Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, float Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, float Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_mat4 &operator/=(hmm_mat4 &Left, float Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_quaternion &operator/=(hmm_quaternion &Left, float Right)
+{
+ return (Left = Left / Right);
+}
+
+HMM_INLINE hmm_bool operator==(hmm_vec2 Left, hmm_vec2 Right)
+{
+ return HMM_EqualsVec2(Left, Right);
+}
+
+HMM_INLINE hmm_bool operator==(hmm_vec3 Left, hmm_vec3 Right)
+{
+ return HMM_EqualsVec3(Left, Right);
+}
+
+HMM_INLINE hmm_bool operator==(hmm_vec4 Left, hmm_vec4 Right)
+{
+ return HMM_EqualsVec4(Left, Right);
+}
+
+HMM_INLINE hmm_bool operator!=(hmm_vec2 Left, hmm_vec2 Right)
+{
+ return !HMM_EqualsVec2(Left, Right);
+}
+
+HMM_INLINE hmm_bool operator!=(hmm_vec3 Left, hmm_vec3 Right)
+{
+ return !HMM_EqualsVec3(Left, Right);
+}
+
+HMM_INLINE hmm_bool operator!=(hmm_vec4 Left, hmm_vec4 Right)
+{
+ return !HMM_EqualsVec4(Left, Right);
+}
+
+#endif /* __cplusplus */
+
+#ifdef __clang__
+#pragma GCC diagnostic pop
+#endif
+
+#endif /* HANDMADE_MATH_H */
+
+#ifdef HANDMADE_MATH_IMPLEMENTATION
+
+float HMM_Power(float Base, int Exponent)
+{
+ float Result = 1.0f;
+ float Mul = Exponent < 0 ? 1.f / Base : Base;
+ unsigned int X = Exponent < 0 ? -Exponent : Exponent;
+ while (X)
+ {
+ if (X & 1)
+ {
+ Result *= Mul;
+ }
+
+ Mul *= Mul;
+ X >>= 1;
+ }
+
+ return (Result);
+}
+
+#ifndef HANDMADE_MATH__USE_SSE
+hmm_mat4 HMM_Transpose(hmm_mat4 Matrix)
+{
+ hmm_mat4 Result;
+
+ int Columns;
+ for(Columns = 0; Columns < 4; ++Columns)
+ {
+ int Rows;
+ for(Rows = 0; Rows < 4; ++Rows)
+ {
+ Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];
+ }
+ }
+
+ return (Result);
+}
+#endif
+
+#ifndef HANDMADE_MATH__USE_SSE
+hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result;
+
+ int Columns;
+ for(Columns = 0; Columns < 4; ++Columns)
+ {
+ int Rows;
+ for(Rows = 0; Rows < 4; ++Rows)
+ {
+ Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows];
+ }
+ }
+
+ return (Result);
+}
+#endif
+
+#ifndef HANDMADE_MATH__USE_SSE
+hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result;
+
+ int Columns;
+ for(Columns = 0; Columns < 4; ++Columns)
+ {
+ int Rows;
+ for(Rows = 0; Rows < 4; ++Rows)
+ {
+ Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows];
+ }
+ }
+
+ return (Result);
+}
+#endif
+
+hmm_mat4 HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right)
+{
+ hmm_mat4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+
+ Result.Columns[0] = HMM_LinearCombineSSE(Right.Columns[0], Left);
+ Result.Columns[1] = HMM_LinearCombineSSE(Right.Columns[1], Left);
+ Result.Columns[2] = HMM_LinearCombineSSE(Right.Columns[2], Left);
+ Result.Columns[3] = HMM_LinearCombineSSE(Right.Columns[3], Left);
+
+#else
+ int Columns;
+ for(Columns = 0; Columns < 4; ++Columns)
+ {
+ int Rows;
+ for(Rows = 0; Rows < 4; ++Rows)
+ {
+ float Sum = 0;
+ int CurrentMatrice;
+ for(CurrentMatrice = 0; CurrentMatrice < 4; ++CurrentMatrice)
+ {
+ Sum += Left.Elements[CurrentMatrice][Rows] * Right.Elements[Columns][CurrentMatrice];
+ }
+
+ Result.Elements[Columns][Rows] = Sum;
+ }
+ }
+#endif
+
+ return (Result);
+}
+
+#ifndef HANDMADE_MATH__USE_SSE
+hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar)
+{
+ hmm_mat4 Result;
+
+ int Columns;
+ for(Columns = 0; Columns < 4; ++Columns)
+ {
+ int Rows;
+ for(Rows = 0; Rows < 4; ++Rows)
+ {
+ Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar;
+ }
+ }
+
+ return (Result);
+}
+#endif
+
+hmm_vec4 HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector)
+{
+ hmm_vec4 Result;
+
+#ifdef HANDMADE_MATH__USE_SSE
+ Result.InternalElementsSSE = HMM_LinearCombineSSE(Vector.InternalElementsSSE, Matrix);
+#else
+ int Columns, Rows;
+ for(Rows = 0; Rows < 4; ++Rows)
+ {
+ float Sum = 0;
+ for(Columns = 0; Columns < 4; ++Columns)
+ {
+ Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns];
+ }
+
+ Result.Elements[Rows] = Sum;
+ }
+#endif
+
+ return (Result);
+}
+
+#ifndef HANDMADE_MATH__USE_SSE
+hmm_mat4 HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar)
+{
+ hmm_mat4 Result;
+
+ int Columns;
+ for(Columns = 0; Columns < 4; ++Columns)
+ {
+ int Rows;
+ for(Rows = 0; Rows < 4; ++Rows)
+ {
+ Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar;
+ }
+ }
+
+ return (Result);
+}
+#endif
+
+hmm_mat4 HMM_Rotate(float Angle, hmm_vec3 Axis)
+{
+ hmm_mat4 Result = HMM_Mat4d(1.0f);
+
+ Axis = HMM_NormalizeVec3(Axis);
+
+ float SinTheta = HMM_SinF(HMM_ToRadians(Angle));
+ float CosTheta = HMM_CosF(HMM_ToRadians(Angle));
+ float CosValue = 1.0f - CosTheta;
+
+ Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta;
+ Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta);
+ Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta);
+
+ Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta);
+ Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta;
+ Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta);
+
+ Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta);
+ Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta);
+ Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta;
+
+ return (Result);
+}
+
+hmm_mat4 HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up)
+{
+ hmm_mat4 Result;
+
+ hmm_vec3 F = HMM_NormalizeVec3(HMM_SubtractVec3(Center, Eye));
+ hmm_vec3 S = HMM_NormalizeVec3(HMM_Cross(F, Up));
+ hmm_vec3 U = HMM_Cross(S, F);
+
+ Result.Elements[0][0] = S.X;
+ Result.Elements[0][1] = U.X;
+ Result.Elements[0][2] = -F.X;
+ Result.Elements[0][3] = 0.0f;
+
+ Result.Elements[1][0] = S.Y;
+ Result.Elements[1][1] = U.Y;
+ Result.Elements[1][2] = -F.Y;
+ Result.Elements[1][3] = 0.0f;
+
+ Result.Elements[2][0] = S.Z;
+ Result.Elements[2][1] = U.Z;
+ Result.Elements[2][2] = -F.Z;
+ Result.Elements[2][3] = 0.0f;
+
+ Result.Elements[3][0] = -HMM_DotVec3(S, Eye);
+ Result.Elements[3][1] = -HMM_DotVec3(U, Eye);
+ Result.Elements[3][2] = HMM_DotVec3(F, Eye);
+ Result.Elements[3][3] = 1.0f;
+
+ return (Result);
+}
+
+hmm_quaternion HMM_InverseQuaternion(hmm_quaternion Left)
+{
+ hmm_quaternion Conjugate;
+ hmm_quaternion Result;
+ float Norm = 0;
+ float NormSquared = 0;
+
+ Conjugate.X = -Left.X;
+ Conjugate.Y = -Left.Y;
+ Conjugate.Z = -Left.Z;
+ Conjugate.W = Left.W;
+
+ Norm = HMM_SquareRootF(HMM_DotQuaternion(Left, Left));
+ NormSquared = Norm * Norm;
+
+ Result.X = Conjugate.X / NormSquared;
+ Result.Y = Conjugate.Y / NormSquared;
+ Result.Z = Conjugate.Z / NormSquared;
+ Result.W = Conjugate.W / NormSquared;
+
+ return (Result);
+}
+
+hmm_quaternion HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right)
+{
+ hmm_quaternion Result;
+ hmm_quaternion QuaternionLeft;
+ hmm_quaternion QuaternionRight;
+
+ float Cos_Theta = HMM_DotQuaternion(Left, Right);
+ float Angle = HMM_ACosF(Cos_Theta);
+
+ float S1 = HMM_SinF((1.0f - Time) * Angle);
+ float S2 = HMM_SinF(Time * Angle);
+ float Is = 1.0f / HMM_SinF(Angle);
+
+ QuaternionLeft = HMM_MultiplyQuaternionF(Left, S1);
+ QuaternionRight = HMM_MultiplyQuaternionF(Right, S2);
+
+ Result = HMM_AddQuaternion(QuaternionLeft, QuaternionRight);
+ Result = HMM_MultiplyQuaternionF(Result, Is);
+
+ return (Result);
+}
+
+hmm_mat4 HMM_QuaternionToMat4(hmm_quaternion Left)
+{
+ hmm_mat4 Result;
+ Result = HMM_Mat4d(1);
+
+ hmm_quaternion NormalizedQuaternion = HMM_NormalizeQuaternion(Left);
+
+ float XX, YY, ZZ,
+ XY, XZ, YZ,
+ WX, WY, WZ;
+
+ XX = NormalizedQuaternion.X * NormalizedQuaternion.X;
+ YY = NormalizedQuaternion.Y * NormalizedQuaternion.Y;
+ ZZ = NormalizedQuaternion.Z * NormalizedQuaternion.Z;
+ XY = NormalizedQuaternion.X * NormalizedQuaternion.Y;
+ XZ = NormalizedQuaternion.X * NormalizedQuaternion.Z;
+ YZ = NormalizedQuaternion.Y * NormalizedQuaternion.Z;
+ WX = NormalizedQuaternion.W * NormalizedQuaternion.X;
+ WY = NormalizedQuaternion.W * NormalizedQuaternion.Y;
+ WZ = NormalizedQuaternion.W * NormalizedQuaternion.Z;
+
+ Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ);
+ Result.Elements[0][1] = 2.0f * (XY + WZ);
+ Result.Elements[0][2] = 2.0f * (XZ - WY);
+
+ Result.Elements[1][0] = 2.0f * (XY - WZ);
+ Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ);
+ Result.Elements[1][2] = 2.0f * (YZ + WX);
+
+ Result.Elements[2][0] = 2.0f * (XZ + WY);
+ Result.Elements[2][1] = 2.0f * (YZ - WX);
+ Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY);
+
+ return (Result);
+}
+
+hmm_quaternion HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation)
+{
+ hmm_quaternion Result;
+
+ hmm_vec3 RotatedVector;
+
+ float AxisNorm = 0;
+ float SineOfRotation = 0;
+
+ AxisNorm = HMM_SquareRootF(HMM_DotVec3(Axis, Axis));
+ SineOfRotation = HMM_SinF(AngleOfRotation / 2.0f);
+ RotatedVector = HMM_MultiplyVec3f(Axis, SineOfRotation);
+
+ Result.W = HMM_CosF(AngleOfRotation / 2.0f);
+ Result.XYZ = HMM_DivideVec3f(RotatedVector, AxisNorm);
+
+ return (Result);
+}
+
+#endif /* HANDMADE_MATH_IMPLEMENTATION */
diff --git a/examples/skinning/morph-targets.cc b/examples/skinning/morph-targets.cc
new file mode 100644
index 0000000..645501b
--- /dev/null
+++ b/examples/skinning/morph-targets.cc
@@ -0,0 +1,22 @@
+#include <vector>
+#include <cstdlib>
+#include <cassert>
+
+void MorthTargets(std::vector<float> &weights,
+ std::vector<std::vector<float>> &targets,
+ std::vector<float> *output)
+{
+ assert(weights.size() > 0);
+ assert(targets.size() > 0);
+ assert(weights.size() == targets.size());
+
+ // Assume all position has same number of vertices;
+
+ // TODO(parallelize)
+ for (size_t v = 0; v < targets[0].size(); v++) { // for each vertex
+ (*output)[v] = 0.0f;
+ for (size_t i = 0; i < weights.size(); i++) {
+ (*output)[v] += weights[i] * targets[i][v];
+ }
+ }
+}
diff --git a/examples/skinning/premake5.lua b/examples/skinning/premake5.lua
index 8d3a969..14bf09c 100644
--- a/examples/skinning/premake5.lua
+++ b/examples/skinning/premake5.lua
@@ -18,7 +18,7 @@
kind "ConsoleApp"
language "C++"
cppdialect "C++11"
- files { "main.cc", "skinning.cc", "../common/trackball.cc", "../common/matrix.cc" }
+ files { "main.cc", "skinning.cc", "morph-targets.cc", "../common/trackball.cc", "../common/matrix.cc" }
includedirs { "./" }
includedirs { "../../" }