/*
  HandmadeMath.h v1.13.0

  This is a single header file with a bunch of useful functions for game and
  graphics math operations.

  =============================================================================

  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_NO_SSE
     #include "HandmadeMath.h"

  =============================================================================

  If you would prefer not to use the HMM_ prefix on function names, you can

  #define HMM_PREFIX

  To use a custom prefix instead, you can

  #define HMM_PREFIX(name) YOUR_PREFIX_##name

  =============================================================================

  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
     #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.

  =============================================================================

  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 (strangezak@protonmail.com && @strangezak)

  Functionality:
   Matt Mascarenhas (@miblo_)
   Aleph
   FieryDrake (@fierydrake)
   Gingerbill (@TheGingerBill)
   Ben Visness (@bvisness)
   Trinton Bullard (@Peliex_Dev)
   @AntonDan

  Fixes:
   Jeroen van Rijn (@J_vanRijn)
   Kiljacken (@Kiljacken)
   Insofaras (@insofaras)
   Daniel Gibson (@DanielGibson)
*/

// Dummy macros for when test framework is not present.
#ifndef COVERAGE
#define COVERAGE(a, b)
#endif

#ifndef ASSERT_COVERED
#define ASSERT_COVERED(a)
#endif

/* 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 */

#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

#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#if (defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) || defined(__clang__)
#pragma GCC diagnostic ignored "-Wmissing-braces"
#endif
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
#endif

#if defined(__GNUC__) || defined(__clang__)
#define HMM_DEPRECATED(msg) __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
#define HMM_DEPRECATED(msg) __declspec(deprecated(msg))
#else
#define HMM_DEPRECATED(msg)
#endif

#ifdef __cplusplus
extern "C"
{
#endif

#define HMM_INLINE static inline

#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))

#ifndef HMM_PREFIX
#define HMM_PREFIX(name) HMM_##name
#endif

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[](const 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[](const 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[](const int &Index)
    {
        return Elements[Index];
    }
#endif
} hmm_vec4;

typedef union hmm_mat4
{
    float Elements[4][4];

#ifdef HANDMADE_MATH__USE_SSE
    __m128 Columns[4];

    HMM_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)
    {
        hmm_vec4 Result;
        float* Column = Elements[Index];
        

        Result.Elements[0] = Column[0];
        Result.Elements[1] = Column[1];
        Result.Elements[2] = Column[2];
        Result.Elements[3] = Column[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];

#ifdef HANDMADE_MATH__USE_SSE
    __m128 InternalElementsSSE;
#endif
} hmm_quaternion;

typedef signed int 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
 */

COVERAGE(HMM_SinF, 1)
HMM_INLINE float HMM_PREFIX(SinF)(float Radians)
{
    ASSERT_COVERED(HMM_SinF);

    float Result = HMM_SINF(Radians);

    return (Result);
}

COVERAGE(HMM_CosF, 1)
HMM_INLINE float HMM_PREFIX(CosF)(float Radians)
{
    ASSERT_COVERED(HMM_CosF);

    float Result = HMM_COSF(Radians);

    return (Result);
}

COVERAGE(HMM_TanF, 1)
HMM_INLINE float HMM_PREFIX(TanF)(float Radians)
{
    ASSERT_COVERED(HMM_TanF);

    float Result = HMM_TANF(Radians);

    return (Result);
}

COVERAGE(HMM_ACosF, 1)
HMM_INLINE float HMM_PREFIX(ACosF)(float Radians)
{
    ASSERT_COVERED(HMM_ACosF);

    float Result = HMM_ACOSF(Radians);

    return (Result);
}

COVERAGE(HMM_ATanF, 1)
HMM_INLINE float HMM_PREFIX(ATanF)(float Radians)
{
    ASSERT_COVERED(HMM_ATanF);

    float Result = HMM_ATANF(Radians);

    return (Result);
}

COVERAGE(HMM_ATan2F, 1)
HMM_INLINE float HMM_PREFIX(ATan2F)(float Left, float Right)
{
    ASSERT_COVERED(HMM_ATan2F);

    float Result = HMM_ATAN2F(Left, Right);

    return (Result);
}

COVERAGE(HMM_ExpF, 1)
HMM_INLINE float HMM_PREFIX(ExpF)(float Float)
{
    ASSERT_COVERED(HMM_ExpF);

    float Result = HMM_EXPF(Float);

    return (Result);
}

COVERAGE(HMM_LogF, 1)
HMM_INLINE float HMM_PREFIX(LogF)(float Float)
{
    ASSERT_COVERED(HMM_LogF);

    float Result = HMM_LOGF(Float);

    return (Result);
}

COVERAGE(HMM_SquareRootF, 1)
HMM_INLINE float HMM_PREFIX(SquareRootF)(float Float)
{
    ASSERT_COVERED(HMM_SquareRootF);

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

COVERAGE(HMM_RSquareRootF, 1)
HMM_INLINE float HMM_PREFIX(RSquareRootF)(float Float)
{
    ASSERT_COVERED(HMM_RSquareRootF);

    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_PREFIX(SquareRootF)(Float);
#endif

    return(Result);
}

COVERAGE(HMM_Power, 2)
HMM_INLINE float HMM_PREFIX(Power)(float Base, int Exponent)
{
    ASSERT_COVERED(HMM_Power);

    float Result = 1.0f;
    float Mul = Exponent < 0 ? 1.f / Base : Base;
    int X = Exponent < 0 ? -Exponent : Exponent;
    while (X)
    {
        if (X & 1)
        {
            ASSERT_COVERED(HMM_Power);

            Result *= Mul;
        }

        Mul *= Mul;
        X >>= 1;
    }

    return (Result);
}

COVERAGE(HMM_PowerF, 1)
HMM_INLINE float HMM_PREFIX(PowerF)(float Base, float Exponent)
{
    ASSERT_COVERED(HMM_PowerF);

    float Result = HMM_EXPF(Exponent * HMM_LOGF(Base));

    return (Result);
}


/*
 * Utility functions
 */

COVERAGE(HMM_ToRadians, 1)
HMM_INLINE float HMM_PREFIX(ToRadians)(float Degrees)
{
    ASSERT_COVERED(HMM_ToRadians);

    float Result = Degrees * (HMM_PI32 / 180.0f);

    return (Result);
}

COVERAGE(HMM_Lerp, 1)
HMM_INLINE float HMM_PREFIX(Lerp)(float A, float Time, float B)
{
    ASSERT_COVERED(HMM_Lerp);

    float Result = (1.0f - Time) * A + Time * B;

    return (Result);
}

COVERAGE(HMM_Clamp, 1)
HMM_INLINE float HMM_PREFIX(Clamp)(float Min, float Value, float Max)
{
    ASSERT_COVERED(HMM_Clamp);

    float Result = Value;

    if(Result < Min)
    {
        Result = Min;
    }

    if(Result > Max)
    {
        Result = Max;
    }

    return (Result);
}


/*
 * Vector initialization
 */

COVERAGE(HMM_Vec2, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Vec2)(float X, float Y)
{
    ASSERT_COVERED(HMM_Vec2);

    hmm_vec2 Result;

    Result.X = X;
    Result.Y = Y;

    return (Result);
}

COVERAGE(HMM_Vec2i, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Vec2i)(int X, int Y)
{
    ASSERT_COVERED(HMM_Vec2i);

    hmm_vec2 Result;

    Result.X = (float)X;
    Result.Y = (float)Y;

    return (Result);
}

COVERAGE(HMM_Vec3, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Vec3)(float X, float Y, float Z)
{
    ASSERT_COVERED(HMM_Vec3);

    hmm_vec3 Result;

    Result.X = X;
    Result.Y = Y;
    Result.Z = Z;

    return (Result);
}

COVERAGE(HMM_Vec3i, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Vec3i)(int X, int Y, int Z)
{
    ASSERT_COVERED(HMM_Vec3i);

    hmm_vec3 Result;

    Result.X = (float)X;
    Result.Y = (float)Y;
    Result.Z = (float)Z;

    return (Result);
}

COVERAGE(HMM_Vec4, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Vec4)(float X, float Y, float Z, float W)
{
    ASSERT_COVERED(HMM_Vec4);

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

COVERAGE(HMM_Vec4i, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Vec4i)(int X, int Y, int Z, int W)
{
    ASSERT_COVERED(HMM_Vec4i);

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

COVERAGE(HMM_Vec4v, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Vec4v)(hmm_vec3 Vector, float W)
{
    ASSERT_COVERED(HMM_Vec4v);

    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
 */

COVERAGE(HMM_AddVec2, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(AddVec2)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_AddVec2);

    hmm_vec2 Result;

    Result.X = Left.X + Right.X;
    Result.Y = Left.Y + Right.Y;

    return (Result);
}

COVERAGE(HMM_AddVec3, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(AddVec3)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_AddVec3);

    hmm_vec3 Result;

    Result.X = Left.X + Right.X;
    Result.Y = Left.Y + Right.Y;
    Result.Z = Left.Z + Right.Z;

    return (Result);
}

COVERAGE(HMM_AddVec4, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(AddVec4)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_AddVec4);

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

COVERAGE(HMM_SubtractVec2, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(SubtractVec2)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_SubtractVec2);

    hmm_vec2 Result;

    Result.X = Left.X - Right.X;
    Result.Y = Left.Y - Right.Y;

    return (Result);
}

COVERAGE(HMM_SubtractVec3, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(SubtractVec3)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_SubtractVec3);

    hmm_vec3 Result;

    Result.X = Left.X - Right.X;
    Result.Y = Left.Y - Right.Y;
    Result.Z = Left.Z - Right.Z;

    return (Result);
}

COVERAGE(HMM_SubtractVec4, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(SubtractVec4)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_SubtractVec4);

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

COVERAGE(HMM_MultiplyVec2, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(MultiplyVec2)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2);

    hmm_vec2 Result;

    Result.X = Left.X * Right.X;
    Result.Y = Left.Y * Right.Y;

    return (Result);
}

COVERAGE(HMM_MultiplyVec2f, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(MultiplyVec2f)(hmm_vec2 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2f);

    hmm_vec2 Result;

    Result.X = Left.X * Right;
    Result.Y = Left.Y * Right;

    return (Result);
}

COVERAGE(HMM_MultiplyVec3, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(MultiplyVec3)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3);

    hmm_vec3 Result;

    Result.X = Left.X * Right.X;
    Result.Y = Left.Y * Right.Y;
    Result.Z = Left.Z * Right.Z;

    return (Result);
}

