#define RipplesOscillate
//oscillate between circle and ripples, for eccect-amplitude

#define innerCircleRadius 2.5
#define transitionRadius  5.
//outerCircleradius=innerCircleRadius+transitionRadius
//negative innerCircleRadius -> lower peak, aborted transition
//negative transitionRadius  -> valley instead of hill
//transitionRadius also limits==sets to/by how much ANY rectangle is stretched|squashed
//as long as transitionRadius!=0, triangles will never be squashed down to 0.

//#define linearMixOnly
//define in to have it soimple, fast, linear only (unclamped)
//undefine to add at least 50% smoothstep (only smoothstep is clamped)

// https://www.shadertoy.com/view/mdyfD1 asymmetric blocks w regular spot, 2023 by jt
// based on https://www.shadertoy.com/view/dstfzf asymmetric blocks compactified float

// Change the regularity in the pattern of
// random-blocks-by-alternating-double-T-crossings
// (aka asymmetric/irregular)
// based on distance to "spotlight" position.
// This implementation is intended for lookup with floats.
// Click to show grid & control spot.
// Click to lower left returns to demo mode.

// This can be used to place windows into walls of asymmetric blocks:
// see https://www.shadertoy.com/view/dtl3Wf Asymmetric Blocks Wall

// tags: random, t, blocks, double, alternating, irregular, asymmetric, morph, grid, animation, animated, regular, symmetric

// The MIT License
// Copyright (c) 2023 Jakob Thomsen
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#define time_scale 10.0

#define pi 3.1415926

// https://www.shadertoy.com/view/WttXWX "Best" Integer Hash by FabriceNeyret2,
// implementing Chris Wellons https://nullprogram.com/blog/2018/07/31/
uint triple32(uint x) // calculate two hashes in parallel
{
    x ^= x >> 17;
    x *= 0xed5ad4bbU;
    x ^= x >> 11;
    x *= 0xac4c1b51U;
    x ^= x >> 15;
    x *= 0x31848babU;
    x ^= x >> 14;
    return x;
}

//// Wellons lowbias32 from http://nullprogram.com/blog/2018/07/31
//// perhaps the best ever devised for this op count, great distribution and cycle
//uint lowbias32(uint x)
//{
//    x ^= x >> 16;
//    x *= 0x7feb352du;
//    x ^= x >> 15;
//    x *= 0x846ca68bu;
//    x ^= x >> 16;
//    return x;
//}

#define HASH(u) triple32(u)
//#define HASH(u) lowbias32(u)

uint uhash(ivec2 v, bool choose)
{
//return uvec2(0u); // verify grid alignment
    return HASH((uint(v.x)*2u+uint(choose) + HASH(uint(v.y)*2u+uint(choose))) /*+ uint(iFrame / 120)*/);
}

vec2 hash22(vec2 p) // https://www.shadertoy.com/view/4djSRW Hash without Sine by Dave_Hoskins
{
    vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
    p3 += dot(p3, p3.yzx+33.33);
    return fract((p3.xx+p3.yz)*p3.zy);
}

struct block
{
    vec2 center;
    vec2 extent;
    ivec2 id;
};

#define RES 8

#define scale (float(RES*7))

//to get a smoothstepped grid: uv=smoothstep(-.1,.1,ss2t(fract(uv*gridSize/iResolution.xy)))
//ss2t() turns a seesaw wave to triangle wave
#define ss2t(a) a=abs(a*2.-1.)


#define applyRadii(a) a=clamp((a-innerCircleRadius)/transitionRadius,0., 1.0)

float spot(vec2 v)
{
   bool demo = !any(greaterThan(vec2(iMouse), vec2(10))); //= iMouse.z <0.;
    //bool demo = any(lessThan(vec2(iMouse), vec2(10)));
    float speed=pi*3.;
    if(demo)
        v -= vec2(cos(speed*iTime/time_scale)
                , sin(speed*iTime/time_scale) )*scale/vec2(RES);
    else
    {
        // hacky screenspace mouse
        vec2 R = iResolution.xy;
        vec2 m = iMouse.xy;
        m = (2.0 * m - R) / R.y;
        v -= m * scale/float(RES);
    }


    float r=length(v);//a circle pattern for effect-strenght


    #ifdef RipplesOscillate

    float R=r;
    R*=.2;
    R=fract(R);
    R=ss2t(R);
    R*=9.;
    applyRadii(r);
    applyRadii(R);
    r=mix(R,r,-cos(iTime*.5)*.5+.5);

    #else

    applyRadii(r);

     #endif

    return r;
}

