uniform sampler2D depthTex;	// depth texture
uniform sampler2D normalTex; // normal tex
uniform sampler2D matTex;
uniform sampler2D colorTex;
uniform sampler2D BGTex; // relected background
uniform sampler2D rotMap;	// rotation normal map
uniform samplerCube	envCube;

uniform int 		NUM_SAMPLES;
uniform vec2		filterTaps[12];

varying vec2 	texCoord;
varying vec2	VPOS;

uniform mat4		eyeToWorld;

uniform vec3		campos;
uniform	float		reflMul;
uniform vec4		ambientColor;	

uniform vec4	TM0,
				TM1,
				TM2,
				TM3;

vec4 decode(vec4 enc)
{
    vec2 fenc = enc.xy*4.0-2.0;
    float f = dot(fenc,fenc);
    float g = sqrt(1.0-f/4.0);
    vec4 n;
    n.xy = fenc.xy*g;
    n.z = 1.0-f/2.0;
	n.w=enc.w;
    return n;
}

vec4 getSSpos(vec4 pos)
{
	vec4 sspos;
		
	// compute texture space beam pos
	sspos.x = dot(pos,TM0);
	sspos.y = dot(pos,TM1);
	sspos.w = dot(pos,TM3);
	sspos.xy=sspos.xy/sspos.w;
	sspos.xy=vec2(1.0-sspos.x,1.0-sspos.y);
	return sspos;
}

vec4 getFinalColor(vec2 coords)
{
	float totalContribution=1.0;
	vec4  	acc=texture2D( BGTex, coords );
	vec4 	tapBlur;
	vec2 	tccoords;
	
	for(int i=0; i<12; i++)
	{
		tccoords=coords+filterTaps[i]*2.0;
		tapBlur=texture2D(BGTex,tccoords);
		acc += tapBlur;
		totalContribution++;
	}
	return acc.rgba/totalContribution;
}

void main(void)
{	
	// compute eye space position
	vec4 ambient = texture2D(colorTex,texCoord.st);
	vec4 mat = texture2D(matTex,texCoord.st);
	vec4 pos = texture2D(depthTex,texCoord.st);
	pos.xy=VPOS.xy*-pos.z;
	pos.w=1.0;
	
	// get normal
	vec4 encoded=texture2D(normalTex,texCoord.st);
	vec4 normal = decode(encoded);
	float reflPow=encoded.z*16.0;
	
	// compute ambient light params ////////////////////////////////////////////////////////////////////////////////
	vec4 eyepos=eyeToWorld*pos;
	
	vec4 N=eyeToWorld*vec4(normal.xyz,0.0);
	vec4 diffuse = textureCubeLod(envCube,-N.xyz,6.0);
	diffuse = (diffuse+vec4(mat.x))/vec4(1+mat.x);
	vec3 vdir=normalize(campos-eyepos.xyz);
	vec3 reflection = reflect(vdir,N.xyz);
	vec4 specular = textureCubeLod(envCube,reflection.xyz,(1.0-mat.y)*7.0);
	
	// compute local reflections //////////////////////////////////////////////////////////////////////////////////
	float t=0.0;
	float t1;
	vec4 reflColor=vec4(0.0,0.0,0.0,1.0);	
	vec3 reflected;
	vec4 curpos;
	vec4 sspos;
	vec2 expUV;
			
	if(-pos.z<NUM_SAMPLES*10.0)
	{
		float rangeMax=NUM_SAMPLES*10.0;
		float rangeMin=rangeMax-200.0;
		t1=1.0-clamp((-pos.z-rangeMin)/(rangeMax-rangeMin),0.0,1.0);
	
		// get eyedir
		vec3 eye=normalize(pos.xyz);
		
		// compute reflected vector
		reflected=reflect(eye,normal.xyz);

		// compute reflected color
		if(reflected.z<0.5)
		{
			t=-reflected.z;
			t=(t-0.2)/0.1;
			t=clamp(t,0.0,1.0);
			
			float jitter=(texture2D(rotMap,texCoord.st).x*2.0-1.0);
			reflected*=10+jitter;
						
			vec4 oldpos;
			curpos=pos;
			int i=0;
			int stepsize=NUM_SAMPLES/15;
			int count=15;
			vec3 reflStep=reflected*stepsize;
			int refine=0;
			
			while(stepsize>1 && i<count)
			{
				oldpos=curpos;
				curpos.xyz+=reflStep;
				sspos=getSSpos(curpos);
				sspos.z=texture2D( depthTex, sspos.xy ).x;
				if(curpos.z<sspos.z+5.0)
				{
					stepsize/=2;
					count*=2;
					i=-1;
					reflStep=reflected*stepsize;
					/*if(stepsize<=1)
					{
						if(curpos.z>sspos.z-25.0)
						{
							refine=1;
						//	break;
						}
					}*/
					curpos=oldpos;
				}
				i++;
			}
			
			curpos=oldpos;
			if(refine)
			{
				reflected*0.25;
				for(int i=0; i<20; i++)
				{
					curpos.xyz+=reflected;
					sspos=getSSpos(curpos);
					sspos.z=texture2D( depthTex, sspos.xy ).x;
					if(curpos.z<=sspos.z+5.0 && curpos.z>=sspos.z-5.0)
					{
						expUV=abs((sspos.xy-vec2(0.5))*vec2(2.0));	
						t*= 1.0-clamp((expUV.x-0.8)*5.0,0.0,1.0);
						t*=	1.0-clamp((expUV.y-0.8)*5.0,0.0,1.0);
						if(sspos.x>=1.0)
							break;
						if(sspos.x<=0.0)
							break;
						if(sspos.y>=1.0)
							break;
						if(sspos.y<=0.0)
							break;
						reflColor=getFinalColor( sspos.xy );
						reflColor.a=1.0;
						break;
					}
				}
			}
		}	
	}
	
//	t*=t1;
	//specular=mix(specular,reflColor,t);
	vec4 finalcolor=ambientColor*(ambient*diffuse+specular*reflMul*mat.y*reflPow);
	gl_FragColor=max(finalcolor,0.0);
}