// Compatibility #ifdefs needed for parameters
#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

// Parameter lines go here:
#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01
#ifdef PARAMETER_UNIFORM
// All parameter floats need to have COMPAT_PRECISION in front of them
uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE;
#else
#define RETRO_PIXEL_SIZE 0.84
#endif

#if defined(VERTEX)

#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying 
#define COMPAT_ATTRIBUTE attribute 
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 COLOR;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 COL0;
COMPAT_VARYING vec4 TEX0;
// out variables go here as COMPAT_VARYING whatever

vec4 _oPosition1; 
uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;

// compatibility #defines
#define vTexCoord TEX0.xy
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
    gl_Position = MVPMatrix * VertexCoord;
    TEX0.xy = VertexCoord.xy;
// Paste vertex contents here:
}

#elif defined(FRAGMENT)

#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;
// in variables go here as COMPAT_VARYING whatever

// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy

#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

// delete all 'params.' or 'registers.' or whatever in the fragment
float iGlobalTime = float(FrameCount)*0.025;
vec2 iResolution = OutputSize.xy;


/*
    
    Transparent Lattice
    -------------------

    Just a transparent lattice. Not much different to my other transparent examples, 
    except this one is point lit... In case it needs to be said, a lot of it is faked, 
    so is more of a novelty than anything else. 

    I wrote it some time ago, then forgot about it. I thought I'd put it up just in 
    case it's of any use to anyone. It runs reasonably fast, considering that the 
    lighting is calculated multiple times a pass, but could benefit from a little more 
    tweaking.

    Related shaders:

    Cloudy Spikeball - Duke
    https://www.shadertoy.com/view/MljXDw
    // Port from a demo by Las - Worth watching.
    // http://www.pouet.net/topic.php?which=7920&page=29&x=14&y=9

    Virtually the same thing, but with rounded cubes and less interesting lighting.
    Transparent Cube Field - Shane
    https://www.shadertoy.com/view/ll2SRy
    
*/



// Cheap vec3 to vec3 hash. Works well enough, but there are other ways.
vec3 hash33(vec3 p){ 
    
    float n = sin(dot(p, vec3(7, 157, 113)));    
    return fract(vec3(2097152, 262144, 32768)*n); 
}


/*
// Rounded cube field, for comparison. It runs at full speed, believe it or not.
float map(vec3 p){
   
    // Creating the repeat cubes, with slightly convex faces. Standard,
    // flat faced cubes don't capture the light quite as well.
    
    // 3D space repetition.
    p = fract(p)-.5; // + o 
    
    // A bit of roundness. Used to give the cube faces a touch of convexity.
    float r = dot(p, p) - 0.21;
    
    // Max of abs(x), abs(y) and abs(z) minus a constant gives a cube.
    // Adding a little bit of "r," above, rounds off the surfaces a bit.
    p = abs(p); 
    return max(max(p.x, p.y), p.z)*.95 + r*0.25 - 0.21;
   
    
    // Alternative. Egg shapes... kind of.
    //float perturb = sin(p.x*10.)*sin(p.y*10.)*sin(p.z*10.);
    //p += hash33(floor(p))*.15;
    //return length(fract(p)-.5)-0.3 + perturb*0.05;
    
}
*/

/*
// A fake noise looking field. Pretty interesting.
float map(vec3 p){

   
    p = (cos(p*.315*2.5 + sin(p.zxy*.875*2.5)));        // + iGlobalTime*.5
     
    float n = length(p);
    
    p = sin(p*6. + cos(p.yzx*6.));
    
    return n - 1. - abs(p.x*p.y*p.z)*.05;

    
}
*/

