// The Xmas Demo 2023: Semi-useful float and vector operations.
// Author: Corneliusen
// More info here: https://www.ignorantus.com/xmasdemo/
// License: https://creativecommons.org/publicdomain/zero/1.0/
#ifndef VECH
#define VECH

#include <stdint.h>
#include <math.h>

// float

// GLSL-style fract()
static inline float fract( float f )
{
    return f - floorf( f );
}

static inline float mix( float a, float b, float w )
{
    return a*(1.0f-w)+b*w;
}

static inline float sinf01( float f )
{
    return (sinf(f)+1.0f)*0.5f;
}

// v2

typedef struct {
    float x, y;
} v2;

static inline v2 v2_set( float x, float y )
{
    v2 r;
    r.x = x;
    r.y = y;
    return r;
}

// v3

typedef struct {
    float x, y, z;
} v3;

static inline v3 v3_set( float x, float y, float z )
{
    v3 v;
    v.x = x;
    v.y = y;
    v.z = z;
    return v;
}

static inline v3 v3_normalize( v3 a )
{
    v3 v;
    float b = 1.0f / sqrtf( a.x * a.x + a.y * a.y + a.z * a.z );
    v.x = a.x * b;
    v.y = a.y * b;
    v.z = a.z * b;
    return v;
}

static inline v3 v3_sub( v3 a, v3 b )
{
    v3 v;
    v.x = a.x - b.x;
    v.y = a.y - b.y;
    v.z = a.z - b.z;
    return v;
}

static inline float v3_dot( v3 a, v3 b )
{
    return a.x * b.x + a.y * b.y + a.z * b.z;
}

static inline float v3_dotsq( v3 a, v3 b )
{
    float c = a.x * b.x + a.y * b.y + a.z * b.z;
    return c * c;
}

// v4

typedef struct {
    float x, y, z, w;
} v4;

static inline v4 v4_set( float x, float y, float z, float w )
{
    v4 v;
    v.x = x;
    v.y = y;
    v.z = z;
    v.w = w;
    return v;
}

static inline v4 v4_set1( float f )
{
    return v4_set( f, f, f, f );
}

static inline v3 v4_get3( v4 w )
{
    v3 v;
    v.x = w.x;
    v.y = w.y;
    v.z = w.z;
    return v;
}

static inline v4 v4_add3( v4 a, v4 b )
{
    v4 v;
    v.x = a.x + b.x;
    v.y = a.y + b.y;
    v.z = a.z + b.z;
    return v;
}

static inline v4 v4_mul3( v4 a, float b )
{
    v4 v;
    v.x = a.x * b;
    v.y = a.y * b;
    v.z = a.z * b;
    v.w = a.w;
    return v;
}

static inline v4 v4_mul4( v4 a, float b )
{
    v4 v;
    v.x = a.x * b;
    v.y = a.y * b;
    v.z = a.z * b;
    v.w = a.w * b;
    return v;
}

static inline v4 v4_normalize3( v4 a )
{
    v4 v;
    float b = 1.0f / sqrtf( a.x * a.x + a.y * a.y + a.z * a.z );
    v.x = a.x * b;
    v.y = a.y * b;
    v.z = a.z * b;
    v.w = a.w;
    return v;
}

static inline v4 v4_mix( v4 a, v4 b, float f )
{
    v4 out;
    out.x = a.x*(1.0f-f)+b.x*f;
    out.y = a.y*(1.0f-f)+b.y*f;
    out.z = a.z*(1.0f-f)+b.z*f;
    out.w = a.w*(1.0f-f)+b.w*f;
    return out;
}

// uv4

typedef struct {
    uint32_t x, y, z, w;
} uv4;

#endif
