mat2 rotate(float angle) {
    return mat2(cos(angle), -sin(angle),
                sin(angle), cos(angle)
    );
}


float random (in vec2 _st) {
    return fract(sin(dot(_st.xy,
                    vec2(12.9898, 78.233)))*
        				 43758.5453123);
}

float random1 (float f) {
    return random(vec2(f, -0.128));
}

vec2 random2( vec2 p ) {
    return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453);
}

// Commutative smooth minimum function. Provided by Tomkh, and taken 
// from Alex Evans's (aka Statix) talk:
float smin(float a, float b, float k){
   float f = max(0., 1. - abs(b - a)/k);
   return min(a, b) - k*.25*f*f;
}

float noise(float s) {	
    float i = floor(s);
    float f = fract(s);
    float n = mix(random(vec2(i, 0.)), 
                  random(vec2(i+1., 0.)), 
                  smoothstep(0.0, 1., f)); 
   
    return n;
}

vec3 rgb2hsv(vec3 c)
{
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

vec3 hsv2rgb(vec3 c)
{
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

float map(float value, float inMin, float inMax, float outMin, float outMax) {

  return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);

} 



vec2 map(vec2 value, vec2 inMin, vec2 inMax, vec2 outMin, vec2 outMax) {

  return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);

}



vec3 map(vec3 value, vec3 inMin, vec3 inMax, vec3 outMin, vec3 outMax) {

  return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);

}



vec4 map(vec4 value, vec4 inMin, vec4 inMax, vec4 outMin, vec4 outMax) {
  return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}

float sin01(float n) {
    return sin(n)/2.+.5;
}


vec4 blend(vec4 bg, vec4 fg) {
    vec4 c = vec4(0.);
    c.a = 1.0 - (1.0 - fg.a) * (1.0 - bg.a);
    if(c.a < .00000) return c;
    
    c.r = fg.r * fg.a / c.a + bg.r * bg.a * (1.0 - fg.a) / c.a;
    c.g = fg.g * fg.a / c.a + bg.g * bg.a * (1.0 - fg.a) / c.a;
    c.b = fg.b * fg.a / c.a + bg.b * bg.a * (1.0 - fg.a) / c.a;
    
    return c;
}

// Some useful functions
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }

//
// Description : GLSL 2D simplex noise function
//      Author : Ian McEwan, Ashima Arts
//  Maintainer : ijm
//     Lastmod : 20110822 (ijm)
//     License :
//  Copyright (C) 2011 Ashima Arts. All rights reserved.
//  Distributed under the MIT License. See LICENSE file.
//  https://github.com/ashima/webgl-noise
//
float snoise(vec2 v) {

    // Precompute values for skewed triangular grid
    const vec4 C = vec4(0.211324865405187,
                        // (3.0-sqrt(3.0))/6.0
                        0.366025403784439,
                        // 0.5*(sqrt(3.0)-1.0)
                        -0.577350269189626,
                        // -1.0 + 2.0 * C.x
                        0.024390243902439);
                        // 1.0 / 41.0

    // First corner (x0)
    vec2 i  = floor(v + dot(v, C.yy));
    vec2 x0 = v - i + dot(i, C.xx);

    // Other two corners (x1, x2)
    vec2 i1 = vec2(0.0);
    i1 = (x0.x > x0.y)? vec2(1.0, 0.0):vec2(0.0, 1.0);
    vec2 x1 = x0.xy + C.xx - i1;
    vec2 x2 = x0.xy + C.zz;

    // Do some permutations to avoid
    // truncation effects in permutation
    i = mod289(i);
    vec3 p = permute(
            permute( i.y + vec3(0.0, i1.y, 1.0))
                + i.x + vec3(0.0, i1.x, 1.0 ));

    vec3 m = max(0.5 - vec3(
                        dot(x0,x0),
                        dot(x1,x1),
                        dot(x2,x2)
                        ), 0.0);

    m = m*m ;
    m = m*m ;

    // Gradients:
    //  41 pts uniformly over a line, mapped onto a diamond
    //  The ring size 17*17 = 289 is close to a multiple
    //      of 41 (41*7 = 287)

    vec3 x = 2.0 * fract(p * C.www) - 1.0;
    vec3 h = abs(x) - 0.5;
    vec3 ox = floor(x + 0.5);
    vec3 a0 = x - ox;

    // Normalise gradients implicitly by scaling m
    // Approximation of: m *= inversesqrt(a0*a0 + h*h);
    m *= 1.79284291400159 - 0.85373472095314 * (a0*a0+h*h);

    // Compute final noise value at P
    vec3 g = vec3(0.0);
    g.x  = a0.x  * x0.x  + h.x  * x0.y;
    g.yz = a0.yz * vec2(x1.x,x2.x) + h.yz * vec2(x1.y,x2.y);
    return dot(m, g);
}


