#ifdef GL_ES
precision highp float;
precision highp int;
#endif

#define PROCESSING_TEXTURE_SHADER

//---------------------------------------------------------------------------------
varying vec2 fragCoord;
uniform vec2 resolution;
uniform float time; 

uniform vec2 mouse;
uniform vec2 yoke;
uniform sampler2D back;
uniform sampler2D background;
uniform sampler2D background2;
uniform int pass;
vec2 r_uv;

//---------------------------------------------------------------------------------

int RSCENE = 3;
bool shadow_enable = true; 
vec3 lightdir = vec3(1,1,1);
float lightsize = 0.1;
vec3 shadow_color = vec3(20);
float gamma = 1.0;
float brightness = 0.3;
float blur = 0.1;
vec3 background_color = vec3(0);

bool enable_lines = false; 
bool enable_grid  = false; 
bool animate_lines = false; 
bool enable_laser  = true;

float amb_tex_amount = 100.0;
float bump_scale = 0.05;
float bump_amount = 2.0;
float refl_amount = 1.0;

#define BOUNCES	 		3
#define SHADOW_VOLUME 	1
#define USE_AMBIENT 	0
#define USE_BUMP        1
#define MULTISAMPLE_TEX	0
#define BARREL	 		0
#define MOVE_CAMERA     1
#define TIME_LINE       1
#define CROP_Y 			0
#define SSAMPLES 		10
#define USE_BAIL        0
#define GAMMA 			1
#define COLOR_GRAIN 	1
#define CONVERGE        0
#define BLEND			0.5
#define BACKGROUND      vec3(30)


#define PI 3.1415926535

//#define mouse 0.001*iMouse
//#define time iTime
//#define resolution iResolution
#define iChannel0 back
#define iChannel1 background

#define PI 3.1415926535


#define MAX_OBJS	 8
#define NUM_SPHERES	 0
#define NUM_PLANES	 0
#define NUM_BOXES	 0


vec4 iMouse; 


vec4 spheres[MAX_OBJS];
vec3 boxpos[MAX_OBJS];
vec3 boxsize[MAX_OBJS];
vec3 boxrot[MAX_OBJS];
bool sphereenable[MAX_OBJS];
bool boxenable[MAX_OBJS];

#define set_sphere(num, pos,r,mat) spheres[num] = vec4(pos, r); sphereenable[num] = true;
#define set_box(num,pos,size,mat) boxpos[num] = pos; boxsize[num] = size; boxenable[num] = true;
#define set_box_rot(num,pos,size,mat) boxrot[num] = pos;


vec3 uniformlyRandomDirection(float seed);
vec3 uniformlyRandomVector(float seed);

vec3 rotatey(in vec3 p, float ang) { return vec3(p.x*cos(ang)-p.z*sin(ang),p.y,p.x*sin(ang)+p.z*cos(ang));  }
vec3 rotatex(in vec3 p, float ang) { return vec3(p.x,p.y*cos(ang)-p.z*sin(ang),p.y*sin(ang)+p.z*cos(ang));  }
vec3 rotatez(in vec3 p, float ang) { return vec3(p.x*cos(ang)-p.y*sin(ang),p.x*sin(ang)+p.y*cos(ang),p.z);  }

vec2 sph(in vec3 p, float r, float o) { return vec2(length(p)-r, o); }
vec2 rbox(in vec3 p, in vec3 b, float r, float o) { return vec2(length(max(abs(p)-b,0.0))-r, o); }
vec2 sdbox( vec3 p, vec3 b, float o ) { vec3 d = abs(p) - b; return vec2(min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0)), o); }
vec2 plane(in vec3 p, in vec3 n, float d, float o) { return vec2(dot(p,n)-d, o); }

vec2 min2(in vec2 o1, in vec2 o2) { if (o1.x < o2.x) return o1; else return o2; }
vec2 max2(in vec2 o1, in vec2 o2) { if (o1.x > o2.x) return o1; else return o2; }

float pModPolar(inout vec2 p, float repetitions) {
	float angle = 2.0*PI/repetitions;
	float a = atan(p.y, p.x) + angle/2.;
	float r = length(p);
	float c = floor(a/angle);
	a = mod(a,angle) - angle/2.;
	p = vec2(cos(a), sin(a))*r;
	// For an odd number of repetitions, fix cell index of the cell in -x direction
	// (cell index would be e.g. -5 and 5 in the two halves of the cell):
	if (abs(c) >= (repetitions/2.0)) c = abs(c);
	return c;
}
float smin1( float a, float b, float k ) { float res = exp( -k*a ) + exp( -k*b ); return -log( res )/k; } // exponential smooth min
float smin2( float a, float b, float k ) { float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 ); return mix( b, a, h ) - k*h*(1.0-h); } // polynomial smooth min
float smin3( float a, float b, float k ) { a = pow( a, k ); b = pow( b, k ); return pow( (a*b)/(a+b), 1.0/k );} // power smooth min

vec3 lightpos;

float random(vec3 scale, float seed) {
	return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
}

vec2 sdLink( vec3 p, float le, float r1, float r2, float o )
{
  vec3 q = vec3( p.x, max(abs(p.y)-le,0.0), p.z );
  return vec2(length(vec2(length(q.xy)-r1,q.z)) - r2,o );
}
vec2 sdTorus( vec3 p, vec2 t, float o)
{
  vec2 q = vec2(length(p.xz)-t.x,p.y);
  return vec2(length(q)-t.y, o);
}
vec2 sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb, float o)
{
  p.x = abs(p.x);
  float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy);
  return vec2(sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb, o);
}

vec2 rot(in vec2 v, in float ang) {
    float si = sin(ang);
    float co = cos(ang);
    return v*mat2(si,co,-co,si);
}
float sdprism( vec3 p, vec2 h )
{
    vec3 q = abs(p);
    return max(q.z-h.y,max(q.x*0.866025+p.y*.5,-p.y)-h.x*0.5);
}

//Capsule / Line - exact

float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
{
  vec3 pa = p - a, ba = b - a;
  float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
  //float h = clamp( dot(pa,ba)/dot(ba,ba), mod(time*12.0, 1.0), mod(time*22.0, 1.0) );
  return length( pa - ba*h ) - r;
}

float rand(float t)
{
    return fract(sin(t*3214.23)*324.03);
}