float map(vec3 p){

    
    
    vec2 c;
 
    // SECTION 1
    //
    // Repeat field entity one, which is just some tubes repeated in all directions every 
    // two units, then combined with a smooth minimum function. Otherwise known as a lattice.
    p = abs(fract(p/3.)*3.-1.5);
    //c.x = sminP(length(p.xy),sminP(length(p.yz),length(p.xz), 0.25), 0.25)-0.75; // EQN 1
    //c.x = sqrt(min(dot(p.xy, p.xy),min(dot(p.yz, p.yz),dot(p.xz, p.xz))))-0.75; // EQN 2
    c.x = min(max(p.x, p.y),min(max(p.y, p.z),max(p.x, p.z)))-0.75; // EQN 3
    //p = abs(p); c.x = max(p.x,max(p.y,p.z)) - .5;
    

    // SECTION 2
    //
    // Repeat field entity two, which is just an abstract object repeated every half unit. 
    p = abs(fract(p*4./3.)*.75 - 0.375);
    c.y = min(p.x,min(p.y,p.z)); // EQN 1
    //c.y = min(max(p.x, p.y),min(max(p.y, p.z),max(p.x, p.z)))-0.125; //-0.175, etc. // EQN 2    
    //c.y = max(p.x,max(p.y,p.z)) - .4;
    
    // SECTION 3
    //
    // Combining the two entities above.
    //return length(c)-.1; // EQN 1
    //return max(c.x, c.y)-.05; // EQN 2
    return max(abs(c.x), abs(c.y))*.75 + length(c)*.25 - .1;
    //return max(abs(c.x), abs(c.y))*.75 + abs(c.x+c.y)*.25 - .1;
    //return max(abs(c.x), abs(c.y)) - .1;
    
}




// Not big on accuracy, but lower on operations. Few distance function calls are important
// during volumetric passes.
vec3 calcNormal(in vec3 p, float d) {
    const vec2 e = vec2(0.01, 0);
    return normalize(vec3(d - map(p - e.xyy), d - map(p - e.yxy),   d - map(p - e.yyx)));
}

/*
// Tetrahedral normal, to save a couple of "map" calls. Courtesy of IQ. Unfortunately, still
// not fast enough in this particular instance.
vec3 calcNormal(in vec3 p){

    // Note the slightly increased sampling distance, to alleviate artifacts due to hit point inaccuracies.
    vec2 e = vec2(0.0025, -0.0025); 
    return normalize(e.xyy * map(p + e.xyy) + e.yyx * map(p + e.yyx) + e.yxy * map(p + e.yxy) + e.x * map(p + e.xxx));
}
*/


