diff --git a/crates/render/shaders/ui.wgsl b/crates/render/shaders/ui.wgsl index ce88b39..7a71cf5 100644 --- a/crates/render/shaders/ui.wgsl +++ b/crates/render/shaders/ui.wgsl @@ -7,6 +7,7 @@ struct InstanceInput { @location(5) size: f32, @location(6) color_transform: vec4, @location(7) sprite_index: u32, + @location(8) mask_index: vec2, }; struct VertexInput { @@ -18,7 +19,9 @@ struct VertexOutput { @builtin(position) position: vec4, @location(0) texture_coords: vec2, @location(1) texture_index: u32, - @location(2) color_transform: vec4, + @location(2) mask_coords: vec2, + @location(3) mask_index: vec2, + @location(4) color_transform: vec4, } @group(0) @binding(0) @@ -72,7 +75,7 @@ fn vertex_main( - // TODO: animate + // TODO: function to get texture from sprite // Pick texture frame let t = global_atlas[u32(animate(instance.sprite_index, global_data.current_time.x, 0.0))]; out.texture_index = u32(t.atlas_texture); @@ -84,16 +87,55 @@ fn vertex_main( out.texture_coords = vec2(out.texture_coords.x, out.texture_coords.y + t.height); } + // Pick mask image if mask is enabled + // x coordinate of mask index is either 0 or 1, telling us whether or not to use a mask. + // y coordinate is mask sprite index + if instance.mask_index.x == 1u { + let ms = global_sprites[instance.mask_index.y].first_frame; + let m = global_atlas[ms]; + out.mask_index = vec2(1u, u32(m.atlas_texture)); + out.mask_coords = vec2(m.xpos, m.ypos); + if vertex.texture_coords.x == 1.0 { + out.mask_coords = vec2(out.mask_coords.x + m.width, out.mask_coords.y); + } + if vertex.texture_coords.y == 1.0 { + out.mask_coords = vec2(out.mask_coords.x, out.mask_coords.y + m.height); + } + } else { + out.mask_coords = vec2(0.0, 0.0); + out.mask_index = vec2(0u, 0u); + } + + return out; } @fragment fn fragment_main(in: VertexOutput) -> @location(0) vec4 { - return textureSampleLevel( + + var mask: f32 = 1.0; + if in.mask_index.x == 1u { + mask = textureSampleLevel( + texture_array[in.mask_index.y], + sampler_array[0], + in.mask_coords, + 0.0 + ).a; + } + + var color: vec4 = textureSampleLevel( texture_array[in.texture_index], sampler_array[0], in.texture_coords, 0.0 ).rgba * in.color_transform; + + // Apply mask and discard fully transparent pixels + color = vec4(color.rgb, color.a *mask); + if color.a == 0.0 { + discard; + } + + return color; } \ No newline at end of file diff --git a/crates/render/src/ui/radar.rs b/crates/render/src/ui/radar.rs index aebfebc..0c9e307 100644 --- a/crates/render/src/ui/radar.rs +++ b/crates/render/src/ui/radar.rs @@ -68,6 +68,7 @@ impl Radar { size: radar_size, color: [1.0, 1.0, 1.0, 1.0], sprite_index: input.ct.get_sprite_handle("ui::radar").get_index(), + mask_index: [0, 0], }); // Draw system objects @@ -96,6 +97,7 @@ impl Radar { size, color: [0.5, 0.5, 0.5, 1.0], sprite_index: planet_sprite.get_index(), + mask_index: [0, 0], }) }; } @@ -149,6 +151,7 @@ impl Radar { size, color, sprite_index: ship_sprite.get_index(), + mask_index: [0, 0], }); } } @@ -176,6 +179,7 @@ impl Radar { size, color, sprite_index: sprite.get_index(), + mask_index: [0, 0], }); state.push_ui_buffer(UiInstance { @@ -189,6 +193,7 @@ impl Radar { size, color, sprite_index: sprite.get_index(), + mask_index: [0, 0], }); state.push_ui_buffer(UiInstance { @@ -202,6 +207,7 @@ impl Radar { size, color, sprite_index: sprite.get_index(), + mask_index: [0, 0], }); state.push_ui_buffer(UiInstance { @@ -215,6 +221,7 @@ impl Radar { size, color, sprite_index: sprite.get_index(), + mask_index: [0, 0], }); } @@ -233,6 +240,7 @@ impl Radar { size: 10.0, color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)], sprite_index: arrow_sprite.get_index(), + mask_index: [0, 0], }); } } diff --git a/crates/render/src/ui/status.rs b/crates/render/src/ui/status.rs index 7f41612..175751c 100644 --- a/crates/render/src/ui/status.rs +++ b/crates/render/src/ui/status.rs @@ -52,6 +52,7 @@ impl Status { size: 200.0, color: [1.0, 1.0, 1.0, 1.0], sprite_index: input.ct.get_sprite_handle("ui::status").get_index(), + mask_index: [0, 0], }); state.push_radialbar_buffer(RadialBarInstance { diff --git a/crates/render/src/vertexbuffer/types.rs b/crates/render/src/vertexbuffer/types.rs index 0551340..0fcfb7e 100644 --- a/crates/render/src/vertexbuffer/types.rs +++ b/crates/render/src/vertexbuffer/types.rs @@ -140,6 +140,11 @@ pub struct UiInstance { /// What texture to use for this sprite pub sprite_index: u32, + + /// What mask to use for this sprite + /// If the first element is not 1, no mask is used. + /// Second element is sprite index of mask. + pub mask_index: [u32; 2], } impl BufferObject for UiInstance { @@ -187,6 +192,12 @@ impl BufferObject for UiInstance { shader_location: 7, format: wgpu::VertexFormat::Uint32, }, + // Mask + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 10]>() as wgpu::BufferAddress, + shader_location: 8, + format: wgpu::VertexFormat::Uint32x2, + }, ], } }