vec4 get_sphere_pos(int i)
{
	if (i == 0) return spheres[0];
	else if (i == 1) return spheres[1];
	else if (i == 2) return spheres[2];
	else if (i == 3) return spheres[3];
	else if (i == 4) return spheres[4];
	else if (i == 5) return spheres[5];
	else if (i == 6) return spheres[6];
	else if (i == 7) return spheres[7];
}

vec3 get_box_pos(const int i) {
	if (i == 0) return boxpos[0];
	else if (i == 1) return boxpos[1];
	else if (i == 2) return boxpos[2];
	else if (i == 3) return boxpos[3];
	else if (i == 4) return boxpos[4];
	else if (i == 5) return boxpos[5];
	else if (i == 6) return boxpos[6];
	else if (i == 7) return boxpos[7];
}

vec3 get_box_size(const int i) {
	if (i == 0) return boxsize[0];
	else if (i == 1) return boxsize[1];
	else if (i == 2) return boxsize[2];
	else if (i == 3) return boxsize[3];
	else if (i == 4) return boxsize[4];
	else if (i == 5) return boxsize[5];
	else if (i == 6) return boxsize[6];
	else if (i == 7) return boxsize[7];
}


vec3 get_box_normal(in vec3 p, int obj)
{
	vec3 c = get_box_pos(obj);
	vec3 d = get_box_size(obj);
	p -= c;
	float bias = 1.00001;
	return normalize(vec3(int(p.x/abs(d.x)*bias), int(p.y/abs(d.y)*bias), int(p.z/abs(d.z)*bias)));
}

vec3 get_sphere_normal(in vec3 p, int obj)
{
	return normalize(p-get_sphere_pos(obj).xyz);
}

float isph(in vec3 ro, in vec3 rd, in vec4 pos)
{
	ro -= pos.xyz;
	float r = pos.w;
	float A = dot(rd, rd);
	float B = 2.0*dot(ro, rd);
	float C = dot(ro, ro) - r*r;
	
	float disc = B*B - 4.0*A*C;
	if (disc < 0.0)
		return -1.0;
	float discSqrt = sqrt(disc);
	float q;
	if (B < 0.0)
		q = (-B - discSqrt)/2.0;
	else
		q = (-B + discSqrt)/2.0;
	float t0 = q/A;
	//return t0;
	float t1 = C/q;
	return min(t0,t1);
	
}

bool intersectBox(in vec3 ro, in vec3 rd, in vec3 inv, vec3 pos, vec3 size, out float tmin, out float tmax)
 {
   vec3 m1 = pos - size;
   vec3 m2 = pos + size;
   float tymin, tymax, tzmin, tzmax;
   float flag = 1.0;

	if (rd.x >= 0.0)
	{
		 tmin = (m1.x - ro.x) * inv.x;
		 tmax = (m2.x - ro.x) * inv.x;
	}
	else
	{
	   tmin = (m2.x - ro.x) * inv.x;
	   tmax = (m1.x - ro.x) * inv.x; ;
	}
	if (rd.y >= 0.0)
	{
	   tymin = (m1.y - ro.y) *inv.y;
	   tymax = (m2.y - ro.y) *inv.y;
	}
	else
	{
	   tymin = (m2.y - ro.y) *inv.y;
	   tymax = (m1.y - ro.y) *inv.y;
	}
	 
	if ((tmin > tymax) || (tymin > tmax)) flag = -1.0;
	if (tymin > tmin) tmin = tymin;
	if (tymax < tmax) tmax = tymax;
	  
	if (rd.z >= 0.0)
	{
	   tzmin = (m1.z - ro.z) *inv.z;
	   tzmax = (m2.z - ro.z) *inv.z;
	}
	else
	{
	   tzmin = (m2.z - ro.z) *inv.z;
	   tzmax = (m1.z - ro.z) *inv.z;
	}
	if ((tmin > tzmax) || (tzmin > tmax)) flag = -1.0;
	if (tzmin > tmin) tmin = tzmin;
	if (tzmax < tmax) tmax = tzmax;
	  
	return (flag > 0.0);
 }
 
 vec2 column(in vec3 p)
{
	vec2 d = vec2(1000.0, 0.0);
	float w = 0.5;
	float h = 0.5;
	float t = 0.1;
	// wall
	d = min2(d, vec2(+1,1)*sdbox(p-vec3(0,-0.0,0), vec3(w,2,w), 3.0));
	// trim
	p.y = abs(p.y);
	d = min2(d, vec2(+1,1)*sdbox(p-vec3(0,2,0), vec3(w+t,0.3,w+t), 3.0)); // trim
	return d;
}

vec2 wallx(in vec3 p)
{
	vec2 d = vec2(1000.0, 0.0);
	// wall
	d = min2(d, vec2(+1,1)*sdbox(p-vec3(0,-0.0,0), vec3(4,2,0.1), 3.0));
	// trim
	//d = min2(d, vec2(+1,1)*sdbox(p-vec3(0,-2,0), vec3(4.0+0.03,0.25,0.1+0.03), 3.0)); // trim
	return d;
}
vec2 wallz(in vec3 p)
{
	vec2 d = vec2(1000.0, 0.0);
	// wall
	d = min2(d, vec2(+1,1)*sdbox(p-vec3(0,+0.05,0), vec3(0.1,2,4), 3.0));
	// trim
	//d = min2(d, vec2(+1,1)*sdbox(p-vec3(0,-2,0), vec3(0.1+0.03,0.25,4.0+0.03), 3.0)); // trim
	return d;
}
vec2 pillar(in vec3 p)
{
	vec2 d = vec2(1000.0, 0);
	p.y = -abs(p.y);
	d = min2(d, vec2(1,1)*rbox(p-vec3(0,0,0), vec3(0.5,3,1),0.03, 3.0));
	d = min2(d, vec2(1,1)*rbox(p-vec3(0,0,0), vec3(1.0,3,0.0),0.03, 3.0));
	d = min2(d, vec2(1,1)*rbox(p-vec3(0,-2,0), vec3(4.0,0.2,1.0),0.05, 3.0));
//	d = min2(d, vec2(1,1)*rbox(p-vec3(0,1,0), vec3(1.2,2.5,0.8), 0.3,3.0));
//	d = min2(d, vec2(1,1)*rbox(p-vec3(0,0,0), vec3(0.8,3,1.2),0.3, 3.0));
	#if 0
	d = min2(d, vec2(1,1)*sdbox(p-vec3(0,-4,0), vec3(1.5,1,1.5), 3.0));
	d = min2(d, vec2(1,1)*sdbox(p-vec3(0,-4,0), vec3(1.8,0.1,1.8), 3.0));
	d = min2(d, vec2(1,1)*sdbox(p-vec3(0,-3.7,0), vec3(1.8,0.1,1.8), 3.0));
	d = min2(d, vec2(1,1)*sdbox(p-vec3(0,-3.4,0), vec3(1.8,0.1,1.8), 3.0));
	#endif
	return d;
}

