/* gb_math.h - v0.
07c - public domain C math library - no warranty implied; use at
your own risk
   A C math library geared towards game development
   use '#define GB_MATH_IMPLEMENTATION' before including to create the
implementation in _ONE_ file
Version History:
      0.07f - Fix constants
      0.07e - Fixed a warning
      0.07d - Fix mat4_inverse
      0.07c - Add gb_random01
      0.07b - Fix mat4_inverse
      0.07a - Fix Mat2
      0.07 - Better Mat4 procedures
      0.06h - Ignore silly warnings
      0.06g - Remove memzero
      0.06f - Remove warning on MSVC
      0.06e - Change brace style and fix some warnings
      0.06d - Bug fix
      0.06c - Remove extra needed define for C++ and inline all operators
      0.06b - Just formatting
      0.06a - Implement rough versions of mod, remainder, copy_sign
      0.06 - Windows GCC Support and C90-ish Support
      0.05 - Less/no dependencies or CRT
      0.04d - License Update
      0.04c - Use 64-bit murmur64 version on WIN64
      0.04b - Fix strict aliasing in gb_quake_rsqrt
      0.04a - Minor bug fixes
      0.04 - Namespace everything with gb
      0.03 - Complete Replacement
      0.01 - Initial Version
LICENSE
      This software is dual-licensed to the public domain and under the following
      license: you are granted a perpetual, irrevocable license to copy, modify,
      publish, and distribute this file as you see fit.
WARNING
      - This library is _slightly_ experimental and features may not work as
expected.
      - This also means that many functions are not documented.
CONTENTS
      - Common Macros
      - Types
            - gbVec(2,3,4)
            - gbMat(2,3,4)
            - gbFloat(2,3,4)
            - gbQuat
            - gbRect(2,3)
            - gbAabb(2,3)
            - gbHalf (16-bit floating point) (storage only)
      - Operations
      - Functions
      - Type Functions
      - Random
      - Hash
*/
#ifndef GB_MATH_INCLUDE_GB_MATH_H
#define GB_MATH_INCLUDE_GB_MATH_H
#include <stddef.h>
#if !defined(GB_MATH_NO_MATH_H)
      #include <math.h>
#else
      #include <intrin.h>
#endif
#ifndef GB_MATH_DEF
      #ifdef GB_MATH_STATIC
            #define GB_MATH_DEF static
      #else
            #define GB_MATH_DEF extern
      #endif
#endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4201)
#endif
typedef union gbVec2 {
      struct { float x, y; };
      float e[2];
} gbVec2;
typedef union gbVec3 {
      struct { float x, y, z; };
      struct { float r, g, b; };
      gbVec2 xy;
      float e[3];
} gbVec3;
typedef union gbVec4 {
      struct { float x, y, z, w; };
      struct { float r, g, b, a; };
      struct { gbVec2 xy, zw; };
      gbVec3 xyz;
      gbVec3 rgb;
      float e[4];
} gbVec4;
typedef union gbMat2 {
      struct { gbVec2 x, y; };
      gbVec2 col[2];
      float e[4];
} gbMat2;
typedef union gbMat3 {
      struct { gbVec3 x, y, z; };
      gbVec3 col[3];
      float e[9];
} gbMat3;
typedef union gbMat4 {
      struct { gbVec4 x, y, z, w; };
      gbVec4 col[4];
      float e[16];
} gbMat4;
typedef union gbQuat {
      struct { float x, y, z, w; };
      gbVec4 xyzw;
      gbVec3 xyz;
      float e[4];
} gbQuat;
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
typedef float gbFloat2[2];
typedef float gbFloat3[3];
typedef float gbFloat4[4];
typedef struct gbRect2 { gbVec2 pos, dim; } gbRect2;
typedef struct gbRect3 { gbVec3 pos, dim; } gbRect3;
typedef struct gbAabb2 { gbVec2 centre, half_size; } gbAabb2;
typedef struct gbAabb3 { gbVec3 centre, half_size; } gbAabb3;
#if defined(_MSC_VER)
      typedef unsigned __int32 gb_math_u32;
      typedef unsigned __int64 gb_math_u64;
#else
      #if defined(GB_USE_STDINT)
            #include <stdint.h>
            typedef uint32_t gb_math_u32;
            typedef uint64_t gb_math_u64;
      #else
            typedef unsigned int       gb_math_u32;
            typedef unsigned long long gb_math_u64;
      #endif
#endif
typedef short gbHalf;
#ifndef GB_MATH_CONSTANTS
#define GB_MATH_CONSTANTS
      #define GB_MATH_EPSILON         1.19209290e-7f
      #define GB_MATH_ZERO            0.0f
      #define GB_MATH_ONE             1.0f
      #define GB_MATH_TWO_THIRDS      0.666666666666666666666666666666666666667f
     #define   GB_MATH_TAU            6.28318530717958647692528676655900576f
     #define   GB_MATH_PI             3.14159265358979323846264338327950288f
     #define   GB_MATH_ONE_OVER_TAU   0.159154943091895335768883763372514362f
     #define   GB_MATH_ONE_OVER_PI    0.318309886183790671537767526745028724f
     #define GB_MATH_TAU_OVER_2     3.14159265358979323846264338327950288f
     #define GB_MATH_TAU_OVER_4     1.570796326794896619231321691639751442f
     #define GB_MATH_TAU_OVER_8     0.785398163397448309615660845819875721f
     #define   GB_MATH_E            2.7182818284590452353602874713526625f
     #define   GB_MATH_SQRT_TWO     1.41421356237309504880168872420969808f
     #define   GB_MATH_SQRT_THREE   1.73205080756887729352744634150587236f
     #define   GB_MATH_SQRT_FIVE    2.23606797749978969640917366873127623f
      #define GB_MATH_LOG_TWO       0.693147180559945309417232121458176568f
      #define GB_MATH_LOG_TEN       2.30258509299404568401799145468436421f
