// slight variation on this tutorial https://www.youtube.com/watch?v=LLZPnh_LK8c

#define S(a, b, t) smoothstep(a,b,t)
#define LAYER_COUNT 20.

#define MOON_COLOR vec3(.99, .95, .95)
#define MOON_RAD .15

//#define STATIC_MOON


float TaperBox(vec2 p, float wb, float wt, float yb, float yt, float blur)
{
    float
    m  = S(-blur, blur, p.y - yb);
    m *=  S(blur, -blur, p.y - yt);

    p.x = abs(p.x);

    // 0 when p.y = yb, and 1 when p.y = yt
    float w = mix(wb, wt, (p.y-yb) / (yt-yb));

    m *=  S(blur, -blur, p.x - w);

    return m;
}

// hash returns value between 0 & 1 (input: vec2, output: float, hence 21)
float Hash21(vec2 p)
{
    p = fract(p*vec2(234.45, 765.34));
    p += dot(p, p+547.123);
    return fract(p.x * p.y);
}

// returns a rgba vector
vec4 Tree(vec2 uv, vec3 col, float blur)
{
    // build tree from taper boxes
    float m = TaperBox(uv, .03, .03, -0.2, .25, blur); // tree trunk
    m += TaperBox(uv, .2, .1, .25, .50, blur); // canopy 1
    m += TaperBox(uv, .15, .05, .50, .75, blur); // canopy 2
    m += TaperBox(uv, .1, .0, .75, 1., blur); // canopy 3

    // add shadows to tree
    float
    shadow = TaperBox(uv - vec2(.2,0), .1, .5, .15, .25, blur);
    shadow += TaperBox(uv + vec2(.25,0), .1, .5, .45, .50, blur);
    shadow += TaperBox(uv - vec2(.25,0), .1, .5, .71, .75, blur);

    col -= shadow * .8;
    return vec4(col, m);
}

float GetGroundHeight(float x)
{
    return sin(x*.432)*0.8 + sin(x)*0.3;
}

vec4 Layer(vec2 uv, float blur)
{
    vec4 col = vec4(0);

    // Add a ground
    float ground = S(blur, -blur, uv.y + GetGroundHeight(uv.x));

    // create row of boxes with ids (dont mess with UV yet)
    float id = floor(uv.x);

    // generate random number (0, 1) from id
    float n = fract(sin(id*234.12) * 5463.3) * 2. - 1.;
    float x = n*.3;
    float y = GetGroundHeight(id + 0.5 + x);

    // now change the uv to be repeating
    uv.x = fract(uv.x) - 0.5;

    vec2 treeScale = vec2(1., 1. + n*.2);
    vec2 treeUV = (uv - vec2(x, -y)) * treeScale;
    vec4 tree = Tree(treeUV, vec3(1.), blur);

    // ----- ISSUE -------
    // the problem is most evident with large blurs.
    // trees do not blend perfectly with the ground plane
    col += ground;

    // blend tree into image based on alpha
    col = mix(col, tree, tree.a);

    // fixes overlapp in blur region (not completely)
    col.a = max(ground, tree.a);

    return col;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (fragCoord -.5*iResolution.xy) / iResolution.y;
    vec2 M = (iMouse.xy / iResolution.xy)*2. - 1.;
    float t = iTime *.5;

    float blur = 0.003;



    // Make stars

    float twinkle = dot(length(sin(uv*1.1+t*0.5)), length(cos(uv*vec2(210.21, 63.17)-t*1.)));
    twinkle = sin(twinkle*10.12)*.5 + .5;
    float stars = pow(Hash21(uv), 100.) * twinkle * 0.7;
    vec4 col = vec4(stars);

    // Make moon

    #ifdef STATIC_MOON
    vec2 moonPos = vec2(.4, .25);
    float moonFade = 1.;
    #else
    float tOffset = 50.;
    float wMoon = 2.;
    float moonPeriod = 90.;
    float tMoon = iTime + tOffset;
    vec2 moonPos;
    moonPos.x = (fract(tMoon / moonPeriod)*2. - 1.)*wMoon;
    moonPos.y = 0.3*abs(cos((tMoon - moonPeriod/2.) * 3.14159 / moonPeriod));

    // fade moonlight in and out when it goes off screen
    float moonFade = abs(fract(tMoon / moonPeriod + 0.5)*2. - 1.) * 0.70 + 0.3;
    #endif

    float moon = S(.01, -.01, length(uv - moonPos) - MOON_RAD);

    // make sure no stars are drawn inside moon
    col *= 1.- moon;

    // subtract another circle to make crescent
    moon *= S(-.01, .1, length(uv - (moonPos + vec2(.1, .05))) - MOON_RAD*1.01);
    col += moon;

    // loop over layers (special way so i goes from 0 to 1)
    vec4 layer;
    for(float i=0.; i<1.; i+=1./LAYER_COUNT)
    {

        float scale = mix(30., 1., i);

        // blur back trees more (aliasing fix)
        blur = mix(.03, .0005, i);

        // make new layer
        layer = Layer(uv * scale + vec2(t+i*100., 2.*i- 1.5) - M, blur);

        // fade & color layers
        layer.rgb *= (1.-i) * vec3(.7, .75, 1.);

        // blend layer into final image
        col = mix(col, layer, layer.a);
    }





    // make moon glow
    float moonLight = 1. - length(uv - moonPos) / (1.4 * moonFade);
    float moonGlow = S(MOON_RAD + 0.3, MOON_RAD ,length(uv-moonPos));



    col.rgb += moonLight * MOON_COLOR * 0.4;
    col.rgb += vec3(moonGlow) * MOON_COLOR * 0.1;


    // add 1 extra foreground tree layer
    layer = Layer(uv*vec2(1. , 0.8) + vec2(t + 90., 0.5) - M, .07);
    col = mix(col, layer*0.008, layer.a);

    float thickness = 1./iResolution.y;
    //if(abs(uv.x)<thickness) col.g = 1.;
    //if(abs(uv.y)<thickness) col.r = 1.;

    // Output to screen
    fragColor = col;
}
