Skip to main content

COMMON

Constant COMMON 

Source
pub const COMMON: &str = r#"
fn src_dim() -> vec2<u32> {
    return min(textureDimensions(src_tex), post.extent.xy);
}

fn load_src(p: vec2<i32>) -> vec4<f32> {
    let dim = vec2<i32>(src_dim());
    if (dim.x <= 0 || dim.y <= 0) { return vec4<f32>(0.0); }
    let c = clamp(p, vec2<i32>(0), dim - vec2<i32>(1));
    return textureLoad(src_tex, c, 0);
}

fn sample_src(x: f32, y: f32) -> vec4<f32> {
    let dim = vec2<f32>(src_dim());
    if (dim.x < 1.0 || dim.y < 1.0) { return vec4<f32>(0.0); }
    let xc = clamp(x, 0.0, dim.x - 1.0);
    let yc = clamp(y, 0.0, dim.y - 1.0);
    let x0 = i32(floor(xc));
    let y0 = i32(floor(yc));
    let tx = xc - floor(xc);
    let ty = yc - floor(yc);
    let a = load_src(vec2<i32>(x0, y0));
    let b = load_src(vec2<i32>(x0 + 1, y0));
    let c = load_src(vec2<i32>(x0, y0 + 1));
    let d = load_src(vec2<i32>(x0 + 1, y0 + 1));
    return mix(mix(a, b, tx), mix(c, d, tx), ty);
}

fn store(p: vec2<u32>, c: vec4<f32>) {
    textureStore(dst_tex, p, c);
}

fn luma(c: vec3<f32>) -> f32 {
    return dot(c, vec3<f32>(0.2126, 0.7152, 0.0722));
}

fn luma_at(x: i32, y: i32) -> f32 {
    return luma(load_src(vec2<i32>(x, y)).rgb);
}

fn sobel(x: i32, y: i32) -> f32 {
    let gx = -luma_at(x - 1, y - 1) + luma_at(x + 1, y - 1) - 2.0 * luma_at(x - 1, y) + 2.0 * luma_at(x + 1, y) - luma_at(x - 1, y + 1) + luma_at(x + 1, y + 1);
    let gy = -luma_at(x - 1, y - 1) - 2.0 * luma_at(x, y - 1) - luma_at(x + 1, y - 1) + luma_at(x - 1, y + 1) + 2.0 * luma_at(x, y + 1) + luma_at(x + 1, y + 1);
    return sqrt(gx * gx + gy * gy);
}

fn normalize3(v: vec3<f32>) -> vec3<f32> {
    let len = length(v);
    if (len < 1e-8) { return vec3<f32>(0.0, 0.0, 1.0); }
    return v / len;
}

fn safe_pow(a: f32, b: f32) -> f32 {
    if (a <= 0.0) { return 0.0; }
    return pow(a, b);
}

fn edge_step(edge0: f32, edge1: f32, x: f32) -> f32 {
    let span = edge1 - edge0;
    if (abs(span) < 1e-8) {
        if (x < edge0) { return 0.0; }
        return 1.0;
    }
    let t = clamp((x - edge0) / span, 0.0, 1.0);
    return t * t * (3.0 - 2.0 * t);
}

fn grain_hash(x: u32, y: u32, seed: u32) -> f32 {
    var h = x * 0x8da6b343u ^ y * 0xd8163841u ^ seed * 0xcb1ab31fu;
    h = h ^ (h >> 15u);
    h = h * 0x2c1b3c6du;
    h = h ^ (h >> 12u);
    return f32(h >> 8u) / 16777216.0;
}

fn mixed_seed() -> u32 {
    return post.seed ^ (post.frame * 0x9e3779b9u);
}

fn hash21(x: f32, y: f32) -> f32 {
    var qx = fract(x * 123.34);
    var qy = fract(y * 456.21);
    let d = qx * (qx + 45.32) + qy * (qy + 45.32);
    qx = qx + d;
    qy = qy + d;
    return fract(qx * qy);
}

fn grain_hash_i(x: i32, y: i32, seed: u32) -> f32 {
    return grain_hash(u32(x), u32(y), seed);
}

fn value_noise(x: f32, y: f32, seed: u32) -> f32 {
    let x0 = floor(x);
    let y0 = floor(y);
    let tx = x - x0;
    let ty = y - y0;
    let sx = tx * tx * (3.0 - 2.0 * tx);
    let sy = ty * ty * (3.0 - 2.0 * ty);
    let xi = i32(x0);
    let yi = i32(y0);
    let a = grain_hash_i(xi, yi, seed);
    let b = grain_hash_i(xi + 1, yi, seed);
    let c = grain_hash_i(xi, yi + 1, seed);
    let d = grain_hash_i(xi + 1, yi + 1, seed);
    let ab = a + (b - a) * sx;
    let cd = c + (d - c) * sx;
    return ab + (cd - ab) * sy;
}

