
//
// base voronoi by iq
// TODO: import base noise texture here
//

// builtin
uniform sampler2D s_NoiseRGBA;

vec3 voronoi_hash( vec3 x )
{
	return texture(s_NoiseRGBA, (x.xy+vec2(3.0,1.0)*x.z+0.5)/256.0, -100.0 ).xyz;
}


// returns closest, second closest, and cell id
vec3 voronoi( in vec3 x )
{
    vec3 p = floor( x );
    vec3 f = fract( x );

	float id = 0.0;
    vec2 res = vec2( 100.0 );
    for( int k=-1; k<=1; k++ )
    for( int j=-1; j<=1; j++ )
    for( int i=-1; i<=1; i++ )
    {
        vec3 b = vec3( float(i), float(j), float(k) );
        vec3 r = vec3( b ) - f + voronoi_hash( p + b );
        float d = dot( r, r );

        if( d < res.x )
        {
			id = dot( p+b, vec3(1.0,57.0,113.0 ) );
            res = vec2( d, res.x );			
        }
        else if( d < res.y )
        {
            res.y = d;
        }
    }

    return vec3( sqrt( res ), abs(id) );
}


//
// everything here is based on the https://www.shadertoy.com/view/MscSDB
//

// The cellular tile routine. Draw a few objects (four spheres, in this case) using a minumum
// blend at various 3D locations on a cubic tile. Make the tile wrappable by ensuring the 
// objects wrap around the edges. That's it.
//
// Believe it or not, you can get away with as few as three spheres. If you sum the total 
// instruction count here, you'll see that it's way, way lower than 2nd order 3D Voronoi.
// Not requiring a hash function provides the biggest benefit, but there is also less setup.
// 
// The result isn't perfect, but 3D cellular tiles can enable you to put a Voronoi looking 
// surface layer on a lot of 3D objects for little cost.
//
float drawSphere(in vec3 p){
    
    // Anything that wraps the domain will suffice, so any of the following will work.
    //p = cos(p*3.14159)*0.5; 
    //p = abs(cos(p*3.14159)*0.5);    
    p = fract(p)-.5;    
    
    return dot(p, p);
    
    // Other metrics to try.
    
    //p = abs(fract(p)-.5);
    //return dot(p, vec3(.5));
    
    //p = abs(fract(p)-.5);
    //return max(max(p.x, p.y), p.z);
    
    //p = cos(p*3.14159)*0.5; 
    //p = abs(cos(p*3.14159)*0.5);
    //p = abs(fract(p)-.5);
    //return max(max(p.x - p.y, p.y - p.z), p.z - p.x);
    //return min(min(p.x - p.y, p.y - p.z), p.z - p.x);
    
}

// Faster (I'm assuming), more streamlined version. See the comments below for an expanded explanation.
// The function below is pretty quick also, and can be expanded to include more spheres. This one
// takes advantage of the fact that only four object need sorting. With three spheres, it'd be even
// better.
float cellTile(in vec3 p){
    
    // Draw four overlapping objects (spheres, in this case) at various positions throughout the tile.
    vec4 v, d; 
    d.x = drawSphere(p - vec3(.81, .62, .53));
    p.xy = vec2(p.y-p.x, p.y + p.x)*.7071;
    d.y = drawSphere(p - vec3(.39, .2, .11));
    p.yz = vec2(p.z-p.y, p.z + p.y)*.7071;
    d.z = drawSphere(p - vec3(.62, .24, .06));
    p.xz = vec2(p.z-p.x, p.z + p.x)*.7071;
    d.w = drawSphere(p - vec3(.2, .82, .64));

    v.xy = min(d.xz, d.yw), v.z = min(max(d.x, d.y), max(d.z, d.w)), v.w = max(v.x, v.y); 
   
    d.x =  min(v.z, v.w) - min(v.x, v.y); // Maximum minus second order, for that beveled Voronoi look. Range [0, 1].
    //d.x =  min(v.x, v.y);
        
    return (d.x*2.66); // Normalize... roughly.
    
}