float sdCappedCylinder(vec3 p, vec3 a, vec3 b, float r)
{
  vec3  ba = b - a;
  vec3  pa = p - a;
  float baba = dot(ba,ba);
  float paba = dot(pa,ba);
  float x = length(pa*baba-ba*paba) - r*baba;
  float y = abs(paba-baba*0.5)-baba*0.5;
  float x2 = x*x;
  float y2 = y*y*baba;
  float d = (max(x,y)<0.0)?-min(x2,y2):(((x>0.0)?x2:0.0)+((y>0.0)?y2:0.0));
  return sign(d)*sqrt(abs(d))/baba;
}

//------------------------------------------------------------------------------

// Combined raymarcher and ray tracer (spheres+boxes)
float ifs_6(in vec3 p) {
    float d = p.y + 1.5;
    float sc = 7.0;
    for (int i = 0; i < 12; i++) {
        p = rotatey(p,3.1415*0.25);
        p=sc*.8-abs(mod(p,2.0*sc)-sc);
        d = max(d,min(min(p.x, p.y), p.z));
        sc *= 0.5;
    }
    return d;
}

float ifs_5(in vec3 p) {
    p -= vec3(0,-6,0); 

    float d = 00.0; // p.y + 3.0;
    float s = 12.0;
    
    d = sdbox(p,vec3(150,150,150),3.0).x;
    
    //p -= s/12.;
    //p = abs(p);
    d = max(d, -sdbox((mod((p),s*2.0)-s), vec3(s)*0.9, 3.0).x); 
    s *= 0.5;
    p = rotatez(p, 1.4142*0.5);
    p.xy = abs(p.xy+1.0);
    //p -= s/12.;
    //p = abs(p);
    d = max(d, -sdbox((mod((p),s*2.0)-s), vec3(s)*0.9, 3.0).x); 
    s *= 0.25;
    p = rotatez(p, 1.4142*0.5);
    p.xy = abs(p.xy);
    //p -= s/12.;
    //p = abs(p);
    p.xy = abs(p.xy+0.2);
    d = max(d, -sdbox((mod((p),s*2.0)-s), vec3(s)*0.9, 3.0).x); 
    //s *= 0.5;
    //p = rotatez(p, 1.4142*0.5);
    
    d = max(d, -sph(p, 50.0, 3.0).x);
    return d;
}
float ifs_4(in vec3 p) {
    p -= vec3(0,-3,0);
    vec3 op = p;
    float d = 0.;
    float s = 18.0;
    for (int i = 0; i < 3; i++) {
        op -= s/8.;
        vec2 b = sdbox(mod(abs(op), s*2.)-s, vec3(s*.9), 3.0);
        d = max(-b.x, d);
        if (i==1) {
            op.xz = abs(rot(op.xz,float(i)*1.4142*0.5+0.0));
        } else {
            op.zy = abs(rot(op.zy,float(i)*1.4142*0.0+0.0));
        }
    	s *= 0.5;
    }
    return max(sdprism(p*vec3(0.25,-1.,1.), vec2(80., 120.)), d);
}

float ifs(in vec3 p) {
    p -= vec3(0,-6,0);
    vec3 rp = p;
    float d = 0.;
    float s = 12.0;
    
    for (int i = 0; i < 3; i++) {
        rp -= s/8.;
        vec2 b = sdbox(mod(abs(rp), s*2.)-s, vec3(s*.9), 3.0);
        d = max(-b.x, d);
        if (i == 1) {
            rp.xz = abs(rot(rp.xz,float(i)*1.4142*0.5+0.0));
        } else {
            rp.zy = abs(rot(rp.zy,float(i)*1.4142*0.0+0.0));
        }
    	s /= 5.;
    }
                       
    return max(sdprism(p*vec3(1.,-1.,1.), vec2(60., 40.)), d);
}

float glow = 0.0;


vec2 scene7(in vec3 p)
{
	vec2 d = vec2(1000.0, 0);
	vec3 op = p;
	d = min2(d, vec2(-1,1)*sdbox(p-vec3(0,0,0), vec3(32,2,32), 3.0));
	//p -= vec3(0,0,-8);
	//p = rotatey(p, 4.0);
	p.x = mod(p.x+2.5, 16.0)-8.0;
	p.z = mod(p.z+4.0, 16.0)-8.0;
#if 0
	// x-walls
	d = min2(d, wallz(p-vec3(2,0,-5)));
	d = min2(d, wallz(p-vec3(-5,0,-4)));
	d = min2(d, wallx(p-vec3(7,0,-6)));
	//d = min2(d, wallz(p-vec3(-6,0,-2)));
	//d = min2(d, wallz(p-vec3(-4,0,-2)));
#endif
		
#if 1
	// columns
	p = op;
	p.x = mod(p.x+5.5, 7.0)-3.5;
	p.z = mod(p.z+4.0, 7.0)-3.5;
	d = min2(d, column(p-vec3(0,0,0)));
#endif
	
	
	p = op;
#if 1
	// grid of balls
	p -= vec3(-2,0,-24);
	p = rotatex(p,mouse.y*10.0);
	p = rotatey(p,mouse.x*10.0);
	p.x = mod(p.x, 1.0)-0.5;
	p.y = mod(p.y, 1.0)-0.5;
	d = min2(d, vec2(+1,1)*sph(p, 0.25, 3.0));
#endif
	
#if 0
	// pillars
	p = op;
	p -= vec3(0,0,-8);
	//p = rotatey(p,0.5);
	p.x = mod(p.x, 8.0)-4.0;
	p.z = mod(p.z, 4.0)-2.0;
	d = min2(d, pillar(p));
#endif
	
	return d;
}

