Galactica/crates/render/shaders/radialbar.wgsl

111 lines
3.1 KiB
Plaintext

// INCLUDE: global uniform header
struct InstanceInput {
@location(2) anchor: u32,
@location(3) position: vec2<f32>,
@location(4) diameter: f32,
@location(5) stroke: f32,
@location(6) angle: f32,
@location(7) color: vec4<f32>,
};
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) texture_coords: vec2<f32>,
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(2) center: vec2<f32>,
@location(3) diameter: f32,
@location(4) stroke: f32,
@location(5) angle: f32,
@location(6) color: vec4<f32>,
};
@group(0) @binding(0)
var texture_array: binding_array<texture_2d<f32>>;
@group(0) @binding(1)
var sampler_array: binding_array<sampler>;
// INCLUDE: anchor.wgsl
@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;
// 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<f32> {
// 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 = 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;
}