Constant FX_WGSL
Source pub const FX_WGSL: &str = r#"
const FLAT_BLUR: u32 = 2048u;
const FLAT_ADDITIVE: u32 = 32768u;
const FLAT_UNPICKED: u32 = 65536u;
const FLAT_BLUR_ROWS: u32 = 4u;
const FLAT_BLUR_STEPS: u32 = 48u;
const FLAT_BLUR_FLOOR: f32 = 0.35;
@vertex
fn flat_id_vertex_rich(instance: FlatInstance, @builtin(vertex_index) index: u32) -> FlatVaryings {
var out = flat_place(instance, index);
if ((instance.info.x & 15u) == FLAT_SHADOW || (instance.info.x & FLAT_UNPICKED) != 0u) {
out.position = vec4f(2.0, 2.0, 2.0, 1.0);
}
return out;
}
fn flat_blur_distance(v: FlatVaryings, kind: u32, p: vec2f) -> f32 {
if (kind == FLAT_ICON_FILL || kind == FLAT_ICON_LINE) {
let c = clamp(p, v.shape.xy - v.shape.zw, v.shape.xy + v.shape.zw);
let outside = length(p - c);
if (outside > 0.0) {
return outside + 0.5 * v.stroke.x;
}
return textureSampleLevel(flat_icons, flat_icon_sampler, v.icon.xy + c * v.icon.zw, 0.0).r;
}
return flat_field(v, kind, p).x;
}
fn flat_blur_band(v: FlatVaryings, kind: u32, stroke: bool, p: vec2f) -> f32 {
let d = flat_blur_distance(v, kind, p);
if (!stroke) {
return d;
}
let band = abs(d) - v.stroke.x * 0.5;
if ((v.info.x & FLAT_DASHED) == 0u) {
return band;
}
var along = flat_circle_along(p, v.shape.x);
if (kind == FLAT_RECT) {
along = flat_rect_along(p, v.shape.xy, v.corners);
}
return max(band, flat_dash(along, v.stroke.y, v.stroke.z, v.stroke.w).x);
}
fn flat_blur_cdf(x: f32, span: f32) -> f32 {
let hi = 0.5 * (span + 1.0);
let lo = 0.5 * abs(span - 1.0);
let ramp = min(span, 1.0);
let height = 1.0 / max(span, 1.0);
if (x <= -hi) {
return 0.0;
}
if (x >= hi) {
return 1.0;
}
if (x < -lo) {
let u = x + hi;
return 0.5 * height / ramp * u * u;
}
if (x > lo) {
let u = hi - x;
return 1.0 - 0.5 * height / ramp * u * u;
}
return 0.5 * height * ramp + height * (x + lo);
}
fn flat_blur_line(v: FlatVaryings, kind: u32, stroke: bool, start: vec2f, along: vec2f, unit: f32, span: f32) -> f32 {
let hi = 0.5 * (span + 1.0);
let least = max(FLAT_BLUR_FLOOR, 2.0 * hi / f32(FLAT_BLUR_STEPS - 8u));
var x = -hi;
var s0 = flat_blur_band(v, kind, stroke, start + along * x) / unit;
var total = 0.0;
for (var step = 0u; step < FLAT_BLUR_STEPS; step += 1u) {
if (x >= hi) {
break;
}
let x1 = min(x + max(abs(s0), least), hi);
let s1 = flat_blur_band(v, kind, stroke, start + along * x1) / unit;
if (s0 <= 0.0 && s1 <= 0.0) {
total += flat_blur_cdf(x1, span) - flat_blur_cdf(x, span);
} else if (s0 <= 0.0) {
let r = x + (x1 - x) * s0 / (s0 - s1);
total += flat_blur_cdf(r, span) - flat_blur_cdf(x, span);
} else if (s1 <= 0.0) {
let r = x + (x1 - x) * s0 / (s0 - s1);
total += flat_blur_cdf(x1, span) - flat_blur_cdf(r, span);
}
x = x1;
s0 = s1;
}
if (x < hi && s0 <= 0.0) {
total += 1.0 - flat_blur_cdf(x, span);
}
return total;
}
fn flat_line_empty() -> vec2f {
return vec2f(1.0, -1.0);
}
fn flat_line_merge(a: vec2f, b: vec2f) -> vec2f {
if (a.x >= a.y) {
return b;
}
if (b.x >= b.y) {
return a;
}
return vec2f(min(a.x, b.x), max(a.y, b.y));
}
fn flat_line_disc(start: vec2f, along: vec2f, centre: vec2f, radius: f32) -> vec2f {
if (radius <= 0.0) {
return flat_line_empty();
}
let o = start - centre;
let aa = dot(along, along);
let b = dot(o, along);
let c = dot(o, o) - radius * radius;
let d = b * b - aa * c;
if (d <= 0.0) {
return flat_line_empty();
}
let root = sqrt(d);
return vec2f((-b - root) / aa, (-b + root) / aa);
}
fn flat_line_box(start: vec2f, along: vec2f, half: vec2f) -> vec2f {
if (half.x < 0.0 || half.y < 0.0) {
return flat_line_empty();
}
var low = -1e30;
var high = 1e30;
for (var axis = 0; axis < 2; axis += 1) {
if (abs(along[axis]) < 1e-12) {
if (abs(start[axis]) > half[axis]) {
return flat_line_empty();
}
} else {
let a = (-half[axis] - start[axis]) / along[axis];
let b = (half[axis] - start[axis]) / along[axis];
low = max(low, min(a, b));
high = min(high, max(a, b));
}
}
return vec2f(low, high);
}
fn flat_line_rounded(start: vec2f, along: vec2f, half: vec2f, radius: f32) -> vec2f {
if (half.x <= 0.0 || half.y <= 0.0) {
return flat_line_empty();
}
let r = clamp(radius, 0.0, min(half.x, half.y));
var hit = flat_line_box(start, along, vec2f(half.x, half.y - r));
hit = flat_line_merge(hit, flat_line_box(start, along, vec2f(half.x - r, half.y)));
if (r > 0.0) {
let c = half - vec2f(r);
hit = flat_line_merge(hit, flat_line_disc(start, along, c, r));
hit = flat_line_merge(hit, flat_line_disc(start, along, vec2f(-c.x, c.y), r));
hit = flat_line_merge(hit, flat_line_disc(start, along, vec2f(c.x, -c.y), r));
hit = flat_line_merge(hit, flat_line_disc(start, along, -c, r));
}
return hit;
}
fn flat_blur_weight(hit: vec2f, span: f32) -> f32 {
if (hit.x >= hit.y) {
return 0.0;
}
return flat_blur_cdf(hit.y, span) - flat_blur_cdf(hit.x, span);
}
fn flat_blur_closed(v: FlatVaryings, kind: u32, stroke: bool) -> bool {
if (kind == FLAT_RING) {
return !stroke;
}
if (kind != FLAT_RECT && kind != FLAT_CIRCLE) {
return false;
}
if (kind == FLAT_RECT && any(v.corners != vec4f(v.corners.x))) {
return false;
}
return !stroke || (v.info.x & FLAT_DASHED) == 0u;
}
fn flat_blur_row(v: FlatVaryings, kind: u32, stroke: bool, start: vec2f, a: vec2f, span: f32) -> f32 {
let w = select(0.0, v.stroke.x * 0.5, stroke);
var outer = flat_line_empty();
var inner = flat_line_empty();
if (kind == FLAT_RECT) {
outer = flat_line_rounded(start, a, v.shape.xy + vec2f(w), v.corners.x + w);
if (stroke) {
inner = flat_line_rounded(start, a, v.shape.xy - vec2f(w), max(v.corners.x - w, 0.0));
}
} else if (kind == FLAT_CIRCLE) {
outer = flat_line_disc(start, a, vec2f(0.0), v.shape.x + w);
if (stroke) {
inner = flat_line_disc(start, a, vec2f(0.0), v.shape.x - w);
}
} else {
outer = flat_line_disc(start, a, vec2f(0.0), v.shape.x + 0.5 * v.shape.y);
inner = flat_line_disc(start, a, vec2f(0.0), v.shape.x - 0.5 * v.shape.y);
}
return flat_blur_weight(outer, span) - flat_blur_weight(inner, span);
}
fn flat_blur_cover(v: FlatVaryings, kind: u32, stroke: bool, p: vec2f, inverse: mat2x2f) -> f32 {
let axes = mat2x2f(vec2f(inverse[1].y, -inverse[0].y), vec2f(-inverse[1].x, inverse[0].x))
* (1.0 / determinant(inverse));
let screen = axes * v.material.xy;
let span = max(length(screen), 1e-6);
let direction = screen / span;
let along = inverse * direction;
let across = inverse * vec2f(-direction.y, direction.x);
let unit = max(length(along), 1e-12);
let closed = flat_blur_closed(v, kind, stroke);
var total = 0.0;
for (var row = 0u; row < FLAT_BLUR_ROWS; row += 1u) {
let u = (f32(row) + 0.5) / f32(FLAT_BLUR_ROWS) - 0.5;
if (closed) {
total += flat_blur_row(v, kind, stroke, p + across * u, along, span);
} else {
total += flat_blur_line(v, kind, stroke, p + across * u, along, unit, span);
}
}
return clamp(total / f32(FLAT_BLUR_ROWS), 0.0, 1.0);
}
fn flat_blur(v: FlatVaryings) -> FlatPaint {
let p = v.local;
let inverse = mat2x2f(v.inverse.xy, v.inverse.zw);
let kind = v.info.x & 15u;
let fill_mode = (v.info.x >> FLAT_FILL_SHIFT) & 15u;
let opacity = bitcast<f32>(v.info.w);
var fill = vec4f(0.0);
var fill_cover = 0.0;
if (fill_mode != 0u) {
fill_cover = flat_blur_cover(v, kind, false, p, inverse);
var base = flat_fill_base(v, fill_mode, p);
let pattern = (v.info.x >> 12u) & 7u;
if (pattern != 0u) {
base = flat_pattern_over(base, pattern, v.icon, v.info.z, p, inverse);
}
fill = base * fill_cover;
}
var stroke = vec4f(0.0);
var stroke_cover = 0.0;
if (v.stroke.x > 0.0) {
stroke_cover = flat_blur_cover(v, kind, true, p, inverse);
stroke = vec4f(v.stroke_colour.rgb * v.stroke_colour.a, v.stroke_colour.a) * stroke_cover;
}
let colour = (stroke + fill * (1.0 - stroke.a)) * opacity;
let fill_seen = select(0.0, fill_cover, fill_mode != 0u && flat_fill_alpha(v, fill_mode) > 0.0);
let stroke_seen = select(0.0, stroke_cover, v.stroke_colour.a > 0.0);
let footprint = select(0.0, max(fill_seen, stroke_seen), opacity > 0.0);
return FlatPaint(colour, footprint);
}
"#;