float ifs_4_2(in vec3 p) {
    p -= vec3(0,-6,0); 
    float d = 00.0; // p.y + 3.0;
    float s = 12.0;
    d = sdbox(p,vec3(150,150,150),3.0).x;
    d = max(d, -sdbox((mod((p),s*2.0)-s), vec3(s)*0.9, 3.0).x); 
    s *= 0.5;
    p = rotatez(p, 1.4142*0.5);
    p.xy = abs(p.xy+1.0);
    d = max(d, -sdbox((mod((p),s*2.0)-s), vec3(s)*0.9, 3.0).x); 
    s *= 0.25;
    p = rotatez(p, 1.4142*0.5);
    p.xy = abs(p.xy);
    p.xy = abs(p.xy+0.2);
    d = max(d, -sdbox((mod((p),s*2.0)-s), vec3(s)*0.9, 3.0).x); 
    d = max(d, -sph(p, 100.0*0.1*mod(time*0.1, 10.0), 3.0).x);
    return d;
}

vec3 get_light_pos(inout float lightsize, float t)
{

    vec3 lightpos = vec3(0,0,-100);
    lightsize = 10.0;
    return lightpos;
    
}

float ifs_1(in vec3 p) {
    p -= vec3(0,-6,0);
    vec3 rp = p;
    float d = 0.;
    float s = 12.0;
    
    for (int i = 0; i < 3; i++) {
        rp -= s/8.;
        vec2 b = sdbox(mod(abs(rp), s*2.)-s, vec3(s*.9), 3.0);
        d = max(-b.x, d);
        
        if (mod(float(i),2.) > 0.) {
            rp.xz = abs(rot(rp.xz,float(i)*1.4142*0.5+0.0));
        } else {
            rp.zy = abs(rot(rp.zy,float(i)*1.4142*0.0+0.0));
        }
        
    	s /= 4.0;
    }
    return max(sdprism(p*vec3(1.,-1.,1.), vec2(80., 120.)), d);
}


// Temple like
float ifs_2(in vec3 p) {
    p -= vec3(0,-6,0);
    vec3 rp = p;
    float d = 0.;
    float s = 18.0;
    
    for (int i = 0; i < 3; i++) {
        rp -= s/8.;
        vec2 b = sdbox(mod(abs(rp), s*2.)-s, vec3(s*.9), 3.0);
        d = max(-b.x, d);
        
        if (mod(float(i),2.) > 0.) {
            rp.xz = abs(rot(rp.xz,float(i)*1.4142*0.5+0.0));
        } else {
            rp.xz = abs(rot(rp.xz,float(i)*3.1415*0.5+0.0));
        }
        
    	s /= 4.;
    }
                       
    return max(sdprism(p*vec3(1.,-1.,1.), vec2(60., 40.)), d);
}

vec2 scene(in vec3 p)
{
	vec2 d = vec2(1000.0, 0);
	vec3 op = p;
    float t = mod(time, 10.0);
 if (RSCENE == 2) {
//    d = vec2(ifs_1(p), 3.0); // more square
//    d = max2(d, vec2(-1,1)*sdbox(p-vec3(0,0,0), vec3(3.5,12,20.5), 3.0));
//    d = max2(d, vec2(-1,1)*sph(p-vec3(0,0,0), 40.0, 3.0));
 }
 else if (RSCENE == 3) {
 
    //d = min2(d, vec2(-1,1)*sdbox(p-vec3(0,0,0), vec3(32,2,32), 3.0));    
    //d = vec2(ifs_1(p), 3.0); // more square
    //d = vec2(ifs_2(p), 3.0); // sparse
    //d = vec2(ifs_5(p), 3.0); // indu
    //d = vec2(ifs_6(p), 3.0); // xor marcher
    d = vec2(ifs_4(p), 3.0);
    d = max2(d, vec2(-1,1)*sdbox(p-vec3(0,0,0), vec3(3.5,12,20.5), 3.0));
    d = max2(d, vec2(-1,1)*sph(p-vec3(0,0,0), 40.0, 3.0));
     if (enable_laser) {
            vec2 ls= sph(vec3(1,1,0)*(p-vec3(0,-0,0)), 0.5+sin(time*20.0+p.x*10.0), 1.0);
            d = min2(d, ls);
        }
 }
 else if (RSCENE == 4) 
    {
    //d = min2(d, vec2(-1,1)*sdbox(p-vec3(0,0,0), vec3(32,2,32), 3.0));    
    d = vec2(ifs_4_2(p), 3.0);
    //d = max2(d, vec2(-1,1)*sdbox(p-vec3(0,0,0), vec3(3.5,12,20.5), 3.0));
    if (enable_laser) {
            vec2 ls= sph(vec3(1,1,0)*(p-vec3(0,-5,0)), 1.0+sin(time*20.0+p.x*10.0), 1.0);
            d = min2(d, ls);
        }
    }
	return d;
}

float get_lp(in vec2 p)
{
	p.y *= -1.0;
	p.y += 0.75;
	return exp(-2.0*pow(length(p.xy),2.0))*(-0.2+p.y)*4.0;

}
vec3 get_ambient(in vec3 p)
{
	vec3 s0 = vec3(0);
	s0 += vec3(1)*10.0*get_lp(0.1*(p.xy-vec2(0,0.7)));
	s0 += vec3(1)*10.0*get_lp(0.3*(p.zy-vec2(-4.0,0.0)));
	return vec3(20.0)+s0*2.0+sin(p.z+3.0)*0.0;
}

vec3 get_emission(in vec3 p)
{
	vec3 op = p;
	vec3 col = vec3(0);
	
	//col += vec3(1,1,1)* 24.0*exp(-1.0*pow(0.2*length(vec3(0.3,1,0.4)*(p-vec3(+4,0,-22))),2.0));
	
    
    if (enable_lines) 
    {
        p = op;
        float LT = 0.01;
        //p.x = mod(p.x+0.5, 1.0)-0.5;
        //if (abs(p.x) < LT) return vec3(55);
        float t = mod(floor(time*10.0), 50.0); 
        if (abs(p.z+t) < 500.0) {
            p.z = mod(p.z+0.5, 1.0)-0.5;
            if (animate_lines)
                p.z = mod(p.z+0.5-time*0.1, 1.0)-0.5;
            if (abs(p.z) < LT) return vec3(55);
        }
        //p.y = mod(p.y+0.0, 1.0)-0.5;
        //if (abs(p.y) < LT) return vec3(55);
    }
    if (enable_grid) {
        p = op;
        // grid of lights
        if (abs(p.x) < 32.0 && abs(p.z+24.0) < 32.0) {
            p.x = mod(p.x, 5.0)-2.5;
            p.z = mod(p.z, 5.0)-2.5;
            if (p.y > 1.999 && abs(p.x) < 1.0 && abs(p.z) < 1.0) return vec3(222);
        }
    }
	vec3 lcol = vec3(0);
	p = op;
	return vec3(5,5,5)*0.0+col+lcol+0.0*sin(p.z*0.8+4.0);
}
vec3 get_normal(in vec3 p)
{
	vec3 eps = vec3(0.00001, 0, 0);
	float nx = scene(p + eps.xyy).x - scene(p - eps.xyy).x;
	float ny = scene(p + eps.yxy).x - scene(p - eps.yxy).x;
	float nz = scene(p + eps.yyx).x - scene(p - eps.yyx).x;
	return normalize(vec3(nx,ny,nz));
}