COVERAGE(HMM_MultiplyVec3f, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(MultiplyVec3f)(hmm_vec3 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3f);

    hmm_vec3 Result;

    Result.X = Left.X * Right;
    Result.Y = Left.Y * Right;
    Result.Z = Left.Z * Right;

    return (Result);
}

COVERAGE(HMM_MultiplyVec4, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyVec4)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4);

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

COVERAGE(HMM_MultiplyVec4f, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyVec4f)(hmm_vec4 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4f);

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

COVERAGE(HMM_DivideVec2, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(DivideVec2)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_DivideVec2);

    hmm_vec2 Result;

    Result.X = Left.X / Right.X;
    Result.Y = Left.Y / Right.Y;

    return (Result);
}

COVERAGE(HMM_DivideVec2f, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(DivideVec2f)(hmm_vec2 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec2f);

    hmm_vec2 Result;

    Result.X = Left.X / Right;
    Result.Y = Left.Y / Right;

    return (Result);
}

COVERAGE(HMM_DivideVec3, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(DivideVec3)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_DivideVec3);

    hmm_vec3 Result;

    Result.X = Left.X / Right.X;
    Result.Y = Left.Y / Right.Y;
    Result.Z = Left.Z / Right.Z;

    return (Result);
}

COVERAGE(HMM_DivideVec3f, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(DivideVec3f)(hmm_vec3 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec3f);

    hmm_vec3 Result;

    Result.X = Left.X / Right;
    Result.Y = Left.Y / Right;
    Result.Z = Left.Z / Right;

    return (Result);
}

COVERAGE(HMM_DivideVec4, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(DivideVec4)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_DivideVec4);

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

COVERAGE(HMM_DivideVec4f, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(DivideVec4f)(hmm_vec4 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec4f);

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

COVERAGE(HMM_EqualsVec2, 1)
HMM_INLINE hmm_bool HMM_PREFIX(EqualsVec2)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_EqualsVec2);

    hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y);

    return (Result);
}

COVERAGE(HMM_EqualsVec3, 1)
HMM_INLINE hmm_bool HMM_PREFIX(EqualsVec3)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_EqualsVec3);

    hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z);

    return (Result);
}

COVERAGE(HMM_EqualsVec4, 1)
HMM_INLINE hmm_bool HMM_PREFIX(EqualsVec4)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_EqualsVec4);

    hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W);

    return (Result);
}

COVERAGE(HMM_DotVec2, 1)
HMM_INLINE float HMM_PREFIX(DotVec2)(hmm_vec2 VecOne, hmm_vec2 VecTwo)
{
    ASSERT_COVERED(HMM_DotVec2);

    float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y);

    return (Result);
}

COVERAGE(HMM_DotVec3, 1)
HMM_INLINE float HMM_PREFIX(DotVec3)(hmm_vec3 VecOne, hmm_vec3 VecTwo)
{
    ASSERT_COVERED(HMM_DotVec3);

    float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z);

    return (Result);
}

COVERAGE(HMM_DotVec4, 1)
HMM_INLINE float HMM_PREFIX(DotVec4)(hmm_vec4 VecOne, hmm_vec4 VecTwo)
{
    ASSERT_COVERED(HMM_DotVec4);

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

COVERAGE(HMM_Cross, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Cross)(hmm_vec3 VecOne, hmm_vec3 VecTwo)
{
    ASSERT_COVERED(HMM_Cross);

    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
 */

COVERAGE(HMM_LengthSquaredVec2, 1)
HMM_INLINE float HMM_PREFIX(LengthSquaredVec2)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_LengthSquaredVec2);

    float Result = HMM_PREFIX(DotVec2)(A, A);

    return (Result);
}

COVERAGE(HMM_LengthSquaredVec3, 1)
HMM_INLINE float HMM_PREFIX(LengthSquaredVec3)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_LengthSquaredVec3);

    float Result = HMM_PREFIX(DotVec3)(A, A);

    return (Result);
}