float fbm(vec2 x, float amplitude, float frequency, float offset) {
    x += offset;
    float y = 0.;
    // Properties
    const int octaves = 8;
    float lacunarity = 0.;
    float gain = 0.;
    
    // Initial values
    //sin(u_time) * 5. + 10.;
    //sin(u_time/10. + 10.);
    
    // Loop of octaves
    for (int i = 0; i < octaves; i++) {
        y += amplitude * snoise(frequency*x);
        frequency *= lacunarity;
        amplitude *= gain;
    }
    
    return y;
}




void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
    vec4 color = vec4(0., 0., 0., 1.);


    for(float k=0.; k<2.; k++) {
        vec2 st = (fragCoord - .5 * iResolution.xy) / iResolution.y;
        vec2 uv = st;
        
        st *=2.788;
        st *= rotate(k/10.936);

        // Tile
        vec2 i_st = floor(st);
        vec2 f_st = fract(st);

        float m_dist = 1.; // min distance

        for(int j=-3; j<=3; j++) {
            for(int i=-3; i<=3; i++) {
                vec2 neighbor = vec2(float(i), float(j));
                vec2 offset = random2(i_st + neighbor);

                offset = 0.5 + 0.5 * sin(iTime/1.5 + 6.2831 * offset );
              //  offset = (iMouse - .5 * iResolution.xy) / iResolution.y * 2. * offset;
               // offset += sin(iTime/2. + 6.2831 * offset);

                vec2 pos = neighbor + offset - f_st;
                float dist = length(pos);

                // Metaball
                float diff = k/2. + 0.084;
                diff = k/9.120;
                m_dist = smin(m_dist, dist, 1.640 + diff);            
            }
        }


        float f = m_dist;
        f *= 5.;
        #define steps 4.
        f = ceil(f *steps) / steps;
        f = map(f, -3., 0., 1., 0.000);

                
        float incr = (1./(steps*3.));

        // Map colors to height
       for(float q = 0.; q<steps*3.; q++) {

			// Get the current height
            float fc = smoothstep(q * incr, q*incr+-0.062, f);
          	fc = step(q * incr, f);
            
			// Base color
            float h =  map(q*incr, 0., 1., 0.160, 0.844);
			h +=  + fc + k/3.392;
           float co = sin01(iTime);
           co = map(co, 0., 1., .5, .2);
           h += uv.x * uv.y + co;
           
            // Blend it
            vec4 c = vec4(h, 0.864, 1., 0.0);
       		c = vec4(hsv2rgb(c.xyz), 0.444);
            color = blend(color, c * fc);
        }
        

    }
    
    float p = 0.;
    vec2 st = (fragCoord - .5 * iResolution.xy) / iResolution.y;

    p = fbm(st, 100., .7, iTime/10.);
    p = map(p, 0., 0.432, 0.664, 1.040);
   // color = vec4(color.xyz * p, 1.);

    fragColor = color;
}