// ambient occlusion approximation
// multiply with color
float ambientOcclusion(vec3 p, vec3 n)
{
	const int steps = 3;
	const float delta = 0.5;
	
	float a = 0.0;
	float weight = 1.0;
	for(int i=1; i<=steps; i++) {
		float d = (float(i) / float(steps)) * delta;
		a += weight*(d - scene(p + n*d).x);
		weight *= 0.5;
	}
	return clamp(1.0 - a, 0.0, 1.0);
}


float PHI = 1.61803398874989484820459;  // Φ = Golden Ratio
float gold_noise(in vec2 xy, in float seed){
	return fract(tan(distance(xy*PHI, xy)*seed)*xy.x);
}

float seed;
float rand1()
{
	vec2 s = gl_FragCoord.xy/resolution.xy;
	float n = fract(sin(seed+=1.0)*43758.5453123);
	return fract(n + fract(sin(dot(vec2(n * (s.y+1.0), s.x)*0.123,vec2(12.9898,78.233))) * 43758.5453));
}
//returns a random unit vector inside the given hemisphere
vec3 rndDirHemisphere(vec3 n)
{
	float r2 = rand1();
	float phi = 2.0*PI*rand1();
	float sina = sqrt(r2);
	float cosa = sqrt(1. - r2);
	vec3 w = normalize(n), u = normalize(cross(w.yzx, w)), v = cross(w, u);
	return normalize((u*cos(phi) + v*sin(phi)) * sina + w * cosa);
}


vec3 cosineWeightedDirection(float seed, vec3 normal) {
#if 0
	float a = 2.0*random(vec3(12.9898, 78.233, 151.7182), seed)-1.0;
	float b = 2.0*random(vec3(63.7264, 10.873, 623.6736), seed)-1.0;
	float c = sqrt(1.0-a*a);
	vec3 r = vec3(c*cos(b),a,c*sin(b));
	return dot(r,normal) > 0.0 ? r : -r;
#else
	float u = random(vec3(12.9898, 78.233, 151.7182), seed);
	float v = random(vec3(63.7264, 10.873, 623.6736), seed);
	float r = sqrt(u);
	float angle = 6.283185307179586 * v;
	vec3 sdir, tdir;
	if (abs(normal.x)<.5) {
		sdir = cross(normal, vec3(1,0,0));
	} else {
		sdir = cross(normal, vec3(0,1,0));
	}
	tdir = cross(normal, sdir);
	return r*cos(angle)*sdir + r*sin(angle)*tdir + sqrt(1.-u)*normal;
#endif
}

vec3 uniformlyRandomDirection(float seed) {
	float u = random(vec3(12.9898, 78.233, 151.7182), seed);
	float v = random(vec3(63.7264, 10.873, 623.6736), seed);
	float z = 1.0 - 2.0 * u; float r = sqrt(1.0 - z * z);
	float angle = 6.283185307179586 * v;
	return vec3(r * cos(angle), r * sin(angle), z);
}

vec3 uniformlyRandomVector(float seed) {
	return uniformlyRandomDirection(seed) * sqrt(random(vec3(36.7539, 50.3658, 306.2759), seed));
}

bool shadowray(out float shadow_dist, out vec2 od, in vec3 ro, in vec3 rd, float time)
{
	
	vec3 colorMask = vec3(1.0);
	vec3 color = vec3(0.0);
	vec3 surfaceColor = vec3(0);
	vec3 tex = vec3(0);
	
	vec3 pos = ro;
	float dist = 0.0;
	vec2 d = vec2(0);
	bool hit = true;
	for (int i = 0; i < 128; i++) {
		d = scene(pos);
		if (abs(d.x) < 0.00001) { hit = true; break; }
		pos += rd*d.x;
	}
	dist = length(pos - ro);
	shadow_dist = dist;
	od = d;
	return hit;
}




bool shadowray(in vec3 ro, in vec3 rd, float ldist)
{

    vec3 pos = ro;
    float dist = 0.0;
    vec2 d = vec2(0);
        for (int i = 0; i < 80; i++) {
            d = scene(pos);
            if (abs(d.x) < 0.00001) break;
            pos += rd*d.x;
        }
        
    dist = length(pos-ro);
   if (dist > ldist) return true;
      
   return false; 
}


