uniform float horizonAngle;
uniform float cloudSpeed;

// rainbow based on https://www.shadertoy.com/view/lsfBWs
// level is [0,5], assumed to be a whole number
vec3 rainbow(float level)
{
	float r = float(level <= 2.0) + float(level > 4.0) * 0.5;
	float g = max(1.0 - abs(level - 2.0) * 0.5, 0.0);
	float b = (1.0 - (level - 4.0) * 0.5) * float(level >= 4.0);
	return vec3(r, g, b);
}

vec3 smoothRainbow (float x)
{
    float level1 = floor(x*6.0);
    float level2 = min(6.0, floor(x*6.0) + 1.0);
    
    vec3 a = rainbow(level1);
    vec3 b = rainbow(level2);
    
    return mix(a, b, fract(x*6.0));
}


float hash(vec2 uv) {
  // added terms till it looked okay
  vec3 p3  = mod(uv.xyx * vec3(345.23,234.1,465.745),vec3(2,3,5));
  p3 += dot(p3, p3.yzx + 34.19);
  return fract((p3.x + p3.y) * p3.z);
}

float n2(vec2 st) {
  	vec2 i=floor(st-.5);
    vec2 f=fract(st-.5);
    f = f*f*f*(f*(f*6.0-15.0)+10.0);
    float rt=mix(hash(i),hash(i+vec2(1.,0.)),f.x);
    float rb=mix(hash(i+vec2(0.,1.)),hash(i+vec2(1.,1.)),f.x);
    return mix(rt,rb,f.y);
}

float sky(vec2 uv) {
  float val=0.;
  
  float amp=0.75;
  
  for (float i=1.; i < 13.; ++i) {
    val += n2(vec2(0.4,0.1)*iTime*i/20.+ uv * 20. / i) / 2. * pow(i,0.25)*amp;
    amp *= 0.5;
    uv *= -4.5;
    uv += vec2(0.3,0.4)*0.15*(iTime*amp);
  }
  return val;
}

float map(vec3 p) {
  float erf=length(p)-93.;
  return min(100.-length(p),erf);
}

vec3 moonpos=vec3(450.,520.,2750.);

float moonmap(vec3 ro, vec3 rd, out vec3 normal) {
  float t = dot(moonpos-ro,rd);
  float r = 50.;
  vec3 p = ro + rd * t;
  float y = length(moonpos-p);
  float x = sqrt(r*r-y*y);
  normal = normalize(p-rd*x-moonpos);
  return y - r;
}

vec3 gn(vec3 p) {
  vec2 e=vec2(0.001,0.);
  return normalize(map(p) - vec3(map(p-e.xyy),map(p-e.yxy),map(p-e.yyx)));
}

mat2 rot(float f) {
  return mat2(cos(f), -sin(f), sin(f), cos(f));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  
	vec2 uv = (fragCoord.xy - 0.5*iResolution.xy) / iResolution.y;
	vec3 rd=normalize(vec3(uv,3.));
  rd.yz *= rot(-horizonAngle);
  
  vec3 ro=vec3(0.,93.,-30.);
  float d,t=0.;
  
  for (int i=0; i<170; ++i) {
    d = map(ro+rd*t);
    if (d <0.01) break;
    t += d;
  }
  vec3 fogcol=vec3(0.1,0.1,0.13)*0.91;
  vec3 col =fogcol;//vec3(1,0,0);
  
  
  vec3 p=ro+rd*t;
  
  vec3 ld=normalize(vec3(1.,3.,-15.));
  //return;
  
  if (d <0.01) {
      if (length(p) > 96.) {
      float u= atan(p.x,p.t);
      float v= atan(p.y,p.z);
      //u *=10;
      //v *=10;
      
      //float val=mod(floor(u)+floor(v),2);
      vec2 skyuv = vec2(u,v);
      float val=clamp(sky(skyuv*2.1+vec2(iTime*0.02*cloudSpeed,0.)),0.4,1.);
      vec3 moonn;
      float sun = moonmap(ro,rd, moonn);
      float suncol = 0.;
      float sunglo = smoothstep(120.,0.,pow(sun,1.))*4.;
      if (sun<0.) {
        vec3 sund = normalize(vec3(-60.,0.,99.));
        suncol = 0.2;
      }
      suncol=smoothstep(-0.2,0.1,sun);
      sunglo += 0.;
      col = vec3(0.5,0.5,0.969)*smoothstep(1.,-1.,rd.y)*3.6+ vec3(0.01,0.04,0.23);
      col += +val*(smoothstep(-1.,1.,uv.y))*vec3(.1,0.4,0.5);
      col=mix(col,vec3(1.,1.,0.)*0.2+col*0.6,sunglo/4.);
      
      col = mix(vec3(0.9,0.6,0),col, suncol);
      col = mix(col,vec3(1),sunglo*sunglo*0.04);
      float rainbowLevel = -length(rd.xy)*12.+7.;
      float rainbowMix = smoothstep(-.1,0.,rainbowLevel/6.)*smoothstep(.2,.1,rainbowLevel/6.);
      col = mix(col,smoothRainbow(-length(rd.xy)*12.+7.),rainbowMix/2.);
    }
    else {
      col = vec3(0.01,.6,0.1)*1.4;
      col *= 0.1 + 0.1*dot(ld,gn(p));
    }
  }
  float dp = p.z;
  
  
  col=mix(col,fogcol,(1.-exp(-0.0001*t*t*t))*smoothstep(94.,93.,p.y));
  col = pow(col,vec3(0.4545));
	fragColor = vec4(col, 1.);
}
