#ifndef SKY_GLSL_
#define SKY_GLSL_

#include "stars.glsl"
#include "clouds.glsl"
#include "galaxy.glsl"

layout(
    set = GLSL_TERRAIN_SKYBOX_DESCRIPTOR_SET,
    binding = GLSL_SKYBOX_DATA_INDEX
) uniform SkyboxData {
    mat4 model;
    mat4 antiModel;
    vec3 color;
    vec2 screenSize;
    float playerZ;
    float farZ;
    int debugMode;
    int fxaaEnabled;
} uSkyboxData;

vec3 skySampleSun(vec3 dir, float extent, vec3 background)
{
    vec3 localDir = (uSkyboxData.antiModel * vec4(dir, 0.0)).xyz;

    const float cosSunRadius = cos(radians(9.2));
    const float edge = 0.002;

    const vec3 sunDir = vec3(0.0, 1.0, 0.0);
    float cosTheta = dot(localDir, sunDir);

    float sun = smoothstep(
        cosSunRadius,
        cosSunRadius + edge,
        cosTheta
    );

    sun = pow(sun, 1.3);

    return mix(background, vec3(1.0, 0.2, 0.0), sun);
}

vec3 skySampleSun(vec3 dir, float extent)
{
    return skySampleSun(dir, extent, vec3(0.0));
}

vec3 skySampleStars(vec3 localDir, float extent)
{    
    vec4 starNoise = texture(uStarNoiseSampler, localDir);
    float maxCos = starNoise.x;
    float cosStarRadius = starNoise.y;
    float colorNoise = starNoise.z;
    float brightness = smoothstep(cosStarRadius, 1.0, maxCos);

    brightness = pow(brightness, 3.0);

    vec3 color = vec3(1.0);
    float delta = abs(colorNoise) * 1.0;
    if (colorNoise < 0.0)
    {
        color.gb -= delta;
    }
    else
    {
        color.rg -= delta;
    }

    return color * brightness;
}

// TODO: Actually do something with the extent. The 'extent' is how blurry the sky should be
// based on the cone that samples it. Gonna have to think about it.
vec3 skySample(vec3 dir, float extent)
{
    vec3 cloudsDir = (uFrameData.cloudTransform * vec4(dir, 0.0)).xyz;
    vec3 localDir = (uSkyboxData.antiModel * vec4(dir, 0.0)).xyz;

    float time = float(uFrameData.ticks / 100) * 0.002;

    vec3 stars = skySampleStars(localDir, extent);
    vec3 sunAndStars = skySampleSun(dir, extent, stars);

    vec3 sky = uSkyboxData.color
        + sunAndStars
        + galaxySample(localDir, extent);

    float cloudLevel = cloudsSample(cloudsDir, extent, time, uFrameData.cloudCover);

    return mix(sky, vec3(1.0), cloudLevel);
}

#endif 