fn bayer(x: u32, y: u32) -> f32 {
    var v = 0u;
    var xx = x & 7u;
    var yy = y & 7u;
    var half = 4u;
    var mul = 1u;
    for (var i = 0u; i < 3u; i = i + 1u) {
        let cx = xx >= half;
        let cy = yy >= half;
        if (xx >= half) { xx = xx - half; }
        if (yy >= half) { yy = yy - half; }
        var add = 0u;
        if (cx && !cy) { add = 2u; }
        else if (!cx && cy) { add = 3u; }
        else if (cx && cy) { add = 1u; }
        v = v + add * mul;
        mul = mul * 4u;
        half = half / 2u;
    }
    return (f32(v) + 0.5) / 64.0;
}

fn saturate3(c: vec3<f32>, amount: f32) -> vec3<f32> {
    let l = luma(c);
    return max(vec3<f32>(l) + (c - vec3<f32>(l)) * amount, vec3<f32>(0.0));
}

fn quantize(v: f32, levels: f32) -> f32 {
    let t = clamp(v, 0.0, 1.0);
    let q = min(floor(t * levels), levels - 1.0);
    return q / (levels - 1.0);
}

fn keep_rgb(rgb: vec3<f32>, threshold: f32, knee: f32, knee_width: f32, soft: f32) -> vec3<f32> {
    let l = max(rgb.r, max(rgb.g, rgb.b));
    var hard = 0.0;
    if (l > threshold) { hard = max(l - threshold, 0.0) / max(l, 1e-4); }
    var knee_t = 0.0;
    if (knee_width > 1e-6) { knee_t = clamp((l - knee) / knee_width, 0.0, 1.0); }
    return rgb * (hard + knee_t * knee_t * soft);
}

fn aces_channel(x: f32) -> f32 {
    let a = x * (x * 2.51 + 0.03);
    let b = x * (x * 2.43 + 0.59) + 0.14;
    if (abs(b) < 1e-8) { return 0.0; }
    return clamp(a / b, 0.0, 1.0);
}

fn agx_contrast(x: f32) -> f32 {
    let x2 = x * x;
    let x4 = x2 * x2;
    return 15.5 * x4 * x2 - 40.14 * x4 * x + 31.96 * x4 - 6.868 * x2 * x + 0.4298 * x2 + 0.1191 * x - 0.00232;
}

fn agx(c: vec3<f32>) -> vec3<f32> {
    let r0 = vec3<f32>(0.842479062253094, 0.0784335999999992, 0.0792237451477643);
    let r1 = vec3<f32>(0.0423282422610123, 0.878468636469772, 0.0791661274605434);
    let r2 = vec3<f32>(0.0423756549057051, 0.0784336, 0.879142973793104);
    let v = vec3<f32>(dot(r0, c), dot(r1, c), dot(r2, c));
    let min_ev = -12.47393;
    let max_ev = 4.026069;
    let span = max_ev - min_ev;
    let t0 = clamp((log2(max(v.r, 1e-10)) - min_ev) / span, 0.0, 1.0);
    let t1 = clamp((log2(max(v.g, 1e-10)) - min_ev) / span, 0.0, 1.0);
    let t2 = clamp((log2(max(v.b, 1e-10)) - min_ev) / span, 0.0, 1.0);
    return clamp(vec3<f32>(agx_contrast(t0), agx_contrast(t1), agx_contrast(t2)), vec3<f32>(0.0), vec3<f32>(1.0));
}

fn neutral_map(c: vec3<f32>, start: f32, toe: f32, desat: f32, clamp_hi: bool) -> vec3<f32> {
    let low = min(c.r, min(c.g, c.b));
    var offset = toe;
    if (low < 0.08) { offset = low - 6.25 * low * low; }
    var v = c - vec3<f32>(offset);
    let peak = max(v.r, max(v.g, v.b));
    if (peak >= start && peak > 1e-8) {
        let d = 1.0 - start;
        let denom = peak + d - start;
        var mapped = start;
        if (abs(denom) >= 1e-8) { mapped = 1.0 - d * d / denom; }
        v = v * (mapped / peak);
        let g = 1.0 - 1.0 / (desat * (peak - mapped) + 1.0);
        v = mix(v, vec3<f32>(mapped), g);
    }
    if (clamp_hi) { v = clamp(v, vec3<f32>(0.0), vec3<f32>(1.0)); }
    return v;
}

