in vec2 UV;

out vec4 color;

uniform sampler2D SAMPLER;
uniform sampler2D SAMPLER_UI;
uniform sampler2D DEPTH;
uniform vec2 RESOLUTION;
uniform vec2 WINDOW;
uniform int MODE = 0;
uniform float TIME = 0.0;
uniform float FADE_ANGLE = 0.0;
uniform float FADE_AMOUNT = 0.0;
uniform float BRIGHTNESS = 1.0;
uniform float CONTRAST = 1.0;
uniform float SATURATION = 1.0;

const float PI = 3.1415926535897932384626433832795;

float border(vec2 p, float radius) 
{
	vec2 b = vec2(0.5 - radius, 0.5 - radius);
	p.x -= 0.5;
	p.y -= 0.5;
	float n = length(max(abs(p)-b,0.0))-radius;
	n = step(n, 0.0);
	return n;
}

vec2 contain(vec2 uv, vec2 frameSize, vec2 imageSize) 
{
	float frameRatio = frameSize.x / frameSize.y;
	float imageRatio = imageSize.x / imageSize.y;
	if (frameRatio > imageRatio) 
	{
		float scale = imageRatio / frameRatio;
		uv.x = (uv.x - 0.5) / scale + 0.5;
	} 
	else 
	{
		float scale = frameRatio / imageRatio;
		uv.y = (uv.y - 0.5) / scale + 0.5;
	}
	return uv;
}

float pingpong(float value, float min, float max)
{
	float rangeSize = max - min;
    float normalizedValue = (value - min) / rangeSize;
    float pingpongValue = abs(2.0 * (fract(normalizedValue * 0.5) - 0.5));
    return pingpongValue * rangeSize + min;
}

vec2 pixelUV(vec2 uv, vec2 frameSize, vec2 imageSize)
{
	vec2 snapUV = vec2(floor(uv.x * imageSize.x) / imageSize.x, floor(uv.y * imageSize.y) / imageSize.y);
	return snapUV;
}

vec4 pixelTexture(sampler2D tex, vec2 uv, vec2 frameSize, vec2 imageSize)
{
	vec2 snapUV = vec2(floor(uv.x * imageSize.x) / imageSize.x, floor(uv.y * imageSize.y) / imageSize.y);
	vec4 c = texture(tex, snapUV);
	vec2 off = 0.5 / frameSize;
	vec4 cx = texture(tex, snapUV + vec2(off.x, 0.0));
	vec4 cy = texture(tex, snapUV + vec2(0.0, off.y));
	vec4 darkestColor = min(min(c, cx), cy);
	return darkestColor * 0.07 + c * 0.79 + cx * 0.07 + cy * 0.07;
}

vec4 pixelTextureBlur(sampler2D tex, vec2 uv, vec2 frameSize, vec2 imageSize, float blur)
{
	blur = clamp(blur, 0.0, 1.0);
	vec2 off = 0.5 / frameSize;
	uv = vec2(floor(uv.x * imageSize.x) / imageSize.x, floor(uv.y * imageSize.y) / imageSize.y);
	vec4 c1 = texture(tex, uv);
	vec4 c2 = texture(tex, uv + vec2(off.x, 0.0)) * 0.5;
	c2 += texture(tex, uv + vec2(0.0, off.y)) * 0.5;
	return mix(c1, c2, blur * 0.7);
}

vec3 pauseColor(vec3 c)
{
	float grey = (c.r + c.g + c.b) * 0.333;
	vec3 result = vec3(grey, grey, (grey * grey * 0.9) + (grey * 0.1));
	result = result * 0.8 + c * 0.2;
	result = clamp(result + c * clamp(grey - 0.95, 0.0, 0.05) * 20.0, 0.0, 1.0);
	return result;
}

float sampleDepth(vec2 uv)
{
	float depth = texture(DEPTH, uv).r;
	depth = 0.1 / (60.0 - depth * 59.9);
	depth = depth * 4.0 - 0.7;
	depth = 0.3 - depth;
	return depth;
}

const float OUTLINE_THRESHHOLD = 0.999;

