struct Varying { @location(0) uv: vec2f, @builtin(position) screen: vec4f, } @vertex fn on_vertex(@builtin(vertex_index) vi: u32) -> Varying { let uv = vec2f(vec2(vi, vi >> 1u) & vec2(1u)); let screen = vec4(uv * 2. - 1., 0., 1.); let off = .5 / vec2f(textureDimensions(field)); return Varying(vec2(uv.x, 1. - uv.y) - off, screen); } @group(0) @binding(0) var field: texture_2d; @group(0) @binding(1) var smp: sampler; @fragment fn on_fragment(in: Varying) -> @location(0) u32 { let aa = textureGather(0, field, smp, in.uv, vec2(0, 0)); let ab = textureGather(0, field, smp, in.uv, vec2(0, 1)); let ba = textureGather(0, field, smp, in.uv, vec2(1, 0)); let bb = textureGather(0, field, smp, in.uv, vec2(1, 1)); let s = aa.y; let a = vec4(aa.xzw, bb.y); let b = vec4(ab.xy, ba.yz); var ret = 0u; for (var layer = 0u; layer < 8u; layer++) { let s = s >> layer & 1u; let a = a >> vec4(layer) & vec4(1u); let b = b >> vec4(layer) & vec4(1u); ret |= calc(s, a, b) << layer; } return ret; } fn calc(state: u32, a: vec4u, b: vec4u) -> u32 { let n = dot(a, vec4(1u)) + dot(b, vec4(1u)); switch (n) { case 2u: { return state; } case 3u: { return 1u; } default: { return 0u; } } }