| pub const BG_VERTEX: &str = r#" |
| struct BgInstance { |
| col: u32, row: u32, |
| bg_r: u32, bg_g: u32, bg_b: u32, bg_a: u32, |
| }; |
| @group(0) @binding(0) |
| var<storage, read> instances: array<BgInstance>; |
| |
| struct Uniforms { |
| cell_width: f32, cell_height: f32, |
| screen_cols: u32, screen_rows: u32, |
| }; |
| @group(0) @binding(1) |
| var<uniform> uniforms: Uniforms; |
| |
| struct VertexOutput { |
| @builtin(position) position: vec4<f32>, |
| @location(0) color: vec4<f32>, |
| }; |
| |
| @vertex |
| fn main(@builtin(vertex_index) vertex_idx: u32, @builtin(instance_index) instance_idx: u32) -> VertexOutput { |
| let cell = instances[instance_idx]; |
| var corners = array<vec2<f32>, 6>( |
| vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 0.0), vec2<f32>(0.0, 1.0), |
| vec2<f32>(0.0, 1.0), vec2<f32>(1.0, 0.0), vec2<f32>(1.0, 1.0), |
| ); |
| let corner = corners[vertex_idx]; |
| let x = (f32(cell.col) + corner.x) * uniforms.cell_width; |
| let y = (f32(cell.row) + corner.y) * uniforms.cell_height; |
| let screen_w = f32(uniforms.screen_cols) * uniforms.cell_width; |
| let screen_h = f32(uniforms.screen_rows) * uniforms.cell_height; |
| let ndc_x = (x / screen_w) * 2.0 - 1.0; |
| let ndc_y = -((y / screen_h) * 2.0 - 1.0); |
| var out: VertexOutput; |
| out.position = vec4<f32>(ndc_x, ndc_y, 0.0, 1.0); |
| out.color = vec4<f32>(f32(cell.bg_r) / 255.0, f32(cell.bg_g) / 255.0, f32(cell.bg_b) / 255.0, f32(cell.bg_a) / 255.0); |
| return out; |
| } |
| "#; |
|
|
| pub const BG_FRAGMENT: &str = r#" |
| struct VertexOutput { |
| @builtin(position) position: vec4<f32>, |
| @location(0) color: vec4<f32>, |
| }; |
| @fragment |
| fn main(in: VertexOutput) -> @location(0) vec4<f32> { |
| return in.color; |
| } |
| "#; |
|
|
| pub const TEXT_VERTEX: &str = r#" |
| struct TextInstance { |
| col: f32, row: f32, |
| bearing_x: f32, bearing_y: f32, |
| glyph_w: f32, glyph_h: f32, |
| atlas_x: f32, atlas_y: f32, |
| atlas_w: f32, atlas_h: f32, |
| fg_r: u32, fg_g: u32, fg_b: u32, |
| flags: u32, thickening: f32, |
| }; |
| @group(0) @binding(0) |
| var<storage, read> instances: array<TextInstance>; |
| |
| struct Uniforms { |
| cell_width: f32, cell_height: f32, |
| atlas_size: f32, |
| screen_cols: u32, screen_rows: u32, |
| }; |
| @group(0) @binding(1) |
| var<uniform> uniforms: Uniforms; |
| |
| struct VertexOutput { |
| @builtin(position) position: vec4<f32>, |
| @location(0) uv: vec2<f32>, |
| @location(1) fg_color: vec4<f32>, |
| @location(2) atlas_uv: vec4<f32>, |
| @location(3) thickening: f32, |
| @location(4) flags: u32, |
| }; |
| |
| @vertex |
| fn main(@builtin(vertex_index) vertex_idx: u32, @builtin(instance_index) instance_idx: u32) -> VertexOutput { |
| let cell = instances[instance_idx]; |
| var corners = array<vec2<f32>, 6>( |
| vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 0.0), vec2<f32>(0.0, 1.0), |
| vec2<f32>(0.0, 1.0), vec2<f32>(1.0, 0.0), vec2<f32>(1.0, 1.0), |
| ); |
| let corner = corners[vertex_idx]; |
| let x = (cell.col * uniforms.cell_width) + cell.bearing_x + corner.x * cell.glyph_w; |
| let y = (cell.row * uniforms.cell_height) + cell.bearing_y + corner.y * cell.glyph_h; |
| let screen_w = f32(uniforms.screen_cols) * uniforms.cell_width; |
| let screen_h = f32(uniforms.screen_rows) * uniforms.cell_height; |
| let ndc_x = (x / screen_w) * 2.0 - 1.0; |
| let ndc_y = -((y / screen_h) * 2.0 - 1.0); |
| var out: VertexOutput; |
| out.position = vec4<f32>(ndc_x, ndc_y, 0.0, 1.0); |
| out.uv = corner; |
| out.fg_color = vec4<f32>(f32(cell.fg_r) / 255.0, f32(cell.fg_g) / 255.0, f32(cell.fg_b) / 255.0, 1.0); |
| let norm = uniforms.atlas_size; |
| out.atlas_uv = vec4<f32>(cell.atlas_x / norm, cell.atlas_y / norm, cell.atlas_w / norm, cell.atlas_h / norm); |
| out.thickening = cell.thickening; |
| out.flags = cell.flags; |
| return out; |
| } |
| "#; |
|
|
| pub const TEXT_FRAGMENT: &str = r#" |
| @group(0) @binding(2) |
| var atlas_sampler: sampler; |
| @group(0) @binding(3) |
| var atlas_texture: texture_2d<f32>; |
| |
| struct VertexOutput { |
| @builtin(position) position: vec4<f32>, |
| @location(0) uv: vec2<f32>, |
| @location(1) fg_color: vec4<f32>, |
| @location(2) atlas_uv: vec4<f32>, |
| @location(3) thickening: f32, |
| @location(4) flags: u32, |
| }; |
| |
| fn median(r: f32, g: f32, b: f32) -> f32 { |
| return max(min(r, g), min(max(r, g), b)); |
| } |
| |
| @fragment |
| fn main(in: VertexOutput) -> @location(0) vec4<f32> { |
| let atlas_pos = vec2<f32>( |
| in.atlas_uv.x + in.uv.x * in.atlas_uv.z, |
| in.atlas_uv.y + in.uv.y * in.atlas_uv.w, |
| ); |
| let sample = textureSample(atlas_texture, atlas_sampler, atlas_pos); |
| let sig_dist = median(sample.r, sample.g, sample.b); |
| let threshold = 0.5 - in.thickening * 0.15; |
| let smoothing = 0.05; |
| let opacity = smoothstep(threshold - smoothing, threshold + smoothing, sig_dist); |
| let is_colored = (in.flags & 0x0040u) != 0u; |
| if is_colored { |
| return vec4<f32>(sample.rgb, opacity); |
| } else { |
| return vec4<f32>(in.fg_color.rgb, opacity); |
| } |
| } |
| "#; |
|
|