COVERAGE(HMM_LengthSquaredVec4, 1)
HMM_INLINE float HMM_PREFIX(LengthSquaredVec4)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_LengthSquaredVec4);

    float Result = HMM_PREFIX(DotVec4)(A, A);

    return (Result);
}

COVERAGE(HMM_LengthVec2, 1)
HMM_INLINE float HMM_PREFIX(LengthVec2)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_LengthVec2);

    float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec2)(A));

    return (Result);
}

COVERAGE(HMM_LengthVec3, 1)
HMM_INLINE float HMM_PREFIX(LengthVec3)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_LengthVec3);

    float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec3)(A));

    return (Result);
}

COVERAGE(HMM_LengthVec4, 1)
HMM_INLINE float HMM_PREFIX(LengthVec4)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_LengthVec4);

    float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec4)(A));

    return(Result);
}

COVERAGE(HMM_NormalizeVec2, 2)
HMM_INLINE hmm_vec2 HMM_PREFIX(NormalizeVec2)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_NormalizeVec2);

    hmm_vec2 Result = {0};

    float VectorLength = HMM_PREFIX(LengthVec2)(A);

    /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
    if (VectorLength != 0.0f)
    {
        ASSERT_COVERED(HMM_NormalizeVec2);

        Result.X = A.X * (1.0f / VectorLength);
        Result.Y = A.Y * (1.0f / VectorLength);
    }

    return (Result);
}

COVERAGE(HMM_NormalizeVec3, 2)
HMM_INLINE hmm_vec3 HMM_PREFIX(NormalizeVec3)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_NormalizeVec3);

    hmm_vec3 Result = {0};

    float VectorLength = HMM_PREFIX(LengthVec3)(A);

    /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
    if (VectorLength != 0.0f)
    {
        ASSERT_COVERED(HMM_NormalizeVec3);

        Result.X = A.X * (1.0f / VectorLength);
        Result.Y = A.Y * (1.0f / VectorLength);
        Result.Z = A.Z * (1.0f / VectorLength);
    }

    return (Result);
}

COVERAGE(HMM_NormalizeVec4, 2)
HMM_INLINE hmm_vec4 HMM_PREFIX(NormalizeVec4)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_NormalizeVec4);

    hmm_vec4 Result = {0};

    float VectorLength = HMM_PREFIX(LengthVec4)(A);

    /* NOTE(kiljacken): We need a zero check to not divide-by-zero */
    if (VectorLength != 0.0f)
    {
        ASSERT_COVERED(HMM_NormalizeVec4);

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

COVERAGE(HMM_FastNormalizeVec2, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(FastNormalizeVec2)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_FastNormalizeVec2);

    return HMM_PREFIX(MultiplyVec2f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec2)(A, A)));
}

COVERAGE(HMM_FastNormalizeVec3, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(FastNormalizeVec3)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_FastNormalizeVec3);

    return HMM_PREFIX(MultiplyVec3f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec3)(A, A)));
}

COVERAGE(HMM_FastNormalizeVec4, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(FastNormalizeVec4)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_FastNormalizeVec4);

    return HMM_PREFIX(MultiplyVec4f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec4)(A, A)));
}


/*
 * SSE stuff
 */

#ifdef HANDMADE_MATH__USE_SSE
COVERAGE(HMM_LinearCombineSSE, 1)
HMM_INLINE __m128 HMM_PREFIX(LinearCombineSSE)(__m128 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_LinearCombineSSE);

    __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
 */

COVERAGE(HMM_Mat4, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Mat4)(void)
{
    ASSERT_COVERED(HMM_Mat4);

    hmm_mat4 Result = {0};

    return (Result);
}

COVERAGE(HMM_Mat4d, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Mat4d)(float Diagonal)
{
    ASSERT_COVERED(HMM_Mat4d);

    hmm_mat4 Result = HMM_PREFIX(Mat4)();

    Result.Elements[0][0] = Diagonal;
    Result.Elements[1][1] = Diagonal;
    Result.Elements[2][2] = Diagonal;
    Result.Elements[3][3] = Diagonal;

    return (Result);
}

COVERAGE(HMM_Transpose, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Transpose)(hmm_mat4 Matrix)
{
    ASSERT_COVERED(HMM_Transpose);

    hmm_mat4 Result = Matrix;

#ifdef HANDMADE_MATH__USE_SSE
    _MM_TRANSPOSE4_PS(Result.Columns[0], Result.Columns[1], Result.Columns[2], Result.Columns[3]);
#else
    int Columns;
    for(Columns = 0; Columns < 4; ++Columns)
    {
        int Rows;
        for(Rows = 0; Rows < 4; ++Rows)
        {
            Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];
        }
    }
#endif


    return (Result);
}

COVERAGE(HMM_AddMat4, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(AddMat4)(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_AddMat4);

    hmm_mat4 Result;

#ifdef HANDMADE_MATH__USE_SSE
    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]);
#else
     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];
        }
    }
#endif

   
    return (Result);
}

COVERAGE(HMM_SubtractMat4, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(SubtractMat4)(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_SubtractMat4);

    hmm_mat4 Result;

#ifdef HANDMADE_MATH__USE_SSE
    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]);
#else
    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];
        }
    }
#endif
 
    return (Result);
}

COVERAGE(HMM_MultiplyMat4, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(MultiplyMat4)(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_MultiplyMat4);

    hmm_mat4 Result;

#ifdef HANDMADE_MATH__USE_SSE
    Result.Columns[0] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[0], Left);
    Result.Columns[1] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[1], Left);
    Result.Columns[2] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[2], Left);
    Result.Columns[3] = HMM_PREFIX(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);
}


COVERAGE(HMM_MultiplyMat4f, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(MultiplyMat4f)(hmm_mat4 Matrix, float Scalar)
{
    ASSERT_COVERED(HMM_MultiplyMat4f);

    hmm_mat4 Result;

#ifdef HANDMADE_MATH__USE_SSE
    __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);
#else
    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;
        }
    }
#endif

    return (Result);
}

COVERAGE(HMM_MultiplyMat4ByVec4, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyMat4ByVec4)(hmm_mat4 Matrix, hmm_vec4 Vector)
{
    ASSERT_COVERED(HMM_MultiplyMat4ByVec4);

    hmm_vec4 Result;

#ifdef HANDMADE_MATH__USE_SSE
    Result.InternalElementsSSE = HMM_PREFIX(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);
}


COVERAGE(HMM_DivideMat4f, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(DivideMat4f)(hmm_mat4 Matrix, float Scalar)
{
    ASSERT_COVERED(HMM_DivideMat4f);

    hmm_mat4 Result;

#ifdef HANDMADE_MATH__USE_SSE
    __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);
#else
    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;
        }
    }
#endif

    return (Result);
}

/*
 * Common graphics transformations
 */

COVERAGE(HMM_Orthographic, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Orthographic)(float Left, float Right, float Bottom, float Top, float Near, float Far)
{
    ASSERT_COVERED(HMM_Orthographic);

    hmm_mat4 Result = HMM_PREFIX(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);
}

