diff options
27 files changed, 146 insertions, 68 deletions
diff --git a/examples/custom_widget/src/main.rs b/examples/custom_widget/src/main.rs index c37a1a12..f6bb3b1e 100644 --- a/examples/custom_widget/src/main.rs +++ b/examples/custom_widget/src/main.rs @@ -61,7 +61,7 @@ mod circle { renderer.fill_quad( renderer::Quad { bounds: layout.bounds(), - border_radius: self.radius, + border_radius: self.radius.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, diff --git a/glow/src/quad/compatibility.rs b/glow/src/quad/compatibility.rs index 28a5ea7c..e909162c 100644 --- a/glow/src/quad/compatibility.rs +++ b/glow/src/quad/compatibility.rs @@ -254,7 +254,7 @@ unsafe fn create_buffers( gl.enable_vertex_attrib_array(4); gl.vertex_attrib_pointer_f32( 4, - 1, + 4, glow::FLOAT, false, stride, @@ -268,7 +268,7 @@ unsafe fn create_buffers( glow::FLOAT, false, stride, - 4 * (2 + 2 + 4 + 4 + 1), + 4 * (2 + 2 + 4 + 4 + 4), ); gl.enable_vertex_attrib_array(6); @@ -278,7 +278,7 @@ unsafe fn create_buffers( glow::FLOAT, false, stride, - 4 * (2 + 2 + 4 + 4 + 1 + 1), + 4 * (2 + 2 + 4 + 4 + 4 + 1), ); gl.bind_vertex_array(None); @@ -307,7 +307,7 @@ pub struct Vertex { pub border_color: [f32; 4], /// The border radius of the [`Vertex`]. - pub border_radius: f32, + pub border_radius: [f32; 4], /// The border width of the [`Vertex`]. pub border_width: f32, diff --git a/glow/src/quad/core.rs b/glow/src/quad/core.rs index 16bec385..89036530 100644 --- a/glow/src/quad/core.rs +++ b/glow/src/quad/core.rs @@ -218,7 +218,7 @@ unsafe fn create_instance_buffer( gl.enable_vertex_attrib_array(4); gl.vertex_attrib_pointer_f32( 4, - 1, + 4, glow::FLOAT, false, stride, @@ -233,7 +233,7 @@ unsafe fn create_instance_buffer( glow::FLOAT, false, stride, - 4 * (2 + 2 + 4 + 4 + 1), + 4 * (2 + 2 + 4 + 4 + 4), ); gl.vertex_attrib_divisor(5, 1); diff --git a/glow/src/shader/compatibility/quad.frag b/glow/src/shader/compatibility/quad.frag index 8ea5693d..bb9d8122 100644 --- a/glow/src/shader/compatibility/quad.frag +++ b/glow/src/shader/compatibility/quad.frag @@ -12,7 +12,7 @@ varying vec4 v_Color; varying vec4 v_BorderColor; varying vec2 v_Pos; varying vec2 v_Scale; -varying float v_BorderRadius; +varying vec4 v_BorderRadius; varying float v_BorderWidth; float _distance(vec2 frag_coord, vec2 position, vec2 size, float radius) @@ -33,10 +33,26 @@ float _distance(vec2 frag_coord, vec2 position, vec2 size, float radius) return sqrt(distance.x * distance.x + distance.y * distance.y); } +float selectBorderRadius(vec4 radi, vec2 position, vec2 center) +{ + float rx = radi.x; + float ry = radi.y; + rx = position.x > center.x ? radi.y : radi.x; + ry = position.x > center.x ? radi.z : radi.w; + rx = position.y > center.y ? ry : rx; + return rx; +} + void main() { vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y); - float internal_border = max(v_BorderRadius - v_BorderWidth, 0.0); + float border_radius = selectBorderRadius( + v_BorderRadius, + fragCoord, + (v_Pos + v_Scale * 0.5).xy + ); + + float internal_border = max(border_radius - v_BorderWidth, 0.0); float internal_distance = _distance( fragCoord, @@ -57,11 +73,11 @@ void main() { fragCoord, v_Pos, v_Scale, - v_BorderRadius + border_radius ); float radius_alpha = - 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d); + 1.0 - smoothstep(max(border_radius - 0.5, 0.0), border_radius + 0.5, d); gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); } diff --git a/glow/src/shader/compatibility/quad.vert b/glow/src/shader/compatibility/quad.vert index abe70c0e..89931f06 100644 --- a/glow/src/shader/compatibility/quad.vert +++ b/glow/src/shader/compatibility/quad.vert @@ -5,7 +5,7 @@ attribute vec2 i_Pos; attribute vec2 i_Scale; attribute vec4 i_Color; attribute vec4 i_BorderColor; -attribute float i_BorderRadius; +attribute vec4 i_BorderRadius; attribute float i_BorderWidth; attribute vec2 q_Pos; @@ -13,7 +13,7 @@ varying vec4 v_Color; varying vec4 v_BorderColor; varying vec2 v_Pos; varying vec2 v_Scale; -varying float v_BorderRadius; +varying vec4 v_BorderRadius; varying float v_BorderWidth; @@ -21,9 +21,11 @@ void main() { vec2 p_Pos = i_Pos * u_Scale; vec2 p_Scale = i_Scale * u_Scale; - float i_BorderRadius = min( - i_BorderRadius, - min(i_Scale.x, i_Scale.y) / 2.0 + vec4 i_BorderRadius = vec4( + min(i_BorderRadius.x, min(i_Scale.x, i_Scale.y) / 2.0), + min(i_BorderRadius.y, min(i_Scale.x, i_Scale.y) / 2.0), + min(i_BorderRadius.z, min(i_Scale.x, i_Scale.y) / 2.0), + min(i_BorderRadius.w, min(i_Scale.x, i_Scale.y) / 2.0) ); mat4 i_Transform = mat4( diff --git a/glow/src/shader/core/quad.frag b/glow/src/shader/core/quad.frag index 57e2e8e7..71147aa5 100644 --- a/glow/src/shader/core/quad.frag +++ b/glow/src/shader/core/quad.frag @@ -17,7 +17,7 @@ in vec4 v_Color; in vec4 v_BorderColor; in vec2 v_Pos; in vec2 v_Scale; -in float v_BorderRadius; +in vec4 v_BorderRadius; in float v_BorderWidth; float fDistance(vec2 frag_coord, vec2 position, vec2 size, float radius) @@ -38,14 +38,30 @@ float fDistance(vec2 frag_coord, vec2 position, vec2 size, float radius) return sqrt(distance.x * distance.x + distance.y * distance.y); } +float selectBorderRadius(vec4 radi, vec2 position, vec2 center) +{ + float rx = radi.x; + float ry = radi.y; + rx = position.x > center.x ? radi.y : radi.x; + ry = position.x > center.x ? radi.z : radi.w; + rx = position.y > center.y ? ry : rx; + return rx; +} + void main() { vec4 mixed_color; vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y); + float border_radius = selectBorderRadius( + v_BorderRadius, + fragCoord, + (v_Pos + v_Scale * 0.5).xy + ); + // TODO: Remove branching (?) if(v_BorderWidth > 0.0) { - float internal_border = max(v_BorderRadius - v_BorderWidth, 0.0); + float internal_border = max(border_radius - v_BorderWidth, 0.0); float internal_distance = fDistance( fragCoord, @@ -69,11 +85,11 @@ void main() { fragCoord, v_Pos, v_Scale, - v_BorderRadius + border_radius ); float radius_alpha = - 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d); + 1.0 - smoothstep(max(border_radius - 0.5, 0.0), border_radius + 0.5, d); gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); } diff --git a/glow/src/shader/core/quad.vert b/glow/src/shader/core/quad.vert index b1fb2365..17c3e641 100644 --- a/glow/src/shader/core/quad.vert +++ b/glow/src/shader/core/quad.vert @@ -5,14 +5,14 @@ in vec2 i_Pos; in vec2 i_Scale; in vec4 i_Color; in vec4 i_BorderColor; -in float i_BorderRadius; +in vec4 i_BorderRadius; in float i_BorderWidth; out vec4 v_Color; out vec4 v_BorderColor; out vec2 v_Pos; out vec2 v_Scale; -out float v_BorderRadius; +out vec4 v_BorderRadius; out float v_BorderWidth; vec2 positions[4] = vec2[]( @@ -27,9 +27,11 @@ void main() { vec2 p_Pos = i_Pos * u_Scale; vec2 p_Scale = i_Scale * u_Scale; - float i_BorderRadius = min( - i_BorderRadius, - min(i_Scale.x, i_Scale.y) / 2.0 + vec4 i_BorderRadius = vec4( + min(i_BorderRadius.x, min(i_Scale.x, i_Scale.y) / 2.0), + min(i_BorderRadius.y, min(i_Scale.x, i_Scale.y) / 2.0), + min(i_BorderRadius.z, min(i_Scale.x, i_Scale.y) / 2.0), + min(i_BorderRadius.w, min(i_Scale.x, i_Scale.y) / 2.0) ); mat4 i_Transform = mat4( diff --git a/graphics/src/layer/quad.rs b/graphics/src/layer/quad.rs index 4def8427..0d8bde9d 100644 --- a/graphics/src/layer/quad.rs +++ b/graphics/src/layer/quad.rs @@ -17,7 +17,7 @@ pub struct Quad { pub border_color: [f32; 4], /// The border radius of the [`Quad`]. - pub border_radius: f32, + pub border_radius: [f32; 4], /// The border width of the [`Quad`]. pub border_width: f32, diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 9759d97a..6f1b6f26 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -42,7 +42,7 @@ pub enum Primitive { /// The background of the quad background: Background, /// The border radius of the quad - border_radius: f32, + border_radius: [f32; 4], /// The border width of the quad border_width: f32, /// The border color of the quad diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 036b398c..65350037 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -109,7 +109,7 @@ where self.primitives.push(Primitive::Quad { bounds: quad.bounds, background: background.into(), - border_radius: quad.border_radius, + border_radius: quad.border_radius.into(), border_width: quad.border_width, border_color: quad.border_color, }); diff --git a/native/src/element.rs b/native/src/element.rs index 4cca3870..2f1adeff 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -519,7 +519,7 @@ where bounds: layout.bounds(), border_color: color, border_width: 1.0, - border_radius: 0.0, + border_radius: 0.0.into(), }, Color::TRANSPARENT, ); diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs index 2e4f70b5..099b1a97 100644 --- a/native/src/overlay/menu.rs +++ b/native/src/overlay/menu.rs @@ -287,7 +287,7 @@ where }, border_color: appearance.border_color, border_width: appearance.border_width, - border_radius: appearance.border_radius, + border_radius: appearance.border_radius.into(), }, appearance.background, ); @@ -479,7 +479,7 @@ where bounds, border_color: Color::TRANSPARENT, border_width: 0.0, - border_radius: appearance.border_radius, + border_radius: appearance.border_radius.into(), }, appearance.selected_background, ); diff --git a/native/src/renderer.rs b/native/src/renderer.rs index ef64ac36..5e776be6 100644 --- a/native/src/renderer.rs +++ b/native/src/renderer.rs @@ -50,7 +50,7 @@ pub struct Quad { pub bounds: Rectangle, /// The border radius of the [`Quad`]. - pub border_radius: f32, + pub border_radius: BorderRadius, /// The border width of the [`Quad`]. pub border_width: f32, @@ -59,6 +59,29 @@ pub struct Quad { pub border_color: Color, } +/// The border radi for the corners of a graphics primitive in the order: +/// top-left, top-right, bottom-right, bottom-left. +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct BorderRadius([f32; 4]); + +impl From<f32> for BorderRadius { + fn from(w: f32) -> Self { + Self([w; 4]) + } +} + +impl From<[f32; 4]> for BorderRadius { + fn from(radi: [f32; 4]) -> Self { + Self(radi) + } +} + +impl From<BorderRadius> for [f32; 4] { + fn from(radi: BorderRadius) -> Self { + radi.0 + } +} + /// The styling attributes of a [`Renderer`]. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Style { diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index d68e01c7..bbd9451c 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -393,7 +393,7 @@ where y: bounds.y + styling.shadow_offset.y, ..bounds }, - border_radius: styling.border_radius, + border_radius: styling.border_radius.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, @@ -404,7 +404,7 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: styling.border_radius, + border_radius: styling.border_radius.into(), border_width: styling.border_width, border_color: styling.border_color, }, diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 77d639a9..bec5c448 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -236,7 +236,7 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: custom_style.border_radius, + border_radius: custom_style.border_radius.into(), border_width: custom_style.border_width, border_color: custom_style.border_color, }, diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 1c681091..16d0cb61 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -321,7 +321,7 @@ pub fn draw_background<Renderer>( renderer.fill_quad( renderer::Quad { bounds, - border_radius: appearance.border_radius, + border_radius: appearance.border_radius.into(), border_width: appearance.border_width, border_color: appearance.border_color, }, diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index c3ac6de6..edad993e 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -877,7 +877,7 @@ pub fn draw<Renderer, T>( height: split_region.height, }, }, - border_radius: 0.0, + border_radius: 0.0.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index 8f799a2a..52cb1ad1 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -536,7 +536,7 @@ pub fn draw<T, Renderer>( bounds, border_color: style.border_color, border_width: style.border_width, - border_radius: style.border_radius, + border_radius: style.border_radius.into(), }, style.background, ); diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs index b053d959..f059026f 100644 --- a/native/src/widget/progress_bar.rs +++ b/native/src/widget/progress_bar.rs @@ -129,7 +129,7 @@ where renderer.fill_quad( renderer::Quad { bounds: Rectangle { ..bounds }, - border_radius: style.border_radius, + border_radius: style.border_radius.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, @@ -143,7 +143,7 @@ where width: active_progress_width, ..bounds }, - border_radius: style.border_radius, + border_radius: style.border_radius.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index 743689c7..b95ccc5b 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -245,7 +245,7 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: size / 2.0, + border_radius: (size / 2.0).into(), border_width: custom_style.border_width, border_color: custom_style.border_color, }, @@ -261,7 +261,7 @@ where width: bounds.width - dot_size, height: bounds.height - dot_size, }, - border_radius: dot_size / 2.0, + border_radius: (dot_size / 2.0).into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, diff --git a/native/src/widget/rule.rs b/native/src/widget/rule.rs index e44d8d99..2dc7b6f0 100644 --- a/native/src/widget/rule.rs +++ b/native/src/widget/rule.rs @@ -123,7 +123,7 @@ where renderer.fill_quad( renderer::Quad { bounds, - border_radius: style.radius, + border_radius: style.radius.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 495b7af1..a5e97aa7 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -704,7 +704,7 @@ pub fn draw<Renderer>( renderer.fill_quad( renderer::Quad { bounds: scrollbar.bounds, - border_radius: style.border_radius, + border_radius: style.border_radius.into(), border_width: style.border_width, border_color: style.border_color, }, @@ -721,7 +721,7 @@ pub fn draw<Renderer>( renderer.fill_quad( renderer::Quad { bounds: scrollbar.scroller.bounds, - border_radius: style.scroller.border_radius, + border_radius: style.scroller.border_radius.into(), border_width: style.scroller.border_width, border_color: style.scroller.border_color, }, diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index fd9160a4..87030a4d 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -380,7 +380,7 @@ pub fn draw<T, R>( width: bounds.width, height: 2.0, }, - border_radius: 0.0, + border_radius: 0.0.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, @@ -395,7 +395,7 @@ pub fn draw<T, R>( width: bounds.width, height: 2.0, }, - border_radius: 0.0, + border_radius: 0.0.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, @@ -435,7 +435,7 @@ pub fn draw<T, R>( width: handle_width, height: handle_height, }, - border_radius: handle_border_radius, + border_radius: handle_border_radius.into(), border_width: style.handle.border_width, border_color: style.handle.border_color, }, diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 14e7e1b7..9391d1dd 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -801,7 +801,7 @@ pub fn draw<Renderer>( renderer.fill_quad( renderer::Quad { bounds, - border_radius: appearance.border_radius, + border_radius: appearance.border_radius.into(), border_width: appearance.border_width, border_color: appearance.border_color, }, @@ -833,7 +833,7 @@ pub fn draw<Renderer>( width: 1.0, height: text_bounds.height, }, - border_radius: 0.0, + border_radius: 0.0.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, @@ -877,7 +877,7 @@ pub fn draw<Renderer>( width, height: text_bounds.height, }, - border_radius: 0.0, + border_radius: 0.0.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }, diff --git a/native/src/widget/toggler.rs b/native/src/widget/toggler.rs index 99a56ea8..37cafd92 100644 --- a/native/src/widget/toggler.rs +++ b/native/src/widget/toggler.rs @@ -278,7 +278,7 @@ where renderer.fill_quad( renderer::Quad { bounds: toggler_background_bounds, - border_radius, + border_radius: border_radius.into(), border_width: 1.0, border_color: style .background_border @@ -302,7 +302,7 @@ where renderer.fill_quad( renderer::Quad { bounds: toggler_foreground_bounds, - border_radius, + border_radius: border_radius.into(), border_width: 1.0, border_color: style .foreground_border diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index a117df64..027a34be 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -91,7 +91,7 @@ impl Pipeline { 2 => Float32x2, 3 => Float32x4, 4 => Float32x4, - 5 => Float32, + 5 => Float32x4, 6 => Float32, ), }, diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index 73edd97c..cf4f7e4d 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -11,7 +11,7 @@ struct VertexInput { @location(2) scale: vec2<f32>, @location(3) color: vec4<f32>, @location(4) border_color: vec4<f32>, - @location(5) border_radius: f32, + @location(5) border_radius: vec4<f32>, @location(6) border_width: f32, } @@ -21,7 +21,7 @@ struct VertexOutput { @location(1) border_color: vec4<f32>, @location(2) pos: vec2<f32>, @location(3) scale: vec2<f32>, - @location(4) border_radius: f32, + @location(4) border_radius: vec4<f32>, @location(5) border_width: f32, } @@ -32,9 +32,12 @@ fn vs_main(input: VertexInput) -> VertexOutput { var pos: vec2<f32> = input.pos * globals.scale; var scale: vec2<f32> = input.scale * globals.scale; - var border_radius: f32 = min( - input.border_radius, - min(input.scale.x, input.scale.y) / 2.0 + var min_border_radius = min(input.scale.x, input.scale.y) * 0.5; + var border_radius: vec4<f32> = vec4<f32>( + min(input.border_radius.x, min_border_radius), + min(input.border_radius.y, min_border_radius), + min(input.border_radius.z, min_border_radius), + min(input.border_radius.w, min_border_radius) ); var transform: mat4x4<f32> = mat4x4<f32>( @@ -76,6 +79,18 @@ fn distance_alg( return sqrt(dist.x * dist.x + dist.y * dist.y); } +// Based on the fragement position and the center of the quad, select one of the 4 radi. +// Order matches CSS border radius attribute: +// radi.x = top-left, radi.y = top-right, radi.z = bottom-right, radi.w = bottom-left +fn select_border_radius(radi: vec4<f32>, position: vec2<f32>, center: vec2<f32>) -> f32 { + var rx = radi.x; + var ry = radi.y; + rx = select(radi.x, radi.y, position.x > center.x); + ry = select(radi.w, radi.z, position.x > center.x); + rx = select(rx, ry, position.y > center.y); + return rx; +} + @fragment fn fs_main( @@ -83,14 +98,17 @@ fn fs_main( ) -> @location(0) vec4<f32> { var mixed_color: vec4<f32> = input.color; + var border_radius = select_border_radius( + input.border_radius, + input.position.xy, + (input.pos + input.scale * 0.5).xy + ); + if (input.border_width > 0.0) { - var internal_border: f32 = max( - input.border_radius - input.border_width, - 0.0 - ); + var internal_border: f32 = max(border_radius - input.border_width, 0.0); var internal_distance: f32 = distance_alg( - vec2<f32>(input.position.x, input.position.y), + input.position.xy, input.pos + vec2<f32>(input.border_width, input.border_width), input.scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), internal_border @@ -109,13 +127,14 @@ fn fs_main( vec2<f32>(input.position.x, input.position.y), input.pos, input.scale, - input.border_radius + border_radius ); var radius_alpha: f32 = 1.0 - smoothstep( - max(input.border_radius - 0.5, 0.0), - input.border_radius + 0.5, - dist); + max(border_radius - 0.5, 0.0), + border_radius + 0.5, + dist + ); return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); } |