/*
====================================================================================================

    Copyright (C) 2020 RRe36

    All Rights Reserved unless otherwise explicitly stated.


    By downloading this you have agreed to the license and terms of use.
    These can be found inside the included license-file
    or here: https://rre36.com/copyright-license

    Violating these terms may be penalized with actions according to the Digital Millennium
    Copyright Act (DMCA), the Information Society Directive and/or similar laws
    depending on your country.

====================================================================================================
*/


bool isOnScreenDownscale(vec2 coord, vec2 pixel, const float lod) {
    return clamp(coord, -pixel * lod, 1.0 + pixel * lod) == coord;
}

float rcp(float x) {
    return crcp(x);
}
vec2 rcp(vec2 x) {
    return crcp(x);
}
vec3 rcp(vec3 x) {
    return crcp(x);
}

float sqr(float x) {
    return x*x;
}
float cube(float x) {
    return sqr(x)*x;
}
float pow4(float x) {
    return sqr(x)*sqr(x);
}
float pow5(float x) {
    return pow4(x)*x;
}
float pow6(float x) {
    return pow5(x)*x;
}
float pow8(float x) {
    return pow4(x)*pow4(x);
}

float log10(float x) {
    return log(x) * rLog10;
}
vec2 log10(vec2 x) {
    return log(x) * rLog10;
}
vec3 log10(vec3 x) {
    return log(x) * rLog10;
}

float cubeSmooth(float x) {
    return icubeSmooth(x);
}
vec2 cubeSmooth(vec2 x) {
    return icubeSmooth(x);
}

float v3avg(vec3 x) {
    return (x.x+x.y+x.z)/3.0;
}

float flength(vec2 x) {
    return sqrt(dot(x, x));
}
float flength(vec3 x) {
    return sqrt(dot(x, x));
}

float max2(vec2 x) {
    return max(x.x, x.y);
}
float min2(vec2 x) {
    return min(x.x, x.y);
}

float max3(float x, float y, float z) {
    return max(x, max(y, z));
}
float max3(vec3 x) {
    return max(x.x, max(x.y, x.z));
}
float min3(float x, float y, float z) {
    return min(x, min(y, z));
}
float min3(vec3 x) {
    return min(x.x, min(x.y, x.z));
}

float selfDot2(vec2 x) {
    return dot(x, x);
}
float selfDot3(vec3 x) {
    return dot(x, x);
}

vec3 greaterThanVec3(vec3 x, vec3 y, vec3 a, vec3 b) {
    vec3 data   = vec3(0.0);
        data.x  = x.x > y.x ? a.x : b.x;
        data.y  = x.y > y.y ? a.y : b.y;
        data.z  = x.z > y.z ? a.z : b.z;

    return data;
}
vec3 smallerThanVec3(vec3 x, vec3 y, vec3 a, vec3 b) {
    vec3 data   = vec3(0.0);
        data.x  = x.x < y.x ? a.x : b.x;
        data.y  = x.y < y.y ? a.y : b.y;
        data.z  = x.z < y.z ? a.z : b.z;

    return data;
}

vec2 sqr(vec2 x) {
    return x*x;
}

vec3 sqr(vec3 x) {
    return x*x;
}

float saturate(in float x) {
    return csaturate(x);
}
vec2 saturate(in vec2 x) {
    return csaturate(x);
}
vec3 saturate(in vec3 x) {
    return csaturate(x);
}
vec4 saturate(in vec4 x) {
    return csaturate(x);
}

float linStep(float x, float low, float high) {
    float t = saturate((x-low)/(high-low));
    return t;
}

vec2 linStep(vec2 x, float low, float high) {
    vec2 t = saturate((x-low)/(high-low));
    return t;
}

vec3 linStep(vec3 x, float low, float high) {
    vec3 t = saturate((x-low)/(high-low));
    return t;
}

float thresholdStep(float x, float low) {
    if (x < low) return 0.0;

    float blend = linStep(x, low, low + low * 0.5);
    return x * blend;
}

float getLuma(vec3 x) {
    return dot(x, lumacoeffAP1);
}

vec3 colorSaturation(vec3 x, const float y) {
    return mix(vec3(getLuma(x)), x, y);
}

vec3 blackbody(float temperature){
    vec4 vx = vec4(-0.2661239e9, -0.2343580e6, 0.8776956e3, 0.179910);
    vec4 vy = vec4(-1.1063814, -1.34811020, 2.18555832, -0.20219683);
    float it = rcp(temperature);
    float it2= sqr(it);
    float x = dot(vx, vec4(it * it2, it2, it, 1.0));
    float x2 = sqr(x);
    float y = dot(vy,vec4(x * x2, x2, x, 1.0));
    float z = 1.0 - x - y;
    
    vec3 AP1 = vec3(x * rcp(y), 1.0, z * rcp(y)) * _XYZ_AP1;
    return max(AP1, 0.0);
}

vec4 makeDrawbuffer(in vec3 sceneColor, in float alpha) {
    #ifdef MC_GL_RENDERER_GEFORCE
        vec3 temp   = clamp(sceneColor, 1.0/65530.0, 65535.0);   //NaN fix on nvidia
    #else
        vec3 temp   = clamp(sceneColor, 0.0, 65535.0);
    #endif

    return vec4(temp, alpha);
}
vec4 makeDrawbuffer(in vec3 sceneColor) {
    #ifdef MC_GL_RENDERER_GEFORCE
        vec3 temp   = clamp(sceneColor, 1.0/65530.0, 65535.0);   //NaN fix on nvidia
    #else
        vec3 temp   = clamp(sceneColor, 0.0, 65535.0);
    #endif

    return vec4(temp, 1.0);
}
vec4 makeDrawbuffer(in vec4 sceneColor) {
    #ifdef MC_GL_RENDERER_GEFORCE
        vec3 temp   = clamp(sceneColor.rgb, 1.0/65530.0, 65535.0);
    #else
        vec3 temp   = clamp(sceneColor.rgb, 0.0, 65535.0);
    #endif

    return vec4(temp, max(sceneColor.a, 0.0));
}

//these are for non-scenecolor stuffs
vec4 clampDrawbuffer(in vec3 sceneColor) {
    vec3 temp   = clamp(sceneColor, 0.0, 65535.0);

    return vec4(temp, 1.0);
}
vec4 clampDrawbuffer(in vec4 sceneColor) {
    vec3 temp   = clamp(sceneColor.rgb, 0.0, 65535.0);

    return vec4(temp, max(sceneColor.a, 0.0));
}