// Literal port of the legacy smooth shader; dpdy is reversed for WebGPU's top-left origin. const GPU_SMOOTH = ` struct Params { view: vec4f, world: vec4f, style: vec4f, effects: vec4f, camera: vec4f, light: vec4f, screen: vec4f, extra: vec4f } @group(0) @binding(0) var u: Params; @group(0) @binding(1) var tCol: texture_2d; @group(0) @binding(2) var tBack: texture_2d; @group(0) @binding(3) var tTree: texture_2d; @group(0) @binding(4) var tField: texture_2d; @group(0) @binding(5) var tLight: texture_2d; @group(0) @binding(6) var tGlow: texture_2d; @group(0) @binding(7) var linear: sampler; @group(0) @binding(8) var su: vec4f; @group(0) @binding(9) var tMotion: texture_2d; fn sampleLevel(t: texture_2d, uv: vec2f, level: f32) -> vec4f { return textureSampleLevel(t,linear,uv,level); } fn modulo(x: f32,y: f32) -> f32 { return x-y*floor(x/y); } fn h21(inputP: vec2f) -> f32 { var p=inputP; p = fract(p * vec2f(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } fn vn(p: vec2f) -> f32 { var i: vec2f = floor(p); var f: vec2f = fract(p); f = f * f * (3.0 - 2.0 * f); // Round corner sums before hashing so fused arithmetic cannot give shared corners different hashes. return mix(mix(h21(i), h21(floor(i + vec2f(1, 0))), f.x), mix(h21(floor(i + vec2f(0, 1))), h21(floor(i + vec2f(1, 1))), f.x), f.y); } fn fbm(inputP: vec2f) -> f32 { var p=inputP; var a: f32 = 0.5; var s: f32 = 0.0; for (var k: i32 = 0; k < 4; k++) { s += a * vn(p); p = p * 2.03 + 17.1; a *= 0.5; } return s / 0.9375; } fn lin(t: texture_2d, q: vec2f) -> vec4f { return sampleLevel(t, q / (u.view.zw), 0.0); } fn bsp(t: texture_2d, q: vec2f) -> vec4f { var tc: vec2f = q - 0.5; var i: vec2f = floor(tc); var f: vec2f = tc - i; var f2: vec2f = f * f; var f3: vec2f = f2 * f; var w0: vec2f = (1.0 - 3.0 * f + 3.0 * f2 - f3) / 6.0; var w1: vec2f = (4.0 - 6.0 * f2 + 3.0 * f3) / 6.0; var w2: vec2f = (1.0 + 3.0 * f + 3.0 * f2 - 3.0 * f3) / 6.0; var w3: vec2f = f3 / 6.0; var g0: vec2f = w0 + w1; var g1: vec2f = w2 + w3; var h0: vec2f = (i - 0.5 + w1 / g0) / (u.view.zw); var h1: vec2f = (i + 1.5 + w3 / g1) / (u.view.zw); return g0.y * (g0.x * sampleLevel(t, h0, 0.0) + g1.x * sampleLevel(t, vec2f(h1.x, h0.y), 0.0)) + g1.y * (g0.x * sampleLevel(t, vec2f(h0.x, h1.y), 0.0) + g1.x * sampleLevel(t, h1, 0.0)); } fn cellAt(t: texture_2d, c: vec2i) -> vec4f { return textureLoad(t, clamp(c, vec2i(0), vec2i((u.view.zw)) - 1), 0); } fn cls(c: vec4f) -> i32 { return i32(c.a * 255.0 + 0.5); } fn isT(n: i32) -> f32 { return select( 0.0, 1.0 ,(n == 1 || n == 4 || n == 6 || (n >= 7 && n <= 12)) ); } fn isM(n: i32) -> f32 { return select( isT(n), 1.0 ,n == 2 ); } fn isF(n: i32) -> f32 { return select( 0.0, 1.0 ,(n == 13 || n == 14) ); } fn isBelt(n: i32) -> f32 { return select( 0.0, 1.0 ,(n == 7 || n == 8) ); } fn isN(n: i32, k: i32) -> f32 { return select( 0.0, 1.0 ,n == k ); } fn beltSD(lb: vec2f, endL: bool, endR: bool) -> f32 { var x0: f32 = select( -2.0, 0.15 , endL ); var x1: f32 = select( 6.0, 3.85 , endR ); var r: f32 = 0.75; var c: vec2f = vec2f((x0 + x1) * 0.5, 2.0); var hs: vec2f = vec2f((x1 - x0) * 0.5, 1.85); var q: vec2f = abs(lb - c) - hs + r; return length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - r; } fn beltLineSD(c: vec2i, lb: vec2f) -> f32 { var caps: i32 = i32(cellAt(tTree, c).a * 255.0 + 0.5); return beltSD(lb, (caps & 1) != 0, (caps & 2) != 0); } fn bandRidge(w: vec2f, lb: vec2f, dir: f32, time: f32) -> f32 { var run: f32 = select( -1.0, 1.0 , lb.y < 2.0 ); return step(0.72, fract((w.x - dir * run * time * 30.0) * 0.5)); } fn bandColor(lb: vec2f, rg: f32) -> vec3f { return mix(vec3f(0.2, 0.21, 0.24), vec3f(0.34, 0.35, 0.39), rg) * (select( 0.72, 1.0 ,lb.y < 2.0 )); } ${GPU_SMOOTH_SLOPE_HELPERS} @fragment fn fs(@builtin(position) position: vec4f) -> @location(0) vec4f { let uView=vec4f(u.extra.xy-u.view.xy,u.camera.z,u.screen.y); let uLightMap=vec4f(u.light.xy*u.light.z-u.view.xy,u.light.z,u.light.w); var zp: f32 = uView.z; var px: f32 = 1.0 / zp; var sp: vec2f = vec2f(position.x, position.y); var q: vec2f = sp * px + uView.xy; var w: vec2f = q + (u.view.xy); var cam: vec2f = (u.view.xy) + uView.xy; var scr: vec2f = q - uView.xy; var shc: f32 = uView.w * px; var c: vec2i = vec2i(floor(q)); var qq: vec2f = q - 0.5; var c0: vec2i = vec2i(floor(qq)); var t: vec2f = qq - floor(qq); var k0: vec4f = cellAt(tCol, c0); var k1: vec4f = cellAt(tCol, c0 + vec2i(1, 0)); var k2: vec4f = cellAt(tCol, c0 + vec2i(0, 1)); var k3: vec4f = cellAt(tCol, c0 + vec2i(1, 1)); var n0: i32 = cls(k0); var n1: i32 = cls(k1); var n2: i32 = cls(k2); var n3: i32 = cls(k3); let motionTime = cellAt(tMotion, c).r; var own: vec4f = cellAt(tCol, c); var nc: i32 = cls(own); var s: vec2f = smoothstep(vec2f(0.1), vec2f(0.9), t); var wq: vec4f = vec4f((1.0 - s.x) * (1.0 - s.y), s.x * (1.0 - s.y), (1.0 - s.x) * s.y, s.x * s.y); // Fields and screen derivatives before branching. var Fb: vec4f = bsp(tField, q); var F: vec4f = mix(lin(tField, q), Fb, 0.62); var wl: vec4f = vec4f((1.0 - t.x) * (1.0 - t.y), t.x * (1.0 - t.y), (1.0 - t.x) * t.y, t.x * t.y); var pw: f32 = dot(wl, vec4f(isN(n0, 2), isN(n1, 2), isN(n2, 2), isN(n3, 2))); var M: f32 = clamp(F.r + pw, 0.0, 1.0); var lf: f32 = clamp(mix(F.g, Fb.g, 0.6) + F.r + pw, 0.0, 1.0); var fwT: f32 = max(fwidth(F.r), 1e-4); var fwM: f32 = max(fwidth(M), 1e-4); var fwA: f32 = max(fwidth(F.a), 1e-4); var fwL: f32 = max(fwidth(lf), 1e-4); var gT: vec2f = vec2f(dpdx(mix(Fb.r, M, 0.5)), -dpdy(mix(Fb.r, M, 0.5))); var gL: vec2f = vec2f(dpdx(F.g), -dpdy(F.g)); // Sky, clouds, parallax hills and back-wall AO. var back: vec4f = lin(tBack, q); var C: vec3f = back.rgb; var sky: f32 = back.a; if (sky > 0.01) { var S: vec3f = C; var P0: vec2f = scr + cam * 0.08; var cl: f32 = smoothstep(0.56 - 0.3 * (u.style.y), 0.78 - 0.2 * (u.style.y), fbm(vec2f(P0.x * 0.016 + (su.x) * 0.006, P0.y * 0.05))); var hi: f32 = clamp(((su.y) - 40.0 - w.y) / 50.0, 0.0, 1.0); S = mix(S, mix(vec3f(0.96, 0.95, 0.93), vec3f(0.5, 0.52, 0.56), (u.style.y)), cl * (0.6 + 0.3 * (u.style.y)) * hi); var k1: f32 = 0.16; var P1: vec2f = scr + cam * k1; var base1: f32 = shc * 0.5 + 8.0 + ((su.y) - shc * 0.5) * k1; var top1: f32 = base1 - 36.0 * (0.25 + 0.9 * fbm(vec2f(P1.x * 0.009, 1.7))); var m1: f32 = smoothstep(top1 - px * 1.5, top1 + px * 1.5, P1.y); var far: vec3f = mix(vec3f(0.50, 0.60, 0.72), S, 0.35) * (0.94 + 0.08 * fbm(P1 * 0.05)); S = mix(S, far, m1); var k2: f32 = 0.38; var P2: vec2f = scr + cam * k2; var base2: f32 = shc * 0.5 + 14.0 + ((su.y) - shc * 0.5) * k2; var top2: f32 = base2 - 20.0 * (0.2 + 0.9 * fbm(vec2f(P2.x * 0.016, 7.3))); var m2: f32 = smoothstep(top2 - px * 1.5, top2 + px * 1.5, P2.y); var near: vec3f = vec3f(0.36, 0.5, 0.47) * (0.92 + 0.14 * fbm(P2 * 0.08)); near = mix(near, S, 0.42 - 0.2 * smoothstep(top2, top2 + 30.0, P2.y)); S = mix(S, near, m2); C = mix(C, S, sky); } var notSky: f32 = 1.0 - sky; C *= mix(1.0, 1.08 + 0.4 * fbm(w * 0.21), notSky); var near: f32 = sampleLevel(tField, q / (u.view.zw), 2.2).r; C *= 1.0 - 0.34 * smoothstep(0.12, 0.85, near) * (1.0 - 0.75 * sky); // Trees behind terrain and built pieces. if (F.a > 0.2) { var a0: vec4f = cellAt(tTree, c0); var a1: vec4f = cellAt(tTree, c0 + vec2i(1, 0)); var a2: vec4f = cellAt(tTree, c0 + vec2i(0, 1)); var a3: vec4f = cellAt(tTree, c0 + vec2i(1, 1)); var m: vec4f = vec4f(step(0.4, a0.a), step(0.4, a1.a), step(0.4, a2.a), step(0.4, a3.a)) * wq; var sm: f32 = m.x + m.y + m.z + m.w; if (sm > 1e-4) { var tc: vec3f = (a0.rgb * m.x + a1.rgb * m.y + a2.rgb * m.z + a3.rgb * m.w) / sm; var leaf: f32 = (a0.a * m.x + a1.a * m.y + a2.a * m.z + a3.a * m.w) / sm; var lv: f32 = smoothstep(0.6, 0.9, leaf); tc *= mix(0.86 + 0.22 * vn(vec2f(w.x * 1.4, w.y * 0.25)), 0.72 + 0.5 * fbm(w * 0.42), lv); var d: f32 = (F.a - 0.36) / fwA; tc *= mix(0.55, 1.0, smoothstep(0.4, 1.6, d)); C = mix(C, tc, smoothstep(-0.7, 0.7, d)); } } // Smoke, steam and flame. if (Fb.b > 0.02) { var m: vec4f = vec4f(isN(n0, 5), isN(n1, 5), isN(n2, 5), isN(n3, 5)) * wq; var sm: f32 = m.x + m.y + m.z + m.w; var gc: vec3f = select( own.rgb, (k0.rgb * m.x + k1.rgb * m.y + k2.rgb * m.z + k3.rgb * m.w) / sm , sm > 1e-4 ); if (sm > 1e-4 || nc == 5) { C = mix(C, gc, smoothstep(0.03, 0.55, Fb.b) * 0.92); } } // Liquids with a glossy top edge. var anyL: f32 = isN(n0, 3) + isN(n1, 3) + isN(n2, 3) + isN(n3, 3); if (anyL > 0.0 && lf > 0.3) { var m: vec4f = vec4f(isN(n0, 3), isN(n1, 3), isN(n2, 3), isN(n3, 3)) * (wq + 0.02); var sm: f32 = m.x + m.y + m.z + m.w; var lc: vec3f = (k0.rgb * m.x + k1.rgb * m.y + k2.rgb * m.z + k3.rgb * m.w) / sm; lc *= 0.94 + 0.1 * vn(w * 0.55 + vec2f((su.x) * 0.7, (su.x) * 0.25)); var gl: f32 = length(gL); var topSide: f32 = select( 0.0, clamp(gL.y / gl, 0.0, 1.0) , gl > 1e-5 ); var band: f32 = 1.0 - smoothstep(0.5, 0.75, F.g); lc += vec3f(0.16, 0.18, 0.2) * topSide * band; C = mix(C, lc, smoothstep(0.5 - fwL, 0.5 + fwL, lf)); } // Rounded ground and the seam against loose grains. if (F.r > 0.3) { var m: vec4f = vec4f(isT(n0), isT(n1), isT(n2), isT(n3)) * wq; var sm: f32 = m.x + m.y + m.z + m.w; var blur: vec3f = bsp(tCol, q).rgb; var tc: vec3f = own.rgb; var bd: f32 = 1e9; if (m.x > 0.0) { var e: vec3f = k0.rgb - blur; var dd: f32 = dot(e, e); if (dd < bd) { bd = dd; tc = k0.rgb; } } if (m.y > 0.0) { var e: vec3f = k1.rgb - blur; var dd: f32 = dot(e, e); if (dd < bd) { bd = dd; tc = k1.rgb; } } if (m.z > 0.0) { var e: vec3f = k2.rgb - blur; var dd: f32 = dot(e, e); if (dd < bd) { bd = dd; tc = k2.rgb; } } if (m.w > 0.0) { var e: vec3f = k3.rgb - blur; var dd: f32 = dot(e, e); if (dd < bd) { bd = dd; tc = k3.rgb; } } if (sm < 1e-4) { tc = own.rgb; } tc *= 0.84 + 0.3 * fbm(w * 0.28); tc *= 0.95 + 0.1 * vn(w * 1.6); var gl: f32 = length(gT); var nrm: vec2f = select( vec2f(0.0), -gT / gl , gl > 1e-6 ); var band: f32 = 1.0 - smoothstep(0.5, 0.9, M); var lit: f32 = dot(nrm, normalize(vec2f(-0.5, -1.0))); tc *= 1.0 + 0.42 * lit * band; var dm: f32 = (M - 0.5) / fwM; tc *= mix(0.4, 1.0, smoothstep(0.5, 1.4 + zp * 0.08, dm)); var dt: f32 = (F.r - 0.5) / fwT; if (nc == 1 && pw > 0.0) { tc *= mix(0.65, 1.0, smoothstep(0.0, 1.5, dt)); } C = mix(C, tc, smoothstep(-0.6, 0.6, (F.r - 0.5) / fwT)); } ${GPU_SMOOTH_SLOPE_DRAW} // Round loose grains. var np: i32 = i32(isN(n0, 2) + isN(n1, 2) + isN(n2, 2) + isN(n3, 2)); var closed: bool = isM(n0) + isM(n1) + isM(n2) + isM(n3) > 3.5; if (np > 0) { var best: f32 = 1e9; var gc: vec3f = vec3f(0.0); var gd: vec2f = vec2f(0.0); var gr: f32 = 0.6; for (var k: i32 = 0; k < 4; k++) { var o4: vec2i = vec2i(k & 1, k >> 1); var nk: i32 = select(select(select( n3, n2 , k == 2 ), n1 , k == 1 ), n0 , k == 0 ); if (nk != 2) { continue; } var ck: vec4f = select(select(select( k3, k2 , k == 2 ), k1 , k == 1 ), k0 , k == 0 ); var ce: vec2f = vec2f(c0 + o4) + 0.5; var r: f32 = 0.6 + 0.1 * (h21(ce + (u.view.xy)) - 0.5); var dv: vec2f = (q - ce) / r; var dd: f32 = length(dv); if (dd < best) { best = dd; gc = ck.rgb; gd = dv; gr = r; } } var cover: f32 = select( 1.0 - smoothstep(1.0 - px / gr, 1.0 + px / gr, best), 1.0 , np == 4 ); if (closed && F.r < 0.5) { cover = 1.0; } cover *= 1.0 - smoothstep(-0.6, 0.6, (F.r - 0.5) / fwT); if (cover > 0.0) { var r2: f32 = min(1.0, dot(gd, gd)); var n3: vec3f = normalize(vec3f(gd * 0.85, sqrt(1.0 - r2) + 0.25)); var sh: f32 = 0.98 + 0.18 * max(0.0, dot(n3, normalize(vec3f(-0.45, -0.8, 0.6)))); sh *= mix(1.0, 0.94, smoothstep(0.7 - px * 0.2, 1.15 + px * 0.2, best)); var pc: vec3f = (select( gc, (k0.rgb * wq.x + k1.rgb * wq.y + k2.rgb * wq.z + k3.rgb * wq.w) ,np == 4 )) * sh; if (!closed) { pc *= mix(1.0, 0.72, smoothstep(0.7, 1.0, best)); } C = mix(C, pc, cover); } } // Built pieces: belts, screws, wall tiles and filters. if (nc == 4) { C = own.rgb; } else if (nc == 7 || nc == 8) { var dir: f32 = select( -1.0, 1.0 , nc == 8 ); var lb: vec2f = fract(w * 0.25) * 4.0; var sd: f32 = beltLineSD(c, lb); var inside: f32 = 1.0 - smoothstep(-px, px, sd); if (inside > 0.0) { var edge: f32 = -sd; var bc: vec3f; if (edge < 0.8) { bc = bandColor(lb, bandRidge(w, lb, dir, motionTime)); bc *= mix(0.55, 1.0, smoothstep(0.0, max(px * 1.4, 0.12), edge)); } else { var rc: vec2f = vec2f(select( 3.0, 1.0 ,lb.x < 2.0 ), 2.0); var dv: vec2f = lb - rc; var rd: f32 = length(dv); bc = vec3f(0.15, 0.16, 0.18); if (rd < 0.95) { var ang: f32 = atan2(dv.y, dv.x) - dir * motionTime * 30.0 / 0.95; var spoke: f32 = smoothstep(0.55, 0.85, cos(ang * 3.0)); bc = mix(vec3f(0.5, 0.36, 0.25), vec3f(0.72, 0.53, 0.36), 0.5 + 0.5 * dot(normalize(dv + 1e-4), vec2f(-0.6, -0.8)) * smoothstep(0.2, 0.95, rd)); bc *= mix(1.0, 0.72, spoke * smoothstep(0.25, 0.4, rd)); bc *= mix(1.0, 0.55, smoothstep(0.82, 0.95, rd)); } } C = mix(C, bc, inside); } } else if ((nc >= 9 && nc <= 12) || (nc >= 19 && nc <= 22)) { var vert: bool = nc == 9 || nc == 11; var sp2: f32 = select(select(select( -1.0, 1.0 , nc == 11 ), 1.0 , nc == 10 ), -1.0 , nc == 9 ); var a: f32 = (select( fract(w.y * 0.25), fract(w.x * 0.25) ,vert )) * 4.0; var along: f32 = select( w.x, w.y , vert ); var screwSD: f32 = -1.0; var capRing: f32 = 0.0; var screwTag: vec4f = cellAt(tTree, c); var screwJoins: i32 = i32(screwTag.a * 255.0 + 0.5); var shaped: bool = nc >= 19 || (screwJoins > 0 && screwJoins < 64); if (shaped) { var d: vec2f = vec2f(1.0,select( 1.0, -1.0 , nc == 19 || nc == 21 )); var tag: vec4f = screwTag; var local: vec2f = floor(tag.gb * 255.0 + 0.5) - 8.0 + fract(w) - 2.0; var joins: i32 = screwJoins; screwSD = 100.0; for (var end: i32 = 0; end < 2; end++) { var join: i32 = (joins >> u32(end * 3)) & 7; var side: f32 = select( 1.0, -1.0 , end == 0 ); var diagonal: bool = select( join != 0, join == 0 || join >= 5 , nc >= 19 ); var grade: f32 = select(select( 1.0, -1.0 , join == 1 ), d.y , nc >= 19 ); var ray: vec2f = select(select(select(select(select( vec2f(-1, 0), vec2f(0, 1) , join == 3 ), vec2f(1, 0) , join == 2 ), vec2f(0, -1) , join == 1 ), (select( vec2f(side, 0), vec2f(0, side) ,vert )) , nc < 19 ), (select( vec2f(side, side * grade), vec2f(side * grade, side) ,vert )) * 0.70710678 , diagonal ); var t: f32 = dot(local, ray); var cross2: f32 = dot(local, vec2f(-ray.y, ray.x)); var radius: f32 = length(vec2f(cross2, min(0.0, t))); var cap: f32 = t - (select( 2.0, 2.82842712 ,diagonal )); var sd: f32 = max(radius - 2.0,select( -10.0, cap , (joins & (64 << u32(end))) != 0 )); if (sd < screwSD) { screwSD = sd; a = 2.0 + (select( radius, -radius ,side * cross2 < 0.0 )); along = (select(select( w.x - local.x, w.y - local.y , vert ), dot(w - local, d) * 0.70710678 ,nc >= 19 )) + side * t; capRing = select( 0.0, smoothstep(-0.55, -0.15, cap) ,(joins & (64 << u32(end))) != 0 ); } } if (nc >= 19) { sp2 = select( -1.0, 1.0 ,nc == 19 || nc == 20 ); } } var wall: f32 = 0.62; var tc: vec3f; if (a < wall || a > 4.0 - wall || capRing > 0.5) { var u2: f32 = select( (4.0 - a) / wall, a / wall , a < wall ); var cyl: f32 = sin(clamp(u2, 0.0, 1.0) * 1.5708); tc = vec3f(0.62, 0.41, 0.27) * (0.6 + 0.55 * cyl); if (a < wall) { tc *= 1.08; } var ring: f32 = 1.0 - smoothstep(0.0, 0.3, min(fract(along * 0.25), 1.0 - fract(along * 0.25)) * 4.0); if (nc < 19) { tc *= 1.0 - 0.3 * ring; } tc *= mix(0.5, 1.0, smoothstep(0.0, max(px * 1.3, 0.1), min(a, 4.0 - a))); } else { var full: bool = own.r + own.g + own.b > 0.0; var fl: f32 = fract((along + a * 0.9 - sp2 * motionTime * 14.0) * 0.5); var flight: f32 = smoothstep(0.82, 0.92, fl) * (1.0 - smoothstep(0.92, 1.0, fl)); var bore: vec3f = vec3f(0.11, 0.1, 0.11) * (0.8 + 0.4 * (1.0 - abs(a - 2.0) / 1.4)); tc = select( bore, own.rgb * (0.9 + 0.1 * vn(w * 1.3)) ,full ); tc = mix(tc, vec3f(0.6, 0.48, 0.38), flight * (select( 0.8, 0.35 ,full ))); tc *= 1.0 - 0.25 * smoothstep(0.9, 1.3, abs(a - 2.0)); } if (shaped) { var full: bool = own.r + own.g + own.b > 0.0; if (full) { C = mix(C, own.rgb, 1.0 - smoothstep(0.36, 0.5, length(fract(w) - 0.5))); } C = mix(C, tc, 1.0 - smoothstep(2.0 - px, 2.0 + px, screwSD + 2.0)); } else { C = tc; } } else if (nc == 6 || (nc >= 15 && nc <= 18)) { var lb: vec2f = fract(w * 0.25) * 4.0; var rb: vec2f = 4.0 - lb; var e: f32 = min(min(lb.x, lb.y), min(rb.x, rb.y)); var tc: vec3f = own.rgb * (0.92 + 0.14 * fbm(w * 0.55)); var hl: f32 = max(1.0 - smoothstep(0.0, 0.8, lb.x), 1.0 - smoothstep(0.0, 0.8, lb.y)); var shd: f32 = max(1.0 - smoothstep(0.0, 0.8, rb.x), 1.0 - smoothstep(0.0, 0.8, rb.y)); tc *= 1.0 + 0.2 * hl - 0.26 * shd; tc *= mix(0.5, 1.0, smoothstep(px * 0.5, px * 0.5 + max(px * 1.2, 0.14), e)); if (nc >= 15) { var sl: vec2f = lb; if (nc == 16 || nc == 18) { sl.x = 4.0 - sl.x; } if (nc >= 17) { sl.y = 4.0 - sl.y; } var d: f32 = (sl.y - sl.x) * 0.70710678; tc *= 1.0 + 0.2 * (1.0 - smoothstep(0.0, 0.6, d)); C = mix(C, tc, smoothstep(-px * 0.5, px * 0.5, d)); } else { C = tc; } } else if (nc == 13 || nc == 14) { var dir: f32 = select( -1.0, 1.0 , nc == 14 ); var lb: vec2f = fract(w * 0.25) * 4.0; var tag: vec4f = cellAt(tTree, c); var carry: bool = tag.a > 0.16; var tinted: bool = tag.r + tag.g + tag.b > 0.0; var sd: f32 = beltLineSD(c, lb); var inside: f32 = 1.0 - smoothstep(-px, px, sd); if (inside > 0.0) { var edge: f32 = -sd; var steel: vec3f = vec3f(0.42, 0.44, 0.5); var behind: vec3f = select( C * 0.8, own.rgb , own.r + own.g + own.b > 0.0 ); var cg: vec2f = abs(fract(w) - 0.5); var bw2: f32 = max(px * 0.9, 0.09); var hole: f32 = 1.0 - smoothstep(0.5 - bw2 - px, 0.5 - bw2, max(cg.x, cg.y)); var fc: vec3f; if (edge < 0.8) { var rg: f32 = bandRidge(w, lb, dir, motionTime); var band: vec3f = bandColor(lb, rg); if (tinted && (carry == (lb.y < 2.0))) { band = mix(band, tag.rgb * (select( 0.8, 1.0 ,lb.y < 2.0 )), 0.75 * rg); } fc = mix(band, behind * 0.85, hole * (1.0 - rg) * 0.75); fc *= mix(0.55, 1.0, smoothstep(0.0, max(px * 1.4, 0.12), edge)); } else { fc = mix(steel * 0.78, behind, hole); fc *= mix(0.7, 1.0, smoothstep(0.0, max(px * 1.4, 0.12), edge - 0.8)); } C = mix(C, fc, inside); } } // Light, then the legacy nine-tap glow filter. if (uLightMap.w > 0.5) { C *= sampleLevel(tLight, (q - uLightMap.xy) / uLightMap.z / (vec2f(textureDimensions(tLight))), 0.0).rgb; } if ((su.z) > 0.0) { var gu: vec2f = q / (2.0 * (vec2f(textureDimensions(tGlow)))); var d: vec2f = 1.0 / (vec2f(textureDimensions(tGlow))); var g: vec3f = sampleLevel(tGlow, gu, 0.0).rgb * 0.25; g += (sampleLevel(tGlow, gu + vec2f(d.x, 0), 0.0).rgb + sampleLevel(tGlow, gu - vec2f(d.x, 0), 0.0).rgb + sampleLevel(tGlow, gu + vec2f(0, d.y), 0.0).rgb + sampleLevel(tGlow, gu - vec2f(0, d.y), 0.0).rgb) * 0.125; g += (sampleLevel(tGlow, gu + d, 0.0).rgb + sampleLevel(tGlow, gu - d, 0.0).rgb + sampleLevel(tGlow, gu + vec2f(d.x, -d.y), 0.0).rgb + sampleLevel(tGlow, gu + vec2f(-d.x, d.y), 0.0).rgb) * 0.0625; C += g * (su.z); } return vec4f(C, 1.0); }`;