// https://www.shadertoy.com/view/4lKcDD
float xRandom(float x) {
    return mod(x * 7241.6465 + 2130.465521, 64.984131);
}

float mfunc(float x, float xx, float yy) {
    x /= .20 * 3.14159;
    x = mod((x)*2.0, 2.8) - 1.195;
    x *= 19.0 * 3.14159;
    return abs(8. + abs(-19.15 + abs(-15.0 + yy + abs(-12.25 - yy + abs(-18.0 + xx + abs(-15.0 - xx + abs(.95 * x + 4.0))))))) / 100.;
}

float hash2(in vec2 p) {
    return fract(dot(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077)));
}

float noise2(float y, float t) {
    vec2 fl = vec2(floor(y), floor(t));
    vec2 fr = vec2(fract(y), fract(t));
    float a = mix(hash2(fl + vec2(0.0, 0.0)), hash2(fl + vec2(1.0, 0.0)), fr.x);
    float b = mix(hash2(fl + vec2(0.0, 1.0)), hash2(fl + vec2(1.0, 1.0)), fr.x);
    return mix(a, b, fr.y);
}

float line(vec2 uv, float width, float center) {
    float b = (1. - smoothstep(.0, width / 2., (uv.y - center)))*1.; 
    return b;
}

const vec3 white = vec3(0xdc, 0xe0, 0xd1) / float(0xff);
const vec3 dark = vec3(0x1a, 0x13, 0x21) / float(0xff);
const vec3 bluebg = vec3(0x00, 0x19, 0x5e) / float(0xff);
const vec3 colsun = vec3(0x07, 0xaf, 0x81) / float(0xff);
const vec3 white2 = vec3(0xec, 0xe8, 0x9e) / float(0xff);

const vec3 l1 = vec3(0x07, 0x27, 0x21) / float(0xff);
const vec3 l2 = vec3(0x00, 0x6c, 0xae) / float(0xff);
const vec3 l3 = vec3(0x00, 0x48, 0x7f) / float(0xff);
const vec3 treecol = vec3(0x12, 0x19, 0x27) / float(0xff);
const vec3 watercol = vec3(0xcf, 0xe5, 0xf2) / float(0xff);

const vec3 traincol = vec3(0x00, 0x6a, 0xb9) / float(0xff);
const vec3 trainlcol = vec3(0xef, 0xe8, 0x95) / float(0xff);
const vec3 toplvlcol = vec3(0x00, 0x6a, 0x71) / float(0xff);

float circle(in vec2 uv, float r1, float r2, bool disk) {
    float w = 2.0 * fwidth(uv.x);
    float t = r1 - r2;
    float r = r1;

    if (!disk)
        return smoothstep(-w / 2.0, w / 2.0, abs(length(uv) - r) - t / 2.0);
    else
        return smoothstep(-w / 3.0, w / 3.0, (length(uv) - r));
}

float circle2(in vec2 uv, float r1, float r2, bool disk) {
    float w = 2.0 * fwidth(uv.x);
    float t = r1 - r2;
    float r = r1;
    if (!disk)
        return smoothstep(-w / 2.0, w / 2.0, abs(length(uv) - r) - t / 2.0);
    else
        return smoothstep(-w / 3.0, 1.05 + w / 3.0, (length(uv) - r));
}

float w1(float x) {
    x += -0.45;
    float iTime = mod(iTime+150.1, 310.);
    if (iTime > 150.)
        return 01.5 + 010.15 * mfunc(x * .7, -80. * (cos(0.5 + mod(0. / 150. + 1., 3.))), 0.);
    else
        if (iTime > 5.)
        return 01.5 + 010.15 * mfunc(x * .7, -80. * (cos(0.5 + mod((iTime - 5.) / 140. + 1., 3.))), 0.);
    else
        return 01.5 + 010.15 * mfunc(x * .7, -80. * (cos(0.5 + mod((0.) / 140. + 1., 3.))), 0.);
}

float layer(vec2 uv) {
    float iTime = mod(iTime+150.1, 310.);
    vec2 ouv = uv;
    uv *= 0.5;
    if (iTime > 150.)
        uv.x += ((iTime - 150.) / 200.);
    uv.x += 50.;
    uv.y += -0.21;
    float Range = 100.;
    float Line_Smooth = 1.;
    float Amplitude1 = w1(uv.x);
    vec2 p = uv;
    float Light_Track = line(vec2(p.x, p.y * 1.5 + (Amplitude1 - .5)*.12 * Line_Smooth), .005, .0);
    if (iTime < 150.)
        return Light_Track * smoothstep(0., 5., iTime);
    else if (iTime < 300.)
        return Light_Track * smoothstep(150., 155., iTime);
    else
        return Light_Track * smoothstep(305., 300., iTime);
}

#define PI (4.0 * atan(1.0))
#define TWO_PI PI*2.

float shape(vec2 uv, int N, float radius_in, float radius_out, float zoom) {
    float color = 0.0;
    float d = 0.0;
    float a = atan(uv.x, uv.y) + PI;
    float rx = TWO_PI / float(N);
    d = cos(floor(.5 + a / rx) * rx - a) * length(uv);
    color = smoothstep(.44, .44 + (2. + 1.2 * zoom) / iResolution.y, abs(d - radius_in) + radius_out);
    return (1. - color);
}