COVERAGE(HMM_Perspective, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Perspective)(float FOV, float AspectRatio, float Near, float Far)
{
    ASSERT_COVERED(HMM_Perspective);

    hmm_mat4 Result = HMM_PREFIX(Mat4)();

    // See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml

    float Cotangent = 1.0f / HMM_PREFIX(TanF)(FOV * (HMM_PI32 / 360.0f));

    Result.Elements[0][0] = Cotangent / AspectRatio;
    Result.Elements[1][1] = Cotangent;
    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);
}

COVERAGE(HMM_Translate, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Translate)(hmm_vec3 Translation)
{
    ASSERT_COVERED(HMM_Translate);

    hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f);

    Result.Elements[3][0] = Translation.X;
    Result.Elements[3][1] = Translation.Y;
    Result.Elements[3][2] = Translation.Z;

    return (Result);
}

COVERAGE(HMM_Rotate, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Rotate)(float Angle, hmm_vec3 Axis)
{
    ASSERT_COVERED(HMM_Rotate);

    hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f);

    Axis = HMM_PREFIX(NormalizeVec3)(Axis);

    float SinTheta = HMM_PREFIX(SinF)(HMM_PREFIX(ToRadians)(Angle));
    float CosTheta = HMM_PREFIX(CosF)(HMM_PREFIX(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);
}



COVERAGE(HMM_Scale, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Scale)(hmm_vec3 Scale)
{
    ASSERT_COVERED(HMM_Scale);

    hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f);

    Result.Elements[0][0] = Scale.X;
    Result.Elements[1][1] = Scale.Y;
    Result.Elements[2][2] = Scale.Z;

    return (Result);
}

COVERAGE(HMM_LookAt, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(LookAt)(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up)
{
    ASSERT_COVERED(HMM_LookAt);

    hmm_mat4 Result;

    hmm_vec3 F = HMM_PREFIX(NormalizeVec3)(HMM_PREFIX(SubtractVec3)(Center, Eye));
    hmm_vec3 S = HMM_PREFIX(NormalizeVec3)(HMM_PREFIX(Cross)(F, Up));
    hmm_vec3 U = HMM_PREFIX(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_PREFIX(DotVec3)(S, Eye);
    Result.Elements[3][1] = -HMM_PREFIX(DotVec3)(U, Eye);
    Result.Elements[3][2] = HMM_PREFIX(DotVec3)(F, Eye);
    Result.Elements[3][3] = 1.0f;

    return (Result);
}

/*
 * Quaternion operations
 */

COVERAGE(HMM_Quaternion, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Quaternion)(float X, float Y, float Z, float W)
{
    ASSERT_COVERED(HMM_Quaternion);

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

COVERAGE(HMM_QuaternionV4, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(QuaternionV4)(hmm_vec4 Vector)
{
    ASSERT_COVERED(HMM_QuaternionV4);

    hmm_quaternion Result;

#ifdef HANDMADE_MATH__USE_SSE
    Result.InternalElementsSSE = Vector.InternalElementsSSE;
#else
    Result.X = Vector.X;
    Result.Y = Vector.Y;
    Result.Z = Vector.Z;
    Result.W = Vector.W;
#endif

    return (Result);
}

COVERAGE(HMM_AddQuaternion, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(AddQuaternion)(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_AddQuaternion);

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

COVERAGE(HMM_SubtractQuaternion, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(SubtractQuaternion)(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_SubtractQuaternion);

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

COVERAGE(HMM_MultiplyQuaternion, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(MultiplyQuaternion)(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_MultiplyQuaternion);

    hmm_quaternion Result;

#ifdef HANDMADE_MATH__USE_SSE
    __m128 SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(0, 0, 0, 0)), _mm_setr_ps(0.f, -0.f, 0.f, -0.f));
    __m128 SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(0, 1, 2, 3));
    __m128 SSEResultThree = _mm_mul_ps(SSEResultTwo, SSEResultOne);

    SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(1, 1, 1, 1)) , _mm_setr_ps(0.f, 0.f, -0.f, -0.f));
    SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(1, 0, 3, 2));
    SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));

    SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(2, 2, 2, 2)), _mm_setr_ps(-0.f, 0.f, 0.f, -0.f));
    SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(2, 3, 0, 1));
    SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));

    SSEResultOne = _mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(3, 3, 3, 3));
    SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(3, 2, 1, 0));
    Result.InternalElementsSSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));
#else
    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);
#endif

    return (Result);
}

COVERAGE(HMM_MultiplyQuaternionF, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(MultiplyQuaternionF)(hmm_quaternion Left, float Multiplicative)
{
    ASSERT_COVERED(HMM_MultiplyQuaternionF);

    hmm_quaternion Result;

#ifdef HANDMADE_MATH__USE_SSE
    __m128 Scalar = _mm_set1_ps(Multiplicative);
    Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Scalar);
#else
    Result.X = Left.X * Multiplicative;
    Result.Y = Left.Y * Multiplicative;
    Result.Z = Left.Z * Multiplicative;
    Result.W = Left.W * Multiplicative;
#endif

    return (Result);
}

COVERAGE(HMM_DivideQuaternionF, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(DivideQuaternionF)(hmm_quaternion Left, float Dividend)
{
    ASSERT_COVERED(HMM_DivideQuaternionF);

    hmm_quaternion Result;

#ifdef HANDMADE_MATH__USE_SSE
    __m128 Scalar = _mm_set1_ps(Dividend);
    Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Scalar);
#else
    Result.X = Left.X / Dividend;
    Result.Y = Left.Y / Dividend;
    Result.Z = Left.Z / Dividend;
    Result.W = Left.W / Dividend;
#endif

    return (Result);
}

COVERAGE(HMM_DotQuaternion, 1)
HMM_INLINE float HMM_PREFIX(DotQuaternion)(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_DotQuaternion);

    float Result;

#ifdef HANDMADE_MATH__USE_SSE
    __m128 SSEResultOne = _mm_mul_ps(Left.InternalElementsSSE, Right.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 = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W);
#endif

    return (Result);
}


