rustial-renderer-wgpu 0.0.1

Pure WGPU renderer for the rustial 2.5D map engine
Documentation
// SDF symbol / text rendering shader.
//
// Renders glyphs from an SDF atlas texture.  The signed distance field
// encodes the distance from the glyph edge: values > 0.5 are inside,
// values < 0.5 are outside.  The fragment shader thresholds the SDF to
// produce crisp, resolution-independent text with optional halo.

struct Uniforms {
    view_proj:  mat4x4<f32>,
    fog_color:  vec4<f32>,
    eye_pos:    vec4<f32>,
    fog_params: vec4<f32>,
};

struct SymbolVertexInput {
    @location(0) position:     vec3<f32>,
    @location(1) glyph_offset: vec2<f32>,
    @location(2) tex_coord:    vec2<f32>,
    @location(3) color:        vec4<f32>,
    @location(4) halo_color:   vec4<f32>,
    @location(5) params:       vec4<f32>,  // (halo_width, gamma_scale, 0, 0)
};

struct SymbolVertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) tex_coord:    vec2<f32>,
    @location(1) color:        vec4<f32>,
    @location(2) halo_color:   vec4<f32>,
    @location(3) params:       vec4<f32>,
    @location(4) world_pos:    vec3<f32>,
};

@group(0) @binding(0) var<uniform> u: Uniforms;
@group(1) @binding(0) var sdf_atlas:   texture_2d<f32>;
@group(1) @binding(1) var sdf_sampler: sampler;

@vertex
fn vs_main(in: SymbolVertexInput) -> SymbolVertexOutput {
    let world = in.position + vec3<f32>(in.glyph_offset, 0.0);

    var out: SymbolVertexOutput;
    out.clip_position = u.view_proj * vec4<f32>(world, 1.0);
    out.tex_coord = in.tex_coord;
    out.color = in.color;
    out.halo_color = in.halo_color;
    out.params = in.params;
    out.world_pos = in.position;
    return out;
}

@fragment
fn fs_main(in: SymbolVertexOutput) -> @location(0) vec4<f32> {
    let sdf = textureSample(sdf_atlas, sdf_sampler, in.tex_coord).r;
    let halo_width = in.params.x;
    let gamma = in.params.y;

    // SDF thresholding: 0.5 is the glyph edge.
    let edge = 0.5;
    let aa = gamma * 0.707;  // ~1/sqrt(2) pixel-width anti-aliasing.

    // Halo: expand the glyph outline outward.
    let halo_edge = edge - halo_width;
    let halo_alpha = smoothstep(halo_edge - aa, halo_edge + aa, sdf);
    let fill_alpha = smoothstep(edge - aa, edge + aa, sdf);

    // Composite halo behind fill.
    let halo_rgb = in.halo_color.rgb * in.halo_color.a * halo_alpha * (1.0 - fill_alpha);
    let fill_rgb = in.color.rgb * in.color.a * fill_alpha;
    let combined_rgb = fill_rgb + halo_rgb;
    let combined_a = fill_alpha * in.color.a + halo_alpha * in.halo_color.a * (1.0 - fill_alpha);

    if combined_a < 0.005 {
        discard;
    }

    // --- Horizon fog ---
    let dx = in.world_pos.x - u.eye_pos.x;
    let dy = in.world_pos.y - u.eye_pos.y;
    let ground_dist = sqrt(dx * dx + dy * dy);
    let fog_start = u.fog_params.x;
    let fog_end   = u.fog_params.y;
    let density   = u.fog_params.z;
    let fog_t = clamp(
        (ground_dist - fog_start) / max(fog_end - fog_start, 0.001),
        0.0, 1.0,
    ) * density;
    let fog_mix = fog_t * 0.7;

    let final_rgb = mix(combined_rgb / max(combined_a, 0.001), u.fog_color.rgb, fog_mix);
    return vec4<f32>(final_rgb, combined_a * (1.0 - fog_mix));
}