shader_type canvas_item;

uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_nearest;
uniform float pixel_scale : hint_range(1.0, 8.0, 1.0) = 4.0;
uniform float color_depth : hint_range(2.0, 8.0, 1.0) = 5.0;
uniform float dither_strength : hint_range(0.0, 2.0, 0.05) = 0.8;

float bayer4(ivec2 p) {
	int x = p.x & 3;
	int y = p.y & 3;
	float m[16] = float[16](
		 0.0,  8.0,  2.0, 10.0,
		12.0,  4.0, 14.0,  6.0,
		 3.0, 11.0,  1.0,  9.0,
		15.0,  7.0, 13.0,  5.0
	);
	return m[y * 4 + x] / 16.0 - 0.5;
}

void fragment() {
	vec2 pixel_size = SCREEN_PIXEL_SIZE * pixel_scale;
	vec2 snapped = (floor(SCREEN_UV / pixel_size) + 0.5) * pixel_size;
	vec3 col = texture(SCREEN_TEXTURE, snapped).rgb;

	ivec2 dpos = ivec2(FRAGCOORD.xy / pixel_scale);
	float t = bayer4(dpos) * dither_strength;

	float levels = exp2(color_depth) - 1.0;
	col = clamp(floor(col * levels + t + 0.5) / levels, 0.0, 1.0);

	COLOR = vec4(col, 1.0);
}
