/*FAST MATH*/

const float PI  = 3.14159265359;
const float TAU = 6.28318530718;
const float EPS = 1e-5;

float pow2(float x) {return x*x;}
vec2 pow2(vec2 x) {return x*x;}
vec3 pow2(vec3 x) {return x*x;}
vec4 pow2(vec4 x) {return x*x;}

float pow3(float x) {return x*x*x;}
vec2 pow3(vec2 x) {return x*x*x;}
vec3 pow3(vec3 x) {return x*x*x;}
vec4 pow3(vec4 x) {return x*x*x;}

float pow4(float x) {return pow2(pow2(x));}
vec2 pow4(vec2 x) {return pow2(pow2(x));}
vec3 pow4(vec3 x) {return pow2(pow2(x));}
vec4 pow4(vec4 x) {return pow2(pow2(x));}

float pow8(float x) {return pow4(pow4(x));}
vec2 pow8(vec2 x) {return pow4(pow4(x));}
vec3 pow8(vec3 x) {return pow4(pow4(x));}
vec4 pow8(vec4 x) {return pow4(pow4(x));}

float pow16(float x) {return pow4(pow4(x));}
float pow32(float x) {return pow2(pow16(x));}

#define MaxEPS(x) max(x, EPS)

#define clamp01(x) clamp(x, 0.0, 1.0)
#define clampInv11(x) clamp(x, -1.0, 1.0)

#define clamp00125(x) clamp(x, 0.0, 0.125)

#define clampVec2_01(x) clamp(x, vec2(0.0), vec2(1.0))

#define clampVec3_01(x) clamp(x, vec3(0.0), vec3(1.0))
#define clampVec3Inv_11(x) clamp(x, vec3(-1.0), vec3(1.0))

#define clampVec4_01(x) clamp(x, vec4(0.0) , vec4(1.0))

#define clampLmC_00933(x) clamp(x, vec2(0.0), vec2(0.9333, 1.0))

#define Max0(x) max(x, 0.0)

#define TBN_MATRIX(t, b, n) mat3(t.x, b.x, n.x, t.y, b.y, n.y, t.z, b.z, n.z)

float sqrt1(float x) {
    x = 1.0 - x;
    x *= x;
    return 1.0 - x;
}

float sqrt2(float x) {
    x = 1.0 - x;
    x *= x;
    x *= x;
    return 1.0 - x;
}

float Smooth3(float x)
{
	x = clamp(x, 0.0, 1.0);
	return x * x * (3.0 - 2.0 * x);
}

float range_trigo(float ax){
    float x = mod(ax, TAU);
    if(x > PI) x -= TAU;
    return x;
}

float sin_approx(float ax) {
    #ifdef TRIGO_APPROX
        float x = range_trigo(ax);
        if(x > (PI/2.0)) {
            x = - x + PI;
        }
        if(x < (-PI/2.0)) {
            x = - x - PI;
        }
        float x2 = x * x;
        float x3 = x * x2;
        float x5 = x3 * x2;
        float x7 = x5 * x2;
        return x - x3 / 6.0 + x5 / 120.0 - x7 / 5040.0;
    #else
        return sin(ax);
    #endif
}

vec4 sin_approx_vec4(vec4 v){
    return vec4(
        sin_approx(v.x),
        sin_approx(v.y),
        sin_approx(v.z),
        sin_approx(v.w)
    );
}

float cos_approx(float ax) {
    #ifdef TRIGO_APPROX
        float x = range_trigo(ax);
        float s = 1.0;
        if(abs(x) > (PI/2.0)){
            x = - abs(x) + PI;
            s = - 1.0;
        }
        float x2 = x * x;
        float x4 = x2 * x2;
        float x6 = x4 * x2;
        return (1.0 - x2 / 2.0 + x4 / 24.0 - x6 / 720.0) * s;
    #else
        return cos(ax);
    #endif
}

bool CheckForColor(vec3 albedo, vec3 check) {
      vec3 dif = albedo - check / 255.0;
      return dif == clamp(dif, vec3(-0.001), vec3(0.001));
}