Skip to main content

LOOK_WGSL

Constant LOOK_WGSL 

Source
pub const LOOK_WGSL: &str = r#"
struct LookUniform {
    size: vec4f,
    place: vec4f,
    frame: vec4f,
    p: array<vec4f, 29>,
}

struct LookPalette {
    entries: array<vec4f, 512>,
}

@group(0) @binding(0) var<uniform> look: LookUniform;
@group(0) @binding(1) var look_source: texture_2d<f32>;
@group(0) @binding(2) var look_aux: texture_2d<f32>;
@group(0) @binding(3) var look_sampler: sampler;
@group(0) @binding(4) var<uniform> look_palette: LookPalette;

@vertex
fn look_vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
    let xy = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));
    return vec4f(xy[index], 0.0, 1.0);
}

fn look_layout_at(pixel: vec2f) -> vec2f {
    return (pixel - look.place.yz) / look.place.x;
}

fn look_premultiply(c: vec4f) -> vec4f {
    return vec4f(c.rgb * c.a, c.a);
}

fn look_over(top: vec4f, under: vec4f) -> vec4f {
    return top + under * (1.0 - top.a);
}

fn look_gradient(base: u32, p: vec2f) -> vec4f {
    let header = look.p[base + 11u];
    let count = u32(header.x);
    if (count == 0u) {
        return vec4f(0.0);
    }
    let t = look_gradient_position(header.y, look.p[base + 10u], p);
    let oklab = header.z > 0.5;
    let first = look.p[base + 8u].x;
    if (t <= first) {
        return look_premultiply(look.p[base]);
    }
    for (var i = 0u; i + 1u < count; i += 1u) {
        let a = look.p[base + 8u + i / 4u][i % 4u];
        let j = i + 1u;
        let b = look.p[base + 8u + j / 4u][j % 4u];
        if (t < b) {
            return look_premultiply(look_stop_mix(look.p[base + i], look.p[base + j], (t - a) / (b - a), oklab));
        }
    }
    return look_premultiply(look.p[base + count - 1u]);
}

fn look_grid_cover(distance: f32, width: f32, scale: f32) -> f32 {
    return clamp(width * scale * 0.5 - distance * scale + 0.5, 0.0, 1.0);
}

fn look_grid(p: vec2f) -> vec4f {
    let spacing = look.p[13].xy;
    let origin = look.p[13].zw;
    let line = look.p[14];
    let every = line.y;
    var minor = 0.0;
    var major = 0.0;
    for (var axis = 0u; axis < 2u; axis += 1u) {
        let s = spacing[axis];
        if (s <= 0.0) {
            continue;
        }
        let u = (p[axis] - origin[axis]) / s;
        minor = max(minor, look_grid_cover(abs(u - floor(u + 0.5)) * s, line.x, look.place.x));
        if (every > 0.0) {
            let period = s * every;
            let v = (p[axis] - origin[axis]) / period;
            major = max(major, look_grid_cover(abs(v - floor(v + 0.5)) * period, line.z, look.place.x));
        }
    }
    let paint = look_premultiply(look.p[15]) * minor;
    if (every > 0.0) {
        return look_over(look_premultiply(look.p[16]) * major, paint);
    }
    return paint;
}

@fragment
fn look_backdrop(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let p = look_layout_at(position.xy);
    let flags = look.p[12];
    var base = look_premultiply(look.p[17]) * flags.x;
    base = look_over(look_gradient(0u, p), base);
    if (flags.y > 0.5) {
        base = look_over(look_grid(p), base);
    }
    let top = textureLoad(look_source, vec2i(position.xy), 0);
    return look_over(top, base);
}

fn look_bayer(p: vec2u, bits: u32) -> u32 {
    var value = 0u;
    for (var i = 0u; i < bits; i += 1u) {
        let xb = (p.x >> i) & 1u;
        let yb = (p.y >> i) & 1u;
        value += ((xb ^ yb) * 2u + yb) << (2u * (bits - 1u - i));
    }
    return value;
}

@fragment
fn look_quantise(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let c = textureLoad(look_source, vec2i(position.xy), 0);
    if (c.a <= 0.0) {
        return vec4f(0.0);
    }
    let header = look.p[0];
    let count = u32(header.x);
    let order = u32(header.y);
    var lab = look_oklab(c.rgb / c.a);
    if (order > 1u) {
        let bits = u32(header.w);
        let at = vec2u(position.xy) % vec2u(order);
        let t = (f32(look_bayer(at, bits)) + 0.5) / f32(order * order);
        lab.x += (t - 0.5) * header.z;
    }
    var low = 0u;
    var high = count;
    while (low < high) {
        let middle = (low + high) / 2u;
        if (look_palette.entries[middle].x < lab.x) {
            low = middle + 1u;
        } else {
            high = middle;
        }
    }
    var best = 0u;
    var best_distance = 3.4e38;
    var best_index = 1e9;
    for (var i = low; i < count; i += 1u) {
        let entry = look_palette.entries[i];
        let dl = entry.x - lab.x;
        if (dl * dl > best_distance) {
            break;
        }
        let d = entry.xyz - lab;
        let distance = dot(d, d);
        if (distance < best_distance || (distance == best_distance && entry.w < best_index)) {
            best_distance = distance;
            best = i;
            best_index = entry.w;
        }
    }
    for (var j = low; j > 0u; j -= 1u) {
        let entry = look_palette.entries[j - 1u];
        let dl = entry.x - lab.x;
        if (dl * dl > best_distance) {
            break;
        }
        let d = entry.xyz - lab;
        let distance = dot(d, d);
        if (distance < best_distance || (distance == best_distance && entry.w < best_index)) {
            best_distance = distance;
            best = j - 1u;
            best_index = entry.w;
        }
    }
    return vec4f(look_palette.entries[256u + best].rgb * c.a, c.a);
}

