#version 450 // Sample the glyph atlas (R = coverage 0..1) and mix the cell's bg up to its fg // by that coverage. Output is PREMULTIPLIED: an opaque cell is unchanged, and a // cell whose background is the see-through ground (config.gui_transparent, a // theme with no bg of its own) contributes only its ink, at the ink's own // coverage, so the compositor keeps the rest. layout(set = 2, binding = 0) uniform sampler2D u_atlas; layout(location = 0) in vec2 v_uv; layout(location = 1) in vec3 v_fg; layout(location = 2) in vec3 v_bg; layout(location = 3) in vec2 v_cell_uv; layout(location = 4) flat in uvec4 v_effect; layout(location = 0) out vec4 o_col; float cellNoise(uint serial, uint col, uint row) { uint x = serial ^ (col * 0x9e3779b9u) ^ (row * 0x85ebca6bu); x ^= x >> 16; x *= 0x7feb352du; x ^= x >> 15; x *= 0x846ca68bu; x ^= x >> 16; return float(x & 0xffffu) / 65535.0; } void main() { float a = texture(u_atlas, v_uv).r; bool oldLayer = (v_effect.x & 0x80000000u) != 0u; // 0 where the cell's background IS the ground and the ground is nothing. // src/gui/gui.zig sets that bit; the two flags above it are why the effect // id is masked with 0x3fffffff here and in ui.vert.glsl. float bgA = (v_effect.x & 0x40000000u) != 0u ? 0.0 : 1.0; uint effect = v_effect.x & 0x3fffffffu; float progress = clamp(uintBitsToFloat(v_effect.y), 0.0, 1.0); uint cellCol = v_effect.w & 0xffffu; uint cellRow = v_effect.w >> 16; float noise = cellNoise(v_effect.z, cellCol, cellRow); // Ink over ground, both premultiplied: v_fg*a + (v_bg*bgA)*(1-a), which is // mix() with the ground already premultiplied. At bgA = 1 that is exactly // the mix(v_bg, v_fg, a) at alpha 1 this shader always wrote. vec4 cell = vec4(mix(v_bg * bgA, v_fg, a), mix(bgA, 1.0, a)); // 3 = data dissolve. Changed cells retain the frozen old cell until their // stable threshold, then atomically become the new cell. Exact endpoints // mirror panel_animation.dissolveRevealed, including the zero hash. if (effect == 3u) { bool reveal = progress >= 1.0 || (progress > 0.0 && noise < progress); if (oldLayer ? reveal : !reveal) discard; o_col = cell; return; } // FreeType's hinted grayscale bitmap is already the intended coverage. // Preserve it exactly; weight-changing gamma hacks blur small stems. o_col = cell; }