vec3 rm(in vec3 ro, in vec3 rd, float time)
{
	vec3 colorMask = vec3(1.0);
	vec3 color = vec3(0.0);
	vec3 surfaceColor = vec3(0);
	vec3 tex = vec3(0);
	bool bail = false;
    
    glow = 0.0;
	for (int bounce = 0; bounce < BOUNCES; bounce++) {
		vec3 pos = ro;
		float dist = 10000.0;
		vec2 d = vec2(0);
		vec3 n;
		
		if (bail) break;
		
		if (bounce == 0) {
			for (int i = 0; i < 80; i++) {
				d = scene(pos);
				if (abs(d.x) < 0.00001) break;
				pos += rd*d.x;
			}
		}
		else {
			for (int i = 0; i < 64; i++) {
				d = scene(pos);
				if (abs(d.x) < 0.00001) break;
				pos += rd*d.x;
			}
		}
		dist = length(pos - ro);
		n = get_normal(pos);
		
		// check for raytrace intersections
		{
			float tmin = dist;
			int obj = 0;
			// spheres
			for (int i = 0; i < NUM_SPHERES; i++) {
				float t = isph(ro,rd, get_sphere_pos(i));
				if (t > 0.0 && t < tmin) {
					tmin = t;
					obj = i;
					
					dist = t;
					d = vec2(tmin, 2.0);

					pos = ro + t*rd;
					n = get_sphere_normal(pos, i);
				}
			}
			// boxes
			for (int i = 0; i < NUM_BOXES; i++) {
				vec3 inv = 1.0/rd;
				float t1, t2;
				if (intersectBox(ro,rd,inv,get_box_pos(i),get_box_size(i), t1, t2)) {
					if (t1 > 0.0 && t1 < tmin) {
						tmin = t1;
						obj = i + 200;
						d = vec2(tmin, 3.0);
                        dist = t1;						
						pos = ro + t1*rd;
						n = get_box_normal(pos, i);
					}
					else if (t2 > 0.0 && t2 < tmin) {
                        // inside
						tmin = t2;
						obj = i + 300;
						d = vec2(tmin, 3.0);
						dist = t2;
						pos = ro + t2*rd;
						n = -get_box_normal(pos, i);
					}
				}
			}
		}
		if (dist < 200.0) {
			float o = d.y;
			float shade = 1.0; //0.9+0.1*ambientOcclusion(pos+0.001*n, 1.0*n);

#if USE_AMBIENT
			if (bounce == 0) color += get_ambient(pos);
#endif

			if (true) {
#if MULTISAMPLE_TEX
				tex = vec3(0);
				for (int i = 0; i < 16; i++) {
					float AA = 0.01;
					tex += get_emission(pos + AA*uniformlyRandomVector(float(time)+float(i)));
				}
				tex /= 16.0;
#else
				tex = get_emission(pos);
#endif
			}
			
			float refl = 0.0;
			bool enable = false;
			if (d.y == 1.0) {
				surfaceColor = vec3(1,1,1)*100.0;
			}
			else if (d.y == 2.0) { // unlit
				surfaceColor = tex*vec3(1,1,1)*(0.0);
				refl = 2.0;
			}
			else if (d.y == 3.0) { // unlit
				surfaceColor = tex*vec3(1,1,1)*(1.0);
				refl = refl_amount;
			}
            
            // bump normal
            #if USE_BUMP 
            // sample bump
            vec3 tex_n;
            vec2 flip = vec2(1,-1);

            if (abs(dot(n,vec3(0,0,1))) > 0.5)
                tex_n = 1.0*texture2D(iChannel1,pos.xy*flip*bump_scale+0.5).xyz-0.5;
            if (abs(dot(n,vec3(1,0,0))) > 0.5)
                tex_n = 1.0*texture2D(iChannel1,pos.yz*flip*bump_scale+0.5).xyz-0.5;
            if (abs(dot(n,vec3(0,1,0))) > 0.5)
                tex_n = 1.0*texture2D(iChannel1,pos.xz*flip*bump_scale+0.5).xyz-0.5;
            // apply the bump
            n += 1.0*tex_n*bump_amount;
            #endif

            if (bounce == 0) color += amb_tex_amount*vec3(clamp(pow(tex_n+0.5, vec3(5.4)).x,0.0,0.05));
            
            float t = mod(time, 10.0);
#if SHADOW_VOLUME 
            vec3 ldir;
            float ldist;
            {
            //lightdir = vec3(sin(time*0.3),sin(time*0.5),sin(time*0.6));
            ldir = normalize(lightdir+lightsize*uniformlyRandomVector(time+float(bounce))-0.5); 
            ldist = 1000.0;
            }
            if (shadow_enable &&
                shadowray(pos+0.1*n, ldir, ldist)) {
                color += shadow_color;
            }

#endif
			color += 1.0*shade*surfaceColor*clamp(dist, 1.0, 1.0); //*colorMask;
			colorMask *= surfaceColor;
			
			// update position, normal for bounces
			float rr = random(vec3(36.7539, 50.3658, 306.2759), time+float(bounce));
			refl = clamp(refl*rr, 0.0, 1.0);
			ro = pos+n*0.0001;
			vec3 rd2 = reflect(rd, n);
			//rd = normalize(cosineWeightedDirection(time+float(bounce), n));
			rd = normalize(rndDirHemisphere(n));
			rd = normalize(mix(rd, rd2, refl));
		}
        else {
            // no intersection found
            // background color
            color += background_color;
        }
    //color += 2000.0/(1.0+0.2*glow);
	}
    
	return clamp(color*0.05, 0.0, 100.0);
}


void calc_cam(out vec3 ro, out vec3 rd, in vec2 p, in vec3 campos, in vec3 camtar, float fov)
{
	vec3 camup = vec3(0,1,0);
	vec3 camdir = normalize(camtar-campos);
	vec3 cu = normalize(cross(camdir, camup));
	vec3 cv = normalize(cross(cu, camdir));
    ro = campos;
    rd = normalize(p.x*cu + p.y*cv + camdir*fov);

}