float msine(vec2 uv) {
    float heightA = 0.025;
    float heightB = 0.025;
    float heightC = 0.013; //+0.071*sin(iTime/105.); //xD
    uv.y = sin((uv.x + (1.))*5.0) * heightA;
    uv.y = uv.y + sin((uv.x + (0. / 5.))*3.0) * heightB;
    uv.y = uv.y + sin((uv.x + (1.))*2.0) * heightC;
    return uv.y;
}

float trees(vec2 uv) {
    float zoom = 10.;
    uv.x += iTime / 35.;
    uv *= zoom;
    vec2 tuvy = vec2(0., 08. * msine(vec2(floor(uv.x / (0.38)), uv.y) / zoom));
    float rval = xRandom(floor(uv.x / 0.38));
    float d = 0.;
    if (rval > (85.) * fract(cos(rval)) + 85. * (sin(rval))) {
        rval = max(1., 2.5 * abs(sin(rval)));
        uv.x = mod(uv.x, 0.38) - 0.19;
        uv += tuvy;
        uv *= rval;
        float xval = 1.2 * sin(xRandom(tuvy.y))*0.19 * (1.25 - rval);
        uv.y += 0.75 / rval;
        uv.x += xval;
        vec2 ouv = uv;
        uv.y *= .85;
        d = shape(uv, int(3.), -0.380, 0., zoom + rval);
        uv.y += .12;
        uv.y *= .75;
        d = max(d, shape(uv, int(3.), -0.370, 0., zoom + rval));
        uv.y += .1;
        uv.y *= 1.2;
        d = max(d, shape(uv, int(3.), -0.3650, 0., zoom + rval));
        d = max(d, smoothstep(0.02 + (2. + 1.2 * (zoom + rval)) / iResolution.y, 0.02, abs(uv.x)) * step(ouv.y, 0.)) *
                step(-0.75 + 0.12 * (2.5 - rval), ouv.y);
    }
    return d;
}

float layer_bghills(vec2 uv) {
    uv.x += iTime / 35.;
    float d = smoothstep(0.5 + 20. / iResolution.y, 0.5, msine(uv / 0.38 - 0.038)*10. + uv.y * 10. + 01.6);
    return d;
}

float treex(vec2 uv) {
    uv.y += 0.08;
    float d = trees(uv);
    return d;
}

float water(vec2 uv) {
    float d;
    d = step(uv.y, -0.25);
    return d;
}


#define HASHSCALE1 443.8975

float hash11(float p) {
    vec3 p3 = fract(vec3(p) * HASHSCALE1);
    p3 += dot(p3, p3.yzx + 19.19);
    return fract((p3.x + p3.y) * p3.z);
}

float lerp(float a, float b, float t) {
    return a + t * (b - a);
}

float noise(float p) {
    float i = floor(p);
    float f = fract(p);
    float t = f * f * (3.0 - 2.0 * f);
    return lerp(f * hash11(i), (f - 1.0) * hash11(i + 1.0), t);
}

float fbm(float x, float persistence, int octaves) {
    float total = 0.0;
    float maxValue = 0.0;
    float amplitude = 1.0;
    float frequency = 1.0;
    for (int i = 0; i < octaves; ++i) {
        total += noise(x * frequency) * amplitude;
        maxValue += amplitude;
        amplitude *= persistence;
        frequency *= 2.0;
    }
    return (total / maxValue);
}

float msine2(vec2 uv) {
    return (fbm(uv.x / 10., 0.25, 4)*20. + 0.5);
}

float trees2(vec2 uv) {
    float zoom = 10.;
    uv.x += iTime / 45.;
    uv *= zoom;
    vec2 tuvy = vec2(0., 0.2 * msine2(vec2(floor(uv.x / 0.38), uv.y)));
    float rval = xRandom(floor(uv.x / 0.38));
    float d = 0.;
    if (rval > (55.) * fract(cos(rval)) + 85. * (sin(rval))) {
        rval = max(1.5, 2.5 * abs(sin(rval)));
        uv.x = mod(uv.x, 0.38) - 0.19;
        uv += tuvy;
        uv *= rval;
        float xval = -1.2 * sin(xRandom(tuvy.y))*0.19 * (1.25 - rval);
        uv.y += -0.25 / rval;
        uv.x += xval;
        vec2 ouv = uv;
        uv.y *= .85;
        d = shape(uv, int(3.), -0.380, 0., zoom + rval);
        uv.y += .12;
        uv.y *= .75;
        d = max(d, shape(uv, int(3.), -0.370, 0., zoom + rval));
        uv.y += .1;
        uv.y *= 1.2;
        d = max(d, shape(uv, int(3.), -0.3650, 0., zoom + rval));
        d = max(d, smoothstep(0.02 + (2. + 1.2 * (zoom + rval)) / iResolution.y, 0.02, abs(uv.x)) * step(ouv.y, 0.)) *
                step(-0.75 + 0.12 * (2.5 - rval), ouv.y);
    }
    return d;
}

