#version 450 core // Unified backdrop blur vertex shader. // Handles both the 1D separable blur passes (fullscreen triangle, mode 0; used for // BOTH the H-pass and V-pass) and the composite pass (instanced unit-quad over // Backdrop_Primitive storage buffer, mode 1) for the second PSO of the backdrop bracket. // The first PSO (downsample) uses backdrop_fullscreen.vert. // // No vertex buffer for either mode. Mode 0 uses gl_VertexIndex 0..2 for a single // fullscreen triangle; mode 1 uses gl_VertexIndex 0..5 for a unit-quad (two // triangles, TRIANGLELIST topology) and gl_InstanceIndex to select the primitive. // // Mode 0 viewport+scissor are CPU-set per sigma group to the work region (union AABB // of that group's backdrop primitives + halo, clamped to swapchain bounds). Mode 1 // renders into source_texture with the screen-space orthographic projection; the // per-primitive bounds drive the quad in screen space. // // Backdrop primitives have NO rotation — backdrop sampling is in screen space, so // a rotated mask over a stationary blur sample would look wrong. // --- Outputs to fragment shader --- // p_local: shape-local position in physical pixels (origin at shape center). // Only meaningful in mode 1 (V-composite). Zero-init for mode 0. layout(location = 0) out vec2 p_local; // f_color: tint, unpacked from primitive.color. Only meaningful in mode 1. layout(location = 1) out mediump vec4 f_color; // f_half_size: RRect half extents in physical pixels (mode 1 only). layout(location = 2) flat out vec2 f_half_size; // f_radii: per-corner radii in physical pixels (mode 1 only). layout(location = 3) flat out vec4 f_radii; // f_half_feather: SDF anti-aliasing feather (mode 1 only). layout(location = 4) flat out float f_half_feather; // --- Uniforms (set 1) --- // Backdrop pipeline's own uniform block — distinct from the main pipeline's // Vertex_Uniforms. `mode` selects between H-blur (0) and V-composite (1). layout(set = 1, binding = 0) uniform Uniforms { mat4 projection; float dpi_scale; uint mode; // 0 = H-blur, 1 = V-composite vec2 _pad0; }; // --- Backdrop primitive storage buffer (set 0) --- // 48 bytes, std430-natural layout (no implicit padding). vec4 members are // front-loaded so their 16-byte alignment is satisfied without holes; the // vec2 and scalar tail packs tight to land the struct at a clean 48-byte // stride (a multiple of 16, so the array stride needs no rounding either). // Field semantics match the CPU-side Backdrop_Primitive declared in // levlib/draw/backdrop.odin; keep both in sync. // // Backdrop primitives are tint-only: outline is intentionally absent. Specialized // edge effects (e.g. liquid-glass-style refraction outlines) would be a dedicated // primitive type with its own pipeline rather than a flag bit here. struct Backdrop_Primitive { vec4 bounds; // 0-15: min_xy, max_xy (world-space) vec4 radii; // 16-31: per-corner radii (physical px) vec2 half_size; // 32-39: RRect half extents (physical px) float half_feather; // 40-43: SDF anti-aliasing feather (physical px) uint color; // 44-47: tint, packed RGBA u8x4 }; layout(std430, set = 0, binding = 0) readonly buffer Backdrop_Primitives { Backdrop_Primitive primitives[]; }; void main() { if (mode == 0u) { // ---- Mode 0: H-blur fullscreen triangle ---- // gl_VertexIndex 0 -> ( -1, -1) // gl_VertexIndex 1 -> ( 3, -1) // gl_VertexIndex 2 -> ( -1, 3) vec2 ndc = vec2( (gl_VertexIndex == 1) ? 3.0 : -1.0, (gl_VertexIndex == 2) ? 3.0 : -1.0); gl_Position = vec4(ndc, 0.0, 1.0); // Mode 0 doesn't read the per-primitive varyings; zero-init for safety. p_local = vec2(0.0); f_color = vec4(0.0); f_half_size = vec2(0.0); f_radii = vec4(0.0); f_half_feather = 0.0; } else { // ---- Mode 1: V-composite instanced unit-quad over Backdrop_Primitive ---- Backdrop_Primitive p = primitives[gl_InstanceIndex]; // Unit-quad corners for TRIANGLELIST (2 triangles, 6 vertices): // index 0 -> (0,0) index 3 -> (0,1) // index 1 -> (1,0) index 4 -> (1,0) // index 2 -> (0,1) index 5 -> (1,1) vec2 quad_corners[6] = vec2[6]( vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 1.0), vec2(1.0, 0.0), vec2(1.0, 1.0)); vec2 corner = quad_corners[gl_VertexIndex]; vec2 world_pos = mix(p.bounds.xy, p.bounds.zw, corner); vec2 center = 0.5 * (p.bounds.xy + p.bounds.zw); // Shape-local position in physical pixels (no rotation for backdrops). p_local = (world_pos - center) * dpi_scale; f_color = unpackUnorm4x8(p.color); f_half_size = p.half_size; f_radii = p.radii; f_half_feather = p.half_feather; gl_Position = projection * vec4(world_pos * dpi_scale, 0.0, 1.0); } }