uniform sampler2D depthTex;		// depth texture
uniform sampler2D normalTex; 	// normal tex
uniform sampler2D BGTex; 		// relected background
uniform sampler2D matTex;
uniform sampler2D colorTex;
uniform sampler2D brdfLUT;
uniform sampler2D rotMap;

//uniform vec3 	shk[32];		// sphere kernel

//uniform sampler2D rotMap;	// rotation normal map
//uniform float reflScale;
uniform float camfar;

uniform float NUM_SAMPLES;

varying vec2 	texCoord;
varying vec2 	texCoord1;
varying vec2	VPOS;

uniform vec4 	ambientColor;
uniform float	reflMul;
uniform float 	specThreshold;

uniform float 	saturation;

/*uniform vec4	TM0,
				TM1,
				TM2,
				TM3;*/
				
//uniform mat4 reprojTM;
uniform mat4 projTM;

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=projTM*pos;
	sspos.xy=sspos.xy/sspos.w;
	sspos.xy=vec2(1.0)-sspos.xy;
	return sspos;
}

/*float specularPowerToConeAngle(float specularPower)
{
    // based on phong distribution model
    if(specularPower >= exp2(CNST_MAX_SPECULAR_EXP))
    {
        return 0.0f;
    }
    const float xi = 0.244f;
    float exponent = 1.0f / (specularPower + 1.0f);
    return acos(pow(xi, exponent));
}

float isoscelesTriangleOpposite(float adjacentLength, float coneTheta)
{
    // simple trig and algebra - soh, cah, toa - tan(theta) = opp/adj, opp = tan(theta) * adj, then multiply * 2.0f for isosceles triangle base
    return 2.0f * tan(coneTheta) * adjacentLength;
}

float isoscelesTriangleInRadius(float a, float h)
{
    float a2 = a * a;
    float fh2 = 4.0f * h * h;
    return (a * (sqrt(a2 + fh2) - a)) / (4.0f * h);
}

float4 coneSampleWeightedColor(float2 samplePos, float mipChannel, float gloss)
{
    float3 sampleColor = colorBuffer.SampleLevel(sampTrilinearClamp, samplePos, mipChannel).rgb;
    return float4(sampleColor * gloss, gloss);
}

float isoscelesTriangleNextAdjacent(float adjacentLength, float incircleRadius)
{
    // subtract the diameter of the incircle to get the adjacent side of the next level on the cone
    return adjacentLength - (incircleRadius * 2.0f);
}*/