COVERAGE(HMM_InverseQuaternion, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(InverseQuaternion)(hmm_quaternion Left)
{
    ASSERT_COVERED(HMM_InverseQuaternion);
    
    hmm_quaternion Result;

    Result.X = -Left.X;
    Result.Y = -Left.Y;
    Result.Z = -Left.Z;
    Result.W = Left.W;

    Result = HMM_PREFIX(DivideQuaternionF)(Result, (HMM_PREFIX(DotQuaternion)(Left, Left)));

    return (Result);
}


COVERAGE(HMM_NormalizeQuaternion, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(NormalizeQuaternion)(hmm_quaternion Left)
{
    ASSERT_COVERED(HMM_NormalizeQuaternion);

    hmm_quaternion Result;

    float Length = HMM_PREFIX(SquareRootF)(HMM_PREFIX(DotQuaternion)(Left, Left));
    Result = HMM_PREFIX(DivideQuaternionF)(Left, Length);

    return (Result);
}

COVERAGE(HMM_NLerp, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(NLerp)(hmm_quaternion Left, float Time, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_NLerp);

    hmm_quaternion Result;

#ifdef HANDMADE_MATH__USE_SSE
    __m128 ScalarLeft = _mm_set1_ps(1.0f - Time);
    __m128 ScalarRight = _mm_set1_ps(Time);
    __m128 SSEResultOne = _mm_mul_ps(Left.InternalElementsSSE, ScalarLeft);
    __m128 SSEResultTwo = _mm_mul_ps(Right.InternalElementsSSE, ScalarRight);
    Result.InternalElementsSSE = _mm_add_ps(SSEResultOne, SSEResultTwo);
#else
    Result.X = HMM_PREFIX(Lerp)(Left.X, Time, Right.X);
    Result.Y = HMM_PREFIX(Lerp)(Left.Y, Time, Right.Y);
    Result.Z = HMM_PREFIX(Lerp)(Left.Z, Time, Right.Z);
    Result.W = HMM_PREFIX(Lerp)(Left.W, Time, Right.W);
#endif
    Result = HMM_PREFIX(NormalizeQuaternion)(Result);

    return (Result);
}

COVERAGE(HMM_Slerp, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Slerp)(hmm_quaternion Left, float Time, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_Slerp);

    hmm_quaternion Result;
    hmm_quaternion QuaternionLeft;
    hmm_quaternion QuaternionRight;

    float Cos_Theta = HMM_PREFIX(DotQuaternion)(Left, Right);
    float Angle = HMM_PREFIX(ACosF)(Cos_Theta);

    float S1 = HMM_PREFIX(SinF)((1.0f - Time) * Angle);
    float S2 = HMM_PREFIX(SinF)(Time * Angle);
    float Is = 1.0f / HMM_PREFIX(SinF)(Angle);

    QuaternionLeft = HMM_PREFIX(MultiplyQuaternionF)(Left, S1);
    QuaternionRight = HMM_PREFIX(MultiplyQuaternionF)(Right, S2);

    Result = HMM_PREFIX(AddQuaternion)(QuaternionLeft, QuaternionRight);
    Result = HMM_PREFIX(MultiplyQuaternionF)(Result, Is);

    return (Result);
}

COVERAGE(HMM_QuaternionToMat4, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(QuaternionToMat4)(hmm_quaternion Left)
{
    ASSERT_COVERED(HMM_QuaternionToMat4);

    hmm_mat4 Result;

    hmm_quaternion NormalizedQuaternion = HMM_PREFIX(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[0][3] = 0.0f;

    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[1][3] = 0.0f;

    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);
    Result.Elements[2][3] = 0.0f;

    Result.Elements[3][0] = 0.0f;
    Result.Elements[3][1] = 0.0f;
    Result.Elements[3][2] = 0.0f;
    Result.Elements[3][3] = 1.0f;

    return (Result);
}

// This method taken from Mike Day at Insomniac Games.
// https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf
//
// Note that as mentioned at the top of the paper, the paper assumes the matrix
// would be *post*-multiplied to a vector to rotate it, meaning the matrix is
// the transpose of what we're dealing with. But, because our matrices are
// stored in column-major order, the indices *appear* to match the paper.
//
// For example, m12 in the paper is row 1, column 2. We need to transpose it to
// row 2, column 1. But, because the column comes first when referencing
// elements, it looks like M.Elements[1][2].
//
// Don't be confused! Or if you must be confused, at least trust this
// comment. :)
COVERAGE(HMM_Mat4ToQuaternion, 4)
HMM_INLINE hmm_quaternion HMM_PREFIX(Mat4ToQuaternion)(hmm_mat4 M)
{
    float T;
    hmm_quaternion Q;

    if (M.Elements[2][2] < 0.0f) {
        if (M.Elements[0][0] > M.Elements[1][1]) {
            ASSERT_COVERED(HMM_Mat4ToQuaternion);

            T = 1 + M.Elements[0][0] - M.Elements[1][1] - M.Elements[2][2];
            Q = HMM_PREFIX(Quaternion)(
                T,
                M.Elements[0][1] + M.Elements[1][0],
                M.Elements[2][0] + M.Elements[0][2],
                M.Elements[1][2] - M.Elements[2][1]
            );
        } else {
            ASSERT_COVERED(HMM_Mat4ToQuaternion);

            T = 1 - M.Elements[0][0] + M.Elements[1][1] - M.Elements[2][2];
            Q = HMM_PREFIX(Quaternion)(
                M.Elements[0][1] + M.Elements[1][0],
                T,
                M.Elements[1][2] + M.Elements[2][1],
                M.Elements[2][0] - M.Elements[0][2]
            );
        }
    } else {
        if (M.Elements[0][0] < -M.Elements[1][1]) {
            ASSERT_COVERED(HMM_Mat4ToQuaternion);

            T = 1 - M.Elements[0][0] - M.Elements[1][1] + M.Elements[2][2];
            Q = HMM_PREFIX(Quaternion)(
                M.Elements[2][0] + M.Elements[0][2],
                M.Elements[1][2] + M.Elements[2][1],
                T,
                M.Elements[0][1] - M.Elements[1][0]
            );
        } else {
            ASSERT_COVERED(HMM_Mat4ToQuaternion);

            T = 1 + M.Elements[0][0] + M.Elements[1][1] + M.Elements[2][2];
            Q = HMM_PREFIX(Quaternion)(
                M.Elements[1][2] - M.Elements[2][1],
                M.Elements[2][0] - M.Elements[0][2],
                M.Elements[0][1] - M.Elements[1][0],
                T
            );
        }
    }

    Q = HMM_PREFIX(MultiplyQuaternionF)(Q, 0.5f / HMM_PREFIX(SquareRootF)(T));

    return Q;
}

COVERAGE(HMM_QuaternionFromAxisAngle, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(QuaternionFromAxisAngle)(hmm_vec3 Axis, float AngleOfRotation)
{
    ASSERT_COVERED(HMM_QuaternionFromAxisAngle);

    hmm_quaternion Result;

    hmm_vec3 AxisNormalized = HMM_PREFIX(NormalizeVec3)(Axis);
    float SineOfRotation = HMM_PREFIX(SinF)(AngleOfRotation / 2.0f);

    Result.XYZ = HMM_PREFIX(MultiplyVec3f)(AxisNormalized, SineOfRotation);
    Result.W = HMM_PREFIX(CosF)(AngleOfRotation / 2.0f);

    return (Result);
}

#ifdef __cplusplus
}
#endif

#ifdef __cplusplus

COVERAGE(HMM_LengthVec2CPP, 1)
HMM_INLINE float HMM_PREFIX(Length)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_LengthVec2CPP);

    float Result = HMM_PREFIX(LengthVec2)(A);
    return (Result);
}

COVERAGE(HMM_LengthVec3CPP, 1)
HMM_INLINE float HMM_PREFIX(Length)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_LengthVec3CPP);

    float Result = HMM_PREFIX(LengthVec3)(A);

    return (Result);
}

COVERAGE(HMM_LengthVec4CPP, 1)
HMM_INLINE float HMM_PREFIX(Length)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_LengthVec4CPP);

    float Result = HMM_PREFIX(LengthVec4)(A);

    return (Result);
}

COVERAGE(HMM_LengthSquaredVec2CPP, 1)
HMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_LengthSquaredVec2CPP);

    float Result = HMM_PREFIX(LengthSquaredVec2)(A);

    return (Result);
}

