//Noise algorithms
float rand1(highp float p){
	return fract(sin(p)*69.);
	}
float rand(highp vec2 c){	
	return fract(sin(dot(c ,vec2(12.9898,78.233))) * 43758.5453);
}
float rand3(highp vec3 c){	
	return fract(sin(dot(c ,vec3(12.9898,78.233,4.1414))) * 43758.5453);
}
vec2 rand2(vec2 n){
	return fract(sin(vec2(dot(n, vec2(12.9898, 4.1414)))));
	}
vec3 rand3d(highp vec2 p ){
    //highp vec3 q = vec3( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)), dot(p,vec2(419.2,371.9)) );
    highp vec3 q = vec3(dot(p,vec2(12.9898,78.233)));
	return fract(sin(q)*43758.5453);
}


float value_noise( vec3 x )
{
    vec3 i = floor(x);
    vec3 f = fract(x);
    f = f*f*(3.0-2.0*f);
	
    return mix(mix(mix( rand3(i+vec3(0,0,0)), 
                        rand3(i+vec3(1,0,0)),f.x),
                   mix( rand3(i+vec3(0,1,0)), 
                        rand3(i+vec3(1,1,0)),f.x),f.y),
               mix(mix( rand3(i+vec3(0,0,1)), 
                        rand3(i+vec3(1,0,1)),f.x),
                   mix( rand3(i+vec3(0,1,1)), 
                        rand3(i+vec3(1,1,1)),f.x),f.y),f.z);
}
	
float voronoi(vec2 n, float time){
	float dis = 1.0;
	const float intensity = 32.0;
	for(float y = 0.0; y <= 1.0; y++){
		for(float x = 0.0; x <= 1.0; x++){
			// Neighbor place in the grid
			vec2 p = floor(n) + vec2(x, y);
			float d = length((0.27 * sin(rand2(p) * intensity + time * 2.0)) + vec2(x, y) - fract(n));
			dis = min(dis, d);
			}
		}
	return dis;
	}


float value(highp float p){
	highp float i = floor(p); float f = fract(p);
	return mix(rand1(i), rand1(i + 1.), f * f * f * (f * (f * 6. - 15.) + 10.));
}
	

vec2 GetGradient(highp vec2 intPos, highp float t) {
    intPos = vec2(mod(intPos.x, 16.),mod(intPos.y, 16.*.25));
    // Uncomment for calculated rand
    float rand = fract(sin(dot(intPos, vec2(12.9898, 78.233))) * 43758.5453);
    
    
    // Rotate gradient: random starting rotation, random rotation rate
    float angle = 6.283185 * rand + 4.0 * t * rand;
    return vec2(cos(angle), sin(angle));
}


float simplex3d(highp vec3 pos) {
    vec2 i = floor(pos.xy);
    vec2 f = pos.xy - i;
    vec2 blend = f * f * (3.0 - 2.0 * f);
    float noiseVal = 
        mix(
            mix(
                dot(GetGradient(i + vec2(0, 0), pos.z), f - vec2(0, 0)),
                dot(GetGradient(i + vec2(1, 0), pos.z), f - vec2(1, 0)),
                blend.x),
            mix(
                dot(GetGradient(i + vec2(0, 1), pos.z), f - vec2(0, 1)),
                dot(GetGradient(i + vec2(1, 1), pos.z), f - vec2(1, 1)),
                blend.x),
        blend.y
    );
    return noiseVal / 0.7; // normalize to about [-1..1]
}


////// Underwater water caustics

float h12(highp vec2 p)
{
    return fract(sin(dot(p,vec2(32.52554,45.5634)))*12432.2355);
}

float n12(highp vec2 p)
{
    vec2 i = floor(p);
    vec2 f = fract(p);
    f *= f * (3.-2.*f);
    return mix(
        mix(h12(i+vec2(0.,0.)),h12(i+vec2(1.,0.)),f.x),
        mix(h12(i+vec2(0.,1.)),h12(i+vec2(1.,1.)),f.x),
        f.y
    );
}

float caustics(highp vec2 p, highp float t)
{
    vec3 k = vec3(p,t);
    float l;
    mat3 m = mat3(-2,-1,2,3,-2,1,1,2,2);
    float n = n12(p);
    k = k*m*.5;
    l = length(.5 - fract(k+n));
    k = k*m*.4;
    l = min(l, length(.5-fract(k+n)));
    k = k*m*.3;
    l = min(l, length(.5-fract(k+n)));
    return pow(l,7.)*25.;
}



float rainRipples(highp vec2 x, highp float time){
    highp vec2 p = floor(x);
    highp vec2 f = fract(x);
		
	float va = 0.0;
	
	
    for( int j=-1; j<=1; j++ )
    for( int i=-1; i<=1; i++ )
    {
        vec2 g = vec2( float(i),float(j) );
		vec3 o = rand3d( p + g );
		//vec3 o = vec3(rand1(p.x+g.x),rand1(p.y+g.y),rand1(p.z+g.z));
		vec2 r = g - f + o.xy;
		float d = sqrt(dot(r,r));
	    va += max(mix(smoothstep(0.99,0.999,max(cos(d - time * 2. + (o.x + o.y) * 5.0), 0.)), 0., d), 0.);
    }

	
    return va;
}