void main(void)
{	
	// compute eye space position
	vec4 pos;
	pos.z = texture2D(depthTex,texCoord.st).r;
	pos.xy=VPOS.xy*-pos.z;
	pos.w=1.0;

	float reflalpha=0.0;
	float t=0.0;
	float t1=0.0;
	vec4 reflColor=vec4(0.0,0.0,0.0,0.0);	
	
	
	float noise = texture2D(rotMap, texCoord1).r*20.0-10.0;
//	rotSample = (2.0 * rotSample - 1.0);
		
	vec4 metalColor=texture2D(colorTex,texCoord.st);
	vec4 encoded=texture2D(normalTex,texCoord.st);
	vec4 normal = decode(encoded);
	
	vec4 mat=texture2D(matTex,texCoord.st);
//	mat.y=sqrt(mat.y);
	float reflPow=encoded.z;//max((-0.5),0.0)*2.0;//*16.0;
	float metal=0.0;

	/*if(reflPow>0.0)
	{*/
		float eps=1.0-specThreshold;
		if(/*(1.0-mat.y)>specThreshold*/mat.y<eps)
		{
			float coneWidth=mat.y;// 0 to 1
	
			float rangeMax=3000.0;//camfar;//NUM_SAMPLES*15.0;
			if(-pos.z<rangeMax)
			{
				vec3 reflected;
				vec4 curpos;
				vec4 sspos;
				vec2 expUV;
			
				float rangeMin=rangeMax-2000.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
				t=1.0-reflected.z;
				//t=(t-0.2)*1.25;//5.0;
				t*=t1;	
				if(t>0.0)
				{
					reflected*=2.5;
							
					// roughness
					float roughness=clamp(sqrt(coneWidth),0.05,1.0);
					float len=0.0;							
					float rLod=0.0;
					
					vec4 oldpos;
					curpos=pos;
					float i=0;
					float count=24+noise;//24;
					float stepsize=(NUM_SAMPLES/float(count));
					float FADE_END=NUM_SAMPLES;
					float FADE_START=FADE_END-(NUM_SAMPLES*0.5);
					vec3 reflStep=reflected*stepsize;
						
					while(stepsize>1.0 && i<count)
					{
						oldpos=curpos;
						curpos.xyz+=reflStep;				
						sspos=getSSpos(curpos);
						
						//len=length(curpos-pos);
						//rLod=min(roughness*(len/250.0)*10.0,10.0);		
						
						sspos.z=texture2D( depthTex, sspos.xy).r;
						
						if(curpos.z<sspos.z)
						{
							stepsize*=0.5;
							if(stepsize<=1.0)
							{
								if(curpos.z<sspos.z-5.0)
									t=0.0;
								break;
							}
							i=-1;
							reflStep=reflected*stepsize;
							curpos=oldpos;
						}
						i+=1;
					}
					
					// distance from surface
					curpos=oldpos;
					len=length(curpos-pos);	
					t*=1.0 - ((len - FADE_START)/(FADE_END-FADE_START));
					if(t>0.0)
					{
						// metalness
						metal=mat.x*step(metalColor.a,0.0);
					
						// reflectivity
						vec3 REFL=mix(vec3(0.04)*max((reflPow-0.5),0.0)*2.0/*reflPow*/,metalColor.xyz/*reflPow*/,metal);
						
						//float F = reflPow + (max(mat.y, reflPow) - reflPow) * pow(1.0 - max(dot(-eye,normal.xyz),0.0), 5.0);
						vec2 brdf = texture2D(brdfLUT, vec2(max(dot(-eye,normal.xyz),0.0), roughness)).xy;
						vec3 IBL=REFL*brdf.x+brdf.y*reflPow;
						//IBL=mix(IBL*reflPow,IBL,metal);
								
						// reproject the point
						sspos=getSSpos(curpos);
						sspos.xy=clamp(sspos.xy,vec2(0.0),vec2(1.0));

						expUV=abs((sspos.xy-vec2(0.5))*vec2(2.0));	
						t*=1.0-clamp((expUV.x-0.2)*1.25,0.0,1.0);
						t*=1.0-clamp((expUV.y-0.2)*1.25,0.0,1.0);

						float sslen=length(sspos.xy-texCoord.st);
						float ConeW=roughness*clamp(sslen/*/250.0*/,0.0,1.0);
						rLod=min(ConeW*10.0,10.0);
						//t*=mix(1.0,0.0,rLod/10.0);
						//t*=mix(1.0,0.0,clamp(ConeW,0.0,1.0));
						t*=mix(1.0,0.0,clamp((mat.y-(eps-0.1))/0.1,0.0,1.0));
						reflalpha=clamp(t,0.0,1.0);
						
						reflColor.rgb=texture2DLod( BGTex, sspos.xy, rLod ).rgb*IBL*reflMul;
						reflColor.rgb*=reflalpha;	
						
						// DESATURATE SPEC
						float lum=dot(reflColor.rgb,vec3(0.3,0.59,0.11));
						reflColor.rgb=mix(vec3(lum),reflColor.rgb,saturation);
					}
				}
			}
		}
	//}
	
//	vec3 metalness=reflColor.rgb*metalColor.rgb;
	gl_FragColor.xyz = reflColor.xyz;// mix(reflColor.xyz,metalness,metal);//*clamp(reflScale,0.0,1.0)*reflmul;
	gl_FragColor.a=reflalpha;
}