float outlineFactor(vec2 uv, float dist)
{
	vec2 px = vec2(1.0 / RESOLUTION.x, 1.0 / RESOLUTION.y) * dist;
	float depth = sampleDepth(uv);
	float depthb = sampleDepth(vec2(uv.x - px.x, uv.y));
	float depthc = sampleDepth(vec2(uv.x, uv.y - px.y));
	float outline = 1.0 - (abs(depth - depthb) + abs(depth - depthc) * 2.0);
	outline *= outline * outline;
	outline *= step(depth, OUTLINE_THRESHHOLD);
	return clamp(1.0 - outline, 0.0, 1.0);
}

float sampleDepthOrtho(vec2 uv)
{
	float depth = texture(DEPTH, uv).r;
	depth = clamp(depth - 0.1, 0.0, 1.0) * 4.0;
	return clamp(1.0 - depth, 0.0, 1.0);
}

float outlineFactorOrtho(vec2 uv)
{
	vec2 px = vec2(1.0 / RESOLUTION.x, 1.0 / RESOLUTION.y);
	float depth = sampleDepthOrtho(uv);
	float depthb = sampleDepthOrtho(vec2(uv.x + px.x, uv.y));
	float depthc = sampleDepthOrtho(vec2(uv.x, uv.y + px.y));
	float outline = 1.0 - (abs(depth - depthb) + abs(depth - depthc) * 2.0);
	outline *= outline * outline;
	return clamp(1.0 - outline, 0.0, 1.0);
}

vec3 addOutline(vec3 color, float factor, float darkness)
{
	float solidFactor = 1.0 - step(factor, 0.1);
	factor = mix(factor, solidFactor, clamp(darkness, 0.0, 1.0));
	color *= 1.0 - (step(color.r + color.g + color.b, 2.0) * factor);
	return color;
}

vec3 fadeLinear(vec2 uv, vec3 color, float angle, float amount, float bandwidth)
{
	angle = PI * 1.5 - angle;
	amount = 1.5 - (amount * 2.0);
    vec2 dir = vec2(cos(angle), sin(angle));
    float dist = dot(uv - vec2(0.5), dir);
    return color * step(dist, amount);
}

vec3 fadePong(vec2 uv, vec3 color, float angle, float amount, float bandwidth)
{
    angle = PI * 1.5 - angle;
    amount = 1.5 - (amount * 2.0);
    vec2 dir = vec2(cos(angle), sin(angle));
    float dist = dot(uv - vec2(0.5), dir);
    vec2 perpDir = vec2(-dir.y, dir.x);
    float uvPerpendicular = dot(uv, perpDir);
    float aspectRatio = RESOLUTION.x / RESOLUTION.y;
    float adjustedAspectRatio = aspectRatio > 1.0 ? 1.0 / aspectRatio : aspectRatio;
    float adjustedFrequency = 0.05 * adjustedAspectRatio;
    dist += pingpong(uvPerpendicular, 0.0, adjustedFrequency);
    return color * step(dist, amount);
}

float vignettePower(vec2 uv, float divisor)
{
	float dx = uv.x - 0.5;
	float dy = uv.y - 0.5;
	float vig = sqrt(dx * dx + dy * dy) * divisor;
	vig = 1.0 - vig;
	return vig;
}

vec3 vignette(vec3 color, vec2 uv)
{
	float vig = vignettePower(uv, 1.2);
	vig += step(0.9, (color.r + color.g + color.b) / 3.0) * 0.5;
	color *= vig;
	color = clamp(color, 0.0, 1.0);
	return color;
}

vec3 mixinUI(vec3 color, vec2 uv, float fade)
{
	vec4 ui = texture(SAMPLER_UI, uv);
	float lum = color.r * 0.4 + color.g * 0.3 + color.b * 0.3;
	vec3 faded = vec3(color.r, color.g * 0.7, color.b * 0.3) * 0.1 + vec3(lum, lum * 0.68, lum * 0.74);
	color = mix(color, faded * fade, MODE);
	return mix(color, ui.rgb, ui.a);
}

vec3 mixinColor(vec3 color, vec4 ui_color, float fade)
{
	color = mix(color, color * fade, MODE);
	return mix(color, ui_color.rgb, ui_color.a);
}

vec3 applyFilters(vec3 c)
{
	c *= BRIGHTNESS;
	float lum = c.r * 0.4 + c.g * 0.3 + c.b * 0.3;
	c = mix(vec3(lum), c, clamp(SATURATION, 0.0, 2.0));
	c = 0.5 + (c - 0.5) * CONTRAST;
	return c;
}