rustraight 0.5.2

A simple 2D game library for Rust, inspired by DXLib
// shaders.rs — レンダリングで使う WGSL シェーダーソースを定数として定義する。

// screen_texture(ストレートアルファ)をスワップチェーンへ乗算済みアルファとしてブリットする。
// sRGB スワップチェーン向け: GPU が自動的にガンマ補正を適用するため、
// ALPHA_BLENDING で得たリニア乗算済み RGB をそのまま通す。
pub(super) const BLIT_SHADER: &str = r#"
struct Vout { @builtin(position) pos: vec4<f32>, @location(0) uv: vec2<f32> }
@vertex fn vs(@builtin(vertex_index) vi: u32) -> Vout {
    var p = array<vec2<f32>,6>(vec2(-1.,-1.),vec2(1.,-1.),vec2(-1.,1.),vec2(1.,-1.),vec2(1.,1.),vec2(-1.,1.));
    var u = array<vec2<f32>,6>(vec2(0.,1.),vec2(1.,1.),vec2(0.,0.),vec2(1.,1.),vec2(1.,0.),vec2(0.,0.));
    return Vout(vec4(p[vi],0.,1.), u[vi]);
}
@group(0) @binding(0) var t: texture_2d<f32>;
@group(0) @binding(1) var s: sampler;
@fragment fn fs(in: Vout) -> @location(0) vec4<f32> {
    let c = textureSample(t, s, in.uv);
    return vec4(c.rgb, c.a);
}
"#;

// Bgra8Unorm スワップチェーン向け(transparent=true 時に使用): GPU がガンマ補正を
// 適用しないため、手動で sRGB エンコードする。アルファはそのまま
// (ALPHA_BLENDING 由来のリニア乗算済み RGB が既に正しい乗算済み値のため)。
pub(super) const BLIT_SHADER_UNORM: &str = r#"
struct Vout { @builtin(position) pos: vec4<f32>, @location(0) uv: vec2<f32> }
@vertex fn vs(@builtin(vertex_index) vi: u32) -> Vout {
    var p = array<vec2<f32>,6>(vec2(-1.,-1.),vec2(1.,-1.),vec2(-1.,1.),vec2(1.,-1.),vec2(1.,1.),vec2(-1.,1.));
    var u = array<vec2<f32>,6>(vec2(0.,1.),vec2(1.,1.),vec2(0.,0.),vec2(1.,1.),vec2(1.,0.),vec2(0.,0.));
    return Vout(vec4(p[vi],0.,1.), u[vi]);
}
@group(0) @binding(0) var t: texture_2d<f32>;
@group(0) @binding(1) var s: sampler;
fn lin_to_srgb(x: f32) -> f32 {
    if x <= 0.0031308 { return x * 12.92; }
    return 1.055 * pow(x, 1.0 / 2.4) - 0.055;
}
@fragment fn fs(in: Vout) -> @location(0) vec4<f32> {
    let c = textureSample(t, s, in.uv);
    if c.a < 0.0001 { return vec4(0., 0., 0., 0.); }
    let lin = c.rgb / c.a;
    let srgb = vec3(lin_to_srgb(lin.r), lin_to_srgb(lin.g), lin_to_srgb(lin.b));
    return vec4(srgb * c.a, c.a);
}
"#;

// テクスチャ付き画像の矩形を描画する。マスクによる減衰と頂点ごとのアルファに対応。
pub(super) const SPRITE_SHADER: &str = r#"
struct Vin {
    @location(0) pos:       vec2<f32>,
    @location(1) uv:        vec2<f32>,
    @location(2) screen_xy: vec2<f32>,
    @location(3) mask_ox:   f32,
    @location(4) mask_oy:   f32,
    @location(5) mask_w:    f32,
    @location(6) mask_h:    f32,
    @location(7) mask_on:   f32,
    @location(8) alpha:     f32,
}
struct Vout {
    @builtin(position) clip: vec4<f32>,
    @location(0) uv:        vec2<f32>,
    @location(1) screen_xy: vec2<f32>,
    @location(2) mask_ox:   f32,
    @location(3) mask_oy:   f32,
    @location(4) mask_w:    f32,
    @location(5) mask_h:    f32,
    @location(6) mask_on:   f32,
    @location(7) alpha:     f32,
}
@group(0) @binding(0) var t_image: texture_2d<f32>;
@group(0) @binding(1) var t_mask:   texture_2d<f32>;
@group(0) @binding(2) var s_samp:   sampler;
@vertex fn vs(v: Vin) -> Vout {
    return Vout(vec4(v.pos, 0., 1.), v.uv, v.screen_xy, v.mask_ox, v.mask_oy, v.mask_w, v.mask_h, v.mask_on, v.alpha);
}
@fragment fn fs(in: Vout) -> @location(0) vec4<f32> {
    var c = textureSample(t_image, s_samp, in.uv);
    if in.mask_on > 0.5 {
        let mx = (in.screen_xy.x - in.mask_ox) / in.mask_w;
        let my = (in.screen_xy.y - in.mask_oy) / in.mask_h;
        if mx >= 0. && mx <= 1. && my >= 0. && my <= 1. {
            c.a *= textureSample(t_mask, s_samp, vec2(mx, my)).a;
        } else {
            c.a = 0.;
        }
    }
    c.a *= in.alpha;
    return c;
}
"#;

