Skip to main content

SDF_GLYPH_FRAG

Constant SDF_GLYPH_FRAG 

Source
pub const SDF_GLYPH_FRAG: &str = "// sdf_glyph.frag \u{2014} SDF glyph fragment shader\r\n//\r\n// Renders signed distance field glyphs with:\r\n//   - Razor-sharp edges at any scale via smoothstep on the distance field\r\n//   - Optional outline effect (second smoothstep at wider threshold)\r\n//   - Optional drop shadow (UV-offset SDF sample)\r\n//   - Optional glow (distance field as glow intensity)\r\n//   - Bold mode (threshold shift)\r\n//   - UV distortion effects (wave, shake, glitch)\r\n//   - Dual output: color + emission for bloom pipeline\r\n\r\n#version 330 core\r\n\r\nin vec2  f_uv;\r\nin vec4  f_color;\r\nin float f_emission;\r\nin vec3  f_glow_color;\r\nin float f_glow_radius;\r\nin vec2  f_screen_pos;\r\nin float f_scale_factor;\r\n\r\nuniform sampler2D u_sdf_atlas;\r\n\r\n// SDF parameters\r\nuniform float u_threshold;       // typically 0.5\r\nuniform float u_smoothing;       // typically 0.05, auto-adjusted by scale\r\nuniform float u_time;\r\n\r\n// Outline\r\nuniform float u_outline_enabled; // 0.0 or 1.0\r\nuniform float u_outline_width;   // in SDF-space (0.0 to ~0.2)\r\nuniform vec4  u_outline_color;\r\n\r\n// Shadow\r\nuniform float u_shadow_enabled;\r\nuniform float u_shadow_softness;\r\nuniform vec2  u_shadow_uv_offset;\r\nuniform vec4  u_shadow_color;\r\n\r\n// Glow\r\nuniform float u_glow_enabled;\r\nuniform float u_glow_sdf_radius; // in SDF-space\r\nuniform vec4  u_glow_color_param;\r\n\r\n// Distortion\r\nuniform float u_wave_amplitude;\r\nuniform float u_wave_frequency;\r\nuniform float u_shake_amount;\r\nuniform float u_glitch_intensity;\r\n\r\nlayout(location = 0) out vec4 o_color;\r\nlayout(location = 1) out vec4 o_emission;\r\n\r\n// Pseudo-random hash for glitch/shake effects.\r\nfloat hash(vec2 p) {\r\n    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);\r\n}\r\n\r\nvoid main() {\r\n    vec2 uv = f_uv;\r\n\r\n    // \u{2500}\u{2500} UV Distortion effects \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    if (u_wave_amplitude > 0.0) {\r\n        uv.y += sin(uv.x * u_wave_frequency + u_time * 3.0) * u_wave_amplitude * 0.01;\r\n        uv.x += cos(uv.y * u_wave_frequency * 0.7 + u_time * 2.5) * u_wave_amplitude * 0.005;\r\n    }\r\n\r\n    if (u_shake_amount > 0.0) {\r\n        float shake = u_shake_amount * 0.01;\r\n        uv.x += (hash(f_screen_pos + u_time) - 0.5) * shake;\r\n        uv.y += (hash(f_screen_pos + u_time + 1.0) - 0.5) * shake;\r\n    }\r\n\r\n    if (u_glitch_intensity > 0.0) {\r\n        float glitch_line = step(0.95, hash(vec2(floor(f_screen_pos.y * 0.1), u_time * 10.0)));\r\n        uv.x += glitch_line * u_glitch_intensity * 0.05 * (hash(vec2(u_time * 100.0, f_screen_pos.y)) - 0.5);\r\n    }\r\n\r\n    // \u{2500}\u{2500} SDF sampling \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    float distance = texture(u_sdf_atlas, uv).r;\r\n\r\n    // Adaptive smoothing: sharper at large sizes, softer at small sizes.\r\n    float smoothing = u_smoothing;\r\n    if (f_scale_factor > 0.0) {\r\n        smoothing = clamp(0.25 / f_scale_factor, 0.001, 0.25);\r\n    }\r\n\r\n    float threshold = u_threshold;\r\n\r\n    // \u{2500}\u{2500} Glyph alpha (the core SDF operation) \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    float alpha = smoothstep(threshold - smoothing, threshold + smoothing, distance);\r\n\r\n    // \u{2500}\u{2500} Drop shadow \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    vec4 final_color = vec4(0.0);\r\n\r\n    if (u_shadow_enabled > 0.5) {\r\n        float shadow_dist = texture(u_sdf_atlas, uv + u_shadow_uv_offset).r;\r\n        float shadow_smooth = smoothing + u_shadow_softness;\r\n        float shadow_alpha = smoothstep(threshold - shadow_smooth, threshold + shadow_smooth, shadow_dist);\r\n        final_color = u_shadow_color * shadow_alpha;\r\n    }\r\n\r\n    // \u{2500}\u{2500} Glow (distance-based) \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    if (u_glow_enabled > 0.5) {\r\n        float glow_outer = threshold - u_glow_sdf_radius;\r\n        float glow_alpha = smoothstep(glow_outer - smoothing, threshold, distance);\r\n        vec4 glow_contrib = u_glow_color_param * glow_alpha * (1.0 - alpha);\r\n        final_color = mix(final_color, glow_contrib, glow_contrib.a);\r\n    }\r\n\r\n    // \u{2500}\u{2500} Outline \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    if (u_outline_enabled > 0.5) {\r\n        float outline_outer = threshold - u_outline_width;\r\n        float outline_alpha = smoothstep(outline_outer - smoothing, outline_outer + smoothing, distance);\r\n        // Outline is visible where outline_alpha > 0 but alpha == 0 (between outline and glyph).\r\n        float outline_mask = outline_alpha * (1.0 - alpha);\r\n        vec4 outline_contrib = vec4(u_outline_color.rgb, u_outline_color.a * outline_mask);\r\n        final_color = mix(final_color, outline_contrib, outline_mask);\r\n    }\r\n\r\n    // \u{2500}\u{2500} Main glyph color \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    vec4 glyph_color = f_color * alpha;\r\n    final_color = mix(final_color, glyph_color, alpha);\r\n\r\n    if (final_color.a < 0.01) discard;\r\n\r\n    o_color = final_color;\r\n\r\n    // \u{2500}\u{2500} Emission for bloom \u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\r\n    float bloom_strength = clamp(f_emission - 0.3, 0.0, 1.0);\r\n    float glow_boost = clamp(f_glow_radius * 0.15, 0.0, 0.8);\r\n    o_emission = vec4(f_glow_color * (bloom_strength + glow_boost), final_color.a);\r\n}\r\n";