varying vec2 TexCoord0;
uniform sampler2D tex;
uniform vec2 texSize;
uniform float intensity;

const float CAMERA_COMPRESSION = 1.0; // More compression -> smaller camera size
const float ZOOM = 0.95; // For avoiding shifting over the texture border

float circle(float size, float dist, float sharpness)
{
	return pow(clamp(size * dist, 0.0, 1.0), sharpness);
}

vec4 blur(vec2 uv)
{
	float continuousScale = max(0.34, intensity * 0.015 * max(texSize.x, texSize.y) / 3.0);
	int size = int(continuousScale * 3.0);
	float scale = float(size) * 0.33;
	float sigma = -0.5 / (scale * scale);
	vec2 localStep = vec2(2.0 / texSize.x, 0.0);

	float sum = 1.0;
	vec4 color = texture2D(tex, uv);
	for(int i = 1; i <= size; ++i)
	{
		float keof = exp(sigma * float(i) * float(i));
		sum += 2.0 * keof;
		vec2 shift = localStep * float(i);
		color += texture2D(tex, uv + shift) * keof;
		color += texture2D(tex, uv - shift) * keof;
	}
	return color / sum;
}

void main()
{
	vec4 texColor = texture2D(tex, TexCoord0);
	vec2 uv = vec2(TexCoord0.x, 1.0 - TexCoord0.y);

	// Keep lens round both in cases with portrait and landscape input
	vec2 aspect;
	if (texSize.x > texSize.y)
		aspect = vec2(texSize.x / texSize.y, 1.0);
	else
		aspect = vec2(1.0, texSize.y / texSize.x);

	aspect *= CAMERA_COMPRESSION;

	vec2 aspectUV = aspect * uv;
	vec2 lensCenter = aspect * vec2(0.5);

	vec2 delta = lensCenter - aspectUV;
	float dist = length(delta);

	float blackRing = circle(4.0, dist, 64.0);
	blackRing += 0.9 - 0.9 * circle(4.02, dist, 128.0);

	blackRing *= circle(8.0, dist, 128.0);
	blackRing += 1.0 - circle(8.03, dist, 128.0);

	blackRing *= circle(9.0, dist, 128.0);
	blackRing += 1.0 - circle(9.04, dist, 128.0);

	float frostRing = circle(18.0, dist, 256.0);
	frostRing *= 1.0 - circle(8.0, dist, 256.0);

	float ring = 1.0 - circle(1.2, dist, 8.0);
	blackRing *= ring;

	vec2 grid = mod(delta * 10.0, 1.0);
	grid = clamp(grid, 0.0, 1.0);
	grid.x = pow(grid.x, 30.0);
	grid.y = pow(grid.y, 30.0);
	grid.x *= grid.y;
	grid.x = 1.0 - grid.x;

	vec2 pattern = delta * 45.0;
	pattern = mod(pattern, 1.0);
	pattern = clamp(pattern, 0.0, 1.0);
	frostRing *= pattern.x * pattern.y;
	float frostOffset = -intensity * frostRing;

	vec2 middle = floor(-delta.yx + vec2(1.0));
	float splitRing = 1.0 - circle(18.1, dist, 256.0);
	frostRing += splitRing;
	splitRing *= mix(-intensity, intensity, middle.x);
	float splitOffset = splitRing;

	uv.x += splitOffset * 0.01;
	uv += frostOffset * vec2(0.01);
	uv.y = 1.0 - uv.y;

	vec2 shift = -(1.0 - ring) * delta;
	const float aber = 0.06;

	vec2 shiftedCoord = uv + shift * aber;
	shiftedCoord = (shiftedCoord - 0.5) * ZOOM + 0.5; // Zoom from center

	vec4 blurColor = blur(shiftedCoord);
	vec4 sharpColor = texture2D(tex, shiftedCoord);
	vec4 color = blackRing * mix(blurColor, sharpColor, frostRing) * grid.x;
	color.a = texColor.a;
	gl_FragColor = vec4(color);
}