COVERAGE(HMM_LengthSquaredVec3CPP, 1)
HMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_LengthSquaredVec3CPP);

    float Result = HMM_PREFIX(LengthSquaredVec3)(A);

    return (Result);
}

COVERAGE(HMM_LengthSquaredVec4CPP, 1)
HMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_LengthSquaredVec4CPP);

    float Result = HMM_PREFIX(LengthSquaredVec4)(A);

    return (Result);
}

COVERAGE(HMM_NormalizeVec2CPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Normalize)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_NormalizeVec2CPP);

    hmm_vec2 Result = HMM_PREFIX(NormalizeVec2)(A);

    return (Result);
}

COVERAGE(HMM_NormalizeVec3CPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Normalize)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_NormalizeVec3CPP);

    hmm_vec3 Result = HMM_PREFIX(NormalizeVec3)(A);

    return (Result);
}

COVERAGE(HMM_NormalizeVec4CPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Normalize)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_NormalizeVec4CPP);

    hmm_vec4 Result = HMM_PREFIX(NormalizeVec4)(A);

    return (Result);
}

COVERAGE(HMM_FastNormalizeVec2CPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(FastNormalize)(hmm_vec2 A)
{
    ASSERT_COVERED(HMM_FastNormalizeVec2CPP);

    hmm_vec2 Result = HMM_PREFIX(FastNormalizeVec2)(A);

    return (Result);
}

COVERAGE(HMM_FastNormalizeVec3CPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(FastNormalize)(hmm_vec3 A)
{
    ASSERT_COVERED(HMM_FastNormalizeVec3CPP);

    hmm_vec3 Result = HMM_PREFIX(FastNormalizeVec3)(A);

    return (Result);
}

COVERAGE(HMM_FastNormalizeVec4CPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(FastNormalize)(hmm_vec4 A)
{
    ASSERT_COVERED(HMM_FastNormalizeVec4CPP);

    hmm_vec4 Result = HMM_PREFIX(FastNormalizeVec4)(A);

    return (Result);
}

COVERAGE(HMM_NormalizeQuaternionCPP, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Normalize)(hmm_quaternion A)
{
    ASSERT_COVERED(HMM_NormalizeQuaternionCPP);

    hmm_quaternion Result = HMM_PREFIX(NormalizeQuaternion)(A);

    return (Result);
}

COVERAGE(HMM_DotVec2CPP, 1)
HMM_INLINE float HMM_PREFIX(Dot)(hmm_vec2 VecOne, hmm_vec2 VecTwo)
{
    ASSERT_COVERED(HMM_DotVec2CPP);

    float Result = HMM_PREFIX(DotVec2)(VecOne, VecTwo);

    return (Result);
}

COVERAGE(HMM_DotVec3CPP, 1)
HMM_INLINE float HMM_PREFIX(Dot)(hmm_vec3 VecOne, hmm_vec3 VecTwo)
{
    ASSERT_COVERED(HMM_DotVec3CPP);

    float Result = HMM_PREFIX(DotVec3)(VecOne, VecTwo);

    return (Result);
}

COVERAGE(HMM_DotVec4CPP, 1)
HMM_INLINE float HMM_PREFIX(Dot)(hmm_vec4 VecOne, hmm_vec4 VecTwo)
{
    ASSERT_COVERED(HMM_DotVec4CPP);

    float Result = HMM_PREFIX(DotVec4)(VecOne, VecTwo);

    return (Result);
}

COVERAGE(HMM_DotQuaternionCPP, 1)
HMM_INLINE float HMM_PREFIX(Dot)(hmm_quaternion QuatOne, hmm_quaternion QuatTwo)
{
    ASSERT_COVERED(HMM_DotQuaternionCPP);

    float Result = HMM_PREFIX(DotQuaternion)(QuatOne, QuatTwo);

    return (Result);
}

COVERAGE(HMM_AddVec2CPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Add)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_AddVec2CPP);

    hmm_vec2 Result = HMM_PREFIX(AddVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddVec3CPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Add)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_AddVec3CPP);

    hmm_vec3 Result = HMM_PREFIX(AddVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddVec4CPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Add)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_AddVec4CPP);

    hmm_vec4 Result = HMM_PREFIX(AddVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddMat4CPP, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Add)(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_AddMat4CPP);

    hmm_mat4 Result = HMM_PREFIX(AddMat4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddQuaternionCPP, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Add)(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_AddQuaternionCPP);

    hmm_quaternion Result = HMM_PREFIX(AddQuaternion)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractVec2CPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Subtract)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_SubtractVec2CPP);

    hmm_vec2 Result = HMM_PREFIX(SubtractVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractVec3CPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Subtract)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_SubtractVec3CPP);

    hmm_vec3 Result = HMM_PREFIX(SubtractVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractVec4CPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Subtract)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_SubtractVec4CPP);

    hmm_vec4 Result = HMM_PREFIX(SubtractVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractMat4CPP, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Subtract)(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_SubtractMat4CPP);

    hmm_mat4 Result = HMM_PREFIX(SubtractMat4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractQuaternionCPP, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Subtract)(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_SubtractQuaternionCPP);

    hmm_quaternion Result = HMM_PREFIX(SubtractQuaternion)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec2CPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Multiply)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2CPP);

    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec2fCPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Multiply)(hmm_vec2 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2fCPP);

    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec3CPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Multiply)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3CPP);

    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec3fCPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Multiply)(hmm_vec3 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3fCPP);

    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec4CPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4CPP);

    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec4fCPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_vec4 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4fCPP);

    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyMat4CPP, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Multiply)(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_MultiplyMat4CPP);

    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyMat4fCPP, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Multiply)(hmm_mat4 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyMat4fCPP);

    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyMat4ByVec4CPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_mat4 Matrix, hmm_vec4 Vector)
{
    ASSERT_COVERED(HMM_MultiplyMat4ByVec4CPP);

    hmm_vec4 Result = HMM_PREFIX(MultiplyMat4ByVec4)(Matrix, Vector);

    return (Result);
}

COVERAGE(HMM_MultiplyQuaternionCPP, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Multiply)(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_MultiplyQuaternionCPP);

    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternion)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyQuaternionFCPP, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Multiply)(hmm_quaternion Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyQuaternionFCPP);

    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec2CPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Divide)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_DivideVec2CPP);

    hmm_vec2 Result = HMM_PREFIX(DivideVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec2fCPP, 1)
HMM_INLINE hmm_vec2 HMM_PREFIX(Divide)(hmm_vec2 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec2fCPP);

    hmm_vec2 Result = HMM_PREFIX(DivideVec2f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec3CPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Divide)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_DivideVec3CPP);

    hmm_vec3 Result = HMM_PREFIX(DivideVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec3fCPP, 1)
HMM_INLINE hmm_vec3 HMM_PREFIX(Divide)(hmm_vec3 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec3fCPP);

    hmm_vec3 Result = HMM_PREFIX(DivideVec3f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec4CPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Divide)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_DivideVec4CPP);

    hmm_vec4 Result = HMM_PREFIX(DivideVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec4fCPP, 1)
HMM_INLINE hmm_vec4 HMM_PREFIX(Divide)(hmm_vec4 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec4fCPP);

    hmm_vec4 Result = HMM_PREFIX(DivideVec4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideMat4fCPP, 1)