float layer_bghills2(vec2 uv) {
    uv.x += 1.2;
    uv.x += iTime / 45.;
    float d = smoothstep(5.5 + 20. / iResolution.y, 5.5, msine2(uv / 0.38 - 0.038)*40. + uv.y * 40. + 010.6);
    d = smoothstep(-0.1555 + 8. / iResolution.y, -0.1555, .2 * msine2((uv * 10.) / 0.38 - 0.038) + uv.y * 11. + 0.86);
    return d;
}

float treex2(vec2 uv) {
    uv.x += 1.2;
    uv.y += 0.08;
    float d = trees2(uv);
    return d;
}

vec3 undw(in vec2 uv, vec3 tc) {
    vec2 res = iResolution.xy / iResolution.y;
    uv.x += iTime / 10.;
    uv += res / 2.;
    uv.y = 1. - uv.y;
    uv.y += -0.759;
    uv.x *= .5;
    uv *= 5.3;
    float divs = 5.;
    float slope = 4.2;
    float y_off = sin(2. * uv.y + 0. * iTime / 1.73);
    float vy = (uv.y + (floor(5. - (uv.y + 02.75) / .52) / 5.) * sin(uv.x * 6.28318 + y_off)*.1 - .05);
    float c = (smoothstep(0., 1., mod(vy*divs, 1.0) * slope) + floor(vy * divs)) / divs;
    vec2 uv_d = vec2(uv.x * 0.3 + y_off * .01, c);
    vec2 uv_d2 = vec2(uv.x + y_off * .05, .3 * c + .7 * vy);
    vec3 fragColor;
    vec3 gamma = vec3(0.65 * 2.2, .8 * 2.2, 2.2);
    gamma = tc;
    fragColor.r = pow(c, 1. / gamma.r);
    fragColor.g = pow(c, 1. / gamma.g);
    fragColor.b = pow(c, 1. / gamma.b);
    fragColor.rgb *= tc * (-noise2(uv_d.x, uv_d.y)*.3 + .7);
    return max(vec3(0.), fragColor);
}

float trainxl(vec2 uv) {
    uv.y += 0.3;
    uv.y += -0.07;
    vec2 ouv = uv;
    uv.x = mod(uv.x, 0.01) - 0.005;
    float d = smoothstep(0.0045 + 2. / iResolution.y, 0.0025, abs(uv.x));
    d *= step(abs(uv.y), 0.0025);
    uv.x = ouv.x;
    uv.x = mod(uv.x, 0.15) - 0.005;
    d *= step(abs(uv.x), 0.0025 * 50.);
    d *= step(ouv.x, -0.05);
    d *= step(-0.50, ouv.x);
    d += smoothstep(0.0110 + 2. / iResolution.y, .01, abs(ouv.x + 0.021)) * step(abs(uv.y), 0.0025);
    d += smoothstep(0.025 + 2. / iResolution.y, .024, abs(ouv.x - 0.035)) * step(abs(uv.y), 0.0025);
    return d;
}

float trainx(vec2 uv) {
    uv.y += 0.325;
    float d = 1. - circle(uv, 0.11, 0., true);
    float stval = step(0.07, uv.y);
    d *= stval;
    d = max(d, step(-0.5, uv.x) * step(uv.x, 0.0) * step(uv.y, 0.109)) * stval;
    d = max(d, 1. - circle(uv + vec2(0.5, 0.), 0.11, 0., true)) * stval;
    return d;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 res = iResolution.xy / iResolution.y;
    vec2 uv = (fragCoord.xy) / iResolution.y - res / 2.0;
    float b = 1. - circle(uv - 0.21, 0.1242, 0.22, true);
    vec3 col = vec3(bluebg);
    float b1 = 1. - circle2(uv - 0.21, 0.1242, 0.22, true);
    float b2 = smoothstep(-01., -0.05, uv.y);
    float lx1 = layer(uv + vec2(0., -0.152));
    col = (col - lx1 * l1 * b1);
    col += (b1) * colsun;
    col = mix(col, white2, min(b, 1. - lx1));
    col = mix(col, l2*b1, layer_bghills2(uv + vec2(0., -0.05)));
    col = mix(col, 3. * treecol*b1, treex2(uv + vec2(0., -0.05)));
    col = mix(col, l3*b1, layer_bghills(uv + vec2(0., 0.0)));
    col = mix(col, treecol*b1, treex(uv + vec2(0., 0.0)));
    vec3 toplvlcol2 = vec3(0.);
    if ((uv.y<-0.25))
        toplvlcol2 = undw(uv, watercol);
    col = mix(col, toplvlcol2 + 0.42 * b2*l2, water(uv));
    uv.x += 0.3 * (sin(0.5 * sin(iTime / 8.) + cos(iTime / 10.)));
    float trx = trainx(uv);
    col = mix(col, traincol*b1, (trx * (1. - water(uv))));
    col = mix(col, trainlcol, trainxl(uv) * trx);
    fragColor = vec4(col, 1.0);
}