Constant SDF_WGSL
Source pub const SDF_WGSL: &str = r#"
const FLAT_RECT: u32 = 0u;
const FLAT_CIRCLE: u32 = 1u;
const FLAT_RING: u32 = 2u;
const FLAT_ARC: u32 = 3u;
const FLAT_ICON_FILL: u32 = 4u;
const FLAT_ICON_LINE: u32 = 5u;
const FLAT_TAU: f32 = 6.283185307179586;
fn flat_sign(value: f32) -> f32 {
return select(-1.0, 1.0, value >= 0.0);
}
fn flat_direction(p: vec2f) -> vec2f {
let length_p = length(p);
return select(vec2f(1.0, 0.0), p / length_p, length_p > 0.0);
}
fn flat_corner(p: vec2f, radii: vec4f) -> f32 {
let right = p.x >= 0.0;
if (p.y >= 0.0) {
return select(radii.w, radii.z, right);
}
return select(radii.x, radii.y, right);
}
fn flat_rect(p: vec2f, half: vec2f, radii: vec4f) -> vec3f {
let radius = flat_corner(p, radii);
let s = vec2f(flat_sign(p.x), flat_sign(p.y));
let q = abs(p) - half + vec2f(radius);
if (q.x > 0.0 && q.y > 0.0) {
let l = length(q);
return vec3f(l - radius, s * q / l);
}
if (q.x > q.y) {
return vec3f(q.x - radius, s.x, 0.0);
}
return vec3f(q.y - radius, 0.0, s.y);
}
fn flat_circle(p: vec2f, radius: f32) -> vec3f {
return vec3f(length(p) - radius, flat_direction(p));
}
fn flat_ring(p: vec2f, radius: f32, width: f32) -> vec3f {
let offset = length(p) - radius;
return vec3f(abs(offset) - width * 0.5, flat_sign(offset) * flat_direction(p));
}
fn flat_turn(p: vec2f, angle: f32) -> vec2f {
let c = cos(angle);
let s = sin(angle);
return vec2f(c * p.x - s * p.y, s * p.x + c * p.y);
}
fn flat_arc(p: vec2f, radius: f32, width: f32, start: f32, sweep: f32) -> vec3f {
if (sweep >= FLAT_TAU) {
return flat_ring(p, radius, width);
}
let half = sweep * 0.5;
let middle = start + half;
let q = flat_turn(p, -middle);
let angle = atan2(q.y, q.x);
if (abs(angle) <= half) {
return flat_ring(p, radius, width);
}
let end = radius * vec2f(cos(half), flat_sign(q.y) * sin(half));
let away = q - end;
return vec3f(length(away) - width * 0.5, flat_turn(flat_direction(away), middle));
}
struct FlatAlong {
s: f32,
tangent: vec2f,
}
fn flat_rect_along(p: vec2f, half: vec2f, radii: vec4f) -> FlatAlong {
let arc = radii * (FLAT_TAU * 0.25);
let top = (half.x - radii.x) + (half.x - radii.y);
let right = (half.y - radii.y) + (half.y - radii.z);
let bottom = (half.x - radii.w) + (half.x - radii.z);
let left = (half.y - radii.x) + (half.y - radii.w);
let at_right = top + arc.y;
let at_bottom_arc = at_right + right;
let at_bottom = at_bottom_arc + arc.z;
let at_left_arc = at_bottom + bottom;
let at_left = at_left_arc + arc.w;
let at_top_arc = at_left + left;
let radius = flat_corner(p, radii);
let inner = half - vec2f(radius);
let q = abs(p) - inner;
if (q.x > 0.0 && q.y > 0.0) {
let s = vec2f(flat_sign(p.x), flat_sign(p.y));
let centre = s * inner;
let offset = p - centre;
let rho = max(length(offset), 1e-6);
let tangent = vec2f(-offset.y, offset.x) / rho * (radius / rho);
var start = top;
var angle = atan2(offset.y, offset.x) + FLAT_TAU * 0.25;
if (s.x > 0.0 && s.y > 0.0) {
start = at_bottom_arc;
angle = atan2(offset.y, offset.x);
} else if (s.x < 0.0 && s.y > 0.0) {
start = at_left_arc;
angle = atan2(offset.y, offset.x) - FLAT_TAU * 0.25;
} else if (s.x < 0.0 && s.y < 0.0) {
start = at_top_arc;
angle = atan2(-offset.y, -offset.x);
}
return FlatAlong(start + radius * clamp(angle, 0.0, FLAT_TAU * 0.25), tangent);
}
if (q.x > q.y) {
if (p.x > 0.0) {
return FlatAlong(at_right + p.y + (half.y - radii.y), vec2f(0.0, 1.0));
}
return FlatAlong(at_left + (half.y - radii.w) - p.y, vec2f(0.0, -1.0));
}
if (p.y < 0.0) {
return FlatAlong(p.x + (half.x - radii.x), vec2f(1.0, 0.0));
}
return FlatAlong(at_bottom + (half.x - radii.z) - p.x, vec2f(-1.0, 0.0));
}
fn flat_circle_along(p: vec2f, radius: f32) -> FlatAlong {
let rho = max(length(p), 1e-6);
var angle = atan2(p.y, p.x);
if (angle < 0.0) {
angle += FLAT_TAU;
}
return FlatAlong(radius * angle, vec2f(-p.y, p.x) / rho * (radius / rho));
}
fn flat_dash(along: FlatAlong, on: f32, off: f32, phase: f32) -> vec3f {
let period = on + off;
let u = along.s + phase - on * 0.5;
let centred = u - period * floor(u / period + 0.5);
return vec3f(abs(centred) - on * 0.5, flat_sign(centred) * along.tangent);
}
fn flat_coverage(field: vec3f, inverse: mat2x2f) -> f32 {
let screen = vec2f(dot(inverse[0], field.yz), dot(inverse[1], field.yz));
return clamp(0.5 - field.x / max(length(screen), 1e-6), 0.0, 1.0);
}
fn flat_coverage_even(distance: f32, inverse: mat2x2f) -> f32 {
let unit = sqrt(abs(determinant(inverse)));
return clamp(0.5 - distance / max(unit, 1e-6), 0.0, 1.0);
}
const FLAT_SHADOW: u32 = 6u;
const FLAT_SHADOW_STEPS: u32 = 8u;
const FLAT_SHADOW_REACH: f32 = 4.0;
fn flat_erf(x: f32) -> f32 {
let t = 1.0 / (1.0 + 0.3275911 * abs(x));
let y = 1.0 - (((((1.0614054 * t - 1.4531521) * t) + 1.4214138) * t - 0.28449674) * t + 0.2548296) * t * exp(-x * x);
return select(-y, y, x >= 0.0);
}
fn flat_shadow_reach(half: vec2f, radius: f32, y: f32) -> f32 {
let delta = min(half.y - radius - abs(y), 0.0);
return half.x - radius + sqrt(max(radius * radius - delta * delta, 0.0));
}
fn flat_shadow_row(x: f32, y: f32, half: vec2f, radii: vec4f, sigma: f32) -> f32 {
var left = radii.w;
var right = radii.z;
if (y < 0.0) {
left = radii.x;
right = radii.y;
}
let k = 0.70710678 / sigma;
return 0.5 * (flat_erf((x + flat_shadow_reach(half, left, y)) * k) - flat_erf((x - flat_shadow_reach(half, right, y)) * k));
}
fn flat_rounded_shadow(p: vec2f, half: vec2f, radii: vec4f, sigma: vec2f) -> f32 {
let k = 0.70710678 / sigma.y;
let low = max(-half.y, p.y - FLAT_SHADOW_REACH * sigma.y);
let high = min(half.y, p.y + FLAT_SHADOW_REACH * sigma.y);
if (high <= low) {
return 0.0;
}
let first = asin(clamp(low / half.y, -1.0, 1.0));
let last = asin(clamp(high / half.y, -1.0, 1.0));
let step = (last - first) / f32(FLAT_SHADOW_STEPS);
var total = 0.0;
var edge = flat_erf((p.y - low) * k);
for (var index = 0u; index < FLAT_SHADOW_STEPS; index += 1u) {
let a = first + step * f32(index);
let b = a + step;
let next = flat_erf((p.y - half.y * sin(b)) * k);
let weight = 0.5 * (edge - next);
edge = next;
total += weight * flat_shadow_row(p.x, half.y * sin((a + b) * 0.5), half, radii, sigma.x);
}
return total;
}
fn flat_stripe(u: f32, width: f32) -> vec2f {
let c = u - floor(u + 0.5);
return vec2f(abs(c) - width * 0.5, flat_sign(c));
}
fn flat_pattern_field(kind: u32, params: vec4f, p: vec2f) -> vec3f {
let scale = params.x;
let width = params.z;
let q = flat_turn(p, -params.y) / scale;
var d = 0.0;
var g = vec2f(1.0, 0.0);
if (kind == 1u) {
let s = flat_stripe(q.x, width);
d = s.x;
g = vec2f(s.y, 0.0);
} else if (kind == 2u) {
let f = q - floor(q + vec2f(0.5));
d = length(f) - width * 0.5;
g = flat_direction(f);
} else if (kind == 3u) {
let a = flat_stripe(q.x, width);
let b = flat_stripe(q.y, width);
if (a.x <= b.x) {
d = a.x;
g = vec2f(a.y, 0.0);
} else {
d = b.x;
g = vec2f(0.0, b.y);
}
} else {
let t = q.y - floor(q.y + 0.5);
let s = flat_stripe(q.x + abs(t), width);
d = s.x * 0.70710678;
g = vec2f(s.y, s.y * flat_sign(t)) * 0.70710678;
}
return vec3f(d * scale, flat_turn(g, params.y));
}
fn flat_pattern_over(base: vec4f, kind: u32, params: vec4f, packed: u32, p: vec2f, inverse: mat2x2f) -> vec4f {
let colour = unpack4x8unorm(packed);
let cover = flat_coverage(flat_pattern_field(kind, params, p), inverse);
let paint = vec4f(colour.rgb * colour.a, colour.a) * cover;
return paint + base * (1.0 - paint.a);
}
"#;