float block_hash(ivec2 t, int x, int y, bool choose, bool mirror)
{
    float m = 1.0;
    ivec2 d = (mirror?ivec2(y, x):ivec2(x, y));
    //if(all(lessThanEqual(abs(t+d), ivec2(2))))
    //if(length(vec2(t+d)) < 2.5)
    //    //return float(choose?d.y:d.x);
    //    m = 0.;
    m = spot(vec2(t+d));

    //vec2 r = fract(hash22(vec2(t+d)))+vec2(d); // float hash
    //return choose?r.y:r.x;
    float r = fract(float(uhash(t+d, choose) % uint(RES))/float(RES))+float(choose?d.y:d.x); // integer hash with fixed resolution

    float h=float(choose?d.y:d.x);

    #ifdef linearMixOnly
    h= mix(h+1.,h-1.,m*.5)*.5;
    #else
    //at least 50% smoothstep. the final result is clamped afterwards (discontinuity)
    h= mix(h+1.,h-1.,m*.5)*.5;
    h+=smoothstep(0.,.5,h)*.5;  //dodo: i fail to get 100% smoothtep?
    #endif
    //becausde smoothstep includes a clamp that mix() does not have
    //and that clamping causes artefacts.
    return h;
}

// Inspired by https://www.shadertoy.com/view/Ws3GRs Asymmetric Blocks by Shane.
// Checkerboard tiling of alternating (horizontal vs. vertical) (double-T-) crossings.
// Returns minimum, maximum, id.
// Compactified using implicit matrix transpose & deferred hash calls.
//(NOTE: inlining the hash-function and using out parameters instead of block structure
//       could be used to turn this into a stand-alone function.)
block blocks_layout(vec2 p) // https://www.shadertoy.com/view/dstfzf asymmetric blocks compactified f by jt
{
    ivec2 tile = ivec2(floor(vec2(p))); // global coordinates of tile
    vec2 local = fract(p);

    //bool flip = (tile.x % 2) != (tile.y % 2); // XXX breaks on windows XXX
    bool flip = (tile.x & 1) != (tile.y & 1); // alternate direction of double T crossings: vertical or horizontal
    //flip = !flip; // "dual" pattern (i.e. T-crossings flipped)

    // layout (NOTE: matrix notation upside down compared to coordinate system!)
    // NW N NE
    //  W C E
    // SW S SE

    // transposed (NOTE: matrix notation upside down compared to coordinate system!)
    // SE W NE
    //  N C S
    // SW E NW

    if(flip) // horizontal line goes through: swap vertical with horizontal
    {
        // swap components
        local = local.yx;
    }

    // vertical line goes through (on flip transpose for horizontal line)

    //                 c
    //   +-+---------+---+-------+
    //   | |         |   |       |
    //   | |         |   #-------+ d
    // d +-#-#-------+---M       |
    //   |   |       |   |       |
    //   +---+-------+---+-------+
    //   |   |       |   |       |
    //   |   m-------+---#---#---+
    //   +---#       |       |   |
    //   |   |       |       |   |
    //   +---+-------+-------+---+

    float c = block_hash(tile, 0, 0,  flip, flip); // offset of central line
    int x = 1-int(local.x < c); // [0,1]
    int X = 2*x-1; // [-1,+1]
    float d = block_hash(tile,+X, 0, !flip, flip); // offset of branching line
    int y = 1-int(local.y < d); // [0,1]
    int Y = 2*y-1; // [-1,+1]

    vec2 v0 =
        vec2
        (
            // primary corner in (0,0) tile
            c,
            d
        );

    vec2 v1 =
        vec2
        (
            // primary corner in (X,Y) tile
            block_hash(tile,X,Y, flip, flip),
            block_hash(tile,0,Y,!flip, flip)
        );

    if(flip) tile = tile.yx;

    v0 += vec2(tile);
    v1 += vec2(tile);

    ivec2 id = tile + ivec2(x,y);

    if(flip) // horizontal line goes through: unswap vertical with horizontal
    {
        v0 = v0.yx;
        v1 = v1.yx;
        id = id.yx;
    }

    bool flag = v0.y > v1.y;

    // fix order of min/max corners
    vec2 center = (v0.xy+v1.xy)/2.0;
    vec2 extent = abs(v0.xy-v1.xy)/2.0;

    return block(center, extent, id);
}

vec3 hash32(vec2 p) // https://www.shadertoy.com/view/4djSRW Hash without Sine by Dave_Hoskins
{
    vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
    p3 += dot(p3, p3.yxz+33.33);
    return fract((p3.xxy+p3.yzz)*p3.zyx);
}

float line(vec2 p, vec2 a, vec2 b) // https://iquilezles.org/articles/distfunctions2d/
{
    vec2 pa = p-a, ba = b-a;
    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
    return length( pa - ba*h );
}