#endif
#if defined(__cplusplus)
extern "C" {
#endif
#ifndef   gb_clamp
#define   gb_clamp(x, lower, upper) (gb_min(gb_max(x, (lower)), (upper)))
#endif
#ifndef   gb_clamp01
#define   gb_clamp01(x) gb_clamp(x, 0, 1)
#endif
#ifndef gb_square
#define gb_square(x) ((x)*(x))
#endif
#ifndef gb_cube
#define gb_cube(x) ((x)*(x)*(x))
#endif
#ifndef gb_abs
#define gb_abs(x) ((x) > 0 ? (x) : -(x))
#endif
#ifndef gb_sign
#define gb_sign(x) ((x) >= 0 ? 1 : -1)
#endif
GB_MATH_DEF float gb_to_radians(float degrees);
GB_MATH_DEF float gb_to_degrees(float radians);
/* NOTE(bill): Because to interpolate angles */
GB_MATH_DEF float gb_angle_diff(float radians_a, float radians_b);
#ifndef   gb_min
#define   gb_min(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef   gb_max
#define   gb_max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef gb_min3
#define gb_min3(a, b, c) gb_min(gb_min(a, b), c)
#endif
#ifndef gb_max3
#define gb_max3(a, b, c) gb_max(gb_max(a, b), c)
#endif
GB_MATH_DEF float gb_copy_sign (float          x, float y);
GB_MATH_DEF float gb_remainder (float          x, float y);
GB_MATH_DEF float gb_mod        (float         x, float y);
GB_MATH_DEF float gb_sqrt       (float         a);
GB_MATH_DEF float gb_rsqrt      (float         a);
GB_MATH_DEF float gb_quake_rsqrt(float         a); /* NOTE(bill): It's probably better to
use 1.0f/gb_sqrt(a)
                                                     * And for simd, there is usually isqrt
functions too!
                                                   */
GB_MATH_DEF   float   gb_sin    (float   radians);
GB_MATH_DEF   float   gb_cos    (float   radians);
GB_MATH_DEF   float   gb_tan    (float   radians);
GB_MATH_DEF   float   gb_arcsin (float   a);
GB_MATH_DEF   float   gb_arccos (float   a);
GB_MATH_DEF   float   gb_arctan (float   a);
GB_MATH_DEF   float   gb_arctan2(float   y, float x);
GB_MATH_DEF   float   gb_exp        (float   x);
GB_MATH_DEF   float   gb_exp2       (float   x);
GB_MATH_DEF   float   gb_log        (float   x);
GB_MATH_DEF   float   gb_log2       (float   x);
GB_MATH_DEF   float   gb_fast_exp   (float   x);   /* NOTE(bill): Only valid from -1 <= x <=
+1 */
GB_MATH_DEF   float gb_fast_exp2(float x); /* NOTE(bill): Only valid from -1 <= x <=
+1 */
GB_MATH_DEF   float gb_pow          (float x, float y); /* x^y */
GB_MATH_DEF float gb_round(float x);
GB_MATH_DEF float gb_floor(float x);
GB_MATH_DEF float gb_ceil (float x);
GB_MATH_DEF float gb_half_to_float(gbHalf value);
GB_MATH_DEF gbHalf gb_float_to_half(float value);
GB_MATH_DEF gbVec2 gb_vec2_zero(void);
GB_MATH_DEF gbVec2 gb_vec2     (float x, float y);
GB_MATH_DEF gbVec2 gb_vec2v    (float x[2]);
GB_MATH_DEF gbVec3 gb_vec3_zero(void);
GB_MATH_DEF gbVec3 gb_vec3     (float x, float y, float z);
GB_MATH_DEF gbVec3 gb_vec3v    (float x[3]);
GB_MATH_DEF gbVec4 gb_vec4_zero(void);
GB_MATH_DEF gbVec4 gb_vec4     (float x, float y, float z, float w);
GB_MATH_DEF gbVec4 gb_vec4v    (float x[4]);
GB_MATH_DEF   void   gb_vec2_add(gbVec2   *d,   gbVec2   v0,   gbVec2 v1);
GB_MATH_DEF   void   gb_vec2_sub(gbVec2   *d,   gbVec2   v0,   gbVec2 v1);
GB_MATH_DEF   void   gb_vec2_mul(gbVec2   *d,   gbVec2   v,    float s);
GB_MATH_DEF   void   gb_vec2_div(gbVec2   *d,   gbVec2   v,    float s);
GB_MATH_DEF   void   gb_vec3_add(gbVec3   *d,   gbVec3   v0,   gbVec3 v1);
GB_MATH_DEF   void   gb_vec3_sub(gbVec3   *d,   gbVec3   v0,   gbVec3 v1);
GB_MATH_DEF   void   gb_vec3_mul(gbVec3   *d,   gbVec3   v,    float s);
GB_MATH_DEF   void   gb_vec3_div(gbVec3   *d,   gbVec3   v,    float s);
GB_MATH_DEF   void   gb_vec4_add(gbVec4   *d,   gbVec4   v0,   gbVec4 v1);
GB_MATH_DEF   void   gb_vec4_sub(gbVec4   *d,   gbVec4   v0,   gbVec4 v1);
GB_MATH_DEF   void   gb_vec4_mul(gbVec4   *d,   gbVec4   v,    float s);
GB_MATH_DEF   void   gb_vec4_div(gbVec4   *d,   gbVec4   v,    float s);
GB_MATH_DEF   void   gb_vec2_addeq(gbVec2   *d,   gbVec2 v);
GB_MATH_DEF   void   gb_vec2_subeq(gbVec2   *d,   gbVec2 v);
GB_MATH_DEF   void   gb_vec2_muleq(gbVec2   *d,   float s);
GB_MATH_DEF   void   gb_vec2_diveq(gbVec2   *d,   float s);
GB_MATH_DEF   void   gb_vec3_addeq(gbVec3   *d,   gbVec3 v);
GB_MATH_DEF   void   gb_vec3_subeq(gbVec3   *d,   gbVec3 v);
GB_MATH_DEF   void   gb_vec3_muleq(gbVec3   *d,   float s);
GB_MATH_DEF   void   gb_vec3_diveq(gbVec3   *d,   float s);
GB_MATH_DEF   void   gb_vec4_addeq(gbVec4   *d,   gbVec4 v);
GB_MATH_DEF   void   gb_vec4_subeq(gbVec4   *d,   gbVec4 v);
GB_MATH_DEF   void   gb_vec4_muleq(gbVec4   *d,   float s);
GB_MATH_DEF   void   gb_vec4_diveq(gbVec4   *d,   float s);
GB_MATH_DEF float gb_vec2_dot(gbVec2 v0, gbVec2 v1);
GB_MATH_DEF float gb_vec3_dot(gbVec3 v0, gbVec3 v1);
GB_MATH_DEF float gb_vec4_dot(gbVec4 v0, gbVec4 v1);
GB_MATH_DEF void gb_vec2_cross(float *d, gbVec2 v0, gbVec2 v1);
GB_MATH_DEF void gb_vec3_cross(gbVec3 *d, gbVec3 v0, gbVec3 v1);
GB_MATH_DEF float gb_vec2_mag2(gbVec2 v);
GB_MATH_DEF float gb_vec3_mag2(gbVec3 v);
GB_MATH_DEF float gb_vec4_mag2(gbVec4 v);
GB_MATH_DEF float gb_vec2_mag(gbVec2 v);
GB_MATH_DEF float gb_vec3_mag(gbVec3 v);
GB_MATH_DEF float gb_vec4_mag(gbVec4 v);
GB_MATH_DEF void gb_vec2_norm(gbVec2 *d, gbVec2 v);
GB_MATH_DEF void gb_vec3_norm(gbVec3 *d, gbVec3 v);
GB_MATH_DEF void gb_vec4_norm(gbVec4 *d, gbVec4 v);
GB_MATH_DEF void gb_vec2_norm0(gbVec2 *d, gbVec2 v);
GB_MATH_DEF void gb_vec3_norm0(gbVec3 *d, gbVec3 v);
GB_MATH_DEF void gb_vec4_norm0(gbVec4 *d, gbVec4 v);
GB_MATH_DEF   void   gb_vec2_reflect(gbVec2     *d,   gbVec2   i,   gbVec2   n);
GB_MATH_DEF   void   gb_vec3_reflect(gbVec3     *d,   gbVec3   i,   gbVec3   n);
GB_MATH_DEF   void   gb_vec2_refract(gbVec2     *d,   gbVec2   i,   gbVec2   n, float eta);
GB_MATH_DEF   void   gb_vec3_refract(gbVec3     *d,   gbVec3   i,   gbVec3   n, float eta);
GB_MATH_DEF float gb_vec2_aspect_ratio(gbVec2 v);
GB_MATH_DEF void gb_mat2_identity   (gbMat2 *m);
GB_MATH_DEF void gb_float22_identity(float m[2][2]);
GB_MATH_DEF   void    gb_mat2_transpose (gbMat2     *m);
GB_MATH_DEF   void    gb_mat2_mul        (gbMat2    *out, gbMat2 *m1, gbMat2 *m2);
GB_MATH_DEF   void    gb_mat2_mul_vec2   (gbVec2    *out, gbMat2 *m, gbVec2 in);
GB_MATH_DEF   void    gb_mat2_inverse    (gbMat2    *out, gbMat2 *in);
GB_MATH_DEF   float   gb_mat2_determinate(gbMat2    *m);
GB_MATH_DEF   gbMat2 *gb_mat2_v(gbVec2 m[2]);
GB_MATH_DEF   gbMat2 *gb_mat2_f(float m[2][2]);
GB_MATH_DEF   gbFloat2 *gb_float22_m(gbMat2 *m);
GB_MATH_DEF   gbFloat2 *gb_float22_v(gbVec2 m[2]);
GB_MATH_DEF   gbFloat2 *gb_float22_4(float m[4]);
GB_MATH_DEF void gb_float22_transpose(float (*vec)[2]);
GB_MATH_DEF void gb_float22_mul      (float (*out)[2], float (*mat1)[2], float
(*mat2)[2]);
GB_MATH_DEF void gb_float22_mul_vec2 (gbVec2 *out, float m[2][2], gbVec2 in);
GB_MATH_DEF void gb_mat3_identity   (gbMat3 *m);
GB_MATH_DEF void gb_float33_identity(float m[3][3]);
GB_MATH_DEF   void    gb_mat3_transpose (gbMat3     *m);
GB_MATH_DEF   void    gb_mat3_mul        (gbMat3    *out, gbMat3 *m1, gbMat3 *m2);
GB_MATH_DEF   void    gb_mat3_mul_vec3   (gbVec3    *out, gbMat3 *m, gbVec3 in);
GB_MATH_DEF   void    gb_mat3_inverse    (gbMat3    *out, gbMat3 *in);
GB_MATH_DEF   float   gb_mat3_determinate(gbMat3    *m);
GB_MATH_DEF gbMat3 *gb_mat3_v(gbVec3 m[3]);
GB_MATH_DEF gbMat3 *gb_mat3_f(float m[3][3]);
GB_MATH_DEF gbFloat3 *gb_float33_m(gbMat3 *m);
GB_MATH_DEF gbFloat3 *gb_float33_v(gbVec3 m[3]);
GB_MATH_DEF gbFloat3 *gb_float33_9(float m[9]);
GB_MATH_DEF void gb_float33_transpose(float (*vec)[3]);
GB_MATH_DEF void gb_float33_mul      (float (*out)[3], float (*mat1)[3], float
(*mat2)[3]);
GB_MATH_DEF void gb_float33_mul_vec3 (gbVec3 *out, float m[3][3], gbVec3 in);
GB_MATH_DEF void gb_mat4_identity   (gbMat4 *m);
GB_MATH_DEF void gb_float44_identity(float m[4][4]);
GB_MATH_DEF   void    gb_mat4_transpose   (gbMat4   *m);
GB_MATH_DEF   void    gb_mat4_mul         (gbMat4   *out, gbMat4 *m1, gbMat4 *m2);
GB_MATH_DEF   void    gb_mat4_mul_vec4    (gbVec4   *out, gbMat4 *m, gbVec4 in);
GB_MATH_DEF   void    gb_mat4_inverse     (gbMat4   *out, gbMat4 *in);
GB_MATH_DEF gbMat4 *gb_mat4_v(gbVec4 m[4]);
GB_MATH_DEF gbMat4 *gb_mat4_f(float m[4][4]);
GB_MATH_DEF gbFloat4 *gb_float44_m (gbMat4 *m);
GB_MATH_DEF gbFloat4 *gb_float44_v (gbVec4 m[4]);
GB_MATH_DEF gbFloat4 *gb_float44_16(float m[16]);
GB_MATH_DEF void gb_float44_transpose(float (*vec)[4]);
GB_MATH_DEF void gb_float44_mul      (float (*out)[4], float (*mat1)[4], float
(*mat2)[4]);
GB_MATH_DEF void gb_float44_mul_vec4 (gbVec4 *out, float m[4][4], gbVec4 in);
GB_MATH_DEF void gb_mat4_translate           (gbMat4             *out, gbVec3 v);
GB_MATH_DEF void gb_mat4_rotate              (gbMat4             *out, gbVec3 v, float
angle_radians);
GB_MATH_DEF void gb_mat4_scale               (gbMat4             *out, gbVec3 v);
GB_MATH_DEF void gb_mat4_scalef              (gbMat4             *out, float s);
GB_MATH_DEF void gb_mat4_ortho2d             (gbMat4             *out, float left, float right,
float bottom, float top);
GB_MATH_DEF void gb_mat4_ortho3d             (gbMat4             *out, float left, float right,
float bottom, float top, float z_near, float z_far);
GB_MATH_DEF void gb_mat4_perspective         (gbMat4             *out, float fovy, float
aspect, float z_near, float z_far);
GB_MATH_DEF void gb_mat4_infinite_perspective(gbMat4             *out, float fovy, float
aspect, float z_near);
GB_MATH_DEF void gb_mat4_look_at(gbMat4 *out, gbVec3 eye, gbVec3 centre, gbVec3
up);
GB_MATH_DEF   gbQuat   gb_quat             (float x, float y, float z, float w);
GB_MATH_DEF   gbQuat   gb_quatv            (float e[4]);
GB_MATH_DEF   gbQuat   gb_quat_axis_angle (gbVec3 axis, float angle_radians);
GB_MATH_DEF   gbQuat   gb_quat_euler_angles(float pitch, float yaw, float roll);
GB_MATH_DEF   gbQuat   gb_quat_identity    (void);
GB_MATH_DEF   void   gb_quat_add(gbQuat   *d,   gbQuat   q0,   gbQuat   q1);
GB_MATH_DEF   void   gb_quat_sub(gbQuat   *d,   gbQuat   q0,   gbQuat   q1);
GB_MATH_DEF   void   gb_quat_mul(gbQuat   *d,   gbQuat   q0,   gbQuat   q1);
GB_MATH_DEF   void   gb_quat_div(gbQuat   *d,   gbQuat   q0,   gbQuat   q1);
GB_MATH_DEF void gb_quat_mulf(gbQuat *d, gbQuat q, float s);
GB_MATH_DEF void gb_quat_divf(gbQuat *d, gbQuat q, float s);
GB_MATH_DEF   void   gb_quat_addeq(gbQuat   *d,   gbQuat   q);
GB_MATH_DEF   void   gb_quat_subeq(gbQuat   *d,   gbQuat   q);
GB_MATH_DEF   void   gb_quat_muleq(gbQuat   *d,   gbQuat   q);
GB_MATH_DEF   void   gb_quat_diveq(gbQuat   *d,   gbQuat   q);
GB_MATH_DEF void gb_quat_muleqf(gbQuat *d, float s);
GB_MATH_DEF void gb_quat_diveqf(gbQuat *d, float s);
GB_MATH_DEF float gb_quat_dot(gbQuat q0, gbQuat q1);
GB_MATH_DEF float gb_quat_mag(gbQuat q);
GB_MATH_DEF void gb_quat_norm   (gbQuat *d, gbQuat q);
GB_MATH_DEF void gb_quat_conj   (gbQuat *d, gbQuat q);
GB_MATH_DEF void gb_quat_inverse(gbQuat *d, gbQuat q);
GB_MATH_DEF void gb_quat_axis (gbVec3 *axis, gbQuat q);
GB_MATH_DEF float gb_quat_angle(gbQuat q);
GB_MATH_DEF float gb_quat_pitch(gbQuat q);
GB_MATH_DEF float gb_quat_yaw (gbQuat q);
GB_MATH_DEF float gb_quat_roll (gbQuat q);
/* NOTE(bill): Rotate v by q */
GB_MATH_DEF void gb_quat_rotate_vec3(gbVec3 *d, gbQuat q, gbVec3 v);
GB_MATH_DEF void gb_mat4_from_quat (gbMat4 *out, gbQuat q);
GB_MATH_DEF void gb_quat_from_mat4 (gbQuat *out, gbMat4 *m);
/* Interpolations   */
GB_MATH_DEF float   gb_lerp         (float   a,   float   b,   float   t);
GB_MATH_DEF float   gb_unlerp       (float   t,   float   a,   float   b);
GB_MATH_DEF float   gb_smooth_step (float    a,   float   b,   float   t);
GB_MATH_DEF float   gb_smoother_step(float   a,   float   b,   float   t);
GB_MATH_DEF void gb_vec2_lerp(gbVec2 *d, gbVec2 a, gbVec2 b, float t);
GB_MATH_DEF void gb_vec3_lerp(gbVec3 *d, gbVec3 a, gbVec3 b, float t);
GB_MATH_DEF void gb_vec4_lerp(gbVec4 *d, gbVec4 a, gbVec4 b, float t);
GB_MATH_DEF void gb_quat_lerp (gbQuat *d, gbQuat       a,   gbQuat     b,   float t);
GB_MATH_DEF void gb_quat_nlerp(gbQuat *d, gbQuat       a,   gbQuat     b,   float t);
GB_MATH_DEF void gb_quat_slerp(gbQuat *d, gbQuat       a,   gbQuat     b,   float t);
GB_MATH_DEF void gb_quat_nquad(gbQuat *d, gbQuat       p,   gbQuat     a,   gbQuat b, gbQuat q,
float t);
GB_MATH_DEF void gb_quat_squad(gbQuat *d, gbQuat       p, gbQuat a, gbQuat b, gbQuat q,
float t);
GB_MATH_DEF void gb_quat_slerp_approx(gbQuat *d,       gbQuat a, gbQuat b, float t);
GB_MATH_DEF void gb_quat_squad_approx(gbQuat *d,       gbQuat p, gbQuat a, gbQuat b,
gbQuat q, float t);
/* Rects */
GB_MATH_DEF gbRect2 gb_rect2(gbVec2 pos, gbVec2 dim);
GB_MATH_DEF gbRect2 gb_rect2v(float v[4]);
GB_MATH_DEF gbRect3 gb_rect3(gbVec3 pos, gbVec3 dim);
GB_MATH_DEF gbRect3 gb_rect3v(float v[6]);
GB_MATH_DEF int   gb_rect2_contains           (gbRect2         a,   float x, float y);
GB_MATH_DEF int   gb_rect2_contains_vec2      (gbRect2         a,   gbVec2 p);
GB_MATH_DEF int   gb_rect2_intersects         (gbRect2         a,   gbRect2 b);
GB_MATH_DEF int   gb_rect2_intersection_result(gbRect2         a,   gbRect2 b, gbRect2
*intersection);
#ifndef     GB_MURMUR64_DEFAULT_SEED
#define GB_MURMUR64_DEFAULT_SEED 0x9747b28c
#endif
/* Hashing */
GB_MATH_DEF gb_math_u64 gb_hash_murmur64(void const *key, size_t num_bytes,
gb_math_u64 seed);
/* Random */
/* TODO(bill): Use a generator for the random numbers */
GB_MATH_DEF float gb_random_range_float(float min_inc, float max_inc);
GB_MATH_DEF int   gb_random_range_int (int min_inc, int max_inc);
GB_MATH_DEF float gb_random01          (void);
#if defined(__cplusplus)
}
#endif
#if defined(__cplusplus)
/* TODO(bill): How should I apply GB_MATH_DEF to these operator overloads? */
inline bool operator==(gbVec2 a, gbVec2 b) { return (a.x == b.x) && (a.y == b.y); }
inline bool operator!=(gbVec2 a, gbVec2 b) { return !operator==(a, b); }
inline gbVec2 operator+(gbVec2 a) { return a; }
inline gbVec2 operator-(gbVec2 a) { gbVec2 r = {-a.x, -a.y}; return r; }
inline   gbVec2 operator+(gbVec2 a, gbVec2 b) { gbVec2 r; gb_vec2_add(&r, a, b);
return   r; }
inline   gbVec2 operator-(gbVec2 a, gbVec2 b) { gbVec2 r; gb_vec2_sub(&r, a, b);
return   r; }
inline gbVec2 operator*(gbVec2 a, float scalar) { gbVec2 r; gb_vec2_mul(&r, a,
scalar); return r; }
inline gbVec2 operator*(float scalar, gbVec2 a) { return operator*(a, scalar); }
inline gbVec2 operator/(gbVec2 a, float scalar) { return operator*(a, 1.0f/scalar);
}
/* Hadamard Product */
inline gbVec2 operator*(gbVec2 a, gbVec2 b) { gbVec2 r = {a.x*b.x, a.y*b.y}; return
r; }
inline gbVec2 operator/(gbVec2 a, gbVec2 b) { gbVec2 r = {a.x/b.x, a.y/b.y}; return
r; }
inline   gbVec2   &operator+=(gbVec2   &a,   gbVec2 b)       { return (a   =   a   + b); }
inline   gbVec2   &operator-=(gbVec2   &a,   gbVec2 b)       { return (a   =   a   - b); }
inline   gbVec2   &operator*=(gbVec2   &a,   float scalar) { return (a =   a   *   scalar); }
inline   gbVec2   &operator/=(gbVec2   &a,   float scalar) { return (a =   a   /   scalar); }
inline bool operator==(gbVec3 a, gbVec3 b) { return (a.x == b.x) && (a.y == b.y) &&
(a.z == b.z); }
inline bool operator!=(gbVec3 a, gbVec3 b) { return !operator==(a, b); }
inline gbVec3 operator+(gbVec3 a) { return a; }
inline gbVec3 operator-(gbVec3 a) { gbVec3 r = {-a.x, -a.y, -a.z}; return r; }
inline   gbVec3 operator+(gbVec3 a, gbVec3 b) { gbVec3 r; gb_vec3_add(&r, a, b);
return   r; }
inline   gbVec3 operator-(gbVec3 a, gbVec3 b) { gbVec3 r; gb_vec3_sub(&r, a, b);
return   r; }
inline gbVec3 operator*(gbVec3 a, float scalar) { gbVec3 r; gb_vec3_mul(&r, a,
scalar); return r; }
inline gbVec3 operator*(float scalar, gbVec3 a) { return operator*(a, scalar); }
inline gbVec3 operator/(gbVec3 a, float scalar) { return operator*(a, 1.0f/scalar);
}
/* Hadamard Product */
inline gbVec3 operator*(gbVec3 a, gbVec3 b) { gbVec3 r = {a.x*b.x, a.y*b.y,
a.z*b.z}; return r; }
inline gbVec3 operator/(gbVec3 a, gbVec3 b) { gbVec3 r = {a.x/b.x, a.y/b.y,
a.z/b.z}; return r; }
inline   gbVec3   &operator+=(gbVec3   &a,   gbVec3 b)       { return (a   =   a   + b); }
inline   gbVec3   &operator-=(gbVec3   &a,   gbVec3 b)       { return (a   =   a   - b); }
inline   gbVec3   &operator*=(gbVec3   &a,   float scalar) { return (a =   a   *   scalar); }
inline   gbVec3   &operator/=(gbVec3   &a,   float scalar) { return (a =   a   /   scalar); }
inline bool operator==(gbVec4 a, gbVec4 b) { return (a.x == b.x) && (a.y == b.y) &&
(a.z == b.z) && (a.w == b.w); }
inline bool operator!=(gbVec4 a, gbVec4 b) { return !operator==(a, b); }
inline gbVec4 operator+(gbVec4 a) { return a; }
inline gbVec4 operator-(gbVec4 a) { gbVec4 r = {-a.x, -a.y, -a.z, -a.w}; return
r; }
inline   gbVec4 operator+(gbVec4 a, gbVec4 b) { gbVec4 r; gb_vec4_add(&r, a, b);
return   r; }
inline   gbVec4 operator-(gbVec4 a, gbVec4 b) { gbVec4 r; gb_vec4_sub(&r, a, b);
return   r; }
inline gbVec4 operator*(gbVec4 a, float scalar) { gbVec4 r; gb_vec4_mul(&r, a,
scalar); return r; }
inline gbVec4 operator*(float scalar, gbVec4 a) { return operator*(a, scalar); }
inline gbVec4 operator/(gbVec4 a, float scalar) { return operator*(a, 1.0f/scalar);
}
/* Hadamard Product */
inline gbVec4 operator*(gbVec4 a, gbVec4 b) { gbVec4 r = {a.x*b.x, a.y*b.y,
a.z*b.z, a.w*b.w}; return r; }
inline gbVec4 operator/(gbVec4 a, gbVec4 b) { gbVec4 r = {a.x/b.x, a.y/b.y,
a.z/b.z, a.w/b.w}; return r; }
inline   gbVec4   &operator+=(gbVec4   &a,   gbVec4 b)       { return (a   =   a   + b); }
inline   gbVec4   &operator-=(gbVec4   &a,   gbVec4 b)       { return (a   =   a   - b); }
inline   gbVec4   &operator*=(gbVec4   &a,   float scalar) { return (a =   a   *   scalar); }
inline   gbVec4   &operator/=(gbVec4   &a,   float scalar) { return (a =   a   /   scalar); }
inline gbMat2 operator+(gbMat2 const &a, gbMat2 const &b) {
      int i, j;
      gbMat2 r = {0};
      for (j = 0; j < 2; j++) {
            for (i = 0; i < 2; i++)
                  r.e[2*j+i] = a.e[2*j+i] + b.e[2*j+i];
      }
      return r;
}
inline gbMat2 operator-(gbMat2 const &a, gbMat2 const &b) {
      int i, j;
      gbMat2 r = {0};
      for (j = 0; j < 2; j++) {
            for (i = 0; i < 2; i++)
                 r.e[2*j+i] = a.e[2*j+i] - b.e[2*j+i];
     }
     return r;
}
inline gbMat2 operator*(gbMat2 const &a, gbMat2 const &b) { gbMat2 r;
gb_mat2_mul(&r, (gbMat2 *)&a, (gbMat2 *)&b); return r; }
inline gbVec2 operator*(gbMat2 const &a, gbVec2 v) { gbVec2 r; gb_mat2_mul_vec2(&r,
(gbMat2 *)&a, v); return r; }
inline gbMat2 operator*(gbMat2 const &a, float scalar) {
      gbMat2 r = {0};
      int i;
      for (i = 0; i < 2*2; i++) r.e[i] = a.e[i] * scalar;
      return r;
}
inline gbMat2 operator*(float scalar, gbMat2 const &a) { return operator*(a,
scalar); }
inline gbMat2 operator/(gbMat2 const &a, float scalar) { return operator*(a,
1.0f/scalar); }
inline gbMat2& operator+=(gbMat2& a, gbMat2 const &b) { return (a = a + b); }
inline gbMat2& operator-=(gbMat2& a, gbMat2 const &b) { return (a = a - b); }
inline gbMat2& operator*=(gbMat2& a, gbMat2 const &b) { return (a = a * b); }
inline gbMat3 operator+(gbMat3 const &a, gbMat3 const &b) {
      int i, j;
      gbMat3 r = {0};
      for (j = 0; j < 3; j++) {
            for (i = 0; i < 3; i++)
                  r.e[3*j+i] = a.e[3*j+i] + b.e[3*j+i];
      }
      return r;
}
inline gbMat3 operator-(gbMat3 const &a, gbMat3 const &b) {
      int i, j;
      gbMat3 r = {0};
      for (j = 0; j < 3; j++) {
            for (i = 0; i < 3; i++)
                  r.e[3*j+i] = a.e[3*j+i] - b.e[3*j+i];
      }
      return r;
}
inline gbMat3 operator*(gbMat3 const &a, gbMat3 const &b) { gbMat3 r;
gb_mat3_mul(&r, (gbMat3 *)&a, (gbMat3 *)&b); return r; }
inline gbVec3 operator*(gbMat3 const &a, gbVec3 v) { gbVec3 r; gb_mat3_mul_vec3(&r,
(gbMat3 *)&a, v); return r; } inline gbMat3 operator*(gbMat3 const &a, float
scalar) {
      gbMat3 r = {0};
      int i;
      for (i = 0; i < 3*3; i++) r.e[i] = a.e[i] * scalar;
      return r;
}
inline gbMat3 operator*(float scalar, gbMat3 const &a) { return operator*(a,
scalar); }
inline gbMat3 operator/(gbMat3 const &a, float scalar) { return operator*(a,
1.0f/scalar); }
inline gbMat3& operator+=(gbMat3& a, gbMat3 const &b) { return (a = a + b); }
inline gbMat3& operator-=(gbMat3& a, gbMat3 const &b) { return (a = a - b); }
inline gbMat3& operator*=(gbMat3& a, gbMat3 const &b) { return (a = a * b); }
inline gbMat4 operator+(gbMat4 const &a, gbMat4 const &b) {
      int i, j;
      gbMat4 r = {0};
      for (j = 0; j < 4; j++) {
            for (i = 0; i < 4; i++)
                  r.e[4*j+i] = a.e[4*j+i] + b.e[4*j+i];
      }
      return r;
}
inline gbMat4 operator-(gbMat4 const &a, gbMat4 const &b) {
      int i, j;
      gbMat4 r = {0};
      for (j = 0; j < 4; j++) {
            for (i = 0; i < 4; i++)
                  r.e[4*j+i] = a.e[4*j+i] - b.e[4*j+i];
      }
      return r;
}
inline gbMat4 operator*(gbMat4 const &a, gbMat4 const &b) { gbMat4 r;
gb_mat4_mul(&r, (gbMat4 *)&a, (gbMat4 *)&b); return r; }
inline gbVec4 operator*(gbMat4 const &a, gbVec4 v) { gbVec4 r; gb_mat4_mul_vec4(&r,
(gbMat4 *)&a, v); return r; }
inline gbMat4 operator*(gbMat4 const &a, float scalar) {
      gbMat4 r = {0};
      int i;
      for (i = 0; i < 4*4; i++) r.e[i] = a.e[i] * scalar;
      return r;
}
inline gbMat4 operator*(float scalar, gbMat4 const &a) { return operator*(a,
scalar); }
inline gbMat4 operator/(gbMat4 const &a, float scalar) { return operator*(a,
1.0f/scalar); }
inline gbMat4& operator+=(gbMat4 &a, gbMat4 const &b) { return (a = a + b); }
inline gbMat4& operator-=(gbMat4 &a, gbMat4 const &b) { return (a = a - b); }
inline gbMat4& operator*=(gbMat4 &a, gbMat4 const &b) { return (a = a * b); }
inline bool operator==(gbQuat a, gbQuat b) { return a.xyzw == b.xyzw; }
inline bool operator!=(gbQuat a, gbQuat b) { return !operator==(a, b); }
inline gbQuat operator+(gbQuat q) { return q; }
inline gbQuat operator-(gbQuat q) { return gb_quat(-q.x, -q.y, -q.z, -q.w); }
inline   gbQuat operator+(gbQuat a, gbQuat b) { gbQuat r; gb_quat_add(&r, a, b);
return   r; }
inline   gbQuat operator-(gbQuat a, gbQuat b) { gbQuat r; gb_quat_sub(&r, a, b);
return   r; }
inline   gbQuat   operator*(gbQuat a, gbQuat b)        { gbQuat r; gb_quat_mul(&r, a, b);
return   r; }
inline   gbQuat   operator*(gbQuat q, float s) { gbQuat r; gb_quat_mulf(&r, q, s);
return   r; }
inline   gbQuat   operator*(float s, gbQuat q) { return operator*(q, s); }
inline   gbQuat   operator/(gbQuat q, float s) { gbQuat r; gb_quat_divf(&r, q, s);
return   r; }
inline   gbQuat   &operator+=(gbQuat   &a,   gbQuat   b)   {   gb_quat_addeq(&a,   b);   return   a;   }
inline   gbQuat   &operator-=(gbQuat   &a,   gbQuat   b)   {   gb_quat_subeq(&a,   b);   return   a;   }
inline   gbQuat   &operator*=(gbQuat   &a,   gbQuat   b)   {   gb_quat_muleq(&a,   b);   return   a;   }
inline   gbQuat   &operator/=(gbQuat   &a,   gbQuat   b)   {   gb_quat_diveq(&a,   b);   return   a;   }
inline gbQuat &operator*=(gbQuat &a, float b) { gb_quat_muleqf(&a, b); return a; }
inline gbQuat &operator/=(gbQuat &a, float b) { gb_quat_diveqf(&a, b); return a; }
/* Rotate v by a */
inline gbVec3 operator*(gbQuat q, gbVec3 v) { gbVec3 r; gb_quat_rotate_vec3(&r, q,
v); return r; }
#endif
#endif /* GB_MATH_INCLUDE_GB_MATH_H */
/****************************************************************
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 * Implementation
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 ****************************************************************/
#define GB_MATH_IMPLEMENTATION
#if defined(GB_MATH_IMPLEMENTATION) && !defined(GB_MATH_IMPLEMENTATION_DONE)
#define GB_MATH_IMPLEMENTATION_DONE
 #if (defined(__GCC__) || defined(__GNUC__)) && !defined(__clang__)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wattributes"
 #pragma GCC diagnostic ignored "-Wmissing-braces"
 #elif __clang__
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wattributes"
 #pragma clang diagnostic ignored "-Wmissing-braces"
 #endif
