76 lines
1.9 KiB
Plaintext
76 lines
1.9 KiB
Plaintext
shader_type canvas_item;
|
|
|
|
uniform bool shader_enabled = true;
|
|
|
|
uniform sampler2D palette;
|
|
uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, filter_linear_mipmap;
|
|
uniform bool dithering = false;
|
|
uniform int dithering_size : hint_range(1, 16) = 2;
|
|
uniform int resolution_scale : hint_range(1, 64) = 2;
|
|
uniform int quantization_level : hint_range(2, 64) = 64;
|
|
|
|
int dithering_pattern(ivec2 fragcoord) {
|
|
const int pattern[] = {
|
|
-4, +0, -3, +1,
|
|
+2, -2, +3, -1,
|
|
-3, +1, -4, +0,
|
|
+3, -1, +2, -2
|
|
};
|
|
int x = fragcoord.x % 4;
|
|
int y = fragcoord.y % 4;
|
|
return pattern[y * 4 + x] * dithering_size;
|
|
}
|
|
|
|
float color_distance(vec3 a, vec3 b) {
|
|
vec3 diff = a - b;
|
|
return dot(diff, diff);
|
|
}
|
|
|
|
vec3 quantize_color(vec3 color, int levels) {
|
|
if (levels <= 1) return vec3(0.0);
|
|
float step = 1.0 / float(levels - 1);
|
|
return round(color / step) * step;
|
|
}
|
|
|
|
void fragment() {
|
|
vec4 final_color;
|
|
|
|
if (!shader_enabled) {
|
|
final_color = texture(SCREEN_TEXTURE, UV);
|
|
} else {
|
|
vec2 tex_size = vec2(textureSize(SCREEN_TEXTURE, 0));
|
|
|
|
if (tex_size.x <= 0.0 || tex_size.y <= 0.0) {
|
|
final_color = vec4(0.0);
|
|
} else {
|
|
ivec2 texel_coord = ivec2(floor(UV * tex_size / float(resolution_scale)));
|
|
vec3 color = texelFetch(SCREEN_TEXTURE, texel_coord * resolution_scale, 0).rgb;
|
|
|
|
if (dithering) {
|
|
int dither = dithering_pattern(texel_coord);
|
|
color += vec3(float(dither) / 255.0);
|
|
}
|
|
color = clamp(color, 0.0, 1.0);
|
|
color = quantize_color(color, quantization_level);
|
|
|
|
int palette_size = 64;
|
|
float closest_distance = 9999.0;
|
|
vec4 closest_color = vec4(0.0);
|
|
|
|
for (int i = 0; i < palette_size; i++) {
|
|
float u = float(i) / float(palette_size - 1);
|
|
vec3 palette_color = texture(palette, vec2(u, 0.0)).rgb;
|
|
float dist = color_distance(color, palette_color);
|
|
if (dist < closest_distance) {
|
|
closest_distance = dist;
|
|
closest_color = vec4(palette_color, 1.0);
|
|
}
|
|
}
|
|
|
|
final_color = closest_color;
|
|
}
|
|
}
|
|
|
|
COLOR = final_color;
|
|
}
|