void make_camera(out vec3 ro, out vec3 rd, in vec2 p, float time)
{
	
	float AA = 0.0025;
	p += uniformlyRandomVector(time).xy*AA*1.0;
	vec3 campos = vec3(0,0,10.0-mod(time*0.1, 10.0));
	vec3 camtar = vec3(0.0,mod(time*0.1, 10.0),-10);
	vec3 camup = vec3(0,1,0);
	
	vec3 camdir = normalize(camtar-campos);
	vec3 cu = normalize(cross(camdir, camup));
	vec3 cv = normalize(cross(cu, camdir));
	
    float t = mod(time, 10.0);
    float cam_height = 0.0;
    
    vec4 cam = vec4(0,0,0,0);
    float fov = 2.0;
    float rot_z = 0.0;
    
    float bl = 1.954*4.0;
    int cam_scene = 0;
    
    #if 0
    if (time < 60.0)
        bl = 1.954*4.0;
    else if (time > 120.0)
        bl = 1.954*4.0;
    else
        bl = 1.954*2.0;
    #endif
        
    bl = 1.954*3.0;
    //float seed = 1232.0;
    //float seed = 1238.0;
    //float seed = 3230.0;

    float seed = 1325.0; // pretty nice
    //float seed = 1394.0; // pretty nice
    
    //float seed = 4328.0; // pretty nice
    //float seed = 1240.0; // pretty nice
    //float seed = 1248.0; // pretty nice
    //float seed = 12208.0; // pretty nice
    //float seed = 12214.0; // pretty nice
    
    // random scene
    cam_scene = int(mod(sin(floor(time/bl)*2132.0+seed)*2132.0, 22.0));
    t = mod(time*2.0, bl*10.0);

//    cam_scene = 14;

    // manual override
    // TIME LINE
    #if 1
    if (time >= 12.0 && time < 22.0) {
        cam_scene = 20;
    }
    if (time >= 22.0 && time < 36.0) {
        cam_scene = 21;
    }
    if (time >= 47.0 && time < 60.0) {
        cam_scene = 18;
    }
    if (time >= 75.0 && time < 85.0) {
        cam_scene = 10;
    }
    else if (time >= 107.0 && time < 113.0) {
        cam_scene = 3;
    }
    else if (time >= 113.0 && time < 126.0) {
        cam_scene = 13;
    }
    else if (time >= 126.0 && time < 134.0) {
        cam_scene = 11;
    }
    else if (time >= 156.0 && time < 166.0) {
        cam_scene = 18;
    }
    else if (time >= 187.0 && time < 198.0) {
        cam_scene = 22;
    }
    else if (time >= 198.0 && time < 200.0) {
        cam_scene = 20;
    }
    #endif
    
    if (time > 46.0)
        animate_lines = true;
    
    #if TIME_LINE
    
    if (cam_scene == -1) {
        // black 
        background_color = vec3(0);
        brightness = 0.0;
    }
    if (cam_scene == 0) {
        // zoom in structure
        RSCENE = 3;
        cam = vec4(262.0,264.0+t*0.0,252.0+t*0.1,250)*0.001;
        cam_height += 0.5*t;
        background_color = vec3(50);
    }
    else if (cam_scene == 1 ) {
        // centered laser, time > 78s 
        RSCENE = 4;
        cam = vec4(498,28,122,206)*0.001;
        cam.w += -mod(time, 200.0)*0.001;
    }
    else if (cam_scene == 2) {
        // side view, time > 78s 
        RSCENE = 4;
        cam = vec4(-80,108,266,267)*0.001;
        cam.w += -mod(time, 200.0)*0.001;
        cam.y += -mod(time, 200.0)*0.001;
        background_color = vec3(55);
    }
    else if (cam_scene == 3) {
        // circle scene RSCENE 3
        RSCENE = 3;
        cam = vec4(451,201,188,185)*0.001;
        cam.z += 0.001*t;
    }
    else if (cam_scene == 4) {
        // ifs scene RSCENE 3
        RSCENE = 2;
        cam = vec4(408, 186, 74, 75)*0.001;
        cam.y += 0.001*t;
    }
    else if (cam_scene == 5) {
        // horiz panning 
        // doesn't work?
        RSCENE = 4;
        background_color = vec3(50);
        cam = vec4(-90.0+1.0*mod(time,200.0),186,329,268)*0.001;
        cam.w += 0.001*t;
        refl_amount = 4.0;
        animate_lines = true;
    }
    else if (cam_scene == 6) {
        // aligned
        RSCENE = 4;
        cam = vec4(22,265,212,185)*0.001;
        cam.x += 0.001*t;
    }
    else if (cam_scene == 7) {
        // looking left of the circle
        RSCENE = 4;
        cam = vec4(322,150,247,184)*0.001;
    }
    else if (cam_scene == 8) {
        // looking right of the circle
        // t = 50 ... 73 
        RSCENE = 4;
        cam = vec4(633,224,247,184)*0.001;
        fov = 3.0;
        cam.w -= 0.001*t;
    }
    else if (cam_scene == 9) {
        // plasma generator, t > 70.0
        RSCENE = 4;
        cam = vec4(437,317.0+0.0*mod(time, 200.0),265.0,164)*0.001;
        fov = 2.0;
        cam.w += 0.001*t;
    }
    else if (cam_scene == 10) {
        // angled dissovled, t > 88.0
        RSCENE = 4; 
        cam = vec4(266,142,264,259)*0.001;
        cam.w -= 0.001*t;
    }
    else if (cam_scene == 11) {
        // symmetric dissolve, t > 111.0
        RSCENE = 4;
        cam = vec4(471,107,200,166)*0.001;
        cam.z += 0.001*t;
        cam.w += 0.001*t;
    }
    else if (cam_scene == 12) {
        // start scene 
        RSCENE = 3;
        cam = vec4(463,193,195,187)*0.001;
        cam.y += 0.001*t;
    }
    else if (cam_scene == 13) {
        // second scene 
        RSCENE = 3;
        cam = vec4(569,150.0+t*1.0,203,201)*0.001;
        cam.x -= 0.001*t;
        cam_height = -14.0;
    }
    else if (cam_scene == 14) {
        // close up, zoom out from XK logo
        RSCENE = 2;
        cam = vec4(447,360,219,360)*0.001;
        cam.x -= 0.002*mod(time, 200.0);
        background_color = vec3(30);
    }
    else if (cam_scene == 15) {
        // plasma zoom, t > 20.0, t < 34.0
        RSCENE = 3;
        cam = vec4(407,199,284,10.0)*0.001;
        cam.w -= 0.001*t;
        cam.w -= 0.001*t;
    }
    else if (cam_scene == 16) {
        // extreme closeup 1  
        RSCENE = 4;
        cam = vec4(569,150.0+t*0.5,203,201)*0.001;
        cam_height = -14.0;
        fov = 12.0;
    }
    else if (cam_scene == 17) {
        // extreme closeup 2  
        // RSCENE 3, t = 00...20
        // RSCENE 4, t = 30...40 
        RSCENE = 3;
        cam = vec4(519,158.0,203.0,201.0-t*0.3)*0.001;
        cam_height = -14.0;
        fov = 11.0;
    }
    else if (cam_scene == 18) {
        // extreme closeup 2b  
        // RSCENE 4, t = 30...40 
        RSCENE = 4;
        cam = vec4(519,158.0,203.0,201.0-t*0.3)*0.001;
        cam_height = -14.0;
        fov = 11.0;
    }
    else if (cam_scene == 19) {
        // extreme closeup 3, t = 20...36
        RSCENE = 3;
        cam = vec4(419,158.0,203.0+t*0.2,201.0-t*0.3)*0.001;
        cam_height = -14.0;
        fov = 11.0;
    }
    else if (cam_scene == 20) {
        // zoom out
        RSCENE = 3;
        cam = vec4(520,181,182.0+1.0*t,184)*0.001;
        rot_z += 0.025*t;
    }
    else if (cam_scene == 21) {
        // zoom in
        RSCENE = 3;
        cam = vec4(520,181,182.0+1.0*t,184)*0.001;
        rot_z += -0.025*t;
        cam.y += 3.1415/4.0;
        animate_lines = true;
    }
    else if (cam_scene == 22) {
        // half cover
        RSCENE = 3; 
        cam = vec4(357.0+1.0*t,183,170,347)*0.001;
        rot_z += 0.025*t;
        bump_scale *= 0.1;
    }
    else if (cam_scene == 23) {
        cam = vec4(329,201,191,78)*0.001;
        cam.y -= 0.1*0.025*t;
        //fov = 1.0;
    }
    #endif
    if (RSCENE == 1) {
        background_color = vec3(30);
        shadow_enable = true;
        lightdir = vec3(sin(-5.0+time*0.05),sin(-1.0+time*0.1),sin(1.0+time*0.05));
    }
    else if (RSCENE == 3) {
        enable_lines = true; 
        enable_grid = false;
        lightdir = vec3(sin(-1.0+time*0.06),sin(-1.0+time*0.1),sin(1.0+time*0.05));
        lightsize = 0.01;
        shadow_color = vec3(50);
        enable_laser = false;
        //background_color = vec3(30);
        //animate_lines = true;
        //shadow_enable = false;
        //amb_tex_amount = 100.0;
    }
    else if (RSCENE == 4) {
        enable_lines = true; 
        enable_grid = true;
        shadow_enable = false;
    }
    else if (RSCENE == 5) {
        enable_lines = false; 
        enable_grid = true;
    }
    if (time > 60.0) 
        enable_laser = true;
    else
        enable_laser = false;
    
    float downbeat = 7.8048; // seconds
    // TIME LINE
    if (time > 0.0 && time < 50.0) {
        // fade in
        brightness = 0.3*clamp(0.3*(time - 0.0), 0.0, 1.0);
    }
    else if (time > 200.0 && time < 220.0) {
        // fade out
        brightness = 1.0-clamp(0.3*(time - 200.0), 0.0, 1.0);
    }
    else if (time > 50.0 && time < 80.0) {
    #if 0
        RSCENE = 3;
        animate_lines = true; 
        shadow_enable = false;
        
        // fade out
        brightness = 1.0-clamp((time - 50.0), 0.0, 1.0);
    #endif
    }
    else if (time > 120.0) {
        //background_color = vec3(38,40,65)*0.9;
        background_color = vec3(48,50,55)*0.9;
    }
    
    
    #if 1
        // flash laser
        if (enable_laser && fract(123.0*sin(time*1234.0)) > 0.01) {
            enable_laser = true; 
        }
        else {
            enable_laser = false;
        }
    #endif

#if MOVE_CAMERA
	ro = vec3(-100.0+200.0*cam.x,cam_height,-200.0+1000.0*abs(cam.z));
	rd = normalize(vec3(p.x,p.y,-fov));
	rd = rotatex(rd, -10.0+abs(cam.w)*20.0);
	rd = rotatey(rd, -10.0+cam.y*20.0);
	rd = rotatez(rd, rot_z);
#endif
	//vec3 ro = campos;
	//vec3 rd = normalize(p.x*cu + p.y*cv + camdir);
}

