diff --git a/bevy_kayak_ui/src/render/unified/font/extract.rs b/bevy_kayak_ui/src/render/unified/font/extract.rs index 689a82fbaf6093ce2a013f39507a00e4f5526e82..65dbaba5c67fcee97a9d284be6718b06c399f468 100644 --- a/bevy_kayak_ui/src/render/unified/font/extract.rs +++ b/bevy_kayak_ui/src/render/unified/font/extract.rs @@ -76,6 +76,7 @@ pub fn extract_texts( z_index: layout.z_index, quad_type: UIQuadType::Text, type_index: 0, + border_radius: (0.0, 0.0, 0.0, 0.0), }, }); } diff --git a/bevy_kayak_ui/src/render/unified/pipeline.rs b/bevy_kayak_ui/src/render/unified/pipeline.rs index 5d01dcd28622597ee3c7d7289703dc9c416b6578..744969b56c5e8a9bb00e3286644f2d761cb1992a 100644 --- a/bevy_kayak_ui/src/render/unified/pipeline.rs +++ b/bevy_kayak_ui/src/render/unified/pipeline.rs @@ -4,7 +4,7 @@ use bevy::{ lifetimeless::{Read, SQuery, SRes}, SystemState, }, - math::{const_vec3, Mat4, Quat, Vec3}, + math::{const_vec3, Mat4, Quat, Vec3, Vec4}, prelude::{Bundle, Entity, FromWorld, Handle, Query, Res, ResMut, World}, render2::{ color::Color, @@ -113,7 +113,7 @@ impl FromWorld for UnifiedPipeline { }); let vertex_buffer_layout = VertexBufferLayout { - array_stride: 40, + array_stride: 60, step_mode: VertexStepMode::Vertex, attributes: vec![ VertexAttribute { @@ -127,10 +127,15 @@ impl FromWorld for UnifiedPipeline { shader_location: 1, }, VertexAttribute { - format: VertexFormat::Float32x3, + format: VertexFormat::Float32x4, offset: 28, shader_location: 2, }, + VertexAttribute { + format: VertexFormat::Float32x4, + offset: 44, + shader_location: 3, + }, ], }; @@ -217,6 +222,7 @@ pub struct ExtractedQuad { pub font_handle: Option<Handle<KayakFont>>, pub quad_type: UIQuadType, pub type_index: u32, + pub border_radius: (f32, f32, f32, f32), } #[repr(C)] @@ -224,7 +230,8 @@ pub struct ExtractedQuad { struct QuadVertex { pub position: [f32; 3], pub color: [f32; 4], - pub uv: [f32; 3], + pub uv: [f32; 4], + pub pos_size: [f32; 4], } #[repr(C)] @@ -286,12 +293,32 @@ pub fn prepare_quads( UIQuadType::Text => extracted_sprite.type_index = text_type_offset, }; - let bottom_left = Vec3::new(0.0, 1.0, extracted_sprite.char_id as f32); - let top_left = Vec3::new(0.0, 0.0, extracted_sprite.char_id as f32); - let top_right = Vec3::new(1.0, 0.0, extracted_sprite.char_id as f32); - let bottom_right = Vec3::new(1.0, 1.0, extracted_sprite.char_id as f32); - - let uvs: [[f32; 3]; 6] = [ + let bottom_left = Vec4::new( + 0.0, + 1.0, + extracted_sprite.char_id as f32, + extracted_sprite.border_radius.0, + ); + let top_left = Vec4::new( + 0.0, + 0.0, + extracted_sprite.char_id as f32, + extracted_sprite.border_radius.1, + ); + let top_right = Vec4::new( + 1.0, + 0.0, + extracted_sprite.char_id as f32, + extracted_sprite.border_radius.2, + ); + let bottom_right = Vec4::new( + 1.0, + 1.0, + extracted_sprite.char_id as f32, + extracted_sprite.border_radius.3, + ); + + let uvs: [[f32; 4]; 6] = [ bottom_left.into(), top_right.into(), top_left.into(), @@ -312,6 +339,12 @@ pub fn prepare_quads( position: final_position.into(), color, uv: uvs[index], + pos_size: [ + sprite_rect.min.x, + sprite_rect.min.y, + sprite_rect.size().x, + sprite_rect.size().y, + ], }); } } diff --git a/bevy_kayak_ui/src/render/unified/quad/extract.rs b/bevy_kayak_ui/src/render/unified/quad/extract.rs index fe74d223732f7f5cc512d1272fb6686110c9ae8d..20a4c8ec13fefe9e1b58418ce777747b23dbe1ab 100644 --- a/bevy_kayak_ui/src/render/unified/quad/extract.rs +++ b/bevy_kayak_ui/src/render/unified/quad/extract.rs @@ -24,11 +24,12 @@ pub fn extract_quads(mut commands: Commands, context: Res<BevyContext>) { let mut extracted_quads = Vec::new(); for render_primitive in quad_commands { - let (background_color, layout) = match render_primitive { + let (background_color, layout, border_radius) = match render_primitive { RenderPrimitive::Quad { background_color, layout, - } => (background_color, layout), + border_radius, + } => (background_color, layout, border_radius), _ => panic!(""), }; @@ -45,6 +46,7 @@ pub fn extract_quads(mut commands: Commands, context: Res<BevyContext>) { font_handle: None, quad_type: UIQuadType::Quad, type_index: 0, + border_radius: *border_radius, }, }); } diff --git a/bevy_kayak_ui/src/render/unified/shader.wgsl b/bevy_kayak_ui/src/render/unified/shader.wgsl index 0032221714c236b71c256a3f3b923a6e1515de11..11c8108a5453172a28d28b8b5da034e5c8de3eab 100644 --- a/bevy_kayak_ui/src/render/unified/shader.wgsl +++ b/bevy_kayak_ui/src/render/unified/shader.wgsl @@ -18,18 +18,28 @@ struct VertexOutput { [[builtin(position)]] position: vec4<f32>; [[location(0)]] color: vec4<f32>; [[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; }; [[stage(vertex)]] fn vertex( [[location(0)]] vertex_position: vec3<f32>, [[location(1)]] vertex_color: vec4<f32>, - [[location(2)]] vertex_uv: vec3<f32>, + [[location(2)]] vertex_uv: vec4<f32>, + [[location(3)]] vertex_pos_size: vec4<f32>, ) -> VertexOutput { var out: VertexOutput; out.color = vertex_color; + out.pos = vertex_pos_size.xy; out.position = view.view_proj * vec4<f32>(vertex_position, 1.0); - out.uv = vertex_uv; + out.screen_position = (view.view_proj * vec4<f32>(vertex_position, 1.0)).xy; + out.uv = vertex_uv.xyz; + out.size = vertex_pos_size.zw; + out.border_radius = vertex_uv.w; + return out; } @@ -40,10 +50,43 @@ var sprite_sampler: sampler; let RADIUS: f32 = 0.5; + +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); +} + [[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, + ); + 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); + } if (quad_type.t == 1) { - var x = textureSample(sprite_texture, sprite_sampler, in.uv.xy, i32(in.uv.z)); + var x = textureSample(sprite_texture, sprite_sampler, in.uv.xy, i32(in.uv.z)); var v = max(min(x.r, x.g), min(max(x.r, x.g), x.b)); var c = v; //remap(v); diff --git a/kayak_components/src/window.rs b/kayak_components/src/window.rs index 0671ff4a64a3cefd8ec23084f3090ef2516eacab..85c7e3e6be92d3353c86c225d015a761c16eef52 100644 --- a/kayak_components/src/window.rs +++ b/kayak_components/src/window.rs @@ -18,22 +18,38 @@ pub fn Window( ) { *styles = Some(Style { background_color: StyleProp::Value(Color::new(0.125, 0.125, 0.125, 1.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), left: StyleProp::Value(Units::Pixels(position.0)), top: StyleProp::Value(Units::Pixels(position.1)), width: StyleProp::Value(Units::Pixels(size.0)), height: StyleProp::Value(Units::Pixels(size.1)), + padding_left: StyleProp::Value(Units::Pixels(5.0)), + padding_right: StyleProp::Value(Units::Pixels(5.0)), + padding_top: StyleProp::Value(Units::Pixels(5.0)), + padding_bottom: StyleProp::Value(Units::Pixels(5.0)), ..styles.clone().unwrap_or_default() }); let title_background_styles = Style { 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)), + left: StyleProp::Value(Units::Pixels(-5.0)), + right: StyleProp::Value(Units::Pixels(-5.0)), + top: StyleProp::Value(Units::Pixels(-5.0)), + bottom: StyleProp::Value(Units::Pixels(-5.0)), + padding_left: StyleProp::Value(Units::Pixels(5.0)), + padding_top: StyleProp::Value(Units::Stretch(1.0)), + padding_bottom: StyleProp::Value(Units::Stretch(1.0)), ..Style::default() }; - let title_text_styles = Style { ..Style::default() }; + let title_text_styles = Style { + height: StyleProp::Value(Units::Pixels(16.0)), + ..Style::default() + }; let title = title.clone(); rsx! { diff --git a/kayak_core/src/node.rs b/kayak_core/src/node.rs index 47d79ca0c63d20eeb006ed1eb2347d561d3255b7..c421915cb0f8aeaf5db43a9a12642e3dc6689cf9 100644 --- a/kayak_core/src/node.rs +++ b/kayak_core/src/node.rs @@ -219,20 +219,56 @@ impl<'a> morphorm::Node<'a> for NodeIndex { Some(morphorm::Units::Auto) } - fn child_left(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { - Some(morphorm::Units::Auto) + fn child_left(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(self.0) { + if let Some(node) = node { + return match node.styles.padding_left { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(prop), + _ => Some(morphorm::Units::Auto), + }; + } + } + return Some(morphorm::Units::Auto); } - fn child_right(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { - Some(morphorm::Units::Auto) + fn child_right(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(self.0) { + if let Some(node) = node { + return match node.styles.padding_right { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(prop), + _ => Some(morphorm::Units::Auto), + }; + } + } + return Some(morphorm::Units::Auto); } - fn child_top(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { - Some(morphorm::Units::Auto) + fn child_top(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(self.0) { + if let Some(node) = node { + return match node.styles.padding_top { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(prop), + _ => Some(morphorm::Units::Auto), + }; + } + } + return Some(morphorm::Units::Auto); } - fn child_bottom(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { - Some(morphorm::Units::Auto) + fn child_bottom(&self, store: &'_ Self::Data) -> Option<morphorm::Units> { + if let Some(node) = store.get(self.0) { + if let Some(node) = node { + return match node.styles.padding_bottom { + StyleProp::Default => Some(morphorm::Units::Auto), + StyleProp::Value(prop) => Some(prop), + _ => Some(morphorm::Units::Auto), + }; + } + } + return Some(morphorm::Units::Auto); } fn row_between(&self, _store: &'_ Self::Data) -> Option<morphorm::Units> { diff --git a/kayak_core/src/render_primitive.rs b/kayak_core/src/render_primitive.rs index 6fa65a70890db73a6c8b68fc758cba027250934d..3208f6c1f4fe58fe4f16149fb7e02d5fd279659d 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_radius: (f32, f32, f32, f32), }, Text { layout: Rect, @@ -53,6 +54,7 @@ impl From<&Style> for RenderPrimitive { }, RenderCommand::Quad => Self::Quad { background_color: background_color, + border_radius: style.border_radius.resolve(), layout: Rect::default(), }, RenderCommand::Text { diff --git a/kayak_core/src/styles.rs b/kayak_core/src/styles.rs index 7302522dc86ee6b9be2791a77e83529928c3087f..17266dc971130ef194237f890258de14561921b6 100644 --- a/kayak_core/src/styles.rs +++ b/kayak_core/src/styles.rs @@ -34,6 +34,7 @@ where #[derive(Debug, Clone, PartialEq)] pub struct Style { pub background_color: StyleProp<Color>, + pub border_radius: StyleProp<(f32, f32, f32, f32)>, pub bottom: StyleProp<Units>, pub color: StyleProp<Color>, pub height: StyleProp<Units>, @@ -44,12 +45,17 @@ pub struct Style { 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>, } impl Default for Style { fn default() -> Self { Self { background_color: StyleProp::Default, + border_radius: StyleProp::Default, render_command: StyleProp::Value(RenderCommand::Empty), bottom: StyleProp::Default, color: StyleProp::Inherit, @@ -60,6 +66,10 @@ impl Default for Style { 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, } } } @@ -72,6 +82,12 @@ impl Style { } _ => (), } + match self.border_radius { + StyleProp::Inherit => { + self.border_radius = other.border_radius.clone(); + } + _ => (), + } match self.bottom { StyleProp::Inherit => { self.bottom = other.bottom.clone(); @@ -132,5 +148,21 @@ impl Style { } _ => (), } + match self.padding_left { + StyleProp::Inherit => self.padding_left = other.padding_left.clone(), + _ => (), + } + match self.padding_right { + StyleProp::Inherit => self.padding_right = other.padding_right.clone(), + _ => (), + } + match self.padding_top { + StyleProp::Inherit => self.padding_top = other.padding_top.clone(), + _ => (), + } + match self.padding_bottom { + StyleProp::Inherit => self.padding_bottom = other.padding_bottom.clone(), + _ => (), + } } } diff --git a/kayak_core/src/widget_manager.rs b/kayak_core/src/widget_manager.rs index 3be622a90ae58a6c97e1346136284103b14ba348..97ed85ebe3fdb3f78e6f8eab4e98726d97f87058 100644 --- a/kayak_core/src/widget_manager.rs +++ b/kayak_core/src/widget_manager.rs @@ -124,11 +124,16 @@ impl WidgetManager { pub fn render(&mut self) { let default_styles = Style { background_color: crate::styles::StyleProp::Default, + border_radius: crate::styles::StyleProp::Default, bottom: crate::styles::StyleProp::Default, color: crate::styles::StyleProp::Default, height: crate::styles::StyleProp::Default, layout_type: crate::styles::StyleProp::Default, left: crate::styles::StyleProp::Default, + padding_bottom: crate::styles::StyleProp::Default, + padding_left: crate::styles::StyleProp::Default, + padding_right: crate::styles::StyleProp::Default, + padding_top: crate::styles::StyleProp::Default, position_type: crate::styles::StyleProp::Default, render_command: crate::styles::StyleProp::Default, right: crate::styles::StyleProp::Default, diff --git a/kayak_render_macros/src/function_component.rs b/kayak_render_macros/src/function_component.rs index 74ad5b7928cf25b13424de4ce7c6831678701402..c75438a99b2fbc4df706aa1fa02c7b3e17e12e15 100644 --- a/kayak_render_macros/src/function_component.rs +++ b/kayak_render_macros/src/function_component.rs @@ -35,16 +35,6 @@ pub fn create_function_component(f: syn::ItemFn) -> TokenStream { }) .collect(); - // let missing_names = vec!["styles"]; - // missing_names.iter().for_each(|missing| { - // if !input_names - // .iter() - // .any(|input| input.to_string() == missing.to_string()) - // { - // input_names.push(quote! { #missing }); - // } - // }); - let mut input_block_names: Vec<_> = inputs .iter() .filter(|input| { @@ -172,39 +162,5 @@ pub fn create_function_component(f: syn::ItemFn) -> TokenStream { #block } } - - // impl #impl_generics ::kayak_core::Render for #struct_name #ty_generics #where_clause { - // fn render_into(&self, nodes: &mut Vec<::kayak_core::Node>, context: ::std::sync::Arc<::std::sync::RwLock<::kayak_core::KayakContext>>, parent_styles: Option<kayak_core::Style>) -> Option<usize> { - // let _ = rsx! { - // <>{}</> - // }; // Used to fake out the compiler into thinking we require rsx! still. - // let result = { - // #inputs_reading_ref - // let mut styles = styles.clone(); - // let result = if let Ok(mut context) = context.write() { - // context.set_current_id(self.component_id); - // #ref_block - // } else { panic!("Couldn't get write lock for context!"); }; - - // (result, styles) - // }; - // let child_index = ::kayak_core::Render::render_into(&result.0, nodes, context, result.1.clone()); - // let mut builder = ::kayak_core::NodeBuilder::empty() - // .with_id(self.component_id) - // .with_children(vec![ - // child_index - // ].iter().filter_map(|x| *x).collect()); - // if let Some(styles) = result.1 { - // let new_styles = if let Some(parent_styles) = parent_styles { - // styles // parent_styles.merge(&styles) - // } else { styles }; - // builder = builder.with_styles(new_styles) - // } - // let node = builder.build(); - // let node_index = nodes.len(); - // nodes.push(node); - // Some(node_index) - // } - // } }) }