#ifndef CORRUPTION_FUNCTIONS_INCLUDED
#define CORRUPTION_FUNCTIONS_INCLUDED

float3 BlendColorsBranch(float3 col0, float3 col1, int blendType){
    switch (blendType){
        case 0: col0 = col0 + col1; break;
        case 1: col0 = col0 * col1; break;
        case 2: col0 = col0 * col1 * mochie_ColorSpaceDouble; break;
        case 3: col0 = BlendOverlay(col0, col1); break;
        case 4: col0 = BlendScreen(col0, col1); break;
        case 5: col0 = BlendLerp(col0, col1); break;
        default: break;
    }
    return col0;
}

float2 GetScreenUV(v2f i){
    float2 screenUV = i.uv.xy / i.uv.w; 
    #if UNITY_UV_STARTS_AT_TOP
        if (_CameraDepthTexture_TexelSize.y < 0) {
            screenUV.y = 1 - screenUV.y;
        }
    #endif
    screenUV.y = _ProjectionParams.x * .5 + .5 - screenUV.y * _ProjectionParams.x;
    return screenUV;
}

float GetSimplex4DPool(float3 coords, float scale){
    float4 c = float4(coords * scale, _Time.y % 3600 * 0.1 * _NoiseSpeed);
    float n = 0;
    float a = 0.5;

    // doubling the input coordinate makes tanoise4
    // look very close to the original Simplex4D
    #if !defined(_SIMPLEX_ON)
        c *= 2;
    #endif
    for (uint i = 0; i < _NoiseIterations; i++){
        #if defined(_SIMPLEX_ON)
            n += a*Simplex4D(c);
        #else
            n += a*lerp(-1, 1, tanoise4(c).x);
        #endif
        c = c * 2 + float(i)*0.01;
        a *= 0.5;
    }
    
    return (n + 1) * 0.5;
}

void GetDepth(v2f i, out float3 wPos){
    float2 depthUV = GetScreenUV(i);
    float depth = Linear01Depth(DecodeFloatRG(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, depthUV)));
    i.raycast *= (_ProjectionParams.z / i.raycast.z);
    float4 vPos = float4(i.raycast * depth, 1);
    wPos = mul(unity_CameraToWorld, vPos).xyz;
}

float GetSphere(const float r, const Ray ray){
    float3 oc = ray.origin;
    float dotDirOC = dot(oc, ray.dir);
    float root = dotDirOC * dotDirOC - (dot(oc, oc) - r * r);
    if (root < EPS){
        return -1.0;
    }
    return sqrt(root)-dotDirOC;
}

void ApplyTwitch(v2f i, inout float3 axis){
    // UNITY_BRANCH
    // if (_IsRotating > 0)
    // 	axis.xz = mul(GetRotationMatrix(GetNoise(axis.xz)*_Blur*4), axis.xz);
    float2 rot = mul(GetRotationMatrix(_Rotation), axis.xz);
    axis = float3(rot.x, axis.y, rot.y);
}

float3 GetStars(v2f i, Ray cameraRay){
    const float sphere = GetSphere(1737000, cameraRay);
    float movement =  _Time.y * 0.01 * _RotationSpeed;
    float3 normal = normalize((cameraRay.origin + sphere * cameraRay.dir));
    float3 newField = 0;

    [branch]
    if (sphere > 0){
        for (uint j = 0; j < _StarIterations; j++){
            const float4 dotPos = kernel10[j+1];
            const float3x3 rot = AngleAxis3x3(movement, normalize(dotPos.yzw));
            ApplyTwitch(i, normal);
            normal = mul(rot, normal);
            const float u = (atan2(normal.x, normal.z) / UNITY_TWO_PI + 0.5)*2.0;
            const float v = asin(normal.y) / UNITY_PI + 0.5;
            float2 uv = float2(u,v)*_StarTexScale;
            newField = BlendColorsBranch(newField, tex2Dlod(_StarTex, float4(uv,0,0)), _TextureBlendMode);
        }
    }
    return saturate(newField);
}

#endif