@fragment
fn look_upscale(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let p = vec2u(position.xy);
    let offset = vec2u(look.p[0].xy);
    let extent = vec2u(look.p[0].zw);
    let source = vec2u(look.frame.zw);
    if (any(p < offset) || any(p >= offset + extent)) {
        return look.p[1];
    }
    let at = (p - offset) * source / extent;
    return textureLoad(look_source, vec2i(at), 0);
}

@fragment
fn look_vignette(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let c = textureLoad(look_source, vec2i(position.xy), 0);
    let p = look_layout_at(position.xy);
    let q = (p - look.p[0].xy) / max(look.p[0].zw, vec2f(1e-6));
    let t = clamp((length(q) - 1.0) / max(look.p[1].x, 1e-6), 0.0, 1.0);
    let s = t * t * (3.0 - 2.0 * t);
    let shade = look.p[2];
    let light = 1.0 - (1.0 - clamp(look.p[1].y, 0.0, 1.0)) * s * clamp(shade.a, 0.0, 1.0);
    return vec4f(c.rgb * light + shade.rgb * c.a * (1.0 - light), c.a);
}

@fragment
fn look_mix(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let a = textureLoad(look_source, vec2i(position.xy), 0);
    let b = textureLoad(look_aux, vec2i(position.xy), 0);
    let blend = look.p[0];
    var w = blend.x;
    if (blend.y > 0.5) {
        let p = look_layout_at(position.xy);
        let wipe = look.p[1];
        w = clamp((wipe.z - dot(p, wipe.xy)) / max(blend.z, 1e-4) + 0.5, 0.0, 1.0);
    }
    return mix(a, b, w);
}

@fragment
fn look_copy(@builtin(position) position: vec4f) -> @location(0) vec4f {
    return textureLoad(look_source, vec2i(position.xy), 0);
}

@fragment
fn look_bright(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let factor = u32(look.p[0].x);
    let threshold = look.p[0].y;
    let limit = vec2i(look.frame.zw) - vec2i(1);
    let start = vec2i(vec2u(position.xy) * factor);
    var sum = vec4f(0.0);
    for (var y = 0u; y < factor; y += 1u) {
        for (var x = 0u; x < factor; x += 1u) {
            let c = textureLoad(look_source, min(start + vec2i(i32(x), i32(y)), limit), 0);
            let luminance = dot(c.rgb, vec3f(0.2126, 0.7152, 0.0722));
            sum += c * (max(luminance - threshold, 0.0) / max(luminance, 1e-4));
        }
    }
    return sum / f32(factor * factor);
}

@fragment
fn look_blur(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let direction = vec2i(look.p[0].xy);
    let sigma = max(look.p[0].z, 1e-3);
    let reach = i32(look.p[0].w);
    let limit = vec2i(look.size.xy) - vec2i(1);
    let centre = vec2i(position.xy);
    var sum = vec4f(0.0);
    var total = 0.0;
    for (var i = -reach; i <= reach; i += 1) {
        let w = exp(-f32(i * i) / (2.0 * sigma * sigma));
        sum += textureLoad(look_source, clamp(centre + direction * i, vec2i(0), limit), 0) * w;
        total += w;
    }
    return sum / total;
}

@fragment
fn look_crt(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let size = look.size.xy;
    let lines = look.p[0];
    let curve = look.p[1];
    let bezel = look_premultiply(look.p[2]);
    let glow = look.p[3];
    var q = position.xy;
    var edge = 1.0;
    let warped = curve.z > 0.5;
    if (warped) {
        let uv = q / size * 2.0 - 1.0;
        let w = uv * (1.0 + curve.x * uv.yx * uv.yx);
        if (any(abs(w) > vec2f(1.0))) {
            return bezel;
        }
        let e = clamp((vec2f(1.0) - abs(w)) / max(curve.y, 1e-5), vec2f(0.0), vec2f(1.0));
        let s = e * e * (vec2f(3.0) - 2.0 * e);
        edge = s.x * s.y;
        q = (w * 0.5 + 0.5) * size;
    }
    var colour = vec4f(0.0);
    if (curve.w > 0.0) {
        let centre = size * 0.5;
        let along = (q - centre) / length(centre) * curve.w;
        let r = textureSampleLevel(look_source, look_sampler, (q + along) / size, 0.0);
        let g = textureSampleLevel(look_source, look_sampler, q / size, 0.0);
        let b = textureSampleLevel(look_source, look_sampler, (q - along) / size, 0.0);
        colour = vec4f(r.r, g.g, b.b, g.a);
    } else if (warped) {
        colour = textureSampleLevel(look_source, look_sampler, q / size, 0.0);
    } else {
        colour = textureLoad(look_source, vec2i(position.xy), 0);
    }
    if (glow.w > 0.5) {
        let light = textureSampleLevel(look_aux, look_sampler, q / size, 0.0);
        colour = vec4f(colour.rgb + light.rgb * glow.rgb, colour.a);
    }
    if (lines.z > 0.5) {
        let y = (q.y - look.place.z) / look.place.x;
        let gain = 1.0 - clamp(lines.y, 0.0, 1.0) * (0.5 + 0.5 * cos(6.283185307179586 * y / max(lines.x, 1e-6)));
        colour = vec4f(colour.rgb * gain, colour.a);
    }
    if (warped) {
        colour = colour * edge + bezel * (1.0 - edge);
    }
    return colour;
}
"#;