struct ScreenUniform {
size: vec2<f32>,
_pad: vec2<f32>,
};
@group(0) @binding(0)
var<uniform> screen: ScreenUniform;
struct InstanceInput {
@location(1) pos: vec2<f32>,
@location(2) size: vec2<f32>,
@location(3) color: vec4<f32>,
// The rectangle of the atlas to sample. An empty one means a flat quad,
// which is what a panel, a button and a glyph all are.
@location(4) uv: vec4<f32>,
};
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) color: vec4<f32>,
@location(1) uv: vec2<f32>,
// Flat: whether this quad is an icon is a property of the instance, and
// interpolating it would give a fraction of an icon at the edges.
@location(2) @interpolate(flat) textured: u32,
};
@group(0) @binding(1)
var atlas: texture_2d<f32>;
@group(0) @binding(2)
var atlas_sampler: sampler;
@vertex
fn vs_main(@location(0) corner: vec2<f32>, instance: InstanceInput) -> VertexOutput {
let pixel_pos = instance.pos + corner * instance.size;
let ndc_x = (pixel_pos.x / screen.size.x) * 2.0 - 1.0;
let ndc_y = 1.0 - (pixel_pos.y / screen.size.y) * 2.0;
var out: VertexOutput;
out.clip_position = vec4<f32>(ndc_x, ndc_y, 0.0, 1.0);
out.color = instance.color;
out.uv = mix(instance.uv.xy, instance.uv.zw, corner);
out.textured = select(0u, 1u, instance.uv.z > instance.uv.x);
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
if in.textured == 0u {
return in.color;
}
// The atlas holds white masks, so the icon's own colour is whatever asked
// for it and the raster only says where the strokes are.
let coverage = textureSample(atlas, atlas_sampler, in.uv).a;
return vec4<f32>(in.color.rgb, in.color.a * coverage);
}