void mainImage( out vec4 fragColor, vec2 fragCoord ) {

    
    // Screen coordinates.
    vec2 uv = (fragCoord.xy - iResolution.xy*.5 )/iResolution.y;
    
    // Unit direction ray. The last term is one of many ways to fish-lens the camera.
    // For a regular view, set "rd.z" to something like "0.5."
    vec3 rd = normalize(vec3(uv, (1.-dot(uv, uv)*.5)*.5)); // Fish lens, for that 1337, but tryhardish, demo look. :)
    
    // There are a few ways to hide artifacts and inconsistencies. Making things go fast is one of them. :)
    // Ray origin, scene color, and surface postion vector.
    vec3 ro = vec3(0., 0., iGlobalTime*1.5), col=vec3(0), sp, sn, lp, ld, rnd;
    
    
    // Swivel the unit ray to look around the scene.
    // Compact 2D rotation matrix, courtesy of Shadertoy user, "Fabrice Neyret."
    vec2 a = sin(vec2(1.5707963, 0) + iGlobalTime*0.375);
    rd.xz = mat2(a, -a.y, a.x)*rd.xz;    
    rd.xy = mat2(a, -a.y, a.x)*rd.xy; 
    
    
    lp = vec3(0, 1, 4);
    lp.xz = mat2(a, -a.y, a.x)*lp.xz;    
    lp.xy = mat2(a, -a.y, a.x)*lp.xy; 
    lp += ro;
    
    
    // Unit ray jitter is another way to hide artifacts. It can also trick the viewer into believing
    // something hard core, like global illumination, is happening. :)
    //rd *= 0.99 + hash33(rd)*0.02;
    
    // Some more randomization, to be used for color based jittering inside the loop.
    rnd = hash33(rd+311.);
    
    
    // Ray distance, bail out layer number, surface distance and normalized accumulated distance.
    float t=0., layers=0., d, aD;
    
    // Light variables.
    float lDist, s, l;
    
    // Surface distance threshold. Smaller numbers gives a thinner membrane, but lessens detail... 
    // hard to explain. It's easier to check it out for yourself.
    float thD = .0125; // + smoothstep(-0.2, 0.2, sin(iGlobalTime*0.75 - 3.14159*0.4))*0.025;
 
    
    // Only a few iterations seemed to be enough. Obviously, more looks better, but is slower.
    for(float i=0.; i<64.; i++) {
        
        // Break conditions. Anything that can help you bail early usually increases frame rate.
        if(layers>31. || dot(col, vec3(.299, .587, .114)) > 1. || t>16.) break;
        
        // Current ray postion. Slightly redundant here, but sometimes you may wish to reuse
        // it during the accumulation stage.
        sp = ro+rd*t;
        
        d = map(sp); // Distance to nearest point on the noise surface.
        
        // If we get within a certain distance of the surface, accumulate some surface values.
        // Values further away have less influence on the total.
        //
        // aD - Accumulated distance. You could smoothly interpolate it, if you wanted.
        //
        // 1/.(1. + t*t*0.1) - Basic distance attenuation. Feel free to substitute your own.
        
         // Normalized distance from the surface threshold value to our current isosurface value.
        aD = (thD-abs(d)*31./32.)/thD;
        
        // If we're within the surface threshold, accumulate some color.
        // Two "if" statements in a shader loop makes me nervous. I don't suspect there'll be any
        // problems, but if there are, let us know.
        if(aD>0.) { 
        
            
            // Add the accumulated surface distance value, along with some basic falloff using the 
            // camera to light distance, "lDist." There's a bit of color jitter there, too.
            
            sn = calcNormal(sp, d)*sign(d);
            ld = (lp - sp); //vec3(.5773)
            lDist = max(length(ld), .001);
            ld /= lDist;
            s = pow(max(dot(reflect(-ld, sn), -rd), 0.), 8.);
            l = max(dot(ld, sn), 0.);
            

            //float c = dot(sin(sp*128. - cos(sp.yzx*64.)), vec3(.166))+.5;
            col += ((l + .1) + vec3(.5, .7, 1)*s)*aD/(1. + lDist*0.25 + lDist*lDist*0.05)*.2;
            // Failed experiment with color jitter to take out more banding.
            //col += ((l + .05 + fract(rnd + i*27.)*.1) + vec3(.5, .7, 1)*s)*aD/(1. + lDist*0.25 + lDist*lDist*0.05)*.2;
            
            
            // The layer number is worth noting. Accumulating more layers gives a bit more glow.
            // Lower layer numbers allow a quicker bailout. A lot of it is guess work.
            layers++;
            
        }
        
        // Kind of weird the way this works. I think not allowing the ray to hone in properly is
        // the very thing that gives an even spread of values. The figures are based on a bit 
        // of knowledge versus trial and error. If you have a faster computer, feel free to tweak
        // them a bit.
        t += max(abs(d)*.75, thD*.25);
        
                
    }
    
    t = min(t, 16.);
    
     
    col = mix(col, vec3(0), 1.-exp(-0.025*t*t));////1.-exp(-0.01*t*t) 1.-1./(1. + t*t*.1)
  
    // Mixing the greytone color with a firey orange vignette. There's no meaning
    // behind it. I just thought the artsy greyscale was a little too artsy.
    uv = abs(fragCoord.xy/iResolution.xy - .5); // Wasteful, but the GPU can handle it.
    col = mix(col, vec3(min(col.x*1.5, 1.), pow(col.x, 2.5), pow(col.x, 12.)).yxz,
               min( dot(pow(uv, vec2(4.)), vec2(1))*8., 1.));
               
    //col = vec3(min(col.z*1.5, 1.), pow(col.z, 2.5), pow(col.z, 12.));

    
    // Mixing the vignette colors up a bit more.
    col = mix(col, col.zxy, dot(sin(rd*5.), vec3(.166)) + 0.166);

    
    // Presenting the color to the screen.
    fragColor = vec4( sqrt(clamp(col, 0., 1.)), 1.0 );
    
     
 }

 void main(void)
{
  //just some shit to wrap shadertoy's stuff
  vec2 FragCoord = vTexCoord.xy*OutputSize.xy;
  mainImage(FragColor,FragCoord);
}
#endif