128 lines
3.2 KiB
Plaintext

[gd_resource type="Shader" format=3 uid="uid://clpby1t4s1pvy"]
[resource]
code = "shader_type canvas_item;
render_mode blend_premul_alpha;
uniform int shape_index;
// if you are reading this file and know
// what hint_color is called in 4.0
// please open an issue or pull request
uniform vec4 color_border;
uniform vec4 color_fill;
uniform vec2 origin;
uniform vec2 shape_size;
uniform float border_width;
uniform vec2 drag_delta;
uniform bool enable_aa;
float get_sdf(vec2 pos, vec2 size) {
size -= vec2(1.0);
if (size == vec2(0.0)) return -1.0;
switch(shape_index) {
case 0: // Rect
return min(
min(pos.x, size.x - pos.x),
min(pos.y, size.y - pos.y)
);
case 1: // Ellipse
// Stolen from:
// https://iquilezles.org/articles/ellipsedist/
vec2 extents = size * 0.5;
vec2 posf = abs(vec2(pos) - extents);
vec2 q = extents * (posf - extents);
vec2 cs = normalize(q.x < q.y ? vec2(0.01, 1) : vec2(1, 0.01));
for (int i = 0; i < 3; i++) {
vec2 u = extents * vec2(+cs.x, cs.y);
vec2 v = extents * vec2(-cs.y, cs.x);
float a = dot(posf - u, v);
float c = dot(posf - u, u) + dot(v, v);
float b = sqrt(c * c - a * a);
cs = vec2(cs.x * b - cs.y * a, cs.y * b + cs.x * a) / c;
}
float d = length(posf - extents * cs);
return dot(posf / extents, posf / extents) > 1.0 ? -d : d;
case 2: // RA Triangle
float aspect = size.x / size.y;
float distance_to_diag = 0.0;
if ((drag_delta.x < 0.0) == (drag_delta.y < 0.0))
// Main diag
if (drag_delta.x < drag_delta.y)
// Bottom filled
distance_to_diag = (pos.x - pos.y * aspect);
else
// Top filled
// !!! incorrest sdf
distance_to_diag = (pos.y * aspect - pos.x);
else
// Secondary diag
if (drag_delta.x < -drag_delta.y)
// Bottom filled
// !!! incorrest sdf
distance_to_diag = (pos.y * aspect - size.x + pos.x);
else
// Top filled
distance_to_diag = (size.x - pos.x - pos.y * aspect);
float rect_dist = min(
min(pos.x, size.x - pos.x),
min(pos.y, size.y - pos.y)
);
return min(distance_to_diag / aspect, rect_dist);
case 3: // Diamond
vec2 from_center = abs(vec2(pos * 2.0) - size) * 0.5;
from_center.y *= size.x / size.y;
return size.x * 0.5 - (from_center.x + from_center.y);
case 4: // Hex
if ((drag_delta.x < 0.0) == (drag_delta.y < 0.0)) {
pos = pos.yx;
size = size.yx;
}
vec2 diamond_from_center = abs(pos * 2.0 - size) * vec2(0.25, 0.5);
return size.x * 0.5 - max(
diamond_from_center.x + diamond_from_center.y * size.x / size.y,
abs(pos.x - size.x * 0.5)
);
return -1.0;
}
vec4 sdf_to_color(float sdf) {
// Debug
// return vec4(sdf * 0.1, -sdf * 0.1, 0.0, 1.0);
if (sdf < -0.5) {
return vec4(color_border.rgb, 0.0);
}
if (sdf < 0.0 && enable_aa) {
sdf = (0.5 + sdf) * 2.0;
return mix(vec4(color_border.rgb, 0.0), color_border, sdf * sdf);
}
if (sdf <= border_width - 0.5) {
return color_border;
}
if (sdf < border_width && enable_aa) {
sdf = -(sdf - border_width + 0.5) * 2.0;
return mix(color_fill, color_border, 1.0 - sdf * sdf);
}
return color_fill;
}
void fragment() {
COLOR = sdf_to_color(get_sdf(
floor(UV / TEXTURE_PIXEL_SIZE) - origin,
shape_size
));
}
"