void main() 
{
    int pass = 0;	
    vec2 p = 2.0*fragCoord-1.0;
	p.x *= resolution.x/resolution.y;
	
	vec2 uv = fragCoord.xy / resolution.xy;
	seed = (uv.y + (time+float(pass)) * 0.523413187) * sqrt(uv.x * 0.77777777 * time);
	
#if CROP_Y
	if (abs(p.y) > 0.8) { gl_FragColor = vec4(0); return; }
#endif
	
	if (time < 0.0) {
		gl_FragColor = vec4(0);
		return;
	}
		
	
	
	// setup sphere positions
	set_sphere(0, vec3(-3,0,-7), 1.0, 2.0);
	set_sphere(1, vec3(-1,0,-7), 1.0, 2.0);
	set_sphere(2, vec3(-2,1.5,-7), 1.0, 2.0);
	set_sphere(3, vec3(-2,-1.5,-7), 1.0, 2.0);
	
	set_box(0, vec3(-2,0,-7.5),vec3(0.5,0.5,4), 3.0);
	
	vec3 color = vec3(0.0);
	vec3 ro, rd;
	for (int i = 0; i < SSAMPLES; i++) {
        float AA = 0.0025;
        vec2 p2 = p;
		blur += 2.0*pow(length(p.xy), 4.0);
        p2 = p + blur*uniformlyRandomVector(time+float(i)).xy*AA;
		make_camera(ro,rd,p2,time+0.01*float(i+pass));
		color += rm(ro, rd, time+0.01*float(i+pass));
	}
	color /= float(SSAMPLES);
	
#if GAMMA
	color = pow(color,1.0/vec3(gamma))*brightness;
#endif

	color *= vec3(0.98,0.98,1.0);
#if COLOR_GRAIN
	color += uniformlyRandomVector(time)*0.05;
#endif

#if CONVERGE
    // fetch parameters from texture memory
    vec2 lastResolution = texture(iChannel0, vec2(0.0,0.0)).xy; 
    float lastFrame = texture(iChannel0, vec2(0.0,0.0)).z; 
    if (iMouse.z > 0.0) {
        // if mouse clicked reset frame counter
        lastFrame = 0.0;
    }
    if (lastResolution.x != resolution.x || lastResolution.y != resolution.y) {
        // if resolution changed reset frame counter
        lastFrame = 0.0;
    }
    if (fragCoord.x == 0.5 && fragCoord.y == 0.5) {
        // write parameters back to the texture memory
        color = vec3(resolution.xy, lastFrame+1.0);
        gl_FragColor = vec4(color, 1.0);
        return;
    }
    float blend = 1.0-1.0/(1.0+float(lastFrame)); 
#else
    float blend = BLEND;
#endif

    // vingetting 
    color *= 1.0-0.5*length(p.xy);
    //float blend = BLEND;
    // accumulate pixel color
      color = mix(color, texture2D(back,vec2(0,1)+vec2(1,-1)*(fragCoord.xy)).xyz, blend);

    gl_FragColor = vec4(color, 1.0);
}

  
