// INCLUDE: global uniform header struct InstanceInput { @location(2) position: vec2, @location(3) diameter: f32, @location(4) stroke: f32, @location(5) angle: f32, @location(6) 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; // TODO: adjust position out.position = vec4(vertex.position, 1.0); out.diameter = instance.diameter; out.stroke = instance.stroke; out.color = instance.color; out.angle = instance.angle; let window_dim = ( vec2(global_data.window_size_w, global_data.window_size_h) / global_data.window_scale ); // Center of this radial bar, in logical pixels, // with (0, 0) at the center of the screen. out.center = (instance.position / window_dim) * ( vec2(global_data.window_size_w, global_data.window_size_h) / global_data.window_scale ); 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 - vec2(global_data.window_size_w, global_data.window_size_h) / 2.0 ) / global_data.window_scale ) - 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 = clamp(0.001, 6.28318 + 0.001, in.angle); // Sanely handle extreme angles 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; }