Skip to main content

LIT_WGSL

Constant LIT_WGSL 

Source
pub const LIT_WGSL: &str = r#"
const FLAT_SLAB: u32 = 512u;
const FLAT_LIT: u32 = 1024u;
const FLAT_PI: f32 = 3.141592653589793;

fn flat_decode(c: vec3f) -> vec3f {
    return select(pow((c + 0.055) / 1.055, vec3f(2.4)), c / 12.92, c <= vec3f(0.04045));
}

fn flat_encode(c: vec3f) -> vec3f {
    let x = clamp(c, vec3f(0.0), vec3f(1.0));
    return select(1.055 * pow(x, vec3f(1.0 / 2.4)) - 0.055, x * 12.92, x <= vec3f(0.0031308));
}

fn flat_footprint(p: vec2f, v: FlatVaryings, kind: u32) -> f32 {
    if (kind == FLAT_RECT) {
        return flat_rect(p, v.shape.xy, v.corners).x;
    } else if (kind == FLAT_ICON_FILL || kind == FLAT_ICON_LINE) {
        return textureSampleLevel(flat_icons, flat_icon_sampler, v.icon.xy + p * v.icon.zw, 0.0).r
            - v.stroke.x * 0.5;
    }
    return length(p) - v.shape.x;
}

fn flat_footprint_field(p: vec2f, v: FlatVaryings, kind: u32, unit: f32) -> vec3f {
    if (kind == FLAT_RECT) {
        return flat_rect(p, v.shape.xy, v.corners);
    } else if (kind == FLAT_CIRCLE) {
        return flat_circle(p, v.shape.x);
    }
    let e = 0.5 * unit;
    let d = flat_footprint(p, v, kind);
    let gradient = vec2f(
        flat_footprint(p + vec2f(e, 0.0), v, kind) - flat_footprint(p - vec2f(e, 0.0), v, kind),
        flat_footprint(p + vec2f(0.0, e), v, kind) - flat_footprint(p - vec2f(0.0, e), v, kind),
    );
    return vec3f(d, flat_direction(gradient));
}

fn flat_slab(q: vec3f, v: FlatVaryings, kind: u32, thickness: f32, bevel: f32) -> f32 {
    let w = vec2f(flat_footprint(q.xy, v, kind) + bevel, abs(q.z + thickness * 0.5) - thickness * 0.5 + bevel);
    return min(max(w.x, w.y), 0.0) + length(max(w, vec2f(0.0))) - bevel;
}

fn flat_ggx(n: vec3f, l: vec3f, v: vec3f, roughness: f32) -> f32 {
    let h = normalize(l + v);
    let nl = max(dot(n, l), 0.0);
    let nv = max(dot(n, v), 1e-4);
    let nh = max(dot(n, h), 0.0);
    let vh = max(dot(v, h), 0.0);
    let a = roughness * roughness;
    let a2 = a * a;
    let denominator = nh * nh * (a2 - 1.0) + 1.0;
    let d = a2 / (FLAT_PI * denominator * denominator);
    let k = a * 0.5;
    let g = nl / (nl * (1.0 - k) + k) * nv / (nv * (1.0 - k) + k);
    let f = 0.04 + 0.96 * pow(1.0 - vh, 5.0);
    return d * g * f / (4.0 * nv);
}

fn flat_reflected(direction: vec3f, roughness: f32) -> vec3f {
    let u = 0.5 + atan2(direction.x, -direction.y) / (2.0 * FLAT_PI);
    let w = acos(clamp(direction.z, -1.0, 1.0)) / FLAT_PI;
    let level = roughness * max(flat_view.environment.x - 1.0, 0.0);
    return textureSampleLevel(flat_environment, flat_environment_sampler, vec2f(u, w), level).rgb
        * flat_view.environment.y;
}

