const MD2_PRIVATE_STATE_DECLS: &str = r#"
// ---- MD2 wrapper private state (per-invocation, module scope) ----
// fs_main + every lifted user function reads/writes these. Values are
// assigned at the top of fs_main; reading them before assignment is
// undefined behavior, but every code path in our wrapper writes first.
var<private> uv: vec2<f32>;
var<private> uv_orig: vec2<f32>;
var<private> rad: f32;
var<private> ang: f32;
var<private> ret: vec3<f32>;
// `_md2_color` is a wrapper scratch slot — kept under a `_md2_`-prefixed
// name to avoid colliding with the very common user-declared `color`.
var<private> _md2_color: vec3<f32>;
var<private> texsize: vec4<f32>;
var<private> aspect: vec4<f32>;
var<private> time: f32;
var<private> fps: f32;
var<private> frame: f32;
var<private> progress: f32;
var<private> bass: f32;
var<private> mid: f32;
var<private> treb: f32;
var<private> vol: f32;
var<private> bass_att: f32;
var<private> mid_att: f32;
var<private> treb_att: f32;
var<private> vol_att: f32;
var<private> rand_preset: vec4<f32>;
var<private> rand_frame: vec4<f32>;
var<private> slow_roam_cos: vec4<f32>;
var<private> slow_roam_sin: vec4<f32>;
var<private> roam_cos: vec4<f32>;
var<private> roam_sin: vec4<f32>;
var<private> blur1_min: f32;
var<private> blur1_max: f32;
var<private> blur2_min: f32;
var<private> blur2_max: f32;
var<private> blur3_min: f32;
var<private> blur3_max: f32;
var<private> hue_shader: vec3<f32>;
// MD1 legacy alias for `texsize` (some old presets read `g_fTexSize.zw`).
var<private> g_fTexSize: vec4<f32>;
var<private> q1: f32;
var<private> q2: f32;
var<private> q3: f32;
var<private> q4: f32;
var<private> q5: f32;
var<private> q6: f32;
var<private> q7: f32;
var<private> q8: f32;
var<private> q9: f32;
var<private> q10: f32;
var<private> q11: f32;
var<private> q12: f32;
var<private> q13: f32;
var<private> q14: f32;
var<private> q15: f32;
var<private> q16: f32;
var<private> q17: f32;
var<private> q18: f32;
var<private> q19: f32;
var<private> q20: f32;
var<private> q21: f32;
var<private> q22: f32;
var<private> q23: f32;
var<private> q24: f32;
var<private> q25: f32;
var<private> q26: f32;
var<private> q27: f32;
var<private> q28: f32;
var<private> q29: f32;
var<private> q30: f32;
var<private> q31: f32;
var<private> q32: f32;
"#;Expand description
MD2 per-invocation private state hoisted to module scope.
Every binding a user shader can reference by its bare MD2 name
(q1..q32, texsize, time, bass, slow_roam_cos, uv, rad,
ang, ret, …) is declared here as var<private>. That makes them
visible to lifted user-defined functions (which live at module scope
alongside these declarations) — the previous design pinned them as
let bindings inside fs_main, so a lifted float3 lavcol(float t) { return pow(.5, 2*t*slow_roam_cos); } would fail naga parse with
“no definition in scope for identifier: slow_roam_cos”.
WGSL var<private> is per-invocation, so each fragment thread has its
own copy — assigning these at the top of fs_main from uniforms.* /
per-pixel values is exactly what the original let site did, just one
scope higher.