// オーバーレイ用の画像シェーダー(メインウィンドウからのはみ出し描画):
// メインウィンドウ矩形の内側にあるフラグメントは破棄する。
pub(super) const MASKED_SPRITE_SHADER: &str = r#"
struct Vin {
    @location(0) pos:       vec2<f32>, @location(1) uv:        vec2<f32>,
    @location(2) screen_xy: vec2<f32>, @location(3) mask_ox:   f32,
    @location(4) mask_oy:   f32,       @location(5) mask_w:    f32,
    @location(6) mask_h:    f32,       @location(7) mask_on:   f32,
    @location(8) alpha:     f32,
}
struct Vout {
    @builtin(position) clip: vec4<f32>,
    @location(0) uv:        vec2<f32>, @location(1) screen_xy: vec2<f32>,
    @location(2) mask_ox:   f32,       @location(3) mask_oy:   f32,
    @location(4) mask_w:    f32,       @location(5) mask_h:    f32,
    @location(6) mask_on:   f32,       @location(7) alpha:     f32,
}
@group(0) @binding(0) var t_image: texture_2d<f32>;
@group(0) @binding(1) var t_mask:   texture_2d<f32>;
@group(0) @binding(2) var s_samp:   sampler;
@group(1) @binding(0) var<uniform> main_rect: vec4<f32>; // x,y,w,h in display pixels
@vertex fn vs(v: Vin) -> Vout {
    return Vout(vec4(v.pos,0.,1.), v.uv, v.screen_xy, v.mask_ox, v.mask_oy, v.mask_w, v.mask_h, v.mask_on, v.alpha);
}
@fragment fn fs(in: Vout) -> @location(0) vec4<f32> {
    let p = in.clip.xy;
    if p.x >= main_rect.x && p.x < main_rect.x + main_rect.z
    && p.y >= main_rect.y && p.y < main_rect.y + main_rect.w { discard; }
    var c = textureSample(t_image, s_samp, in.uv);
    if in.mask_on > 0.5 {
        let mx = (in.screen_xy.x - in.mask_ox) / in.mask_w;
        let my = (in.screen_xy.y - in.mask_oy) / in.mask_h;
        if mx >= 0. && mx <= 1. && my >= 0. && my <= 1. {
            c.a *= textureSample(t_mask, s_samp, vec2(mx, my)).a;
        } else { c.a = 0.; }
    }
    c.a *= in.alpha;
    return c;
}
"#;

// オーバーレイ用の単色図形シェーダー: メインウィンドウ矩形の内側にあるフラグメントは破棄する。
pub(super) const MASKED_COLOR_SHADER: &str = r#"
struct Vin  { @location(0) pos: vec2<f32>, @location(1) color: vec4<f32> }
struct Vout { @builtin(position) clip: vec4<f32>, @location(0) color: vec4<f32> }
@group(0) @binding(0) var<uniform> main_rect: vec4<f32>;
@vertex fn vs(v: Vin) -> Vout { return Vout(vec4(v.pos, 0., 1.), v.color); }
@fragment fn fs(in: Vout) -> @location(0) vec4<f32> {
    let p = in.clip.xy;
    if p.x >= main_rect.x && p.x < main_rect.x + main_rect.z
    && p.y >= main_rect.y && p.y < main_rect.y + main_rect.w { discard; }
    return in.color;
}
"#;

// 単色頂点ジオメトリ(塗りつぶし・線・図形)を描画する。
pub(super) const COLOR_SHADER: &str = r#"
struct Vin  { @location(0) pos: vec2<f32>, @location(1) color: vec4<f32> }
struct Vout { @builtin(position) clip: vec4<f32>, @location(0) color: vec4<f32> }
@vertex fn vs(v: Vin) -> Vout { return Vout(vec4(v.pos, 0., 1.), v.color); }
@fragment fn fs(in: Vout) -> @location(0) vec4<f32> { return in.color; }
"#;