HMM_INLINE hmm_mat4 HMM_PREFIX(Divide)(hmm_mat4 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideMat4fCPP);

    hmm_mat4 Result = HMM_PREFIX(DivideMat4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideQuaternionFCPP, 1)
HMM_INLINE hmm_quaternion HMM_PREFIX(Divide)(hmm_quaternion Left, float Right)
{
    ASSERT_COVERED(HMM_DivideQuaternionFCPP);

    hmm_quaternion Result = HMM_PREFIX(DivideQuaternionF)(Left, Right);

    return (Result);
}

COVERAGE(HMM_EqualsVec2CPP, 1)
HMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_EqualsVec2CPP);

    hmm_bool Result = HMM_PREFIX(EqualsVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_EqualsVec3CPP, 1)
HMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_EqualsVec3CPP);

    hmm_bool Result = HMM_PREFIX(EqualsVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_EqualsVec4CPP, 1)
HMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_EqualsVec4CPP);

    hmm_bool Result = HMM_PREFIX(EqualsVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddVec2Op, 1)
HMM_INLINE hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_AddVec2Op);

    hmm_vec2 Result = HMM_PREFIX(AddVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddVec3Op, 1)
HMM_INLINE hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_AddVec3Op);

    hmm_vec3 Result = HMM_PREFIX(AddVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddVec4Op, 1)
HMM_INLINE hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_AddVec4Op);

    hmm_vec4 Result = HMM_PREFIX(AddVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddMat4Op, 1)
HMM_INLINE hmm_mat4 operator+(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_AddMat4Op);

    hmm_mat4 Result = HMM_PREFIX(AddMat4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddQuaternionOp, 1)
HMM_INLINE hmm_quaternion operator+(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_AddQuaternionOp);

    hmm_quaternion Result = HMM_PREFIX(AddQuaternion)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractVec2Op, 1)
HMM_INLINE hmm_vec2 operator-(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_SubtractVec2Op);

    hmm_vec2 Result = HMM_PREFIX(SubtractVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractVec3Op, 1)
HMM_INLINE hmm_vec3 operator-(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_SubtractVec3Op);

    hmm_vec3 Result = HMM_PREFIX(SubtractVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractVec4Op, 1)
HMM_INLINE hmm_vec4 operator-(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_SubtractVec4Op);

    hmm_vec4 Result = HMM_PREFIX(SubtractVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractMat4Op, 1)
HMM_INLINE hmm_mat4 operator-(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_SubtractMat4Op);

    hmm_mat4 Result = HMM_PREFIX(SubtractMat4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_SubtractQuaternionOp, 1)
HMM_INLINE hmm_quaternion operator-(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_SubtractQuaternionOp);

    hmm_quaternion Result = HMM_PREFIX(SubtractQuaternion)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec2Op, 1)
HMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2Op);

    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec3Op, 1)
HMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3Op);

    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec4Op, 1)
HMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4Op);

    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyMat4Op, 1)
HMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_MultiplyMat4Op);

    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyQuaternionOp, 1)
HMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_MultiplyQuaternionOp);

    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternion)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec2fOp, 1)
HMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2fOp);

    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec3fOp, 1)
HMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3fOp);

    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec4fOp, 1)
HMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4fOp);

    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyMat4fOp, 1)
HMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyMat4fOp);

    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyQuaternionFOp, 1)
HMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyQuaternionFOp);

    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Left, Right);

    return (Result);
}

COVERAGE(HMM_MultiplyVec2fOpLeft, 1)
HMM_INLINE hmm_vec2 operator*(float Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2fOpLeft);

    hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Right, Left);

    return (Result);
}

COVERAGE(HMM_MultiplyVec3fOpLeft, 1)
HMM_INLINE hmm_vec3 operator*(float Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3fOpLeft);

    hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Right, Left);

    return (Result);
}

COVERAGE(HMM_MultiplyVec4fOpLeft, 1)
HMM_INLINE hmm_vec4 operator*(float Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4fOpLeft);

    hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Right, Left);

    return (Result);
}

COVERAGE(HMM_MultiplyMat4fOpLeft, 1)
HMM_INLINE hmm_mat4 operator*(float Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_MultiplyMat4fOpLeft);

    hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Right, Left);

    return (Result);
}

COVERAGE(HMM_MultiplyQuaternionFOpLeft, 1)
HMM_INLINE hmm_quaternion operator*(float Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_MultiplyQuaternionFOpLeft);

    hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Right, Left);

    return (Result);
}

COVERAGE(HMM_MultiplyMat4ByVec4Op, 1)
HMM_INLINE hmm_vec4 operator*(hmm_mat4 Matrix, hmm_vec4 Vector)
{
    ASSERT_COVERED(HMM_MultiplyMat4ByVec4Op);

    hmm_vec4 Result = HMM_PREFIX(MultiplyMat4ByVec4)(Matrix, Vector);

    return (Result);
}

COVERAGE(HMM_DivideVec2Op, 1)
HMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_DivideVec2Op);

    hmm_vec2 Result = HMM_PREFIX(DivideVec2)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec3Op, 1)
HMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_DivideVec3Op);

    hmm_vec3 Result = HMM_PREFIX(DivideVec3)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec4Op, 1)
HMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_DivideVec4Op);

    hmm_vec4 Result = HMM_PREFIX(DivideVec4)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec2fOp, 1)
HMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec2fOp);

    hmm_vec2 Result = HMM_PREFIX(DivideVec2f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec3fOp, 1)
HMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec3fOp);

    hmm_vec3 Result = HMM_PREFIX(DivideVec3f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideVec4fOp, 1)
HMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec4fOp);

    hmm_vec4 Result = HMM_PREFIX(DivideVec4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideMat4fOp, 1)
HMM_INLINE hmm_mat4 operator/(hmm_mat4 Left, float Right)
{
    ASSERT_COVERED(HMM_DivideMat4fOp);

    hmm_mat4 Result = HMM_PREFIX(DivideMat4f)(Left, Right);

    return (Result);
}

COVERAGE(HMM_DivideQuaternionFOp, 1)
HMM_INLINE hmm_quaternion operator/(hmm_quaternion Left, float Right)
{
    ASSERT_COVERED(HMM_DivideQuaternionFOp);

    hmm_quaternion Result = HMM_PREFIX(DivideQuaternionF)(Left, Right);

    return (Result);
}

COVERAGE(HMM_AddVec2Assign, 1)
HMM_INLINE hmm_vec2 &operator+=(hmm_vec2 &Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_AddVec2Assign);

    return (Left = Left + Right);
}

COVERAGE(HMM_AddVec3Assign, 1)
HMM_INLINE hmm_vec3 &operator+=(hmm_vec3 &Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_AddVec3Assign);

    return (Left = Left + Right);
}

COVERAGE(HMM_AddVec4Assign, 1)
HMM_INLINE hmm_vec4 &operator+=(hmm_vec4 &Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_AddVec4Assign);

    return (Left = Left + Right);
}

COVERAGE(HMM_AddMat4Assign, 1)
HMM_INLINE hmm_mat4 &operator+=(hmm_mat4 &Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_AddMat4Assign);

    return (Left = Left + Right);
}

