From 34c0065c2d200a0a0dcec7ea7f82421a4fabb4f5 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 8 Jan 2024 15:17:05 -0800 Subject: [PATCH] Added radialbar shader --- crates/render/shaders/radialbar.wgsl | 109 +++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 crates/render/shaders/radialbar.wgsl diff --git a/crates/render/shaders/radialbar.wgsl b/crates/render/shaders/radialbar.wgsl new file mode 100644 index 0000000..0c6176e --- /dev/null +++ b/crates/render/shaders/radialbar.wgsl @@ -0,0 +1,109 @@ +// INCLUDE: global uniform header + +struct InstanceInput { + @location(2) anchor: u32, + @location(3) position: vec2, + @location(4) diameter: f32, + @location(5) stroke: f32, + @location(6) angle: f32, + @location(7) color: vec4, +}; + +struct VertexInput { + @location(0) position: vec3, + @location(1) texture_coords: vec2, +}; + +struct VertexOutput { + @builtin(position) position: vec4, + @location(2) center: vec2, + @location(3) diameter: f32, + @location(4) stroke: f32, + @location(5) angle: f32, + @location(6) color: vec4, +}; + + +@group(0) @binding(0) +var texture_array: binding_array>; +@group(0) @binding(1) +var sampler_array: binding_array; + +@vertex +fn vertex_main( + vertex: VertexInput, + instance: InstanceInput, +) -> VertexOutput { + var out: VertexOutput; + out.position = vec4(vertex.position, 1.0); + out.diameter = instance.diameter; + out.stroke = instance.stroke; + out.color = instance.color; + out.angle = instance.angle; + + // Center of this radial bar, in logical pixels, + // with (0, 0) at the center of the screen. + if instance.anchor == u32(0) { + out.center = instance.position + ( + (global_data.window_size / global_data.window_scale.x) + - vec2(instance.diameter, instance.diameter) + ) / 2.0; + } else { + out.center = vec2(0.0, 0.0); + } + + return out; +} + +@fragment +fn fragment_main(in: VertexOutput) -> @location(0) vec4 { + // Fragment position in logical pixels, relative to arc center + let p = ( + vec2(1.0, -1.0) * + (in.position.xy - global_data.window_size / 2.0) / + global_data.window_scale.x + ) - in.center; + + let bar_width = in.stroke; // Width of filled bar + let bar_radius = in.diameter / 2.0 - bar_width / 2.0; // Middle radius of the bar + let angle = in.angle - floor(in.angle / 6.283) * 6.28318; // Sanely handle large angles (fmod(angle, 2pi)) + let zero_vector = vec2(0.0, 1.0); // Draw bar clockwise from this vector + let frag_radius = distance(vec2(0.0, 0.0), p); // Radius of this fragment + let feather = 2.0; // Size of feather, in logical pixels + + // Clockwise angle between zero_vector and fragment location + let frag_angle = atan2( + p.y*zero_vector.x - p.x*zero_vector.y, + -dot(p, zero_vector) + ) + 3.14159; + + + // Line fill & feather + if abs(frag_radius - bar_radius) <= bar_width / 2.0 && frag_angle <= angle { + let x = (abs(frag_radius - bar_radius) - (bar_width/2.0 - feather)) / feather; + return in.color * vec4(1.0, 1.0, 1.0, clamp(1.0 - x, 0.0, 1.0)); + } + + // Round cap centers + let cap_start_center = zero_vector * (in.diameter / 2.0 - (bar_width / 2.0)); + let cap_end_center = mat2x2( + vec2(cos(-angle), sin(-angle)), + vec2(-sin(-angle), cos(-angle)) + ) * cap_start_center; + + // Cap fill & feather + let cap_start_d = distance(p, cap_start_center); + let cap_end_d = distance(p, cap_end_center); + if ( + cap_start_d <= bar_width / 2.0 || + cap_end_d <= bar_width / 2.0 + ) { + let x = ( + min(cap_start_d, cap_end_d) + - (bar_width/2.0 - feather) + ) / feather; + return in.color * vec4(1.0, 1.0, 1.0, clamp(1.0 - x, 0.0, 1.0)); + } + + discard; +} \ No newline at end of file