fn flat_lit(v: FlatVaryings) -> FlatPaint {
    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);
    let icon = kind == FLAT_ICON_FILL || kind == FLAT_ICON_LINE;
    let slab = (v.info.x & FLAT_SLAB) != 0u;
    let unit = sqrt(abs(determinant(inverse)));
    let local_from_world = mat3x3f(v.frame_x.xyz, v.frame_y.xyz, v.frame_z.xyz);
    let world_from_local = transpose(local_from_world);
    let down = -v.frame_z.xyz;
    var hit = vec3f(v.local, 0.0);
    var normal = vec3f(0.0, 0.0, 1.0);
    var cover = 1.0;
    var settled = false;
    if (slab && down.z < -0.99999) {
        let footprint = flat_footprint_field(v.local, v, kind, unit);
        if (footprint.x >= 1.5 * unit) {
            return FlatPaint(vec4f(0.0), 0.0);
        }
        let bevel = v.material.y;
        let across = footprint.x + bevel;
        if (across > 0.0) {
            let x = min(across, bevel);
            let height = sqrt(max(bevel * bevel - x * x, 0.0));
            normal = normalize(vec3f(footprint.yz * max(x, 1e-6), height));
            hit = vec3f(v.local, height - bevel);
        }
        cover = clamp(0.5 - footprint.x / unit, 0.0, 1.0);
        settled = true;
    }
    if (slab && !settled) {
        let thickness = v.material.x;
        let bevel = v.material.y;
        let reach = thickness / max(-down.z, 0.05) + 2.0 * unit;
        let start = hit;
        var s = 0.0;
        var best = 1e9;
        var closest = hit;
        var found = false;
        for (var step = 0u; step < 32u; step += 1u) {
            let q = start + down * s;
            let distance = flat_slab(q, v, kind, thickness, bevel);
            if (distance < best) {
                best = distance;
                closest = q;
            }
            if (distance < 0.02 * unit) {
                found = true;
                break;
            }
            s += max(distance, 0.1 * unit);
            if (s > reach) {
                break;
            }
        }
        hit = closest;
        if (found) {
            let probe = min(unit, thickness * 0.5);
            let inside = flat_slab(hit + down * probe, v, kind, thickness, bevel);
            cover = clamp(0.5 - inside / max(probe, 1e-6), 0.0, 1.0);
        } else {
            cover = clamp(0.5 - best / unit, 0.0, 1.0);
        }
        let e = 0.25 * unit;
        normal = normalize(vec3f(
            flat_slab(hit + vec3f(e, 0.0, 0.0), v, kind, thickness, bevel)
                - flat_slab(hit - vec3f(e, 0.0, 0.0), v, kind, thickness, bevel),
            flat_slab(hit + vec3f(0.0, e, 0.0), v, kind, thickness, bevel)
                - flat_slab(hit - vec3f(0.0, e, 0.0), v, kind, thickness, bevel),
            flat_slab(hit + vec3f(0.0, 0.0, e), v, kind, thickness, bevel)
                - flat_slab(hit - vec3f(0.0, 0.0, e), v, kind, thickness, bevel),
        ));
    }
    let p = hit.xy;
    let field = flat_field(v, kind, p);
    var fill = vec4f(0.0);
    var fill_cover = 0.0;
    if (fill_mode != 0u) {
        fill_cover = select(select(flat_coverage(field, inverse), flat_coverage_even(field.x, inverse), icon), 1.0, slab);
        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 = select(flat_stroke_cover(v, kind, p, field, inverse), 1.0, slab && kind == FLAT_ICON_LINE);
        stroke = vec4f(v.stroke_colour.rgb * v.stroke_colour.a, v.stroke_colour.a) * stroke_cover;
    }
    let painted = stroke + fill * (1.0 - stroke.a);
    let alpha = painted.a;
    if (alpha <= 0.0) {
        return FlatPaint(vec4f(0.0), 0.0);
    }
    let albedo = flat_decode(painted.rgb / alpha);
    let world_normal = normalize(world_from_local * normal);
    let key = flat_view.light.xyz;
    let view = vec3f(0.0, 0.0, 1.0);
    let lean = length(world_normal.xy);
    var shade = 1.0;
    if (slab) {
        let ambient = flat_view.light.w;
        let ratio = clamp(dot(world_normal, key) / max(key.z, 0.05), 0.0, 1.5);
        shade = 1.0 + (1.0 - ambient) * (ratio - 1.0);
    }
    var linear = albedo * shade;
    let roughness = v.frame_y.w;
    if (lean > 0.0) {
        linear += vec3f(lean * v.material.z * flat_ggx(world_normal, key, view, roughness) * max(dot(world_normal, key), 0.0));
        if (v.frame_x.w > 0.0 && flat_view.environment.z > 0.0) {
            let nv = max(dot(world_normal, view), 0.0);
            let fresnel = 0.04 + 0.96 * pow(1.0 - nv, 5.0);
            linear += lean * v.frame_x.w * fresnel * flat_reflected(reflect(-view, world_normal), roughness);
        }
    }
    let coverage = alpha * cover * opacity;
    var colour = painted * (cover * opacity);
    if (any(linear != albedo)) {
        colour += vec4f((flat_encode(linear) - flat_encode(albedo)) * coverage, 0.0);
    }
    let footprint = select(0.0, select(max(fill_cover, stroke_cover), cover, slab), opacity > 0.0);
    return FlatPaint(colour, footprint);
}

fn flat_rich(v: FlatVaryings) -> FlatPaint {
    var paint: FlatPaint;
    if ((v.info.x & FLAT_BLUR) != 0u) {
        paint = flat_blur(v);
    } else if ((v.info.x & FLAT_LIT) != 0u) {
        paint = flat_lit(v);
    } else {
        paint = flat_paint(v);
    }
    if ((v.info.x & FLAT_ADDITIVE) != 0u) {
        paint.colour.a = 0.0;
    }
    return paint;
}

@fragment
fn flat_colour_lit(v: FlatVaryings) -> @location(0) vec4f {
    return flat_rich(v).colour;
}

@fragment
fn flat_id_lit(v: FlatVaryings) -> @location(0) u32 {
    if ((v.info.x & FLAT_UNPICKED) != 0u) {
        discard;
    }
    var footprint = 0.0;
    if ((v.info.x & FLAT_BLUR) != 0u) {
        footprint = flat_paint(v).footprint;
    } else {
        footprint = flat_rich(v).footprint;
    }
    if (footprint < 0.5) {
        discard;
    }
    return v.info.y;
}
"#;