/* NOTE(bill): To remove the need for memcpy */
static void gb__memcpy_4byte(void *dest, void const *src, size_t size) {
      size_t i;
      unsigned int *d, *s;
      d = (unsigned int *)dest;
      s = (unsigned int *)src;
      for (i = 0; i < size/4; i++) {
            *d++ = *s++;
      }
}
float gb_to_radians(float degrees) { return degrees * GB_MATH_TAU / 360.0f; }
float gb_to_degrees(float radians) { return radians * 360.0f / GB_MATH_TAU; }
float gb_angle_diff(float radians_a, float radians_b) {
      float delta = gb_mod(radians_b-radians_a, GB_MATH_TAU);
      delta = gb_mod(delta + 1.5f*GB_MATH_TAU, GB_MATH_TAU);
      delta -= 0.5f*GB_MATH_TAU;
      return delta;
}
float gb_copy_sign(float x, float y) {
      int ix, iy;
      ix = *(int *)&x;
      iy = *(int *)&y;
     ix &= 0x7fffffff;
     ix |= iy & 0x80000000;
     return *(float *)&ix;
}
float gb_remainder(float x, float y) {
      return x - (gb_round(x/y)*y);
}
float gb_mod(float x, float y) {
     float result;
     y = gb_abs(y);
     result = gb_remainder(gb_abs(x), y);
     if (gb_sign(result)) result += y;
     return gb_copy_sign(result, x);
}
float gb_quake_rsqrt(float a) {
      union {
            int i;
            float f;
      } t;
      float x2;
      float const three_halfs = 1.5f;
      x2 = a * 0.5f;
      t.f = a;
      t.i = 0x5f375a86 - (t.i >> 1);                /* What the fuck? */
      t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 1st iteration */
      t.f = t.f * (three_halfs - (x2 * t.f * t.f)); /* 2nd iteration, this can be
removed */
     return t.f;
}
#if defined(GB_MATH_NO_MATH_H)
#if defined(_MSC_VER)
      float gb_rsqrt(float a) { return
_mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); }
      float gb_sqrt(float a) { return
_mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); };
      float
      gb_sin(float a)
      {
            static float const a0 = +1.91059300966915117e-31f;
            static float const a1 = +1.00086760103908896f;
            static float const a2 = -1.21276126894734565e-2f;
            static float const a3 = -1.38078780785773762e-1f;
            static float const a4 = -2.67353392911981221e-2f;
            static float const a5 = +2.08026600266304389e-2f;
            static float const a6 = -3.03996055049204407e-3f;
            static float const a7 = +1.38235642404333740e-4f;
            return a0 + a*(a1 + a*(a2 + a*(a3 + a*(a4 + a*(a5 + a*(a6 + a*a7))))));
      }
      float
      gb_cos(float a)
      {
            static float const a0 = +1.00238601909309722f;
            static float const a1 = -3.81919947353040024e-2f;
            static float const a2 = -3.94382342128062756e-1f;
            static float const a3 = -1.18134036025221444e-1f;
            static float const a4 = +1.07123798512170878e-1f;
            static float const a5 = -1.86637164165180873e-2f;
            static float const a6 = +9.90140908664079833e-4f;
            static float const a7 = -5.23022132118824778e-14f;
            return a0 + a*(a1 + a*(a2 + a*(a3 + a*(a4 + a*(a5 + a*(a6 + a*a7))))));
     }
     float
     gb_tan(float radians)
     {
           float rr = radians*radians;
           float a = 9.5168091e-03f;
           a *= rr;
           a += 2.900525e-03f;
           a *= rr;
           a += 2.45650893e-02f;
           a *= rr;
           a += 5.33740603e-02f;
           a *= rr;
           a += 1.333923995e-01f;
           a *= rr;
           a += 3.333314036e-01f;
           a *= rr;
           a += 1.0f;
           a *= radians;
           return a;
     }
      float gb_arcsin(float a) { return gb_arctan2(a, gb_sqrt((1.0f + a) * (1.0f -
a))); }
      float gb_arccos(float a) { return gb_arctan2(gb_sqrt((1.0f + a) * (1.0 - a)),
a); }
      float
      gb_arctan(float a)
      {
            float u = a*a;
            float u2 = u*u;
            float u3 = u2*u;
            float u4 = u3*u;
            float f = 1.0f+0.33288950512027f*u-
0.08467922817644f*u2+0.03252232640125f*u3-0.00749305860992f*u4;
            return a/f;
      }
      float
      gb_arctan2(float y, float x)
      {
            if (gb_abs(x) > gb_abs(y)) {
                  float a = gb_arctan(y/x);
                  if (x > 0.0f)
                        return a;
                  else
                        return y > 0.0f ? a+GB_MATH_TAU_OVER_2:a-
GB_MATH_TAU_OVER_2;
            } else {
                  float a = gb_arctan(x/y);
                  if (x > 0.0f)
                        return y > 0.0f ? GB_MATH_TAU_OVER_4-a:-GB_MATH_TAU_OVER_4-
a;
                  else
                        return y > 0.0f ? GB_MATH_TAU_OVER_4+a:-
GB_MATH_TAU_OVER_4+a;
            }
        }
        float
        gb_exp(float a)
        {
              union { float f; int i; } u, v;
              u.i = (int)(6051102 * a + 1056478197);
              v.i = (int)(1056478197 - 6051102 * a);
              return u.f / v.f;
        }
        float
        gb_log(float a)
        {
              union { float f; int i; } u = {a};
              return (u.i - 1064866805) * 8.262958405176314e-8f; /* 1 / 12102203.0;
*/
        }
        float
        gb_pow(float a, float b)
        {
              int flipped = 0, e;
              float f, r = 1.0f;
              if (b < 0) {
                    flipped = 1;
                    b = -b;
              }
                e = (int)b;
                f = gb_exp(b - e);
                while (e) {
                      if (e & 1) r *= a;
                      a *= a;
                      e >>= 1;
                }
                r *= f;
                return flipped ? 1.0f/r : r;
        }
