#define smooth3(x) 3.*x*x-2.*x*x*x
#define smooth5(x) 6.*x*x*x*x*x-15.*x*x*x*x+10.*x*x*x
#define smooth7(x) -20.*x*x*x*x*x*x*x+70.*x*x*x*x*x*x-84.*x*x*x*x*x+35.*x*x*x*x
#define r(t) mat2(cos(t), -sin(t), sin(t), cos(t))
#define NO_UNROLL min(iTime, 0.)

vec2 hash22(vec2 p)
{
    vec3 p3 = fract(p.xyx * vec3(.1031, .1030, .0973));
    p3 += dot(p3, p3.yzx+33.33);
    return fract((p3.xx+p3.yz)*p3.zy);
}

float perlinNoise(vec2 p, float t)
{
    vec4 f = vec4(floor(p), ceil(p));
    mat2 r = r(t);
    return mix(mix(dot(p - f.xy,  r*(normalize(hash22(f.xy) - 0.5))),
                   dot(p - f.xw,  r*(normalize(hash22(f.xw) - 0.5))), smooth5(fract(p.y))),
               mix(dot(p - f.zy,  r*(normalize(hash22(f.zy) - 0.5))),
                   dot(p - f.zw,  r*(normalize(hash22(f.zw) - 0.5))), smooth5(fract(p.y))),
                                                                      smooth5(fract(p.x)));
}

vec2 normal(vec2 p, float t, float eps)
{
    mat2 o = mat2(eps*0.5);
    return vec2(perlinNoise(p+o[0], t)-perlinNoise(p-o[0], t),
                perlinNoise(p+o[1], t)-perlinNoise(p-o[1], t))/eps;
}

vec3 gradToVec(vec2 d, float str)
{
    vec3 a = normalize(vec3(1, -d.x*str, 0)),
         b = normalize(vec3(0, -d.y*str, 1));
    return cross(a, b);
}

vec2 distort(in vec2 p, float scale, float t, float dst, float it)
{
    for(float i = NO_UNROLL; i < it; i++)
    {
        p += normal(p*scale, t, 0.001)/it*dst;
    }
    return p;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (fragCoord*2.-iResolution.xy)/iResolution.y;
    vec2 m =  (iMouse.xy*2.-iResolution.xy)/iResolution.y;

    uv = distort(uv+iTime*0.2, 5., iTime, 0.1, 5.);
    m = distort(m+iTime*0.2, 5., iTime, 0.1, 3.);

    vec2 n = normal(uv*5., iTime, 0.001);
    vec3 env = texture(iChannel0, gradToVec(n, 0.4)).rgb;
    env *= env;

    fragColor = vec4(vec3(sqrt(env*0.5+0.2*max(0., dot(n, normalize(uv-m))))), 1);
}