diff options
author | 2022-11-03 00:35:01 +0100 | |
---|---|---|
committer | 2022-11-03 22:48:26 +0100 | |
commit | c0596179bd8582e4f4b5289cdeee8de4fa3de464 (patch) | |
tree | b1ed80cf49aa846ba7a93cc97128c3ec6eadd123 | |
parent | d222b5c8b0befab665c20ba0112b28199df0ae44 (diff) | |
download | iced-c0596179bd8582e4f4b5289cdeee8de4fa3de464.tar.gz iced-c0596179bd8582e4f4b5289cdeee8de4fa3de464.tar.bz2 iced-c0596179bd8582e4f4b5289cdeee8de4fa3de464.zip |
non uniform border radius for quads
-rw-r--r-- | examples/custom_widget/src/main.rs | 2 | ||||
-rw-r--r-- | glow/src/quad/compatibility.rs | 10 | ||||
-rw-r--r-- | glow/src/quad/core.rs | 4 | ||||
-rw-r--r-- | glow/src/shader/core/quad.frag | 24 | ||||
-rw-r--r-- | glow/src/shader/core/quad.vert | 12 | ||||
-rw-r--r-- | graphics/src/layer/quad.rs | 2 | ||||
-rw-r--r-- | graphics/src/primitive.rs | 2 | ||||
-rw-r--r-- | graphics/src/renderer.rs | 2 | ||||
-rw-r--r-- | native/src/element.rs | 2 | ||||
-rw-r--r-- | native/src/overlay/menu.rs | 4 | ||||
-rw-r--r-- | native/src/renderer.rs | 26 | ||||
-rw-r--r-- | native/src/widget/button.rs | 4 | ||||
-rw-r--r-- | native/src/widget/checkbox.rs | 2 | ||||
-rw-r--r-- | native/src/widget/container.rs | 2 | ||||
-rw-r--r-- | native/src/widget/pane_grid.rs | 2 | ||||
-rw-r--r-- | native/src/widget/pick_list.rs | 2 | ||||
-rw-r--r-- | native/src/widget/progress_bar.rs | 4 | ||||
-rw-r--r-- | native/src/widget/radio.rs | 4 | ||||
-rw-r--r-- | native/src/widget/rule.rs | 2 | ||||
-rw-r--r-- | native/src/widget/scrollable.rs | 4 | ||||
-rw-r--r-- | native/src/widget/slider.rs | 6 | ||||
-rw-r--r-- | native/src/widget/text_input.rs | 6 | ||||
-rw-r--r-- | native/src/widget/toggler.rs | 4 | ||||
-rw-r--r-- | wgpu/src/quad.rs | 2 | ||||
-rw-r--r-- | wgpu/src/shader/quad.wgsl | 47 |
25 files changed, 121 insertions, 60 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..5734c159 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, @@ -325,7 +325,7 @@ impl Vertex { size: quad.size, color: quad.color, border_color: quad.color, - border_radius: quad.border_radius, + border_radius: [quad.border_radius[0]; 4], border_width: quad.border_width, q_position: [0.0, 0.0], }; 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/core/quad.frag b/glow/src/shader/core/quad.frag index 57e2e8e7..d036ea1a 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 borderRadius = 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(borderRadius - v_BorderWidth, 0.0); float internal_distance = fDistance( fragCoord, @@ -69,11 +85,11 @@ void main() { fragCoord, v_Pos, v_Scale, - v_BorderRadius + borderRadius ); float radius_alpha = - 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d); + 1.0 - smoothstep(max(borderRadius - 0.5, 0.0), borderRadius + 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 b481ac0b..84f04624 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -41,7 +41,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 cdbc4f40..46d37cd6 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.to_array(), border_width: quad.border_width, border_color: quad.border_color, }); diff --git a/native/src/element.rs b/native/src/element.rs index 074e422e..955e1bee 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -503,7 +503,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 08135872..dbcf23d4 100644 --- a/native/src/overlay/menu.rs +++ b/native/src/overlay/menu.rs @@ -299,7 +299,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, ); @@ -491,7 +491,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..39c1b4c7 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: QuadBorderRadius, /// The border width of the [`Quad`]. pub border_width: f32, @@ -59,6 +59,30 @@ pub struct Quad { pub border_color: Color, } +/// The border radi for the corners of a [`Quad`] in the order: +/// top-left, top-right, bottom-right, bottom-left. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct QuadBorderRadius([f32; 4]); + +impl QuadBorderRadius { + /// Convert the corners of the Quad into an array [top_left, top_right, bottom_left, bottom_right]. + pub fn to_array(self) -> [f32; 4] { + self.0 + } +} + +impl From<f32> for QuadBorderRadius { + fn from(w: f32) -> Self { + Self([w; 4]) + } +} + +impl From<[f32; 4]> for QuadBorderRadius { + fn from(radi: [f32; 4]) -> Self { + Self(radi) + } +} + /// 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 6c0b8f6e..14759cfd 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 dc3c0bd0..8f30037a 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 2afad3f2..b0c4938a 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 96cf78ef..45090ecf 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -828,7 +828,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 896f5b35..a92ea655 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -514,7 +514,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 8a945433..5f8892fe 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 cb83f745..10e89870 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 56f8c80d..1d1c04cf 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 4ebb07a0..b445e505 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -698,7 +698,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, }, @@ -715,7 +715,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 585d9c35..011454de 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 54a6aaf8..ae0305dc 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -766,7 +766,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, }, @@ -798,7 +798,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, }, @@ -842,7 +842,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 7893f78c..c5c2d82a 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); } |