ryot 0.2.2

MMORPG library based on the concepts of open tibia written in rust and bevy.
Documentation
#import bevy_sprite::mesh2d_view_bindings::globals
struct SpriteMaterial {
    index: u32,
    counts: vec2<f32>,
    outline_thickness: f32,
    outline_color: vec4<f32>,
    tint: vec4<f32>,
    alpha: f32,
};
@group(2) @binding(0)
var<uniform> material: SpriteMaterial;
@group(2) @binding(1)
var texture: texture_2d<f32>;
@group(2) @binding(2)
var texture_sampler: sampler;


fn get_sample(
    probe: vec2<f32>
) -> vec4<f32> {
    return textureSample(texture, texture_sampler, probe);
}

#import bevy_pbr::forward_io::VertexOutput
@fragment
fn fragment(
    in: VertexOutput,
) -> @location(0) vec4<f32> {
    // This assumes the bottom center of the mesh.
    let centered_uv = (in.uv - vec2<f32>(0.25, 0.25));

    let uv = vec2<f32>(centered_uv.x * 2.0, centered_uv.y * 2.0);
    let ux = uv.x / material.counts.x;
    let uy = uv.y / material.counts.y;
    let cuv = vec2(ux, uy);
    let thickness = material.outline_thickness / 1000.;

    let base = pixel(vec2(0., 0.), cuv, vec2(0., 0.));

    var outline_alpha : f32 = 0.;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(thickness, 0.)).a;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(-thickness, 0.)).a;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(0., thickness)).a;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(0., -thickness)).a;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(thickness, -thickness)).a;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(-thickness, thickness)).a;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(thickness, thickness)).a;
    outline_alpha += pixel(vec2(0., 0.), cuv, vec2(-thickness, -thickness)).a;
    outline_alpha = min(outline_alpha, 1.0);

    let outline_color = material.outline_color * vec4<f32>(1.0, 1.0, 1.0, outline_alpha);
    let lower = vec2<f32>(0.25, 0.25);
    let upper = vec2<f32>(0.75, 0.75);
    let lower_thickness = lower - vec2<f32>(thickness, thickness);
    let upper_thickness = upper + vec2<f32>(thickness, thickness);

    if (in.uv.x < lower_thickness.x || in.uv.x > upper_thickness.x) {
        discard;
    }

    if (in.uv.y < lower_thickness.y || in.uv.y > upper_thickness.y) {
        discard;
    }

    if (in.uv.x < lower.x || in.uv.x > upper.x) {
        return outline_color;
    }

    if (in.uv.y < lower.y || in.uv.y > upper.y) {
        return outline_color;
    }

    var outlined = mix(base, outline_color, outline_alpha - base.a);
    var tinted = mix(outlined, vec4<f32>(outlined.rgb * material.tint.rgb, outlined.a), material.tint.a);
    tinted.a *= material.alpha;
    return tinted;
}

fn pixel(offset: vec2<f32>, uv: vec2<f32>, adjustment: vec2<f32>) -> vec4<f32> {
    let base_uv = uv_offset(offset, vec2<f32>(0, 0));
    // Use a small inset to avoid sampling the borders
    let inset = 0.001;

    // Calculate inset boundaries for the sprite to avoid texture bleeding
    let sprite_size = vec2<f32>(1.0 / material.counts.x, 1.0 / material.counts.y);
    let min_uv = base_uv + vec2<f32>(inset) * sprite_size;
    let max_uv = base_uv + sprite_size - vec2<f32>(inset) * sprite_size;

    // Calculate adjusted UV coordinates
    let uv_adjusted = uv_offset(offset, uv) + adjustment;

    // Clamp the adjusted UV coordinates within the inset boundaries of the sprite
    let clamped_uv = clamp(uv_adjusted, min_uv, max_uv);

    // Sample the texture using the clamped UV coordinates
    return get_sample(clamped_uv);
}

fn uv_offset(offset: vec2<f32>, uv: vec2<f32>) -> vec2<f32> {
    let uvx = uv.x + (f32(material.index % u32(material.counts.x)) + offset.x) / material.counts.x;
    let uvy = uv.y + (f32(material.index / u32(material.counts.y)) + offset.y) / material.counts.y;
    return vec2(uvx, uvy);
}