// shapes.wgsl — fragment dispatch for the main pipeline.
// Material functions are auto-generated by build.rs into materials_generated.wgsl.
// vs_main is in common.wgsl (shared by all pipelines).
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var color = in.color;
let fw = length(vec2(dpdx(in.logical.x), dpdy(in.logical.y)));
// ── High-Fidelity SDF Clipping ───────────────────────────────────────
let p_clip_pos = in.clip.xy * scene.scale_factor;
let p_clip_size = in.clip.zw * scene.scale_factor;
let pixel_pos = (in.clip_position.xy * 0.5 + 0.5) * scene.resolution * scene.scale_factor;
let clip_d = sd_box(pixel_pos - (p_clip_pos + p_clip_size * 0.5), p_clip_size * 0.5);
var clip_alpha = 1.0 - smoothstep(-1.0, 1.0, clip_d);
if (in.clip.z > 15000.0) { clip_alpha = 1.0; }
color.a *= clip_alpha;
// Geometric Slice (Mjolnir Slice)
if (in.slice.z > 0.5) {
let angle_rad = in.slice.x * 0.01745329251;
let normal_dir = vec2<f32>(cos(angle_rad), sin(angle_rad));
let dist = dot(in.world_pos, normal_dir) - in.slice.y;
if (dist > 0.0) { discard; }
}
// ── Material Dispatch ────────────────────────────────────────────────
// Calls the appropriate material function based on material_id.
// Material functions are auto-generated from MaterialGraph definitions.
color = dispatch_material(in.material_id, in, color);
// ── Berserker Rage Effect (applied to all materials) ─────────────────
let rage = scene.berzerker_rage;
if rage > 0.05 {
let noise_coord = in.logical * 0.05 + vec2(scene.time * 0.5);
let n = fbm(noise_coord);
let pulse = 0.5 + 0.5 * sin(scene.time * 10.0 * rage);
let rage_color = mix(theme.ember_core, theme.shatter_neon, pulse * 0.3);
color = mix(color, rage_color, n * rage * 0.7);
if rage > 0.8 {
color.r *= 1.1;
color.b *= 0.9;
}
}
if color.a <= 0.0 { discard; }
return color;
}