rustial-renderer-wgpu 0.0.1

Pure WGPU renderer for the rustial 2.5D map engine
Documentation
// ---------------------------------------------------------------------------
// Line-pattern shader — textured line rendering with repeating pattern.
//
// Extends the solid line shader with a pattern texture sampled at per-vertex
// UVs.  U maps along the line centreline, V maps across the line width.
// Retains dash-pattern evaluation, SDF cap/join AA, and horizon fog.
// ---------------------------------------------------------------------------

struct Uniforms {
    view_proj:   mat4x4<f32>,
    fog_color:   vec4<f32>,
    eye_pos:     vec4<f32>,
    fog_params:  vec4<f32>,   // (start, end, density, 0)
    line_style:  vec4<f32>,   // (dash_length, gap_length, cap_round, 0)
};

struct LinePatternVertexInput {
    @location(0) position:      vec3<f32>,
    @location(1) color:         vec4<f32>,
    @location(2) line_normal:   vec2<f32>,
    @location(3) line_distance: f32,
    @location(4) cap_join:      f32,
    @location(5) uv:            vec2<f32>,
};

struct LinePatternVertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) color:         vec4<f32>,
    @location(1) world_pos:     vec3<f32>,
    @location(2) line_distance: f32,
    @location(3) line_normal:   vec2<f32>,
    @location(4) cap_join:      f32,
    @location(5) uv:            vec2<f32>,
};

@group(0) @binding(0)
var<uniform> u: Uniforms;

@group(1) @binding(0)
var pattern_texture: texture_2d<f32>;

@group(1) @binding(1)
var pattern_sampler: sampler;

@vertex
fn vs_main(in: LinePatternVertexInput) -> LinePatternVertexOutput {
    var out: LinePatternVertexOutput;
    out.clip_position = u.view_proj * vec4<f32>(in.position, 1.0);
    out.color = in.color;
    out.world_pos = in.position;
    out.line_distance = in.line_distance;
    out.line_normal = in.line_normal;
    out.cap_join = in.cap_join;
    out.uv = in.uv;
    return out;
}

@fragment
fn fs_main(in: LinePatternVertexOutput) -> @location(0) vec4<f32> {
    // Sample the repeating pattern texture.
    let pattern_color = textureSample(pattern_texture, pattern_sampler, in.uv);

    // --- Dash pattern (optional) ---
    let dash_len = u.line_style.x;
    let gap_len  = u.line_style.y;
    let cycle = dash_len + gap_len;

    var alpha = pattern_color.a;

    if cycle > 0.0 {
        let d = in.line_distance % cycle;
        if d > dash_len {
            discard;
        }
        let edge_aa = 0.5;
        let dash_edge = smoothstep(0.0, edge_aa, d) *
                        smoothstep(0.0, edge_aa, dash_len - d);
        alpha *= dash_edge;
    }

    // --- Edge antialiasing ---
    let edge_dist = length(in.line_normal);

    if in.cap_join > 0.5 {
        // SDF circle AA for round cap/join regions.
        if edge_dist > 1.0 {
            discard;
        }
        let sdf_aa = smoothstep(1.0, 0.92, edge_dist);
        alpha *= sdf_aa;
    } else {
        // Linear edge AA for ribbon body.
        let ribbon_aa = smoothstep(1.0, 0.95, edge_dist);
        alpha *= ribbon_aa;
    }

    // --- 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 blended_rgb = mix(pattern_color.rgb, u.fog_color.rgb, fog_mix);
    return vec4<f32>(blended_rgb, alpha * (1.0 - fog_mix));
}