//https://www.shadertoy.com/view/ltKBzm
/*
	Improved Layer Starfield
	Credits:	https://www.shadertoy.com/view/4djSRW
				https://www.shadertoy.com/view/lscczl
*/
#define R iResolution.xy
#define T iTime

mat2 rotate(float a) {
    float c = cos(a);
    float s = sin(a);
    return mat2(c, s, -s, c);
}


// one dimensional | 1 in 1 out
float hash11(float p) {
    p = fract(p * 35.35);
    p += dot(p, p + 45.85);
    return fract(p * 7858.58);
}

// two dimensional | 2 in 1 out
float hash21(vec2 p) {
    p = fract(p * vec2(451.45, 231.95));
    p += dot(p, p + 78.78);
    return fract(p.x * p.y);
}

// two dimensional | 2 in 2 out
vec2 hash22(vec2 p) {
    vec3 q = fract(p.xyx * vec3(451.45, 231.95, 7878.5));
    q += dot(q, q + 78.78);
    return fract(q.xz * q.y);
}


float layer(vec2 uv) {

    float c = 0.;

    uv *= 5.;
	
    // id and coordinates per cell
    // f -> [-1, 1] to allow more size and glow variations
    // tf: stop the neighbour cells "cutting off" star glow
    vec2 i = floor(uv);
    vec2 f = 2. * fract(uv) - 1.; 
		
    // random position for the star in the cell
    vec2 p = .3 * hash22(i); 
    float d = length(f - p);
    
    // create fuzzier stars with random radius
    // col * (1. / d) -> glow
    c += smoothstep(.1 + .8 * hash21(i), .01, d);
    c *= (1. / d) * .2;

    return c;

}


vec3 render(vec2 uv) {

    vec3 col = vec3(0.);
    
    // rotate the whole scene
    uv *= rotate(T * .1);
    
    // oscillation to add more variations
	uv += 2. * vec2(cos(T * .001), sin(T * .001));
    
    // num layers - increase for more stars
    // adjust based on your machine
    const float num = 20.;
    const float inc = 1. / num;
    
    for (float i = 0.; i < 1.; i += inc) {
	
        // random rotate - stop repeating stars in consequent layers
        uv *= rotate(hash11(i) * 6.28);
        
        // i mapped to t -> [0, 1]
        float t = fract(i - T * .05);
        
    	// smoothstep is useful for scaling and fading
        float s = smoothstep(.001, .95, t); // z-position of layer
        float f = smoothstep(0., 1., t); // fade per layer
        f *= smoothstep(1., 0., t);
        
        // random offset per layer - gives each layer the
      	// appearance of drifiting
        vec2 k = .1 * hash22(vec2(i, i * 5.));
        float l = layer((uv - k) * s);
        
        // mix bg and fg colors
        col += mix(vec3(.03, .01, .04), vec3(.9, .4, 0.), l) * f;

    }
	
    // optional - just some subtle noise on top
    col += .02 * hash21(uv + T * .001);
    return col;

}

void mainImage(out vec4 O, in vec2 I) {
	vec2 uv = (2. * I - R) / R.y;
    vec3 color = render(uv);
	O = vec4(color, 1.);
}