#else
        float   gb_rsqrt(float a)              {   return   1.0f/__builtin_sqrt(a); }
        float   gb_sqrt(float a)               {   return   __builtin_sqrt(a); }
        float   gb_sin(float radians)          {   return   __builtin_sinf(radians); }
        float   gb_cos(float radians)          {   return   __builtin_cosf(radians); }
        float   gb_tan(float radians)          {   return   __builtin_tanf(radians); }
        float   gb_arcsin(float a)             {   return   __builtin_asinf(a); }
        float   gb_arccos(float a)             {   return   __builtin_acosf(a); }
        float   gb_arctan(float a)             {   return   __builtin_atanf(a); }
        float   gb_arctan2(float y, float x)   {   return   __builtin_atan2f(y, x); }
        float gb_exp(float x)    { return __builtin_expf(x); }
        float gb_log(float x)    { return __builtin_logf(x); }
        // TODO(bill): Should this be gb_exp(y * gb_log(x)) ???
        float gb_pow(float x, float y) { return __builtin_powf(x, y); }
#endif
#else
        float   gb_rsqrt(float a)              {   return   1.0f/sqrtf(a); }
        float   gb_sqrt(float a)               {   return   sqrtf(a); };
        float   gb_sin(float radians)          {   return   sinf(radians); };
        float   gb_cos(float radians)          {   return   cosf(radians); };
        float   gb_tan(float radians)          {   return   tanf(radians); };
        float   gb_arcsin(float a)             {   return   asinf(a); };
        float   gb_arccos(float a)             {   return   acosf(a); };
        float   gb_arctan(float a)             {   return   atanf(a); };
        float   gb_arctan2(float y, float x)   {   return   atan2f(y, x); };
      float gb_exp(float x)          { return expf(x); }
      float gb_log(float x)          { return logf(x); }
      float gb_pow(float x, float y) { return powf(x, y); }
#endif
float gb_exp2(float x) { return gb_exp(GB_MATH_LOG_TWO * x); }
float gb_log2(float x) { return gb_log(x) / GB_MATH_LOG_TWO; }
float gb_fast_exp(float x) {
      /* NOTE(bill): Only works in the range -1 <= x <= +1 */
      float e = 1.0f + x*(1.0f + x*0.5f*(1.0f + x*0.3333333333f*(1.0f +
x*0.25f*(1.0f + x*0.2f))));
      return e;
}
float gb_fast_exp2(float x) { return gb_fast_exp(GB_MATH_LOG_TWO * x); }
float gb_round(float x) { return (float)((x >= 0.0f) ? gb_floor(x + 0.5f) :
gb_ceil(x - 0.5f)); }
float gb_floor(float x) { return (float)((x >= 0.0f) ? (int)x : (int)(x-
0.9999999999999999f)); }
float gb_ceil(float x) { return (float)((x < 0) ? (int)x : ((int)x)+1); }
float gb_half_to_float(gbHalf     value) {
      union { unsigned int i;     float f; } result;
      int s = (value >> 15) &     0x001;
      int e = (value >> 10) &     0x01f;
      int m = value         &     0x3ff;
        if (e == 0) {
              if (m == 0) {
                    /* Plus or minus zero */
                    result.i = (unsigned int)(s << 31);
                    return result.f;
              } else {
                    /* Denormalized number */
                    while (!(m & 0x00000400)) {
                       m <<= 1;
                       e -= 1;
                 }
                 e += 1;
                 m &= ~0x00000400;
           }
     } else if (e == 31) {
           if (m == 0) {
                 /* Positive or negative infinity */
                 result.i = (unsigned int)((s << 31) | 0x7f800000);
                 return result.f;
           } else {
                 /* Nan */
                 result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13));
                 return result.f;
           }
     }
     e = e + (127 - 15);
     m = m << 13;
     result.i = (unsigned int)((s << 31) | (e << 23) | m);
     return result.f;
}
gbHalf gb_float_to_half(float value) {
      union { unsigned int i; float f; } v;
      int i, s, e, m;
     v.f = value;
     i = (int)v.i;
     s = (i >> 16) & 0x00008000;
     e = ((i >> 23) & 0x000000ff) - (127 - 15);
     m =   i        & 0x007fffff;
     if (e <= 0) {
           if (e < -10) return (gbHalf)s;
           m = (m | 0x00800000) >> (1 - e);
           if (m & 0x00001000)
                 m += 0x00002000;
           return (gbHalf)(s | (m >> 13));
     } else if (e == 0xff - (127 - 15)) {
           if (m == 0) {
                 return (gbHalf)(s | 0x7c00); /* NOTE(bill): infinity */
           } else {
                 /* NOTE(bill): NAN */
                 m >>= 13;
                 return (gbHalf)(s | 0x7c00 | m | (m == 0));
           }
     } else {
           if (m & 0x00001000) {
                 m += 0x00002000;
                 if (m & 0x00800000) {
                       m = 0;
                       e += 1;
                 }
           }
           if (e > 30) {
                 float volatile f = 1e12f;
                 int j;
                 for (j = 0; j < 10; j++)
                       f *= f; /* NOTE(bill): Cause overflow */
                 return (gbHalf)(s | 0x7c00);
           }
           return (gbHalf)(s | (e << 10) | (m >> 13));
     }
}
#define GB_VEC2_2OP(a,c,post)    \
      a->x =        c.x post;        \
      a->y =        c.y post;
#define GB_VEC2_3OP(a,b,op,c,post) \
      a->x = b.x op c.x post;        \
      a->y = b.y op c.y post;
#define GB_VEC3_2OP(a,c,post) \
      a->x =        c.x post;   \
      a->y =        c.y post;   \
      a->z =        c.z post;
