vec3 nvec3(vec4 pos){
	return pos.xyz/pos.w;
}

vec4 nvec4(vec3 pos){
	return vec4(pos.xyz,1.);
}

float cdist(vec2 coord){
	return max(abs(coord.x-.5),abs(coord.y-.5))*1.95;
}

vec4 Raytrace(sampler2D depthtex,vec3 viewPos,vec3 normal,float dither,
float maxf,float stp,float ref,float inc){
	vec3 pos=vec3(0.);
	float dist=0.;
	
	#if AA > 1
	dither=fract(dither+frameTimeCounter);
	#endif
	
	vec3 start=viewPos;
	
	vec3 vector=stp*reflect(normalize(viewPos),normalize(normal));
	viewPos+=vector;
	vec3 tvector=vector;
	
	int sr=0;
	
	for(int i=0;i<30;i++){
		pos=nvec3(gbufferProjection*nvec4(viewPos))*.5+.5;
		if(pos.x<-.05||pos.x>1.05||pos.y<-.05||pos.y>1.05)break;
		
		vec3 rfragpos=vec3(pos.xy,texture2D(depthtex,pos.xy).r);
		rfragpos=nvec3(gbufferProjectionInverse*nvec4(rfragpos*2.-1.));
		dist=length(start-rfragpos);
		
		float err=length(viewPos-rfragpos);
		if(err<pow(length(vector)*pow(length(tvector),.11),1.1)*1.2){
			sr++;
			if(sr>=maxf)break;
			tvector-=vector;
			vector*=ref;
		}
		vector*=inc;
		tvector+=vector;
		viewPos=start+tvector*(dither*.05+.975);
	}
	
	#ifdef REFLECTION_PREVIOUS

	vec4 viewPosPrev=gbufferProjectionInverse*vec4(pos*2.-1.,1.);
	viewPosPrev/=viewPosPrev.w;
	
	viewPosPrev=gbufferModelViewInverse*viewPosPrev;
	
	vec4 previousPosition=viewPosPrev+vec4(cameraPosition-previousCameraPosition,0.);
	previousPosition=gbufferPreviousModelView*previousPosition;
	previousPosition=gbufferPreviousProjection*previousPosition;
	pos.xy=previousPosition.xy/previousPosition.w*.5+.5;
	#endif
	
	return vec4(pos,dist);
}