/*
// Draw some spheres throughout a repeatable cubic tile. The offsets were partly based on 
// science, but for the most part, you could choose any combinations you want. Note the 
// normalized planar positional roation between sphere rendering to really mix things up. This 
// particular function is used by the raymarcher, so involves fewer spheres.
//
float cellTile(in vec3 p){

    // Storage for the closest distance metric, second closest and the current
    // distance for comparisson testing.
    //
    // Set the maximum possible value - dot(vec3(.5), vec3(.5)). I think my reasoning is
    // correct, but I have lousy deductive reasoning, so you may want to double check. :)
    vec3 d = (vec3(.75)); 
   
    
    // Draw some overlapping objects (spheres, in this case) at various positions on the tile.
    // Then do the fist and second order distance checks. Very simple.
    d.z = drawSphere(p - vec3(.81, .62, .53));
    d.x = min(d.x, d.z); //d.y = max(d.x, min(d.y, d.z)); // Not needed on the first iteration.
    
    p.xy = vec2(p.y-p.x, p.y + p.x)*.7071;
    d.z = drawSphere(p - vec3(.39, .2, .11));
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);
    
    p.yz = vec2(p.z-p.y, p.z + p.y)*.7071;
    d.z = drawSphere(p - vec3(.62, .24, .06));
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);
    
    p.xz = vec2(p.z-p.x, p.z + p.x)*.7071; 
    d.z = drawSphere(p - vec3(.2, .82, .64));
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);

     
	// More spheres means better patterns, but slows things down.
    //p.xy = vec2(p.y-p.x, p.y + p.x)*.7071;
    //d.z = drawSphere(p - vec3(.48, .29, .2));
    //d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);
    
    //p.yz = vec2(p.z-p.y, p.z + p.y)*.7071;
    //d.z = drawSphere(p - vec3(.06, .87, .78));
    //d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z); 
	

    
    // Returning what I'm hoping is a normalized result. Not that it
    // matters too much, but I'd like it normalized.
    // 2.66 seems to work, but I'll double check at some stage.
    // d.x: Minimum distance. Regular round Voronoi looking.
    // d.y - d.x - Maximum minus minimum, for that beveled Voronoi look.
    //
    return (d.y - d.x)*2.66; 
    //return 1. - d.x*2.66;
    //return 1. - sqrt(d.x)*1.63299; // etc.

    
}
*/

// Just like the function above, but used to return the regional cell ID...
// kind of. Either way, it's used to color individual raised sections in
// the same way that a regular Voronoi function can. It's only called once,
// so doesn't have to be particularly fast. It's kept separate to the
// raymarched version, because you don't want to be performing ID checks
// several times a frame when you don't have to. By the way, that applies
// to identifying any object in any scene.
//
// By the way, it's customary to bundle the respective distance and cell
// ID into a vector (vec3(d.x, d.y, cellID)) and return that, but I'm 
// keeping it simple here.
//
int cellTileID(in vec3 p){
   
    int cellID = 0;
    
    // Storage for the closest distance metric, second closest and the current
    // distance for comparisson testing.
    vec3 d = (vec3(.75)); // Set the maximum.
    
    // Draw some overlapping objects (spheres, in this case) at various positions on the tile.
    // Then do the fist and second order distance checks. Very simple.
    d.z = drawSphere(p - vec3(.81, .62, .53)); if(d.z<d.x) cellID = 1;
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);
    
    p.xy = vec2(p.y-p.x, p.y + p.x)*.7071;
    d.z = drawSphere(p - vec3(.39, .2, .11)); if(d.z<d.x) cellID = 2;
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);
    
    p.yz = vec2(p.z-p.y, p.z + p.y)*.7071;
    d.z = drawSphere(p - vec3(.62, .24, .06)); if(d.z<d.x) cellID = 3;
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);
   
    p.xz = vec2(p.z-p.x, p.z + p.x)*.7071; 
    d.z = drawSphere(p - vec3(.2, .82, .64)); if(d.z<d.x) cellID = 4;
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);

/* 
    p.xy = vec2(p.y-p.x, p.y + p.x)*.7071;
    d.z = drawSphere2(p - vec3(.48, .29, .2)); if(d.z<d.x) cellID = 5;
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z);
    
    p.yz = vec2(p.z-p.y, p.z + p.y)*.7071;
    d.z = drawSphere2(p - vec3(.06, .87, .78)); if(d.z<d.x) cellID = 6;
    d.y = max(d.x, min(d.y, d.z)); d.x = min(d.x, d.z); 

*/ 
    return cellID;
}

