From e21757ce341dee0197aa11b2f528d5886679af91 Mon Sep 17 00:00:00 2001 From: StarArawn <toasterthegamer@gmail.com> Date: Sat, 22 Jan 2022 10:34:33 -0500 Subject: [PATCH] Added properly SDF rendering of rounded rectangles. Added borders. --- .../src/render/unified/image/extract.rs | 10 ++- .../src/render/unified/quad/extract.rs | 64 +++++++++++++------ bevy_kayak_ui/src/render/unified/shader.wgsl | 59 ++++++++--------- examples/image.rs | 5 ++ kayak_core/src/node.rs | 44 +++++++++++-- kayak_core/src/render_primitive.rs | 4 ++ kayak_core/src/styles.rs | 60 +++++++++-------- src/widgets/window.rs | 6 +- 8 files changed, 165 insertions(+), 87 deletions(-) diff --git a/bevy_kayak_ui/src/render/unified/image/extract.rs b/bevy_kayak_ui/src/render/unified/image/extract.rs index 04cfce8..c6b6e21 100644 --- a/bevy_kayak_ui/src/render/unified/image/extract.rs +++ b/bevy_kayak_ui/src/render/unified/image/extract.rs @@ -11,8 +11,12 @@ pub fn extract_images( image_manager: &Res<ImageManager>, dpi: f32, ) -> Vec<ExtractQuadBundle> { - let (layout, handle) = match render_command { - RenderPrimitive::Image { layout, handle } => (layout, handle), + let (border_radius, layout, handle) = match render_command { + RenderPrimitive::Image { + border_radius, + layout, + handle, + } => (*border_radius, layout, handle), _ => panic!(""), }; @@ -29,7 +33,7 @@ pub fn extract_images( font_handle: None, quad_type: UIQuadType::Image, type_index: 0, - border_radius: (0.0, 0.0, 0.0, 0.0), + border_radius, image: image_manager .get_handle(handle) .and_then(|a| Some(a.clone_weak())), diff --git a/bevy_kayak_ui/src/render/unified/quad/extract.rs b/bevy_kayak_ui/src/render/unified/quad/extract.rs index deb1acc..fa33c3e 100644 --- a/bevy_kayak_ui/src/render/unified/quad/extract.rs +++ b/bevy_kayak_ui/src/render/unified/quad/extract.rs @@ -7,32 +7,58 @@ use crate::{ }; pub fn extract_quads(render_primitive: &RenderPrimitive, dpi: f32) -> Vec<ExtractQuadBundle> { - let (background_color, layout, border_radius) = match render_primitive { + let (background_color, layout, border_radius, border) = match render_primitive { RenderPrimitive::Quad { background_color, layout, border_radius, - } => (background_color, layout, border_radius), + border, + } => (background_color, layout, border_radius, border), _ => panic!(""), }; - vec![ExtractQuadBundle { - extracted_quad: ExtractedQuad { - rect: Rect { - min: Vec2::new(layout.posx, layout.posy), - max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height) * dpi, + vec![ + // Border + ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(layout.posx, layout.posy), + max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height) * dpi, + }, + color: bevy::prelude::Color::rgba(0.0781, 0.0898, 0.101, 1.0), + vertex_index: 0, + char_id: 0, + z_index: layout.z_index, + font_handle: None, + quad_type: UIQuadType::Quad, + type_index: 0, + border_radius: *border_radius, + image: None, + uv_max: None, + uv_min: None, }, - color: to_bevy_color(background_color), - vertex_index: 0, - char_id: 0, - z_index: layout.z_index, - font_handle: None, - quad_type: UIQuadType::Quad, - type_index: 0, - border_radius: *border_radius, - image: None, - uv_max: None, - uv_min: None, }, - }] + ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(layout.posx + border.3, layout.posy + border.0), + max: Vec2::new( + (layout.posx + layout.width) - border.1, + (layout.posy + layout.height) - border.2, + ) * dpi, + }, + color: to_bevy_color(background_color), + vertex_index: 0, + char_id: 0, + z_index: layout.z_index, + font_handle: None, + quad_type: UIQuadType::Quad, + type_index: 0, + border_radius: *border_radius, + image: None, + uv_max: None, + uv_min: None, + }, + }, + ] } diff --git a/bevy_kayak_ui/src/render/unified/shader.wgsl b/bevy_kayak_ui/src/render/unified/shader.wgsl index 1eb16eb..6195f7a 100644 --- a/bevy_kayak_ui/src/render/unified/shader.wgsl +++ b/bevy_kayak_ui/src/render/unified/shader.wgsl @@ -17,8 +17,8 @@ struct VertexOutput { [[location(1)]] uv: vec3<f32>; [[location(2)]] pos: vec2<f32>; [[location(3)]] size: vec2<f32>; - [[location(4)]] screen_position: vec2<f32>; - [[location(5)]] border_radius: f32; + [[location(4)]] border_radius: f32; + [[location(5)]] pixel_position: vec2<f32>; }; [[stage(vertex)]] @@ -30,9 +30,9 @@ fn vertex( ) -> VertexOutput { var out: VertexOutput; out.color = vertex_color; - out.pos = vertex_pos_size.xy; + out.pos = (vertex_position.xy - vertex_pos_size.xy); out.position = view.view_proj * vec4<f32>(vertex_position, 1.0); - out.screen_position = (view.view_proj * vec4<f32>(vertex_position, 1.0)).xy; + out.pixel_position = out.position.xy; out.uv = vertex_uv.xyz; out.size = vertex_pos_size.zw; out.border_radius = vertex_uv.w; @@ -51,39 +51,26 @@ var image_sampler: sampler; let RADIUS: f32 = 0.1; -fn sd_box_rounded( - frag_coord: vec2<f32>, - position: vec2<f32>, - size: vec2<f32>, - radius: f32, -) -> f32 { - var inner_size: vec2<f32> = size - radius * 2.0; - var top_left: vec2<f32> = position + radius; - var bottom_right: vec2<f32> = top_left + inner_size; - - var top_left_distance: vec2<f32> = top_left - frag_coord; - var bottom_right_distance: vec2<f32> = frag_coord - bottom_right; - - var dist = max(max(top_left_distance, bottom_right_distance), vec2<f32>(0.0)); - - return length(dist); +fn sdRoundBox(p: vec2<f32>, b: vec2<f32>, r: f32) -> f32 +{ + var q = abs(p)-b+r; + return min(max(q.x, q.y), 0.0) + length(max(q, vec2<f32>(0.0))) - r; } [[stage(fragment)]] fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> { if (quad_type.t == 0) { - var dist = sd_box_rounded( - in.position.xy, - in.pos, - in.size, - in.border_radius, + var border = 10.0; + var size = in.size; + var pos = in.pos.xy * 2.0; + var bs = min(in.border_radius * 2.0, min(in.size.x, in.size.y)); + var rect_dist = sdRoundBox( + pos - size, + size, + bs, ); - dist = 1.0 - smoothStep( - max(in.border_radius - 0.5, 0.0), - in.border_radius + 0.5, - dist); - - return vec4<f32>(in.color.rgb, dist); + rect_dist = 1.0 - smoothStep(0.0, fwidth(rect_dist), rect_dist); + return vec4<f32>(in.color.rgb, rect_dist); } if (quad_type.t == 1) { var px_range = 3.5; @@ -93,12 +80,18 @@ fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> { var v = max(min(x.r, x.g), min(max(x.r, x.g), x.b)); var sig_dist = (v - 0.5) * dot(msdf_unit, 0.5 / fwidth(in.uv.xy)); var a = clamp(sig_dist + 0.5, 0.0, 1.0); - return vec4<f32>(in.color.rgb, a); } if (quad_type.t == 2) { + var bs = min(in.border_radius, min(in.size.x, in.size.y)); + var mask = sdRoundBox( + in.pos.xy * 2.0 - (in.size.xy), + in.size.xy, + bs, + ); + mask = 1.0 - smoothStep(0.0, fwidth(mask), mask); var color = textureSample(image_texture, image_sampler, vec2<f32>(in.uv.x, 1.0 - in.uv.y)); - return vec4<f32>(color.rgb * in.color.rgb, color.a * in.color.a); + return vec4<f32>(color.rgb * in.color.rgb, color.a * in.color.a * mask); } return in.color; } \ No newline at end of file diff --git a/examples/image.rs b/examples/image.rs index 9ec14ed..ec63e30 100644 --- a/examples/image.rs +++ b/examples/image.rs @@ -3,6 +3,7 @@ use bevy::{ window::WindowDescriptor, DefaultPlugins, }; +use kayak_core::styles::PositionType; use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, ImageManager, UICameraBundle}; use kayak_ui::core::{ render, @@ -23,6 +24,10 @@ fn startup( let context = BevyContext::new(|context| { let image_styles = Style { + position_type: StyleProp::Value(PositionType::SelfDirected), + left: StyleProp::Value(Units::Pixels(10.0)), + top: StyleProp::Value(Units::Pixels(10.0)), + border_radius: StyleProp::Value((500.0, 500.0, 500.0, 500.0)), width: StyleProp::Value(Units::Pixels(200.0)), height: StyleProp::Value(Units::Pixels(182.0)), ..Style::default() diff --git a/kayak_core/src/node.rs b/kayak_core/src/node.rs index 09ca564..22b92ed 100644 --- a/kayak_core/src/node.rs +++ b/kayak_core/src/node.rs @@ -336,19 +336,55 @@ impl<'a> morphorm::Node<'a> for Index { Some(1) } - fn border_left(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { + fn border_left(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(*self) { + if let Some(node) = node { + return match node.styles.border { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(morphorm::Units::Pixels(prop.3)), + _ => Some(morphorm::Units::Auto), + }; + } + } Some(morphorm::Units::Auto) } - fn border_right(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { + fn border_right(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(*self) { + if let Some(node) = node { + return match node.styles.border { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(morphorm::Units::Pixels(prop.1)), + _ => Some(morphorm::Units::Auto), + }; + } + } Some(morphorm::Units::Auto) } - fn border_top(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { + fn border_top(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(*self) { + if let Some(node) = node { + return match node.styles.border { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(morphorm::Units::Pixels(prop.0)), + _ => Some(morphorm::Units::Auto), + }; + } + } Some(morphorm::Units::Auto) } - fn border_bottom(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { + fn border_bottom(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(*self) { + if let Some(node) = node { + return match node.styles.border { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(morphorm::Units::Pixels(prop.2)), + _ => Some(morphorm::Units::Auto), + }; + } + } Some(morphorm::Units::Auto) } } diff --git a/kayak_core/src/render_primitive.rs b/kayak_core/src/render_primitive.rs index 23acaef..3698b22 100644 --- a/kayak_core/src/render_primitive.rs +++ b/kayak_core/src/render_primitive.rs @@ -14,6 +14,7 @@ pub enum RenderPrimitive { Quad { layout: Rect, background_color: Color, + border: (f32, f32, f32, f32), border_radius: (f32, f32, f32, f32), }, Text { @@ -26,6 +27,7 @@ pub enum RenderPrimitive { size: f32, }, Image { + border_radius: (f32, f32, f32, f32), layout: Rect, handle: u16, }, @@ -68,6 +70,7 @@ impl From<&Style> for RenderPrimitive { RenderCommand::Quad => Self::Quad { background_color: background_color, border_radius: style.border_radius.resolve(), + border: style.border.resolve(), layout: Rect::default(), }, RenderCommand::Text { @@ -86,6 +89,7 @@ impl From<&Style> for RenderPrimitive { size, }, RenderCommand::Image { handle } => Self::Image { + border_radius: style.border_radius.resolve(), layout: Rect::default(), handle, }, diff --git a/kayak_core/src/styles.rs b/kayak_core/src/styles.rs index 38b5116..14d014b 100644 --- a/kayak_core/src/styles.rs +++ b/kayak_core/src/styles.rs @@ -36,29 +36,30 @@ where pub struct Style { pub background_color: StyleProp<Color>, pub border_radius: StyleProp<(f32, f32, f32, f32)>, + pub border: StyleProp<(f32, f32, f32, f32)>, pub bottom: StyleProp<Units>, pub color: StyleProp<Color>, pub height: StyleProp<Units>, pub layout_type: StyleProp<LayoutType>, pub left: StyleProp<Units>, - pub position_type: StyleProp<PositionType>, - pub render_command: StyleProp<RenderCommand>, - pub right: StyleProp<Units>, - pub top: StyleProp<Units>, - pub width: StyleProp<Units>, - pub padding_left: StyleProp<Units>, - pub padding_right: StyleProp<Units>, - pub padding_top: StyleProp<Units>, - pub padding_bottom: StyleProp<Units>, + pub margin_bottom: StyleProp<Units>, pub margin_left: StyleProp<Units>, pub margin_right: StyleProp<Units>, pub margin_top: StyleProp<Units>, - pub margin_bottom: StyleProp<Units>, - pub min_width: StyleProp<Units>, - pub min_height: StyleProp<Units>, - pub max_width: StyleProp<Units>, pub max_height: StyleProp<Units>, + pub max_width: StyleProp<Units>, + pub min_height: StyleProp<Units>, + pub min_width: StyleProp<Units>, + pub padding_bottom: StyleProp<Units>, + pub padding_left: StyleProp<Units>, + pub padding_right: StyleProp<Units>, + pub padding_top: StyleProp<Units>, pub pointer_events: StyleProp<PointerEvents>, + pub position_type: StyleProp<PositionType>, + pub render_command: StyleProp<RenderCommand>, + pub right: StyleProp<Units>, + pub top: StyleProp<Units>, + pub width: StyleProp<Units>, } impl Default for Style { @@ -66,29 +67,30 @@ impl Default for Style { Self { background_color: StyleProp::Default, border_radius: StyleProp::Default, - render_command: StyleProp::Value(RenderCommand::Empty), + border: StyleProp::Default, bottom: StyleProp::Default, color: StyleProp::Inherit, height: StyleProp::Default, layout_type: StyleProp::Default, left: StyleProp::Default, - position_type: StyleProp::Default, - right: StyleProp::Default, - top: StyleProp::Default, - width: StyleProp::Default, - padding_left: StyleProp::Default, - padding_right: StyleProp::Default, - padding_top: StyleProp::Default, - padding_bottom: StyleProp::Default, + margin_bottom: StyleProp::Default, margin_left: StyleProp::Default, margin_right: StyleProp::Default, margin_top: StyleProp::Default, - margin_bottom: StyleProp::Default, - min_width: StyleProp::Default, - min_height: StyleProp::Default, - max_width: StyleProp::Default, max_height: StyleProp::Default, + max_width: StyleProp::Default, + min_height: StyleProp::Default, + min_width: StyleProp::Default, + padding_bottom: StyleProp::Default, + padding_left: StyleProp::Default, + padding_right: StyleProp::Default, + padding_top: StyleProp::Default, pointer_events: StyleProp::Default, + position_type: StyleProp::Default, + render_command: StyleProp::Value(RenderCommand::Empty), + right: StyleProp::Default, + top: StyleProp::Default, + width: StyleProp::Default, } } } @@ -107,6 +109,12 @@ impl Style { } _ => (), } + match self.border { + StyleProp::Inherit => { + self.border = other.border.clone(); + } + _ => (), + } match self.bottom { StyleProp::Inherit => { self.bottom = other.bottom.clone(); diff --git a/src/widgets/window.rs b/src/widgets/window.rs index c866c6a..a362b50 100644 --- a/src/widgets/window.rs +++ b/src/widgets/window.rs @@ -18,6 +18,7 @@ pub fn Window( ) { *styles = Some(Style { background_color: StyleProp::Value(Color::new(0.125, 0.125, 0.125, 1.0)), + border: StyleProp::Value((4.0, 4.0, 4.0, 4.0)), border_radius: StyleProp::Value((5.0, 5.0, 5.0, 5.0)), render_command: StyleProp::Value(RenderCommand::Quad), position_type: StyleProp::Value(PositionType::SelfDirected), @@ -35,8 +36,8 @@ pub fn Window( padding_right: StyleProp::Value(Units::Pixels(5.0)), padding_top: StyleProp::Value(Units::Pixels(5.0)), padding_bottom: StyleProp::Value(Units::Pixels(5.0)), - width: StyleProp::Value(Units::Pixels(size.0)), - height: StyleProp::Value(Units::Pixels(size.1)), + width: StyleProp::Value(Units::Stretch(1.0)), + height: StyleProp::Value(Units::Stretch(1.0)), max_width: StyleProp::Value(Units::Pixels(size.0)), max_height: StyleProp::Value(Units::Pixels(size.1)), ..Style::default() @@ -46,6 +47,7 @@ pub fn Window( background_color: StyleProp::Value(Color::new(0.0781, 0.0898, 0.101, 1.0)), border_radius: StyleProp::Value((5.0, 0.0, 0.0, 5.0)), height: StyleProp::Value(Units::Pixels(24.0)), + width: StyleProp::Value(Units::Stretch(1.0)), left: StyleProp::Value(Units::Pixels(0.0)), right: StyleProp::Value(Units::Pixels(0.0)), top: StyleProp::Value(Units::Pixels(0.0)), -- GitLab