// ─────────────────────────────────────────────────────────────────────────────
// THE colour-encoded ID pass (GFX_V2 §7 item 8) — the shader half of
// `render::gpu::picking`.
//
// Each pickable primitive carries its `PickId` as a per-vertex `u32`; the fragment
// stage writes that number, unmodified, into an `R32Uint` attachment. A click reads
// one texel back and decodes it with `PickId::from_rgba` — the SAME encoding
// `facett_core::engine::pick`'s CPU lane returns, so the two lanes answer one
// question with one number (LAW #5).
//
// Three properties are load-bearing, and all three are enforced OUTSIDE this file
// so no shader edit can lose them (see `picking.rs`):
// * `@interpolate(flat)` — an id must never be interpolated. WGSL requires flat
// for integer inter-stage values, so this is checked by the compiler, but it is
// spelled explicitly because the failure mode (a blended id = a wrong click on
// a THIRD object that was never under the cursor) is silent.
// * the target is `R32Uint`, which WebGPU makes non-filterable, non-blendable and
// non-multisampleable — the three things that corrupt an id into a neighbour's.
// * the pass clears to 0 = `PickId::NOTHING`, the reserved miss sentinel that
// `PickId::new` can never produce for a real (layer, feature).
//
// Needs the shared prelude for `px_to_ndc` — compose with `render::gpu::wgsl()`.
// ─────────────────────────────────────────────────────────────────────────────
struct PickUniforms {
/// Target size in PHYSICAL pixels — the space `pos_px` is expressed in.
viewport: vec2<f32>,
_pad: vec2<f32>,
};
@group(0) @binding(0) var<uniform> pick_u: PickUniforms;
struct PickVertexIn {
/// Position in physical pixels, origin top-left (the same space the CPU
/// painter and every other facett GPU lane use).
@location(0) pos_px: vec2<f32>,
/// Clip-space depth in `0..1`, 0 = nearest. Lets the pick pass resolve
/// occlusion the same way the colour pass does, so a 3D click returns the
/// object a viewer can actually see rather than whichever drew last.
@location(1) depth: f32,
/// The encoded `PickId`. Never 0 for a real feature.
@location(2) id: u32,
};
struct PickVertexOut {
@builtin(position) clip: vec4<f32>,
@location(0) @interpolate(flat) id: u32,
};
@vertex
fn pick_vs(v: PickVertexIn) -> PickVertexOut {
var out: PickVertexOut;
out.clip = vec4<f32>(px_to_ndc(v.pos_px, pick_u.viewport), v.depth, 1.0);
out.id = v.id;
return out;
}
@fragment
fn pick_fs(in: PickVertexOut) -> @location(0) u32 {
return in.id;
}