#define GB_VEC3_3OP(a,b,op,c,post) \
      a->x = b.x op c.x post;        \
      a->y = b.y op c.y post;        \
      a->z = b.z op c.z post;
#define GB_VEC4_2OP(a,c,post) \
      a->x =        c.x post;   \
      a->y =        c.y post;   \
      a->z =        c.z post;   \
      a->w =        c.w post;
#define GB_VEC4_3OP(a,b,op,c,post) \
      a->x = b.x op c.x post;        \
      a->y = b.y op c.y post;        \
      a->z = b.z op c.z post;        \
      a->w = b.w op c.w post;
gbVec2 gb_vec2_zero(void)        { gbVec2 v = {0, 0};                return v; }
gbVec2 gb_vec2(float x, float y) { gbVec2 v; v.x = x;    v.y = y;    return v; }
gbVec2 gb_vec2v(float x[2])      { gbVec2 v; v.x = x[0]; v.y = x[1]; return v; }
gbVec3 gb_vec3_zero(void)                 { gbVec3 v = {0, 0, 0};
return v; }
gbVec3 gb_vec3(float x, float y, float z) { gbVec3 v; v.x = x; v.y = y; v.z = z;
return v; }
gbVec3 gb_vec3v(float x[3])               { gbVec3 v; v.x = x[0]; v.y = x[1]; v.z =
x[2]; return v; }
gbVec4 gb_vec4_zero(void)                          { gbVec4 v = {0, 0, 0, 0};
return v; }
gbVec4 gb_vec4(float x, float y, float z, float w) { gbVec4 v; v.x = x; v.y = y;
v.z = z; v.w = w;             return v; }
gbVec4 gb_vec4v(float x[4])                        { gbVec4 v; v.x = x[0]; v.y =
x[1]; v.z = x[2]; v.w = x[3]; return v; }
void   gb_vec2_add(gbVec2   *d,   gbVec2   v0,   gbVec2 v1)   {   GB_VEC2_3OP(d,v0,+,v1,+0);   }
void   gb_vec2_sub(gbVec2   *d,   gbVec2   v0,   gbVec2 v1)   {   GB_VEC2_3OP(d,v0,-,v1,+0);   }
void   gb_vec2_mul(gbVec2   *d,   gbVec2   v,    float s)     {   GB_VEC2_2OP(d,v,* s);        }
void   gb_vec2_div(gbVec2   *d,   gbVec2   v,    float s)     {   GB_VEC2_2OP(d,v,/ s);        }
void   gb_vec3_add(gbVec3   *d,   gbVec3   v0,   gbVec3 v1)   {   GB_VEC3_3OP(d,v0,+,v1,+0);   }
void   gb_vec3_sub(gbVec3   *d,   gbVec3   v0,   gbVec3 v1)   {   GB_VEC3_3OP(d,v0,-,v1,+0);   }
void   gb_vec3_mul(gbVec3   *d,   gbVec3   v,    float s)     {   GB_VEC3_2OP(d,v,* s);        }
void   gb_vec3_div(gbVec3   *d,   gbVec3   v,    float s)     {   GB_VEC3_2OP(d,v,/ s);        }
void   gb_vec4_add(gbVec4   *d,   gbVec4   v0,   gbVec4 v1)   {   GB_VEC4_3OP(d,v0,+,v1,+0);   }
void   gb_vec4_sub(gbVec4   *d,   gbVec4   v0,   gbVec4 v1)   {   GB_VEC4_3OP(d,v0,-,v1,+0);   }
void   gb_vec4_mul(gbVec4   *d,   gbVec4   v,    float s)     {   GB_VEC4_2OP(d,v,* s);        }
void   gb_vec4_div(gbVec4   *d,   gbVec4   v,    float s)     {   GB_VEC4_2OP(d,v,/ s);        }
void   gb_vec2_addeq(gbVec2   *d,   gbVec2 v)     {   GB_VEC2_3OP(d,(*d),+,v,+0);   }
void   gb_vec2_subeq(gbVec2   *d,   gbVec2 v)     {   GB_VEC2_3OP(d,(*d),-,v,+0);   }
void   gb_vec2_muleq(gbVec2   *d,   float s)      {   GB_VEC2_2OP(d,(*d),* s);      }
void   gb_vec2_diveq(gbVec2   *d,   float s)      {   GB_VEC2_2OP(d,(*d),/ s);      }
void   gb_vec3_addeq(gbVec3   *d,   gbVec3 v)     {   GB_VEC3_3OP(d,(*d),+,v,+0);   }
void   gb_vec3_subeq(gbVec3   *d,   gbVec3 v)     {   GB_VEC3_3OP(d,(*d),-,v,+0);   }
void   gb_vec3_muleq(gbVec3   *d,   float s)      {   GB_VEC3_2OP(d,(*d),* s);      }
void   gb_vec3_diveq(gbVec3   *d,   float s)      {   GB_VEC3_2OP(d,(*d),/ s);      }
void   gb_vec4_addeq(gbVec4   *d,   gbVec4 v)     {   GB_VEC4_3OP(d,(*d),+,v,+0);   }
void   gb_vec4_subeq(gbVec4   *d,   gbVec4 v)     {   GB_VEC4_3OP(d,(*d),-,v,+0);   }
void   gb_vec4_muleq(gbVec4   *d,   float s)      {   GB_VEC4_2OP(d,(*d),* s);      }
void   gb_vec4_diveq(gbVec4   *d,   float s)      {   GB_VEC4_2OP(d,(*d),/ s);      }
#undef   GB_VEC2_2OP
#undef   GB_VEC2_3OP
#undef   GB_VEC3_3OP
#undef   GB_VEC3_2OP
#undef   GB_VEC4_2OP
#undef   GB_VEC4_3OP
float gb_vec2_dot(gbVec2 v0, gbVec2 v1) { return v0.x*v1.x + v0.y*v1.y; }
float gb_vec3_dot(gbVec3 v0, gbVec3 v1) { return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z;
}
float gb_vec4_dot(gbVec4 v0, gbVec4 v1) { return v0.x*v1.x + v0.y*v1.y + v0.z*v1.z
+ v0.w*v1.w; }
void gb_vec2_cross(float *d, gbVec2 v0, gbVec2 v1) {   *d = v0.x*v1.y - v1.x*v0.y; }
void gb_vec3_cross(gbVec3 *d, gbVec3 v0, gbVec3 v1)    { d->x = v0.y*v1.z -
v0.z*v1.y;
                                                d->y   = v0.z*v1.x - v0.x*v1.z;
                                                d->z   = v0.x*v1.y - v0.y*v1.x; }