vec3 colorize(ivec2 id)
{
    vec3 color = hash32(vec2(id));
    if(((id.x^id.y)&1)==0)
        color = 1.0 - color;
    return color;
}



//i forgot how to use p,mod here, and remembered, all I need is ss2t() instead:
/*
#define vec1 float
//domain-general pmod():
#define pMOD(d,e) d e(inout d a,d b){d c=floor((a/b)+.5);a=(fract((a/b)+.5)-.5)*b;return c;}
pMOD(vec1,pmod)pMOD(vec2,pmod)pMOD(vec3,pmod)pMOD(vec4,pmod)
    //repetitive only for less repetitive legacy namespace support.
/*
//hg_sdf pmod extensions of https://www.shadertoy.com/view/4ttyDN
//problem, pMod alone has no good efficient interval bound with gradients outside of the bound interval
//pmodInterval() exists, but it has (numerically) bad branches.
//pModr() fixes this
//[s] sets period-length, n sets number of [c0 discontinuities] == [tileBorderCount]
float pmod(inout float u,float s){float r=floor(u/s+.5);u=fract(u/s+.5)*s;return r;} //http://mercury.sexy/hg_sdf/
vec2 pmod(inout vec2 u,vec2 s){vec2 r=floor(u/s+.5);u=fract(u/s+.5)*s;return r;} //http://mercury.sexy/hg_sdf/
//vec2 pMod(vec1 u,vec1 s){return vec2( ff(u/s+.5)*vec2(s,1));}//silly variant
vec1 pModr(inout vec1 p,vec1 s,vec1 n//n==number of repeats (discontinuities), where the smallest discontinuity is at [s]
){float q=p,f=pmod(q,s);p=p+.5*s;vec2 r=vec2(mix(mix(q,p-s*n,step(n,f)),p,step(f,0.)),clamp(f,0.,n))
 ;p=r.x;return r.y;}
//for u<0 and u>s*n the space condinues linearily, without repetition, this is different from hg_sdf.
//it also does not set a start, you must just shift u instead
float pModR(inout float p,vec1 s,vec1 n){float r=pModr(p,s,n);p-=s*.5;return r;}//offset the output for more utility.
//minor flaw; for s==0. special linear case, it still splits a line in 2 segments.
*/

//i failed to use euclideanbeat instead of ss2t()
//Because i could not get the scaling right.
//,euclideanbeat is THE best hairline-grid function
//,because its hauirlines do not vanish on smaller respolutions (unless used wrongly)

void mainImage(out vec4 fragColor, in vec2 p){
    vec2 R = iResolution.xy;
    vec2 P=p;
    p = (2.0 * p - R) / R.y;
    //p+=.2;
    vec2 m = iMouse.xy;
    m = (2.0 * m - R) / R.y;

    block b = blocks_layout(p*scale/vec2(RES));
    b.center *= float(RES);
    b.extent *= float(RES);

    vec3 color = colorize(b.id);
    //color *= spot(p*scale/vec2(RES));
    color = max(color, 1.0-spot(p*scale/vec2(RES)));
    //color = mix(vec3(color.x+color.y+color.z)/3.0, color, spot(p*scale/vec2(RES)));
    //color = mix(1.0-color, color, spot(p*scale/vec2(RES)));

    // differences between pixel-position and corners
    vec2 q0 = p-vec2(b.center-b.extent)/scale;
    vec2 q1 = p-vec2(b.center+b.extent)/scale;
    // visualize edges
    color = min(color, vec3(smoothstep(0.005, 0.01,+q0.x)));
    color = min(color, vec3(smoothstep(0.005, 0.01,+q0.y)));
    color = min(color, vec3(smoothstep(0.005, 0.01,-q1.x)));
    color = min(color, vec3(smoothstep(0.005, 0.01,-q1.y)));

    if(iMouse.z > 0.0)
    {
        //snoothed grid!
        vec2 q = fract(p*scale/float(RES)+.5);
        q=ss2t(q);
        q*=2.;//optionally steeper slope dims the gradient out faster, leaving  a black square instead of a black dot.
        q=smoothstep(-.1,.1, q);//essential for smaller resolutions
        //q=sqrt(q);   //optionally more exponential
        color += vec3(1.0-min(q.x, q.y)); //ADD grid+background

        /*
        #ifdef checkerboard
        lazy slow GLOBAL checkerboard
        vec2 r = p*scale/2.0;
        color *= mix(0.5, 1.0, step(0.0, sin(r.x*pi*2.0)*sin(r.y*pi*2.0))); // checker
        #endif
        /**/
    }

    color = sqrt(color);
    fragColor = vec4(color, 1.0);
}