COVERAGE(HMM_AddQuaternionAssign, 1)
HMM_INLINE hmm_quaternion &operator+=(hmm_quaternion &Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_AddQuaternionAssign);

    return (Left = Left + Right);
}

COVERAGE(HMM_SubtractVec2Assign, 1)
HMM_INLINE hmm_vec2 &operator-=(hmm_vec2 &Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_SubtractVec2Assign);

    return (Left = Left - Right);
}

COVERAGE(HMM_SubtractVec3Assign, 1)
HMM_INLINE hmm_vec3 &operator-=(hmm_vec3 &Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_SubtractVec3Assign);

    return (Left = Left - Right);
}

COVERAGE(HMM_SubtractVec4Assign, 1)
HMM_INLINE hmm_vec4 &operator-=(hmm_vec4 &Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_SubtractVec4Assign);

    return (Left = Left - Right);
}

COVERAGE(HMM_SubtractMat4Assign, 1)
HMM_INLINE hmm_mat4 &operator-=(hmm_mat4 &Left, hmm_mat4 Right)
{
    ASSERT_COVERED(HMM_SubtractMat4Assign);

    return (Left = Left - Right);
}

COVERAGE(HMM_SubtractQuaternionAssign, 1)
HMM_INLINE hmm_quaternion &operator-=(hmm_quaternion &Left, hmm_quaternion Right)
{
    ASSERT_COVERED(HMM_SubtractQuaternionAssign);

    return (Left = Left - Right);
}

COVERAGE(HMM_MultiplyVec2Assign, 1)
HMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2Assign);

    return (Left = Left * Right);
}

COVERAGE(HMM_MultiplyVec3Assign, 1)
HMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3Assign);

    return (Left = Left * Right);
}

COVERAGE(HMM_MultiplyVec4Assign, 1)
HMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4Assign);

    return (Left = Left * Right);
}

COVERAGE(HMM_MultiplyVec2fAssign, 1)
HMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec2fAssign);

    return (Left = Left * Right);
}

COVERAGE(HMM_MultiplyVec3fAssign, 1)
HMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec3fAssign);

    return (Left = Left * Right);
}

COVERAGE(HMM_MultiplyVec4fAssign, 1)
HMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyVec4fAssign);

    return (Left = Left * Right);
}

COVERAGE(HMM_MultiplyMat4fAssign, 1)
HMM_INLINE hmm_mat4 &operator*=(hmm_mat4 &Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyMat4fAssign);

    return (Left = Left * Right);
}

COVERAGE(HMM_MultiplyQuaternionFAssign, 1)
HMM_INLINE hmm_quaternion &operator*=(hmm_quaternion &Left, float Right)
{
    ASSERT_COVERED(HMM_MultiplyQuaternionFAssign);

    return (Left = Left * Right);
}

COVERAGE(HMM_DivideVec2Assign, 1)
HMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_DivideVec2Assign);

    return (Left = Left / Right);
}

COVERAGE(HMM_DivideVec3Assign, 1)
HMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_DivideVec3Assign);

    return (Left = Left / Right);
}

COVERAGE(HMM_DivideVec4Assign, 1)
HMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_DivideVec4Assign);

    return (Left = Left / Right);
}

COVERAGE(HMM_DivideVec2fAssign, 1)
HMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec2fAssign);

    return (Left = Left / Right);
}

COVERAGE(HMM_DivideVec3fAssign, 1)
HMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec3fAssign);

    return (Left = Left / Right);
}

COVERAGE(HMM_DivideVec4fAssign, 1)
HMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, float Right)
{
    ASSERT_COVERED(HMM_DivideVec4fAssign);

    return (Left = Left / Right);
}

COVERAGE(HMM_DivideMat4fAssign, 1)
HMM_INLINE hmm_mat4 &operator/=(hmm_mat4 &Left, float Right)
{
    ASSERT_COVERED(HMM_DivideMat4fAssign);

    return (Left = Left / Right);
}

COVERAGE(HMM_DivideQuaternionFAssign, 1)
HMM_INLINE hmm_quaternion &operator/=(hmm_quaternion &Left, float Right)
{
    ASSERT_COVERED(HMM_DivideQuaternionFAssign);

    return (Left = Left / Right);
}

COVERAGE(HMM_EqualsVec2Op, 1)
HMM_INLINE hmm_bool operator==(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_EqualsVec2Op);

    return HMM_PREFIX(EqualsVec2)(Left, Right);
}

COVERAGE(HMM_EqualsVec3Op, 1)
HMM_INLINE hmm_bool operator==(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_EqualsVec3Op);

    return HMM_PREFIX(EqualsVec3)(Left, Right);
}

COVERAGE(HMM_EqualsVec4Op, 1)
HMM_INLINE hmm_bool operator==(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_EqualsVec4Op);

    return HMM_PREFIX(EqualsVec4)(Left, Right);
}

COVERAGE(HMM_EqualsVec2OpNot, 1)
HMM_INLINE hmm_bool operator!=(hmm_vec2 Left, hmm_vec2 Right)
{
    ASSERT_COVERED(HMM_EqualsVec2OpNot);

    return !HMM_PREFIX(EqualsVec2)(Left, Right);
}

COVERAGE(HMM_EqualsVec3OpNot, 1)
HMM_INLINE hmm_bool operator!=(hmm_vec3 Left, hmm_vec3 Right)
{
    ASSERT_COVERED(HMM_EqualsVec3OpNot);

    return !HMM_PREFIX(EqualsVec3)(Left, Right);
}

COVERAGE(HMM_EqualsVec4OpNot, 1)
HMM_INLINE hmm_bool operator!=(hmm_vec4 Left, hmm_vec4 Right)
{
    ASSERT_COVERED(HMM_EqualsVec4OpNot);

    return !HMM_PREFIX(EqualsVec4)(Left, Right);
}

COVERAGE(HMM_UnaryMinusVec2, 1)
HMM_INLINE hmm_vec2 operator-(hmm_vec2 In)
{
    ASSERT_COVERED(HMM_UnaryMinusVec2);

    hmm_vec2 Result;
    Result.X = -In.X;
    Result.Y = -In.Y;
    return(Result);
}

COVERAGE(HMM_UnaryMinusVec3, 1)
HMM_INLINE hmm_vec3 operator-(hmm_vec3 In)
{
    ASSERT_COVERED(HMM_UnaryMinusVec3);

    hmm_vec3 Result;
    Result.X = -In.X;
    Result.Y = -In.Y;
    Result.Z = -In.Z;
    return(Result);
}

COVERAGE(HMM_UnaryMinusVec4, 1)
HMM_INLINE hmm_vec4 operator-(hmm_vec4 In)
{
    ASSERT_COVERED(HMM_UnaryMinusVec4);

    hmm_vec4 Result;
#if HANDMADE_MATH__USE_SSE
    Result.InternalElementsSSE = _mm_xor_ps(In.InternalElementsSSE, _mm_set1_ps(-0.0f));
#else
    Result.X = -In.X;
    Result.Y = -In.Y;
    Result.Z = -In.Z;
    Result.W = -In.W;
#endif
    return(Result);
}

#endif /* __cplusplus */

#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif

#endif /* HANDMADE_MATH_H */



