// 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; // INCLUDE: anchor.wgsl @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. out.center = anchor( instance.anchor, instance.position, vec2(instance.diameter, instance.diameter) ) / 2.0 * (global_data.window_size / global_data.window_scale.x); // ^ slight correction, since anchor gives us a different result than we need here 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; }