fn band_shade(light: f32, bands: f32, softness: f32, threshold: f32, shadow: f32) -> f32 {
    let bands_f = max(bands, 1.0);
    let light_c = clamp(light, 0.0, 1.0);
    let x = min(light_c * bands_f, bands_f - 1e-4);
    var w = 0.0;
    if (softness > 0.0) { w = edge_step(0.5 - softness * 0.5, 0.5 + softness * 0.5, fract(x)); }
    let idx = floor(x) + w;
    var q = light_c;
    if (bands_f > 1.0) { q = clamp(idx / (bands_f - 1.0), 0.0, 1.0); }
    var gate = 1.0;
    if (softness <= 1e-5) {
        if (light_c < threshold) { gate = 0.0; }
    } else {
        gate = edge_step(threshold - softness, threshold + softness, light_c);
    }
    return q * (shadow + (1.0 - shadow) * gate);
}

fn palette(i: u32) -> vec3<f32> {
    if (i == 0u) { return vec3<f32>(0.0, 0.0, 0.0); }
    if (i == 1u) { return vec3<f32>(0.0122865, 0.0241576, 0.0865005); }
    if (i == 2u) { return vec3<f32>(0.208637, 0.0185002, 0.0865005); }
    if (i == 3u) { return vec3<f32>(0.0, 0.242281, 0.0822827); }
    if (i == 4u) { return vec3<f32>(0.40724, 0.0843762, 0.0368895); }
    if (i == 5u) { return vec3<f32>(0.114435, 0.0953075, 0.0781874); }
    if (i == 6u) { return vec3<f32>(0.539479, 0.545724, 0.571125); }
    if (i == 7u) { return vec3<f32>(1.0, 0.879622, 0.806952); }
    if (i == 8u) { return vec3<f32>(1.0, 0.0, 0.0742136); }
    if (i == 9u) { return vec3<f32>(1.0, 0.366253, 0.0); }
    if (i == 10u) { return vec3<f32>(1.0, 0.838799, 0.0202886); }
    if (i == 11u) { return vec3<f32>(0.0, 0.775822, 0.0368895); }
    if (i == 12u) { return vec3<f32>(0.0221739, 0.417885, 1.0); }
    if (i == 13u) { return vec3<f32>(0.226966, 0.181164, 0.332452); }
    if (i == 14u) { return vec3<f32>(1.0, 0.184475, 0.391572); }
    return vec3<f32>(1.0, 0.603827, 0.401978);
}

fn nearest_palette(c: vec3<f32>) -> vec3<f32> {
    var best = palette(0u);
    var best_d = 1e30;
    for (var i = 0u; i < 16u; i = i + 1u) {
        let swatch = palette(i);
        let d = dot(c - swatch, c - swatch);
        if (d < best_d) { best_d = d; best = swatch; }
    }
    return best;
}

fn encode_channel(c: f32) -> f32 {
    if (c <= 0.0031308) { return c * 12.92; }
    return 1.055 * safe_pow(max(c, 0.0), 1.0 / 2.4) - 0.055;
}

fn gaussian(p: vec2<u32>, dirx: i32, diry: i32, radius: u32, spread: f32) -> vec4<f32> {
    var acc = vec4<f32>(0.0);
    var total = 0.0;
    var s = spread;
    if (s <= 1e-4) { s = 1.0; }
    let r = i32(min(radius, 64u));
    for (var k = -r; k <= r; k = k + 1) {
        let w = exp(-f32(k * k) / s);
        acc = acc + load_src(vec2<i32>(i32(p.x) + k * dirx, i32(p.y) + k * diry)) * w;
        total = total + w;
    }
    return acc / max(total, 1e-8);
}

fn ring_radius(ring: u32) -> f32 {
    if (ring == 0u) { return post.p1.x; }
    if (ring == 1u) { return post.p1.y; }
    if (ring == 2u) { return post.p1.z; }
    return post.p1.w;
}

fn ring_gain(ring: u32) -> f32 {
    if (ring == 0u) { return post.p2.x; }
    if (ring == 1u) { return post.p2.y; }
    if (ring == 2u) { return post.p2.z; }
    return post.p2.w;
}

fn ring_channel(c: f32, threshold: f32, clamp_hi: f32) -> f32 {
    var v = max(c - threshold, 0.0);
    if (clamp_hi > 0.0) { v = min(v, clamp_hi); }
    return v;
}
"#;