float gb_vec2_mag2(gbVec2 v) { return gb_vec2_dot(v, v); }
float gb_vec3_mag2(gbVec3 v) { return gb_vec3_dot(v, v); }
float gb_vec4_mag2(gbVec4 v) { return gb_vec4_dot(v, v); }
/* TODO(bill): Create custom sqrt function */
float gb_vec2_mag(gbVec2 v) { return gb_sqrt(gb_vec2_dot(v, v)); }
float gb_vec3_mag(gbVec3 v) { return gb_sqrt(gb_vec3_dot(v, v)); }
float gb_vec4_mag(gbVec4 v) { return gb_sqrt(gb_vec4_dot(v, v)); }
void gb_vec2_norm(gbVec2 *d, gbVec2 v) {
      float inv_mag = gb_rsqrt(gb_vec2_dot(v, v));
      gb_vec2_mul(d, v, inv_mag);
}
void gb_vec3_norm(gbVec3 *d, gbVec3 v) {
      float mag = gb_vec3_mag(v);
      gb_vec3_div(d, v, mag);
}
void gb_vec4_norm(gbVec4 *d, gbVec4 v) {
      float mag = gb_vec4_mag(v);
      gb_vec4_div(d, v, mag);
}
void gb_vec2_norm0(gbVec2 *d, gbVec2 v) {
      float mag = gb_vec2_mag(v);
      if (mag > 0)
            gb_vec2_div(d, v, mag);
      else
            *d = gb_vec2_zero();
}
void gb_vec3_norm0(gbVec3 *d, gbVec3 v) {
      float mag = gb_vec3_mag(v);
      if (mag > 0)
            gb_vec3_div(d, v, mag);
      else
            *d = gb_vec3_zero();
}
void gb_vec4_norm0(gbVec4 *d, gbVec4 v) {
      float mag = gb_vec4_mag(v);
      if (mag > 0)
            gb_vec4_div(d, v, mag);
      else
            *d = gb_vec4_zero();
}
void gb_vec2_reflect(gbVec2 *d, gbVec2 i, gbVec2 n) {
      gbVec2 b = n;
      gb_vec2_muleq(&b, 2.0f*gb_vec2_dot(n, i));
      gb_vec2_sub(d, i, b);
}
void gb_vec3_reflect(gbVec3 *d, gbVec3 i, gbVec3 n) {
      gbVec3 b = n;
      gb_vec3_muleq(&b, 2.0f*gb_vec3_dot(n, i));
      gb_vec3_sub(d, i, b);
}
void gb_vec2_refract(gbVec2 *d, gbVec2 i, gbVec2 n, float eta) {
      gbVec2 a, b;
      float dv, k;
     dv = gb_vec2_dot(n, i);
     k = 1.0f - eta*eta * (1.0f - dv*dv);
     gb_vec2_mul(&a, i, eta);
     gb_vec2_mul(&b, n, eta*dv*gb_sqrt(k));
     gb_vec2_sub(d, a, b);
     gb_vec2_muleq(d, (float)(k >= 0.0f));
}
void gb_vec3_refract(gbVec3 *d, gbVec3 i, gbVec3 n, float eta) {
      gbVec3 a, b;
      float dv, k;
     dv = gb_vec3_dot(n, i);
     k = 1.0f - eta*eta * (1.0f - dv*dv);
     gb_vec3_mul(&a, i, eta);
     gb_vec3_mul(&b, n, eta*dv*gb_sqrt(k));
     gb_vec3_sub(d, a, b);
     gb_vec3_muleq(d, (float)(k >= 0.0f));
}
float gb_vec2_aspect_ratio(gbVec2 v) { return (v.y < 0.0001f) ? 0.0f : v.x/v.y; }
void gb_mat2_transpose(gbMat2 *m) { gb_float22_transpose(gb_float22_m(m)); }
void gb_mat2_identity(gbMat2 *m) { gb_float22_identity(gb_float22_m(m)); }
void gb_mat2_mul(gbMat2 *out, gbMat2 *m1, gbMat2 *m2)
{ gb_float22_mul(gb_float22_m(out), gb_float22_m(m1), gb_float22_m(m2)); }
void gb_float22_identity(float m[2][2]) {
      m[0][0] = 1; m[0][1] = 0;
      m[1][0] = 0; m[1][1] = 1;
}
void gb_mat2_mul_vec2(gbVec2 *out, gbMat2 *m, gbVec2 in) { gb_float22_mul_vec2(out,
gb_float22_m(m), in); }
gbMat2 *gb_mat2_v(gbVec2 m[2])   { return (gbMat2 *)m; }
gbMat2 *gb_mat2_f(float m[2][2]) { return (gbMat2 *)m; }
gbFloat2 *gb_float22_m(gbMat2 *m)   { return (gbFloat2 *)m; }
gbFloat2 *gb_float22_v(gbVec2 m[2]) { return (gbFloat2 *)m; }
gbFloat2 *gb_float22_4(float m[4])       { return (gbFloat2 *)m; }
void gb_float22_transpose(float (*vec)[2]) {
      int i, j;
      for (j = 0; j < 2; j++) {
            for (i = j + 1; i < 2; i++) {
                  float t = vec[i][j];
                  vec[i][j] = vec[j][i];
                  vec[j][i] = t;
            }
      }
}
void gb_float22_mul(float (*out)[2], float (*mat1)[2], float (*mat2)[2]) {
      int i, j;
      float temp1[2][2], temp2[2][2];
      if (mat1 == out) { gb__memcpy_4byte(temp1, mat1, sizeof(temp1)); mat1 =
temp1; }
      if (mat2 == out) { gb__memcpy_4byte(temp2, mat2, sizeof(temp2)); mat2 =
temp2; }
      for (j = 0; j < 2; j++) {
            for (i = 0; i < 2; i++) {
                  out[j][i] = mat1[0][i]*mat2[j][0]
                            + mat1[1][i]*mat2[j][1];
            }
      }
}
void gb_float22_mul_vec2(gbVec2 *out, float m[2][2], gbVec2 v) {
      out->x = m[0][0]*v.x + m[1][0]*v.y;
      out->y = m[0][1]*v.x + m[1][1]*v.y;
}
float gb_mat2_determinate(gbMat2 *m) {
      gbFloat2 *e = gb_float22_m(m);
      return e[0][0]*e[1][1] - e[1][0]*e[0][1];
}
void gb_mat2_inverse(gbMat2 *out, gbMat2 *in) {
      gbFloat2 *o = gb_float22_m(out);
      gbFloat2 *i = gb_float22_m(in);
     float ood = 1.0f / gb_mat2_determinate(in);
     o[0][0]   =   +i[1][1]   *   ood;
     o[0][1]   =   -i[0][1]   *   ood;
     o[1][0]   =   -i[1][0]   *   ood;
     o[1][1]   =   +i[0][0]   *   ood;
}
void gb_mat3_transpose(gbMat3 *m) { gb_float33_transpose(gb_float33_m(m)); }
void gb_mat3_identity(gbMat3 *m) { gb_float33_identity(gb_float33_m(m)); }
void gb_mat3_mul(gbMat3 *out, gbMat3 *m1, gbMat3 *m2)
{ gb_float33_mul(gb_float33_m(out), gb_float33_m(m1), gb_float33_m(m2)); }
void gb_float33_identity(float m[3][3])   {
      m[0][0] = 1; m[0][1] = 0; m[0][2]   = 0;
      m[1][0] = 0; m[1][1] = 1; m[1][2]   = 0;
      m[2][0] = 0; m[2][1] = 0; m[2][2]   = 1;
}
void gb_mat3_mul_vec3(gbVec3 *out, gbMat3 *m, gbVec3 in) { gb_float33_mul_vec3(out,
gb_float33_m(m), in); }
gbMat3 *gb_mat3_v(gbVec3 m[3])   { return (gbMat3 *)m; }
gbMat3 *gb_mat3_f(float m[3][3]) { return (gbMat3 *)m; }
gbFloat3 *gb_float33_m(gbMat3 *m)   { return (gbFloat3 *)m; }
gbFloat3 *gb_float33_v(gbVec3 m[3]) { return (gbFloat3 *)m; }
gbFloat3 *gb_float33_9(float m[9]) { return (gbFloat3 *)m; }
void gb_float33_transpose(float (*vec)[3]) {
      int i, j;
      for (j = 0; j < 3; j++) {
            for (i = j + 1; i < 3; i++) {
                  float t = vec[i][j];
                  vec[i][j] = vec[j][i];
                  vec[j][i] = t;
            }
      }
}
void gb_float33_mul(float (*out)[3], float (*mat1)[3], float (*mat2)[3]) {
      int i, j;
      float temp1[3][3], temp2[3][3];
      if (mat1 == out) { gb__memcpy_4byte(temp1, mat1, sizeof(temp1)); mat1 =
temp1; }
      if (mat2 == out) { gb__memcpy_4byte(temp2, mat2, sizeof(temp2)); mat2 =
temp2; }
      for (j = 0; j < 3; j++) {
            for (i = 0; i < 3; i++) {
                  out[j][i] = mat1[0][i]*mat2[j][0]
                            + mat1[1][i]*mat2[j][1]
                            + mat1[2][i]*mat2[j][2];
            }
      }
}
void gb_float33_mul_vec3(gbVec3 *out, float m[3][3], gbVec3 v) {
      out->x = m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z;
      out->y = m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z;
      out->z = m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z;
}
float gb_mat3_determinate(gbMat3 *m) {
      gbFloat3 *e = gb_float33_m(m);
      float d = +e[0][0] * (e[1][1] * e[2][2] - e[1][2] * e[2][1])
                -e[0][1] * (e[1][0] * e[2][2] - e[1][2] * e[2][0])
                +e[0][2] * (e[1][0] * e[2][1] - e[1][1] * e[2][0]);
     return d;
}
void gb_mat3_inverse(gbMat3 *out, gbMat3 *in) {
      gbFloat3 *o = gb_float33_m(out);
      gbFloat3 *i = gb_float33_m(in);
     float ood = 1.0f / gb_mat3_determinate(in);
     o[0][0]   =   +(i[1][1]   *   i[2][2]   -   i[2][1]     *   i[1][2])   *   ood;
     o[0][1]   =   -(i[1][0]   *   i[2][2]   -   i[2][0]     *   i[1][2])   *   ood;
     o[0][2]   =   +(i[1][0]   *   i[2][1]   -   i[2][0]     *   i[1][1])   *   ood;
     o[1][0]   =   -(i[0][1]   *   i[2][2]   -   i[2][1]     *   i[0][2])   *   ood;
     o[1][1]   =   +(i[0][0]   *   i[2][2]   -   i[2][0]     *   i[0][2])   *   ood;
     o[1][2]   =   -(i[0][0]   *   i[2][1]   -   i[2][0]     *   i[0][1])   *   ood;
     o[2][0]   =   +(i[0][1]   *   i[1][2]   -   i[1][1]     *   i[0][2])   *   ood;
     o[2][1]   =   -(i[0][0]   *   i[1][2]   -   i[1][0]     *   i[0][2])   *   ood;
     o[2][2]   =   +(i[0][0]   *   i[1][1]   -   i[1][0]     *   i[0][1])   *   ood;
}
void gb_mat4_transpose(gbMat4 *m) { gb_float44_transpose(gb_float44_m(m)); }
void gb_mat4_identity(gbMat4 *m) { gb_float44_identity(gb_float44_m(m)); }
void gb_mat4_mul(gbMat4 *out, gbMat4 *m1, gbMat4 *m2)
{ gb_float44_mul(gb_float44_m(out), gb_float44_m(m1), gb_float44_m(m2)); }
void gb_float44_identity(float m[4][4])            {
      m[0][0] = 1; m[0][1] = 0; m[0][2]            =   0;   m[0][3]   =   0;
      m[1][0] = 0; m[1][1] = 1; m[1][2]            =   0;   m[1][3]   =   0;
      m[2][0] = 0; m[2][1] = 0; m[2][2]            =   1;   m[2][3]   =   0;
      m[3][0] = 0; m[3][1] = 0; m[3][2]            =   0;   m[3][3]   =   1;
}
void gb_mat4_mul_vec4(gbVec4 *out, gbMat4 *m, gbVec4 in) {
      gb_float44_mul_vec4(out, gb_float44_m(m), in);
}
gbMat4 *gb_mat4_v(gbVec4 m[4])   { return (gbMat4 *)m; }
gbMat4 *gb_mat4_f(float m[4][4]) { return (gbMat4 *)m; }
gbFloat4 *gb_float44_m(gbMat4 *m)    { return (gbFloat4 *)m; }
gbFloat4 *gb_float44_v(gbVec4 m[4]) { return (gbFloat4 *)m; }
gbFloat4 *gb_float44_16(float m[16]) { return (gbFloat4 *)m; }
void gb_float44_transpose(float (*vec)[4]) {
      float tmp;
      tmp = vec[1][0]; vec[1][0] = vec[0][1];                vec[0][1]     =   tmp;
      tmp = vec[2][0]; vec[2][0] = vec[0][2];                vec[0][2]     =   tmp;
      tmp = vec[3][0]; vec[3][0] = vec[0][3];                vec[0][3]     =   tmp;
      tmp = vec[2][1]; vec[2][1] = vec[1][2];                vec[1][2]     =   tmp;
     tmp = vec[3][1]; vec[3][1] = vec[1][3]; vec[1][3] = tmp;
     tmp = vec[3][2]; vec[3][2] = vec[2][3]; vec[2][3] = tmp;
}
void gb_float44_mul(float (*out)[4], float (*mat1)[4], float (*mat2)[4]) {
      int i, j;
      float temp1[4][4], temp2[4][4];
      if (mat1 == out) { gb__memcpy_4byte(temp1, mat1, sizeof(temp1)); mat1 =
temp1; }
      if (mat2 == out) { gb__memcpy_4byte(temp2, mat2, sizeof(temp2)); mat2 =
temp2; }
      for (j = 0; j < 4; j++) {
            for (i = 0; i < 4; i++) {
                  out[j][i] = mat1[0][i]*mat2[j][0]
                            + mat1[1][i]*mat2[j][1]
                            + mat1[2][i]*mat2[j][2]
                            + mat1[3][i]*mat2[j][3];
            }
      }
}
void gb_float44_mul_vec4(gbVec4 *out, float m[4][4], gbVec4 v) {
      out->x = m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w;
      out->y = m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w;
      out->z = m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w;
      out->w = m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w;
}
void gb_mat4_inverse(gbMat4 *out, gbMat4 *in) {
      gbFloat4 *o = gb_float44_m(out);
      gbFloat4 *m = gb_float44_m(in);
     float ood;
     float   sf00   =   m[2][2]   *   m[3][3]   -   m[3][2]   *   m[2][3];
     float   sf01   =   m[2][1]   *   m[3][3]   -   m[3][1]   *   m[2][3];
     float   sf02   =   m[2][1]   *   m[3][2]   -   m[3][1]   *   m[2][2];
     float   sf03   =   m[2][0]   *   m[3][3]   -   m[3][0]   *   m[2][3];
     float   sf04   =   m[2][0]   *   m[3][2]   -   m[3][0]   *   m[2][2];
     float   sf05   =   m[2][0]   *   m[3][1]   -   m[3][0]   *   m[2][1];
     float   sf06   =   m[1][2]   *   m[3][3]   -   m[3][2]   *   m[1][3];
     float   sf07   =   m[1][1]   *   m[3][3]   -   m[3][1]   *   m[1][3];
     float   sf08   =   m[1][1]   *   m[3][2]   -   m[3][1]   *   m[1][2];
     float   sf09   =   m[1][0]   *   m[3][3]   -   m[3][0]   *   m[1][3];
     float   sf10   =   m[1][0]   *   m[3][2]   -   m[3][0]   *   m[1][2];
     float   sf11   =   m[1][1]   *   m[3][3]   -   m[3][1]   *   m[1][3];
     float   sf12   =   m[1][0]   *   m[3][1]   -   m[3][0]   *   m[1][1];
     float   sf13   =   m[1][2]   *   m[2][3]   -   m[2][2]   *   m[1][3];
     float   sf14   =   m[1][1]   *   m[2][3]   -   m[2][1]   *   m[1][3];
     float   sf15   =   m[1][1]   *   m[2][2]   -   m[2][1]   *   m[1][2];
     float   sf16   =   m[1][0]   *   m[2][3]   -   m[2][0]   *   m[1][3];
     float   sf17   =   m[1][0]   *   m[2][2]   -   m[2][0]   *   m[1][2];
     float   sf18   =   m[1][0]   *   m[2][1]   -   m[2][0]   *   m[1][1];
     o[0][0]   =   +(m[1][1]   *   sf00   -   m[1][2]   *   sf01   +   m[1][3]   *   sf02);
     o[1][0]   =   -(m[1][0]   *   sf00   -   m[1][2]   *   sf03   +   m[1][3]   *   sf04);
     o[2][0]   =   +(m[1][0]   *   sf01   -   m[1][1]   *   sf03   +   m[1][3]   *   sf05);
     o[3][0]   =   -(m[1][0]   *   sf02   -   m[1][1]   *   sf04   +   m[1][2]   *   sf05);
     o[0][1]   =   -(m[0][1]   *   sf00   -   m[0][2]   *   sf01   +   m[0][3]   *   sf02);
     o[1][1]   =   +(m[0][0]   *   sf00   -   m[0][2]   *   sf03   +   m[0][3]   *   sf04);
     o[2][1]   =   -(m[0][0]   *   sf01   -   m[0][1]   *   sf03   +   m[0][3]   *   sf05);
     o[3][1]   =   +(m[0][0]   *   sf02   -   m[0][1]   *   sf04   +   m[0][2]   *   sf05);
     o[0][2]   =   +(m[0][1]   *   sf06   -   m[0][2]   *   sf07   +   m[0][3]   *   sf08);
     o[1][2]   =   -(m[0][0]   *   sf06   -   m[0][2]   *   sf09   +   m[0][3]   *   sf10);
     o[2][2]   =   +(m[0][0]   *   sf11   -   m[0][1]   *   sf09   +   m[0][3]   *   sf12);
     o[3][2]   =   -(m[0][0]   *   sf08   -   m[0][1]   *   sf10   +   m[0][2]   *   sf12);
     o[0][3]   =   -(m[0][1]   *   sf13   -   m[0][2]   *   sf14   +   m[0][3]   *   sf15);
     o[1][3]   =   +(m[0][0]   *   sf13   -   m[0][2]   *   sf16   +   m[0][3]   *   sf17);
     o[2][3]   =   -(m[0][0]   *   sf14   -   m[0][1]   *   sf16   +   m[0][3]   *   sf18);
     o[3][3]   =   +(m[0][0]   *   sf15   -   m[0][1]   *   sf17   +   m[0][2]   *   sf18);
     ood = 1.0f / (m[0][0] * o[0][0] +
                         m[0][1] * o[1][0] +
                         m[0][2] * o[2][0] +
                         m[0][3] * o[3][0]);
     o[0][0]   *=   ood;
     o[0][1]   *=   ood;
     o[0][2]   *=   ood;
     o[0][3]   *=   ood;
     o[1][0]   *=   ood;
     o[1][1]   *=   ood;
     o[1][2]   *=   ood;
     o[1][3]   *=   ood;
     o[2][0]   *=   ood;
     o[2][1]   *=   ood;
     o[2][2]   *=   ood;
     o[2][3]   *=   ood;
     o[3][0]   *=   ood;
     o[3][1]   *=   ood;
     o[3][2]   *=   ood;
     o[3][3]   *=   ood;
}
void gb_mat4_translate(gbMat4 *out, gbVec3 v) {
      gb_mat4_identity(out);
      out->col[3].xyz = v;
      out->col[3].w = 1;
}
void gb_mat4_rotate(gbMat4 *out, gbVec3 v, float angle_radians) {
      float c, s;
      gbVec3 axis, t;
      gbFloat4 *rot;
     c = gb_cos(angle_radians);
     s = gb_sin(angle_radians);
     gb_vec3_norm(&axis, v);
     gb_vec3_mul(&t, axis, 1.0f-c);
     gb_mat4_identity(out);
     rot = gb_float44_m(out);
     rot[0][0]     =   c + t.x*axis.x;
     rot[0][1]     =   0 + t.x*axis.y + s*axis.z;
     rot[0][2]     =   0 + t.x*axis.z - s*axis.y;
     rot[0][3]     =   0;
     rot[1][0]     =   0 + t.y*axis.x - s*axis.z;
     rot[1][1]     =   c + t.y*axis.y;
     rot[1][2]     =   0 + t.y*axis.z + s*axis.x;
     rot[1][3]     =   0;
     rot[2][0]     =   0 + t.z*axis.x + s*axis.y;
     rot[2][1]     =   0 + t.z*axis.y - s*axis.x;
     rot[2][2]     =   c + t.z*axis.z;
     rot[2][3]     =   0;
}
void gb_mat4_scale(gbMat4 *out, gbVec3 v) {
      gb_mat4_identity(out);
      out->e[0] = v.x;
      out->e[5] = v.y;
      out->e[10] = v.z;
}
void gb_mat4_scalef(gbMat4 *out, float s) {
      gb_mat4_identity(out);
      out->e[0] = s;
      out->e[5] = s;
      out->e[10] = s;
}
void gb_mat4_ortho2d(gbMat4 *out, float left, float right, float bottom, float top)
{
      gbFloat4 *m;
      gb_mat4_identity(out);
      m = gb_float44_m(out);
     m[0][0]   =   2.0f / (right - left);
     m[1][1]   =   2.0f / (top - bottom);
     m[2][2]   =   -1.0f;
     m[3][0]   =   -(right + left) / (right - left);
     m[3][1]   =   -(top + bottom) / (top - bottom);
}
void gb_mat4_ortho3d(gbMat4 *out, float left, float right, float bottom, float top,
float z_near, float z_far) {
      gbFloat4 *m;
      gb_mat4_identity(out);
      m = gb_float44_m(out);
     m[0][0]   =   +2.0f /   (right - left);
     m[1][1]   =   +2.0f /   (top - bottom);
     m[2][2]   =   -2.0f /   (z_far - z_near);
     m[3][0]   =   -(right   + left)   / (right - left);
     m[3][1] = -(top   + bottom) / (top   - bottom);
     m[3][2] = -(z_far + z_near) / (z_far - z_near);
}
void gb_mat4_perspective(gbMat4 *out, float fovy, float aspect, float z_near, float
z_far) {
      float tan_half_fovy = gb_tan(0.5f * fovy);
      gbMat4 zero_mat = {0};
      gbFloat4 *m = gb_float44_m(out);
      *out = zero_mat;
     m[0][0]   =   1.0f / (aspect*tan_half_fovy);
     m[1][1]   =   1.0f / (tan_half_fovy);
     m[2][2]   =   -(z_far + z_near) / (z_far - z_near);
     m[2][3]   =   -1.0f;
     m[3][2]   =   -2.0f*z_far*z_near / (z_far - z_near);
}
void gb_mat4_infinite_perspective(gbMat4 *out, float fovy, float aspect, float
z_near) {
      float range = gb_tan(0.5f * fovy) * z_near;
      float left   = -range * aspect;
      float right = range * aspect;
      float bottom = -range;
      float top    = range;
      gbMat4 zero_mat = {0};
      gbFloat4 *m = gb_float44_m(out);
      *out = zero_mat;
     m[0][0]   =   (2.0f*z_near) / (right - left);
     m[1][1]   =   (2.0f*z_near) / (top   - bottom);
     m[2][2]   =   -1.0f;
     m[2][3]   =   -1.0f;
     m[3][2]   =   -2.0f*z_near;
}
void gb_mat4_look_at(gbMat4 *out, gbVec3 eye, gbVec3 centre, gbVec3 up) {
      gbVec3 f, s, u;
      gbFloat4 *m;
     gb_vec3_sub(&f, centre, eye);
     gb_vec3_norm(&f, f);
     gb_vec3_cross(&s, f, up);
     gb_vec3_norm(&s, s);
     gb_vec3_cross(&u, s, f);
     gb_mat4_identity(out);
     m = gb_float44_m(out);
     m[0][0] = +s.x;
     m[1][0] = +s.y;
     m[2][0] = +s.z;
     m[0][1] = +u.x;
     m[1][1] = +u.y;
     m[2][1] = +u.z;
     m[0][2] = -f.x;
     m[1][2] = -f.y;
     m[2][2] = -f.z;
     m[3][0] = -gb_vec3_dot(s, eye);
     m[3][1] = -gb_vec3_dot(u, eye);
     m[3][2] = +gb_vec3_dot(f, eye);
}
gbQuat gb_quat(float x, float y, float z, float w) { gbQuat q; q.x = x; q.y = y;
q.z = z; q.w = w; return q; }
gbQuat gb_quatv(float e[4]) { gbQuat q; q.x = e[0]; q.y = e[1]; q.z = e[2]; q.w =
e[3]; return q; }
gbQuat gb_quat_axis_angle(gbVec3 axis, float angle_radians) {
      gbQuat q;
      gb_vec3_norm(&q.xyz, axis);
      gb_vec3_muleq(&q.xyz, gb_sin(0.5f*angle_radians));
      q.w = gb_cos(0.5f*angle_radians);
      return q;
}
gbQuat gb_quat_euler_angles(float pitch, float yaw, float roll) {
      /* TODO(bill): Do without multiplication, i.e. make it faster */
      gbQuat q, p, y, r;
      p = gb_quat_axis_angle(gb_vec3(1, 0, 0), pitch);
      y = gb_quat_axis_angle(gb_vec3(0, 1, 0), yaw);
      r = gb_quat_axis_angle(gb_vec3(0, 0, 1), roll);
     gb_quat_mul(&q, y, p);
     gb_quat_muleq(&q, r);
     return q;
}
gbQuat gb_quat_identity(void) { gbQuat q = {0, 0, 0, 1}; return q; }
void gb_quat_add(gbQuat *d, gbQuat q0, gbQuat q1) { gb_vec4_add(&d->xyzw, q0.xyzw,
q1.xyzw); }
void gb_quat_sub(gbQuat *d, gbQuat q0, gbQuat q1) { gb_vec4_sub(&d->xyzw, q0.xyzw,
q1.xyzw); }
void gb_quat_mul(gbQuat *d, gbQuat q0,   gbQuat   q1) {
      d->x = q0.w * q1.x + q0.x * q1.w   + q0.y   * q1.z - q0.z * q1.y;
      d->y = q0.w * q1.y - q0.x * q1.z   + q0.y   * q1.w + q0.z * q1.x;
      d->z = q0.w * q1.z + q0.x * q1.y   - q0.y   * q1.x + q0.z * q1.w;
       d->w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
}
void gb_quat_div(gbQuat *d, gbQuat q0, gbQuat q1){ gbQuat iq1;
gb_quat_inverse(&iq1, q1); gb_quat_mul(d, q0, iq1); }
void gb_quat_mulf(gbQuat *d, gbQuat q0, float s) { gb_vec4_mul(&d->xyzw, q0.xyzw,
s); }
void gb_quat_divf(gbQuat *d, gbQuat q0, float s) { gb_vec4_div(&d->xyzw, q0.xyzw,
s); }
void   gb_quat_addeq(gbQuat   *d,   gbQuat   q)   {   gb_vec4_addeq(&d->xyzw, q.xyzw); }
void   gb_quat_subeq(gbQuat   *d,   gbQuat   q)   {   gb_vec4_subeq(&d->xyzw, q.xyzw); }
void   gb_quat_muleq(gbQuat   *d,   gbQuat   q)   {   gb_quat_mul(d, *d, q); }
void   gb_quat_diveq(gbQuat   *d,   gbQuat   q)   {   gb_quat_div(d, *d, q); }
void gb_quat_muleqf(gbQuat *d, float s) { gb_vec4_muleq(&d->xyzw, s); }
void gb_quat_diveqf(gbQuat *d, float s) { gb_vec4_diveq(&d->xyzw, s); }
float gb_quat_dot(gbQuat q0, gbQuat q1) { float r = gb_vec3_dot(q0.xyz, q1.xyz) +
q0.w*q1.w; return r; }
float gb_quat_mag(gbQuat q)           { float r = gb_sqrt(gb_quat_dot(q, q));
return r; }
void gb_quat_norm(gbQuat *d, gbQuat q)    { gb_quat_divf(d, q, gb_quat_mag(q)); }
void gb_quat_conj(gbQuat *d, gbQuat q)    { d->xyz = gb_vec3(-q.x, -q.y, -q.z); d-
>w = q.w; }
void gb_quat_inverse(gbQuat *d, gbQuat q) { gb_quat_conj(d, q); gb_quat_diveqf(d,
gb_quat_dot(q, q)); }
void gb_quat_axis(gbVec3 *axis, gbQuat q) {
      gbQuat n; gb_quat_norm(&n, q);
      gb_vec3_div(axis, n.xyz, gb_sin(gb_arccos(q.w)));
}
float gb_quat_angle(gbQuat q) {
      float mag = gb_quat_mag(q);
      float c = q.w * (1.0f/mag);
      float angle = 2.0f*gb_arccos(c);
      return angle;
}
float gb_quat_roll(gbQuat q)        { return gb_arctan2(2.0f*q.x*q.y + q.z*q.w, q.x*q.x +
q.w*q.w - q.y*q.y - q.z*q.z);       }
float gb_quat_pitch(gbQuat q)       { return gb_arctan2(2.0f*q.y*q.z + q.w*q.x, q.w*q.w -
q.x*q.x - q.y*q.y + q.z*q.z);       }
float gb_quat_yaw(gbQuat q)         { return gb_arcsin(-2.0f*(q.x*q.z - q.w*q.y)); }
void gb_quat_rotate_vec3(gbVec3 *d, gbQuat q, gbVec3 v) {
      /* gbVec3 t = 2.0f * cross(q.xyz, v);
       * *d = q.w*t + v + cross(q.xyz, t);
       */
      gbVec3 t, p;
      gb_vec3_cross(&t, q.xyz, v);
      gb_vec3_muleq(&t, 2.0f);
     gb_vec3_cross(&p, q.xyz, t);
     gb_vec3_mul(d, t, q.w);
     gb_vec3_addeq(d, v);
     gb_vec3_addeq(d, p);
}
void gb_mat4_from_quat(gbMat4 *out, gbQuat q) {
      gbFloat4 *m;
      gbQuat a;
      float xx, yy, zz,
            xy, xz, yz,
            wx, wy, wz;
     gb_quat_norm(&a,   q);
     xx = a.x*a.x; yy   = a.y*a.y; zz = a.z*a.z;
     xy = a.x*a.y; xz   = a.x*a.z; yz = a.y*a.z;
     wx = a.w*a.x; wy   = a.w*a.y; wz = a.w*a.z;
     gb_mat4_identity(out);
     m = gb_float44_m(out);
     m[0][0] = 1.0f - 2.0f*(yy + zz);
     m[0][1] =        2.0f*(xy + wz);
     m[0][2] =        2.0f*(xz - wy);
     m[1][0] =        2.0f*(xy - wz);
     m[1][1] = 1.0f - 2.0f*(xx + zz);
     m[1][2] =        2.0f*(yz + wx);
     m[2][0] =        2.0f*(xz + wy);
     m[2][1] =        2.0f*(yz - wx);
     m[2][2] = 1.0f - 2.0f*(xx + yy);
}
void gb_quat_from_mat4(gbQuat *out, gbMat4 *mat) {
      gbFloat4 *m;
      float four_x_squared_minus_1, four_y_squared_minus_1,
            four_z_squared_minus_1, four_w_squared_minus_1,
            four_biggest_squared_minus_1;
      int biggest_index = 0;
      float biggest_value, mult;
     m = gb_float44_m(mat);
     four_x_squared_minus_1   =   m[0][0]   -   m[1][1]   -   m[2][2];
     four_y_squared_minus_1   =   m[1][1]   -   m[0][0]   -   m[2][2];
     four_z_squared_minus_1   =   m[2][2]   -   m[0][0]   -   m[1][1];
     four_w_squared_minus_1   =   m[0][0]   +   m[1][1]   +   m[2][2];
     four_biggest_squared_minus_1 = four_w_squared_minus_1;
     if (four_x_squared_minus_1 > four_biggest_squared_minus_1) {
           four_biggest_squared_minus_1 = four_x_squared_minus_1;
           biggest_index = 1;
     }
     if (four_y_squared_minus_1 > four_biggest_squared_minus_1) {
           four_biggest_squared_minus_1 = four_y_squared_minus_1;
           biggest_index = 2;
     }
     if (four_z_squared_minus_1 > four_biggest_squared_minus_1) {
           four_biggest_squared_minus_1 = four_z_squared_minus_1;
           biggest_index = 3;
     }
     biggest_value = gb_sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f;
     mult = 0.25f / biggest_value;
     switch (biggest_index) {
     case 0:
           out->w = biggest_value;
           out->x = (m[1][2] - m[2][1]) * mult;
           out->y = (m[2][0] - m[0][2]) * mult;
           out->z = (m[0][1] - m[1][0]) * mult;
           break;
     case 1:
           out->w = (m[1][2] - m[2][1]) * mult;
           out->x = biggest_value;
           out->y = (m[0][1] + m[1][0]) * mult;
           out->z = (m[2][0] + m[0][2]) * mult;
           break;
     case 2:
           out->w = (m[2][0] - m[0][2]) * mult;
           out->x = (m[0][1] + m[1][0]) * mult;
           out->y = biggest_value;
           out->z = (m[1][2] + m[2][1]) * mult;
           break;
     case 3:
           out->w = (m[0][1] - m[1][0]) * mult;
           out->x = (m[2][0] + m[0][2]) * mult;
           out->y = (m[1][2] + m[2][1]) * mult;
           out->z = biggest_value;
           break;
     default:
           /* NOTE(bill): This shouldn't fucking happen!!! */
           break;
     }
float gb_lerp         (float a, float b, float   t) { return a*(1.0f-t) + b*t; }
float gb_unlerp       (float t, float a, float   b) { return (t-a)/(b-a); }
float gb_smooth_step (float a, float b, float    t) { float x = (t - a)/(b - a);
return x*x*(3.0f - 2.0f*x); }
float gb_smoother_step(float a, float b, float   t) { float x = (t - a)/(b - a);
return x*x*x*(x*(6.0f*x - 15.0f) + 10.0f); }
#define GB_VEC_LERPN(N, d, a, b, t) \
      gbVec##N db; \
      gb_vec##N##_sub(&db, b, a); \
      gb_vec##N##_muleq(&db, t); \
      gb_vec##N##_add(d,   a, db)
void gb_vec2_lerp(gbVec2   *d, gbVec2 a, gbVec2 b, float t) { GB_VEC_LERPN(2, d, a,
b, t); }
void gb_vec3_lerp(gbVec3   *d, gbVec3 a, gbVec3 b, float t) { GB_VEC_LERPN(3, d, a,
b, t); }
void gb_vec4_lerp(gbVec4   *d, gbVec4 a, gbVec4 b, float t) { GB_VEC_LERPN(4, d, a,
b, t); }
#undef GB_VEC_LERPN
void gb_quat_lerp(gbQuat *d, gbQuat a, gbQuat b, float t) { gb_vec4_lerp(&d->xyzw,
a.xyzw, b.xyzw, t); }
void gb_quat_nlerp(gbQuat *d, gbQuat a, gbQuat b, float t) { gb_quat_lerp(d, a, b,
t); gb_quat_norm(d, *d); }
void gb_quat_slerp(gbQuat *d, gbQuat a, gbQuat b, float t) {
      gbQuat x, y, z;
      float cos_theta, angle;
      float s1, s0, is;
     z = b;
     cos_theta = gb_quat_dot(a, b);
     if (cos_theta < 0.0f) {
           z = gb_quat(-b.x, -b.y, -b.z, -b.w);
           cos_theta = -cos_theta;
     }
      if (cos_theta > 1.0f) {
            /* NOTE(bill): Use lerp not nlerp as it's not a real angle or they are
not normalized */
            gb_quat_lerp(d, a, b, t);
      }
     angle = gb_arccos(cos_theta);
     s1 = gb_sin((1.0f - t)*angle);
     s0 = gb_sin(t*angle);
     is = 1.0f/gb_sin(angle);
     gb_quat_mulf(&x, a, s1);
     gb_quat_mulf(&y, z, s0);
     gb_quat_add(d, x, y);
     gb_quat_muleqf(d, is);
}
void gb_quat_slerp_approx(gbQuat *d, gbQuat a, gbQuat b, float t) {
      /* NOTE(bill): Derived by taylor expanding the geometric interpolation
equation
       *             Even works okay for nearly anti-parallel versors!!!
       */
      /* NOTE(bill): Extra interations cannot be used as they require angle^4 which
is not worth it to approximate */
      float tp = t + (1.0f - gb_quat_dot(a, b))/3.0f * t*(-2.0f*t*t + 3.0f*t -
1.0f);
      gb_quat_nlerp(d, a, b, tp);
}
void gb_quat_nquad(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t) {
      gbQuat x, y;
     gb_quat_nlerp(&x, p, q, t);
     gb_quat_nlerp(&y, a, b, t);
     gb_quat_nlerp(d, x, y, 2.0f*t*(1.0f-t));
}
void gb_quat_squad(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float t) {
      gbQuat x, y;
      gb_quat_slerp(&x, p, q, t);
      gb_quat_slerp(&y, a, b, t);
      gb_quat_slerp(d, x, y, 2.0f*t*(1.0f-t));
}
void gb_quat_squad_approx(gbQuat *d, gbQuat p, gbQuat a, gbQuat b, gbQuat q, float
t) {
      gbQuat x, y;
      gb_quat_slerp_approx(&x, p, q, t);
      gb_quat_slerp_approx(&y, a, b, t);
      gb_quat_slerp_approx(d, x, y, 2.0f*t*(1.0f-t));
}
gbRect2 gb_rect2(gbVec2 pos, gbVec2 dim) {
      gbRect2 r;
      r.pos = pos;
      r.dim = dim;
      return r;
}
gbRect2 gb_rect2v(float v[4]) {
      gbRect2 r;
      r.pos = gb_vec2v(&v[0]);
      r.dim = gb_vec2v(&v[2]);
      return r;
}
gbRect3 gb_rect3(gbVec3 pos, gbVec3 dim) {
      gbRect3 r;
      r.pos = pos;
      r.dim = dim;
      return r;
}
gbRect3 gb_rect3v(float v[6]) {
      gbRect3 r;
      r.pos = gb_vec3v(&v[0]);
      r.dim = gb_vec3v(&v[3]);
      return r;
}
int gb_rect2_contains(gbRect2 a, float x, float y) {
      float min_x = gb_min(a.pos.x, a.pos.x+a.dim.x);
      float max_x = gb_max(a.pos.x, a.pos.x+a.dim.x);
      float min_y = gb_min(a.pos.y, a.pos.y+a.dim.y);
      float max_y = gb_max(a.pos.y, a.pos.y+a.dim.y);
     int result = (x >= min_x) & (x < max_x) & (y >= min_y) & (y < max_y);
     return result;
}
int gb_rect2_contains_vec2(gbRect2 a, gbVec2 p) { return gb_rect2_contains(a, p.x,
p.y); }
int gb_rect2_intersects(gbRect2 a, gbRect2 b) {
      gbRect2 r = {0};
      return gb_rect2_intersection_result(a, b, &r);
}
int gb_rect2_intersection_result(gbRect2 a, gbRect2 b, gbRect2 *intersection) {
      float a_min_x = gb_min(a.pos.x, a.pos.x+a.dim.x);
      float a_max_x = gb_max(a.pos.x, a.pos.x+a.dim.x);
      float a_min_y = gb_min(a.pos.y, a.pos.y+a.dim.y);
      float a_max_y = gb_max(a.pos.y, a.pos.y+a.dim.y);
     float   b_min_x     =   gb_min(b.pos.x,   b.pos.x+b.dim.x);
     float   b_max_x     =   gb_max(b.pos.x,   b.pos.x+b.dim.x);
     float   b_min_y     =   gb_min(b.pos.y,   b.pos.y+b.dim.y);
     float   b_max_y     =   gb_max(b.pos.y,   b.pos.y+b.dim.y);
     float   x0   =   gb_max(a_min_x,   b_min_x);
     float   y0   =   gb_max(a_min_y,   b_min_y);
     float   x1   =   gb_min(a_max_x,   b_max_x);
     float   y1   =   gb_min(a_max_y,   b_max_y);
     if ((x0 < x1) && (y0 < y1)) {
           gbRect2 r = gb_rect2(gb_vec2(x0, y0), gb_vec2(x1-x0, y1-y0));
           *intersection = r;
           return 1;
     } else {
           gbRect2 r = {0};
           *intersection = r;
           return 0;
     }
}
#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
      gb_math_u64 gb_hash_murmur64(void const *key, size_t num_bytes, gb_math_u64
seed) {
            gb_math_u64 const m = 0xc6a4a7935bd1e995ULL;
            gb_math_u64 const r = 47;
             gb_math_u64 h = seed ^ (num_bytes * m);
             gb_math_u64 *data = (gb_math_u64 *)(key);
             gb_math_u64 *end = data + (num_bytes / 8);
             unsigned char *data2;
             while (data != end) {
                   gb_math_u64 k = *data++;
                   k *= m;
                   k ^= k >> r;
                   k *= m;
                   h ^= k;
                   h *= m;
            }
            data2 = (unsigned char *)data;
            switch (num_bytes & 7) {
            case 7: h ^= (gb_math_u64)data2[6] <<   48;
            case 6: h ^= (gb_math_u64)data2[5] <<   40;
            case 5: h ^= (gb_math_u64)data2[4] <<   32;
            case 4: h ^= (gb_math_u64)data2[3] <<   24;
            case 3: h ^= (gb_math_u64)data2[2] <<   16;
            case 2: h ^= (gb_math_u64)data2[1] <<   8;
            case 1: h ^= (gb_math_u64)data2[0];
                  h *= m;
            };
            h ^= h >> r;
            h *= m;
            h ^= h >> r;
            return h;
        }
#else
      gb_math_u64 gb_hash_murmur64(void const *key, size_t num_bytes, gb_math_u64
seed) {
            gb_math_u32 const m = 0x5bd1e995;
            gb_math_u32 const r = 24;
            gb_math_u64 h = 0;
            gb_math_u32 h1 = (gb_math_u32)seed ^ (gb_math_u32)num_bytes;
            gb_math_u32 h2 = (gb_math_u32)((gb_math_u64)seed >> 32);
            gb_math_u32 *data = (gb_math_u32 *)key;
            while (num_bytes >= 8) {
                  gb_math_u32 k1, k2;
                  k1 = *data++;
                  k1 *= m;
                  k1 ^= k1 >> r;
                  k1 *= m;
                  h1 *= m;
                  h1 ^= k1;
                  num_bytes -= 4;
                 k2 = *data++;
                 k2 *= m;
                 k2 ^= k2 >> r;
                 k2 *= m;
                 h2 *= m;
                 h2 ^= k2;
                 num_bytes -= 4;
            }
            if (num_bytes >= 4) {
                  gb_math_u32 k1 = *data++;
                  k1 *= m;
                  k1 ^= k1 >> r;
                  k1 *= m;
                  h1 *= m;
                     h1 ^= k1;
                     num_bytes -= 4;
           }
           switch (num_bytes) {
           gb_math_u32 a, b, c;
           case 3: c = data[2]; h2 ^= c << 16;
           case 2: b = data[1]; h2 ^= b << 8;
           case 1: a = data[0]; h2 ^= a << 0;
                 h2 *= m;
           };
           h1   ^=   h2   >> 18;
           h1   *=   m;
           h2   ^=   h1   >> 22;
           h2   *=   m;
           h1   ^=   h2   >> 17;
           h1   *=   m;
           h2   ^=   h1   >> 19;
           h2   *=   m;
           h = (gb_math_u64)(h << 32) | (gb_math_u64)h2;
           return h;
      }
#endif
/* TODO(bill): Make better random number generators */
float gb_random_range_float(float min_inc, float max_inc) {
      int int_result = gb_random_range_int(0, 2147483646); /* Prevent integer
overflow */
      float result = int_result/(float)2147483646;
      result *= max_inc - min_inc;
      result += min_inc;
      return result;
}
int gb_random_range_int(int min_inc, int max_inc) {
      static unsigned int random_value = 0xdeadbeef; /* Random Value */
      unsigned int diff, result;
      random_value = random_value * 2147001325 + 715136305; /* BCPL generator */
      diff = max_inc - min_inc + 1;
      result = random_value % diff;
      result += min_inc;
     return result;
}
float gb_random01(void) {
      return gb_random_range_float(0.0f, 1.0f);
}
#if defined(__GCC__) || defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif /* GB_MATH_IMPLEMENTATION */