#version 330 core

// Interpolated values from the vertex shaders
in vec2 UV;
uniform sampler2D prev;
uniform float dt;
uniform float iGlobalTime;

// output
layout(location = 0) out vec4 state;


// noise
float noise(vec2 pos)
{
	return fract( sin( dot(pos*0.001 ,vec2(24.12357, 36.789) ) ) * 12345.123);	
}

float noise(int a, int b, int c)
{
	return noise(vec2(float(a + sin(float(c))), float(b + c)));
}

vec4 dnoise3f( vec3 inp )
{
	float x = inp.x;
	float y = inp.y;
	float z = inp.z;

    int   i, j, k;
    float u, v, w;

    i = int(floor(x)); u = fract(x);
    j = int(floor(y)); v = fract(y);
    k = int(floor(z)); w = fract(z);

    float du = 30.0f*u*u*(u*(u-2.0f)+1.0f);
    float dv = 30.0f*v*v*(v*(v-2.0f)+1.0f);
    float dw = 30.0f*w*w*(w*(w-2.0f)+1.0f);

    u = u*u*u*(u*(u*6.0f-15.0f)+10.0f);
    v = v*v*v*(v*(v*6.0f-15.0f)+10.0f);
    w = w*w*w*(w*(w*6.0f-15.0f)+10.0f);

    float a = noise( i+0, j+0, k+0 );
    float b = noise( i+1, j+0, k+0 );
    float c = noise( i+0, j+1, k+0 );
    float d = noise( i+1, j+1, k+0 );
    float e = noise( i+0, j+0, k+1 );
    float f = noise( i+1, j+0, k+1 );
    float g = noise( i+0, j+1, k+1 );
    float h = noise( i+1, j+1, k+1 );

    float k0 =   a;
    float k1 =   b - a;
    float k2 =   c - a;
    float k3 =   e - a;
    float k4 =   a - b - c + d;
    float k5 =   a - c - e + g;
    float k6 =   a - b - e + f;
    float k7 = - a + b + c - d + e - f - g + h;

    return vec4(k0 + k1*u + k2*v + k3*w + k4*u*v + k5*v*w + k6*w*u + k7*u*v*w,
    	        du * (k1 + k4*v + k6*w + k7*v*w),
    	        dv * (k2 + k5*w + k4*u + k7*w*u),
    	        dw * (k3 + k6*u + k5*v + k7*u*v));
}

vec3 spawn(vec3 state) {
  float a = noise(vec2(state.x, state.z + 0.0001 * iGlobalTime) + state.yx) * 3.141;
  float b = noise(vec2(state.z + 0.0001 * iGlobalTime, state.x) + state.xy) * 2 * 3.141;

  float r = 1.1;
  return r * vec3(sin(a) * cos(b),
                  sin(a) * sin(b),
                  cos(a));
}

void main() {
  vec4 prevstate = texture(prev, UV);
  vec4 perlin = dnoise3f(2.0*prevstate.xyz + 0.001 * vec3(0.1 * iGlobalTime, prevstate.z, -sin(iGlobalTime)));
  vec3 derivs = perlin.gba;
  vec3 velo = vec3(
  	derivs.y - derivs.z,
  	derivs.z - derivs.x,
  	derivs.x - derivs.y
  	); // hashtag hope

  state = prevstate + 0.01*(vec4(velo, 0.0) + 0.1*vec4(state.xyz, 10.0));

  if (state.a >= 1.0) {
    state.xyz = spawn(state.xyz);
    state.a = noise(state.xy + vec2(iGlobalTime * 0.001 - state.y, state.z));
  }
}