From eb12a6a319f20e3a2775f5c5133dfcaadbca399a Mon Sep 17 00:00:00 2001 From: Aleksander Date: Thu, 25 Sep 2025 23:21:11 +0200 Subject: [PATCH] overflow: hidden/scroll scissor support, remove depth --- uidev/src/main.rs | 16 ++- uidev/src/vulkan.rs | 10 +- wgui/src/components/button.rs | 2 + wgui/src/drawing.rs | 106 ++++++++++++++---- wgui/src/event.rs | 4 +- wgui/src/gfx/cmd.rs | 3 + wgui/src/layout.rs | 2 +- wgui/src/lib.rs | 6 +- wgui/src/renderer_vk/context.rs | 4 +- wgui/src/renderer_vk/rect.rs | 30 +++--- wgui/src/renderer_vk/shaders/rect.vert | 4 +- wgui/src/renderer_vk/shaders/text.vert | 3 +- wgui/src/renderer_vk/text/mod.rs | 30 ++---- wgui/src/renderer_vk/text/text_atlas.rs | 25 +---- wgui/src/renderer_vk/text/text_renderer.rs | 4 - wgui/src/stack.rs | 108 +++++++++++++++++++ wgui/src/transform_stack.rs | 51 --------- wgui/src/widget/label.rs | 1 - wgui/src/widget/mod.rs | 6 +- wgui/src/widget/rectangle.rs | 1 - wgui/src/widget/sprite.rs | 6 +- wlx-overlay-s/src/backend/openxr/lines.rs | 5 +- wlx-overlay-s/src/backend/openxr/skybox.rs | 7 +- wlx-overlay-s/src/backend/wayvr/display.rs | 2 +- wlx-overlay-s/src/gui/panel/mod.rs | 11 +- wlx-overlay-s/src/overlays/screen/capture.rs | 23 ++-- wlx-overlay-s/src/overlays/wayvr.rs | 6 +- wlx-overlay-s/src/state.rs | 5 +- 28 files changed, 299 insertions(+), 182 deletions(-) create mode 100644 wgui/src/stack.rs delete mode 100644 wgui/src/transform_stack.rs diff --git a/uidev/src/main.rs b/uidev/src/main.rs index 4a689b0..fc6fa4d 100644 --- a/uidev/src/main.rs +++ b/uidev/src/main.rs @@ -77,7 +77,7 @@ fn load_testbed( fn main() -> Result<(), Box> { init_logging(); - let (gfx, event_loop, window, surface) = init_window()?; + let (gfx, event_loop, window, surface) = init_window("[-/=]: gui scale, F10: debug draw")?; let inner_size = window.inner_size(); let mut swapchain_size = [inner_size.width, inner_size.height]; @@ -115,6 +115,8 @@ fn main() -> Result<(), Box> { render_context.update_viewport(&mut shared_context, swapchain_size, scale)?; log::trace!("new swapchain_size: {swapchain_size:?}"); + let mut debug_draw_enabled = false; + let mut profiler = profiler::Profiler::new(1000); let mut frame_index: u64 = 0; @@ -218,6 +220,11 @@ fn main() -> Result<(), Box> { .. } => { if event.state == ElementState::Pressed { + if event.physical_key == PhysicalKey::Code(KeyCode::F10) { + debug_draw_enabled = !debug_draw_enabled; + testbed.layout().borrow_mut().mark_redraw(); + } + if event.physical_key == PhysicalKey::Code(KeyCode::Equal) { scale *= 1.25; render_context @@ -323,7 +330,12 @@ fn main() -> Result<(), Box> { .begin_rendering(tgt, WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.1])) .unwrap(); - let primitives = wgui::drawing::draw(&testbed.layout().borrow_mut()).unwrap(); + let draw_params = wgui::drawing::DrawParams { + layout: &testbed.layout().borrow_mut(), + debug_draw: debug_draw_enabled, + }; + + let primitives = wgui::drawing::draw(&draw_params).unwrap(); render_context .draw(&mut shared_context, &mut cmd_buf, &primitives) .unwrap(); diff --git a/uidev/src/vulkan.rs b/uidev/src/vulkan.rs index 92d26de..17e22a7 100644 --- a/uidev/src/vulkan.rs +++ b/uidev/src/vulkan.rs @@ -14,7 +14,9 @@ fn get_vulkan_library() -> &'static Arc { } #[allow(clippy::type_complexity)] -pub fn init_window() -> anyhow::Result<( +pub fn init_window( + title: &str, +) -> anyhow::Result<( Arc, winit::event_loop::EventLoop<()>, Arc, @@ -40,7 +42,11 @@ pub fn init_window() -> anyhow::Result<( #[allow(deprecated)] let window = Arc::new( event_loop - .create_window(Window::default_attributes().with_transparent(true)) + .create_window( + Window::default_attributes() + .with_transparent(true) + .with_title(title), + ) .unwrap(), // want panic ); let surface = Surface::from_window(instance.clone(), window.clone())?; diff --git a/wgui/src/components/button.rs b/wgui/src/components/button.rs index 79c9cfb..da0911f 100644 --- a/wgui/src/components/button.rs +++ b/wgui/src/components/button.rs @@ -233,6 +233,8 @@ pub fn construct( style.align_items = Some(AlignItems::Center); style.justify_content = Some(JustifyContent::Center); style.padding = length(1.0); + style.overflow.x = taffy::Overflow::Hidden; + style.overflow.y = taffy::Overflow::Hidden; // update colors to default ones if they are not specified let color = if let Some(color) = params.color { diff --git a/wgui/src/drawing.rs b/wgui/src/drawing.rs index 926d7d5..045275c 100644 --- a/wgui/src/drawing.rs +++ b/wgui/src/drawing.rs @@ -8,7 +8,7 @@ use crate::{ drawing, layout::Widget, renderer_vk::text::custom_glyph::CustomGlyph, - transform_stack::{self, TransformStack}, + stack::{self, ScissorStack, TransformStack}, widget::{self}, }; @@ -37,6 +37,22 @@ impl Boundary { size: Vec2::new(transform.dim.x, transform.dim.y), } } + + pub const fn top(&self) -> f32 { + self.pos.y + } + + pub const fn bottom(&self) -> f32 { + self.pos.y + self.size.y + } + + pub const fn left(&self) -> f32 { + self.pos.x + } + + pub const fn right(&self) -> f32 { + self.pos.x + self.size.x + } } #[derive(Debug, Copy, Clone)] @@ -115,7 +131,6 @@ pub struct Rectangle { pub struct PrimitiveExtent { pub(super) boundary: Boundary, pub(super) transform: Mat4, - pub(super) depth: f32, // FIXME: remove this } pub enum RenderPrimitive { @@ -126,15 +141,39 @@ pub enum RenderPrimitive { ScissorDisable, } +pub struct DrawParams<'a> { + pub layout: &'a Layout, + pub debug_draw: bool, +} + +fn has_overflow_clip(style: &taffy::Style) -> bool { + style.overflow.x != taffy::Overflow::Visible || style.overflow.y != taffy::Overflow::Visible +} + +fn primitive_debug_rect(boundary: &Boundary, transform: &Mat4, color: drawing::Color) -> drawing::RenderPrimitive { + drawing::RenderPrimitive::Rectangle( + PrimitiveExtent { + boundary: *boundary, + transform: *transform, + }, + Rectangle { + border: 1.0, + border_color: color, + color: Color::new(0.0, 0.0, 0.0, 0.0), + ..Default::default() + }, + ) +} + fn draw_widget( - layout: &Layout, + params: &DrawParams, state: &mut DrawState, node_id: taffy::NodeId, style: &taffy::Style, widget: &Widget, parent_transform: &glam::Mat4, ) { - let Ok(l) = layout.state.tree.layout(node_id) else { + let Ok(l) = params.layout.state.tree.layout(node_id) else { debug_assert!(false); return; }; @@ -148,16 +187,34 @@ fn draw_widget( None => (Vec2::default(), None), }; - state.transform_stack.push(transform_stack::Transform { + state.transform_stack.push(stack::Transform { pos: Vec2::new(l.location.x, l.location.y) - shift, transform, dim: Vec2::new(l.size.width, l.size.height), }); - // FIXME: this is temporary - // FIXME: implement scissor stack (do not allow growing!) - if info.is_some() { + if params.debug_draw { let boundary = drawing::Boundary::construct(state.transform_stack); + state.primitives.push(primitive_debug_rect( + &boundary, + &transform, + Color::new(0.0, 1.0, 1.0, 0.5), + )); + } + + let scissor_pushed = info.is_some() && has_overflow_clip(style); + + if scissor_pushed { + let boundary = drawing::Boundary::construct(state.transform_stack); + state.scissor_stack.push(boundary); + if params.debug_draw { + state.primitives.push(primitive_debug_rect( + &boundary, + &transform, + Color::new(1.0, 0.0, 1.0, 1.0), + )); + } + state.primitives.push(drawing::RenderPrimitive::ScissorEnable(boundary)); } @@ -169,10 +226,11 @@ fn draw_widget( widget_state.draw_all(state, &draw_params); - draw_children(layout, state, node_id, &transform); + draw_children(params, state, node_id, &transform); - if info.is_some() { + if scissor_pushed { state.primitives.push(drawing::RenderPrimitive::ScissorDisable); + state.scissor_stack.pop(); } state.transform_stack.pop(); @@ -182,7 +240,9 @@ fn draw_widget( } } -fn draw_children(layout: &Layout, state: &mut DrawState, parent_node_id: taffy::NodeId, model: &glam::Mat4) { +fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taffy::NodeId, model: &glam::Mat4) { + let layout = ¶ms.layout; + for node_id in layout.state.tree.child_ids(parent_node_id) { let Some(widget_id) = layout.state.tree.get_node_context(node_id).copied() else { debug_assert!(false); @@ -199,33 +259,37 @@ fn draw_children(layout: &Layout, state: &mut DrawState, parent_node_id: taffy:: continue; }; - state.depth += 0.01; - draw_widget(layout, state, node_id, style, widget, model); - state.depth -= 0.01; + draw_widget(params, state, node_id, style, widget, model); } } -pub fn draw(layout: &Layout) -> anyhow::Result> { +pub fn draw(params: &DrawParams) -> anyhow::Result> { let mut primitives = Vec::::new(); let mut transform_stack = TransformStack::new(); + let mut scissor_stack = ScissorStack::new(); let model = glam::Mat4::IDENTITY; - let Some(root_widget) = layout.state.widgets.get(layout.root_widget) else { + let Some(root_widget) = params.layout.state.widgets.get(params.layout.root_widget) else { panic!(); }; - let Ok(style) = layout.state.tree.style(layout.root_node) else { + let Ok(style) = params.layout.state.tree.style(params.layout.root_node) else { panic!(); }; - let mut params = DrawState { + scissor_stack.push(Boundary { + pos: Default::default(), + size: Vec2::splat(1.0e12), + }); + + let mut state = DrawState { primitives: &mut primitives, transform_stack: &mut transform_stack, - layout, - depth: 0.0, + scissor_stack: &mut scissor_stack, + layout: params.layout, }; - draw_widget(layout, &mut params, layout.root_node, style, root_widget, &model); + draw_widget(params, &mut state, params.layout.root_node, style, root_widget, &model); Ok(primitives) } diff --git a/wgui/src/event.rs b/wgui/src/event.rs index c7ba4ca..6e90b9a 100644 --- a/wgui/src/event.rs +++ b/wgui/src/event.rs @@ -10,7 +10,7 @@ use crate::{ animation::{self, Animation}, i18n::I18n, layout::{LayoutState, WidgetID}, - transform_stack::{Transform, TransformStack}, + stack::{Transform, TransformStack}, widget::{WidgetData, WidgetObj}, }; @@ -170,7 +170,7 @@ impl CallbackMetadata { pub fn get_mouse_pos_relative(&self, transform_stack: &TransformStack) -> Option { let mouse_pos_abs = self.get_mouse_pos_absolute()?; - Some(mouse_pos_abs - transform_stack.get_pos()) + Some(mouse_pos_abs - transform_stack.get().pos) } } diff --git a/wgui/src/gfx/cmd.rs b/wgui/src/gfx/cmd.rs index 6c8c343..55152f6 100644 --- a/wgui/src/gfx/cmd.rs +++ b/wgui/src/gfx/cmd.rs @@ -47,6 +47,7 @@ impl WCommandBuffer { #[derive(Clone, Copy)] pub enum WGfxClearMode { Keep, + DontCare, Clear([f32; 4]), } @@ -58,10 +59,12 @@ impl WCommandBuffer { load_op: match &clear_mode { WGfxClearMode::Keep => AttachmentLoadOp::Load, WGfxClearMode::Clear(_) => AttachmentLoadOp::Clear, + WGfxClearMode::DontCare => AttachmentLoadOp::DontCare, }, store_op: AttachmentStoreOp::Store, clear_value: match &clear_mode { WGfxClearMode::Keep => None, + WGfxClearMode::DontCare => None, WGfxClearMode::Clear(color) => Some(ClearValue::Float(*color)), }, ..RenderingAttachmentInfo::image_view(render_target) diff --git a/wgui/src/layout.rs b/wgui/src/layout.rs index 288567f..c34b29a 100644 --- a/wgui/src/layout.rs +++ b/wgui/src/layout.rs @@ -9,7 +9,7 @@ use crate::{ components::{Component, InitData}, event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection}, globals::WguiGlobals, - transform_stack::Transform, + stack::Transform, widget::{self, EventParams, WidgetObj, WidgetState, div::WidgetDiv}, }; diff --git a/wgui/src/lib.rs b/wgui/src/lib.rs index 57131e0..2ef7cf4 100644 --- a/wgui/src/lib.rs +++ b/wgui/src/lib.rs @@ -15,7 +15,9 @@ clippy::option_if_let_else, clippy::significant_drop_tightening, clippy::float_cmp, - clippy::needless_pass_by_ref_mut + clippy::needless_pass_by_ref_mut, + clippy::use_self, + clippy::match_same_arms )] pub mod animation; @@ -30,7 +32,7 @@ pub mod i18n; pub mod layout; pub mod parser; pub mod renderer_vk; -pub mod transform_stack; +pub mod stack; pub mod widget; // re-exported libs diff --git a/wgui/src/renderer_vk/context.rs b/wgui/src/renderer_vk/context.rs index 16e2dd0..7072884 100644 --- a/wgui/src/renderer_vk/context.rs +++ b/wgui/src/renderer_vk/context.rs @@ -242,7 +242,7 @@ impl Context { drawing::RenderPrimitive::Rectangle(extent, rectangle) => { pass .rect_renderer - .add_rect(extent.boundary, *rectangle, &extent.transform, extent.depth); + .add_rect(extent.boundary, *rectangle, &extent.transform); } drawing::RenderPrimitive::Text(extent, text) => { pass.text_areas.push(TextArea { @@ -253,7 +253,6 @@ impl Context { scale: self.pixel_scale, default_color: cosmic_text::Color::rgb(0, 0, 0), custom_glyphs: &[], - depth: extent.depth, transform: extent.transform, }); } @@ -266,7 +265,6 @@ impl Context { scale: self.pixel_scale, custom_glyphs: sprites.as_slice(), default_color: cosmic_text::Color::rgb(255, 0, 255), - depth: extent.depth, transform: extent.transform, }); } diff --git a/wgui/src/renderer_vk/rect.rs b/wgui/src/renderer_vk/rect.rs index 1f2f7d4..6ed324b 100644 --- a/wgui/src/renderer_vk/rect.rs +++ b/wgui/src/renderer_vk/rect.rs @@ -30,8 +30,6 @@ pub struct RectVertex { pub in_border_color: u32, #[format(R32_UINT)] pub round_border_gradient: [u8; 4], - #[format(R32_SFLOAT)] - pub depth: f32, } /// Cloneable pipeline & shaders to be shared between `RectRenderer` instances. @@ -68,7 +66,7 @@ pub struct RectRenderer { pipeline: RectPipeline, rect_vertices: Vec, vert_buffer: Subbuffer<[RectVertex]>, - vert_buffer_size: usize, + vert_buffer_len: usize, model_buffer: ModelBuffer, pass: Option, } @@ -77,16 +75,17 @@ impl RectRenderer { pub fn new(pipeline: RectPipeline) -> anyhow::Result { const BUFFER_SIZE: usize = 32; - let vert_buffer = pipeline - .gfx - .empty_buffer(BufferUsage::VERTEX_BUFFER | BufferUsage::TRANSFER_DST, BUFFER_SIZE as _)?; + let vert_buffer = pipeline.gfx.empty_buffer( + BufferUsage::VERTEX_BUFFER | BufferUsage::TRANSFER_DST, + (std::mem::size_of::() * BUFFER_SIZE) as _, + )?; Ok(Self { model_buffer: ModelBuffer::new(&pipeline.gfx)?, pipeline, rect_vertices: vec![], vert_buffer, - vert_buffer_size: BUFFER_SIZE, + vert_buffer_len: BUFFER_SIZE, pass: None, }) } @@ -96,7 +95,7 @@ impl RectRenderer { self.model_buffer.begin(); } - pub fn add_rect(&mut self, boundary: Boundary, rectangle: Rectangle, transform: &Mat4, depth: f32) { + pub fn add_rect(&mut self, boundary: Boundary, rectangle: Rectangle, transform: &Mat4) { let in_model_idx = self .model_buffer .register_pos_size(&boundary.pos, &boundary.size, transform); @@ -113,18 +112,17 @@ impl RectRenderer { rectangle.gradient as u8, 0, // unused ], - depth, }); } fn upload_verts(&mut self) -> anyhow::Result<()> { - if self.vert_buffer_size < self.rect_vertices.len() { - let new_size = self.vert_buffer_size * 2; - self.vert_buffer = self - .pipeline - .gfx - .empty_buffer(BufferUsage::VERTEX_BUFFER | BufferUsage::TRANSFER_DST, new_size as _)?; - self.vert_buffer_size = new_size; + if self.vert_buffer_len < self.rect_vertices.len() { + let new_size = self.vert_buffer_len * 2; + self.vert_buffer = self.pipeline.gfx.empty_buffer( + BufferUsage::VERTEX_BUFFER | BufferUsage::TRANSFER_DST, + (std::mem::size_of::() * new_size) as _, + )?; + self.vert_buffer_len = new_size; } self.vert_buffer.write()?[0..self.rect_vertices.len()].clone_from_slice(&self.rect_vertices); diff --git a/wgui/src/renderer_vk/shaders/rect.vert b/wgui/src/renderer_vk/shaders/rect.vert index 0a25313..5732142 100644 --- a/wgui/src/renderer_vk/shaders/rect.vert +++ b/wgui/src/renderer_vk/shaders/rect.vert @@ -9,7 +9,6 @@ layout(location = 2) in uint in_color; layout(location = 3) in uint in_color2; layout(location = 4) in uint in_border_color; layout(location = 5) in uint round_border_gradient; -layout(location = 6) in float depth; layout(location = 0) out vec4 out_color; layout(location = 1) out vec4 out_color2; @@ -41,8 +40,7 @@ void main() { out_rect_size = rect_size; - gl_Position = - uniforms.projection * model_matrix * vec4(corner_pos, depth, 1.0); + gl_Position = uniforms.projection * model_matrix * vec4(corner_pos, 0.0, 1.0); out_border_color = vec4(float((in_border_color & 0x00ff0000u) >> 16u) / 255.0, diff --git a/wgui/src/renderer_vk/shaders/text.vert b/wgui/src/renderer_vk/shaders/text.vert index 2ec97bc..164db7c 100644 --- a/wgui/src/renderer_vk/shaders/text.vert +++ b/wgui/src/renderer_vk/shaders/text.vert @@ -8,7 +8,6 @@ layout(location = 1) in uint in_rect_dim; layout(location = 2) in uint in_uv; layout(location = 3) in uint in_color; layout(location = 4) in uint in_content_type; -layout(location = 5) in float depth; layout(location = 7) in float scale; layout(location = 0) out vec4 out_color; @@ -41,7 +40,7 @@ void main() { mat4 model_matrix = model_buffer.models[in_model_idx]; gl_Position = - uniforms.projection * model_matrix * vec4(corner_pos * scale, depth, 1.0); + uniforms.projection * model_matrix * vec4(corner_pos * scale, 0.0, 1.0); out_content_type = in_content_type & 0xffffu; diff --git a/wgui/src/renderer_vk/text/mod.rs b/wgui/src/renderer_vk/text/mod.rs index 10da9e2..4892333 100644 --- a/wgui/src/renderer_vk/text/mod.rs +++ b/wgui/src/renderer_vk/text/mod.rs @@ -5,9 +5,7 @@ pub mod text_renderer; use std::{cell::RefCell, rc::Rc, sync::LazyLock}; -use cosmic_text::{ - Align, Attrs, Buffer, Color, FontSystem, Metrics, Style, SwashCache, Weight, Wrap, -}; +use cosmic_text::{Align, Attrs, Buffer, Color, FontSystem, Metrics, Style, SwashCache, Weight, Wrap}; use custom_glyph::{ContentType, CustomGlyph}; use etagere::AllocId; use glam::Mat4; @@ -15,10 +13,8 @@ use parking_lot::Mutex; use crate::drawing::{self}; -pub static FONT_SYSTEM: LazyLock> = - LazyLock::new(|| Mutex::new(FontSystem::new())); -pub static SWASH_CACHE: LazyLock> = - LazyLock::new(|| Mutex::new(SwashCache::new())); +pub static FONT_SYSTEM: LazyLock> = LazyLock::new(|| Mutex::new(FontSystem::new())); +pub static SWASH_CACHE: LazyLock> = LazyLock::new(|| Mutex::new(SwashCache::new())); /// Used in case no `font_size` is defined const DEFAULT_FONT_SIZE: f32 = 14.; @@ -26,10 +22,8 @@ const DEFAULT_FONT_SIZE: f32 = 14.; /// In case no `line_height` is defined, use `font_size` * `DEFAULT_LINE_HEIGHT_RATIO` const DEFAULT_LINE_HEIGHT_RATIO: f32 = 1.43; -pub(crate) const DEFAULT_METRICS: Metrics = Metrics::new( - DEFAULT_FONT_SIZE, - DEFAULT_FONT_SIZE * DEFAULT_LINE_HEIGHT_RATIO, -); +pub(crate) const DEFAULT_METRICS: Metrics = + Metrics::new(DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE * DEFAULT_LINE_HEIGHT_RATIO); #[derive(Default, Clone)] pub struct TextStyle { @@ -66,11 +60,7 @@ impl From<&TextStyle> for Metrics { impl From<&TextStyle> for Wrap { fn from(value: &TextStyle) -> Self { - if value.wrap { - Self::WordOrGlyph - } else { - Self::None - } + if value.wrap { Self::WordOrGlyph } else { Self::None } } } @@ -155,11 +145,7 @@ impl From for drawing::Color { // glyphon types below pub(super) enum GpuCacheStatus { - InAtlas { - x: u16, - y: u16, - content_type: ContentType, - }, + InAtlas { x: u16, y: u16, content_type: ContentType }, SkipRasterization, } @@ -215,8 +201,6 @@ pub struct TextArea<'a> { pub default_color: Color, /// Additional custom glyphs to render. pub custom_glyphs: &'a [CustomGlyph], - /// Distance from camera, 0.0..=1.0 - pub depth: f32, /// Text transformation pub transform: Mat4, } diff --git a/wgui/src/renderer_vk/text/text_atlas.rs b/wgui/src/renderer_vk/text/text_atlas.rs index 3fc4a2a..1f6c5bd 100644 --- a/wgui/src/renderer_vk/text/text_atlas.rs +++ b/wgui/src/renderer_vk/text/text_atlas.rs @@ -42,10 +42,7 @@ impl TextPipeline { true, )?; - Ok(Self { - gfx, - inner: pipeline, - }) + Ok(Self { gfx, inner: pipeline }) } } @@ -63,8 +60,6 @@ pub struct GlyphVertex { #[format(R32_UINT)] pub in_content_type: [u16; 2], // 2 bytes unused! TODO #[format(R32_SFLOAT)] - pub depth: f32, - #[format(R32_SFLOAT)] pub scale: f32, } @@ -86,12 +81,7 @@ impl InnerAtlas { const INITIAL_SIZE: u32 = 256; fn new(common: TextPipeline, kind: Kind) -> anyhow::Result { - let max_texture_dimension_2d = common - .gfx - .device - .physical_device() - .properties() - .max_image_dimension2_d; + let max_texture_dimension_2d = common.gfx.device.physical_device().properties().max_image_dimension2_d; let size = Self::INITIAL_SIZE.min(max_texture_dimension_2d); let packer = BucketedAtlasAllocator::new(size2(size as i32, size as i32)); @@ -180,11 +170,7 @@ impl InnerAtlas { self.kind.num_channels() } - pub(super) fn grow( - &mut self, - font_system: &mut FontSystem, - cache: &mut SwashCache, - ) -> anyhow::Result { + pub(super) fn grow(&mut self, font_system: &mut FontSystem, cache: &mut SwashCache) -> anyhow::Result { const GROWTH_FACTOR: u32 = 2; if self.size >= self.max_texture_dimension_2d { @@ -327,10 +313,7 @@ impl TextAtlas { Ok(did_grow) } - pub(super) const fn inner_for_content_mut( - &mut self, - content_type: ContentType, - ) -> &mut InnerAtlas { + pub(super) const fn inner_for_content_mut(&mut self, content_type: ContentType) -> &mut InnerAtlas { match content_type { ContentType::Color => &mut self.color_atlas, ContentType::Mask => &mut self.mask_atlas, diff --git a/wgui/src/renderer_vk/text/text_renderer.rs b/wgui/src/renderer_vk/text/text_renderer.rs index 1f489fe..d30eb6d 100644 --- a/wgui/src/renderer_vk/text/text_renderer.rs +++ b/wgui/src/renderer_vk/text/text_renderer.rs @@ -116,7 +116,6 @@ impl TextRenderer { bounds_min_y, bounds_max_x, bounds_max_y, - depth: text_area.depth, transform: &text_area.transform, }, |_cache, _font_system| -> Option { @@ -192,7 +191,6 @@ impl TextRenderer { bounds_min_y, bounds_max_x, bounds_max_y, - depth: text_area.depth, transform: &text_area.transform, }, |cache, font_system| -> Option { @@ -319,7 +317,6 @@ struct PrepareGlyphParams<'a> { bounds_min_y: i32, bounds_max_x: i32, bounds_max_y: i32, - depth: f32, } #[allow(clippy::too_many_lines)] @@ -484,7 +481,6 @@ fn prepare_glyph( content_type as u16, 0, // unused (TODO!) ], - depth: par.depth, scale: par.glyph_scale, })) } diff --git a/wgui/src/stack.rs b/wgui/src/stack.rs new file mode 100644 index 0000000..f365949 --- /dev/null +++ b/wgui/src/stack.rs @@ -0,0 +1,108 @@ +use glam::Vec2; + +use crate::drawing; + +pub trait Pushable { + fn push(&mut self, item: &T); +} + +pub struct GenericStack { + pub stack: [T; STACK_MAX], + top: u8, +} + +pub trait StackItem: Default + Clone + Copy + Pushable {} + +impl, const STACK_MAX: usize> GenericStack { + pub fn new() -> Self { + Self { + stack: [Default::default(); STACK_MAX], + top: 1, + } + } + + pub fn push(&mut self, mut item: T) { + assert!(self.top < STACK_MAX as u8); + let idx = (self.top - 1) as usize; + let upper_item = &self.stack[idx]; + item.push(upper_item); + self.stack[self.top as usize] = item; + self.top += 1; + } + + pub fn pop(&mut self) { + assert!(self.top > 0); + self.top -= 1; + } + + pub const fn get(&self) -> &T { + &self.stack[(self.top - 1) as usize] + } +} + +impl, const STACK_MAX: usize> Default for GenericStack { + fn default() -> Self { + Self::new() + } +} + +// ######################################## +// Transform stack +// ######################################## + +#[derive(Default, Copy, Clone)] +pub struct Transform { + pub pos: Vec2, + pub transform: glam::Mat4, + pub dim: Vec2, // for convenience +} + +impl StackItem for Transform where Transform: Pushable {} + +impl Pushable for Transform { + fn push(&mut self, upper: &Transform) { + self.pos += upper.pos; + } +} + +pub type TransformStack = GenericStack; + +// ######################################## +// Scissor stack +// ######################################## + +impl StackItem for drawing::Boundary where drawing::Boundary: Pushable {} + +impl Pushable for drawing::Boundary { + fn push(&mut self, upper: &drawing::Boundary) { + let mut display_pos = self.pos; + let mut display_size = self.size; + + // limit in x-coord + if display_pos.x < upper.left() { + display_size.x -= upper.left() - display_pos.x; + display_pos.x = upper.left(); + } + + // limit in y-coord + if display_pos.y < upper.top() { + display_size.y -= upper.top() - display_pos.y; + display_pos.y = upper.top(); + } + + // limit in width + if display_pos.x + display_size.x > upper.right() { + display_size.x = upper.right() - display_pos.x; + } + + // limit in height + if display_pos.y + display_size.y > upper.bottom() { + display_size.y = upper.bottom() - display_pos.y; + } + + self.pos = display_pos; + self.size = display_size; + } +} + +pub type ScissorStack = GenericStack; diff --git a/wgui/src/transform_stack.rs b/wgui/src/transform_stack.rs deleted file mode 100644 index 96c1c19..0000000 --- a/wgui/src/transform_stack.rs +++ /dev/null @@ -1,51 +0,0 @@ -use glam::Vec2; - -#[derive(Default, Copy, Clone)] -pub struct Transform { - pub pos: Vec2, - pub transform: glam::Mat4, - - pub dim: Vec2, // for convenience -} - -const TRANSFORM_STACK_MAX: usize = 64; -pub struct TransformStack { - pub stack: [Transform; TRANSFORM_STACK_MAX], - top: u8, -} - -impl TransformStack { - pub fn new() -> Self { - Self { - stack: [Default::default(); TRANSFORM_STACK_MAX], - top: 1, - } - } - - pub fn push(&mut self, mut t: Transform) { - assert!(self.top < TRANSFORM_STACK_MAX as u8); - let idx = (self.top - 1) as usize; - t.pos += self.stack[idx].pos; - self.stack[self.top as usize] = t; - self.top += 1; - } - - pub fn pop(&mut self) { - assert!(self.top > 0); - self.top -= 1; - } - - pub const fn get(&self) -> &Transform { - &self.stack[(self.top - 1) as usize] - } - - pub const fn get_pos(&self) -> Vec2 { - self.stack[(self.top - 1) as usize].pos - } -} - -impl Default for TransformStack { - fn default() -> Self { - Self::new() - } -} diff --git a/wgui/src/widget/label.rs b/wgui/src/widget/label.rs index be80922..093caec 100644 --- a/wgui/src/widget/label.rs +++ b/wgui/src/widget/label.rs @@ -121,7 +121,6 @@ impl WidgetObj for WidgetLabel { state.primitives.push(drawing::RenderPrimitive::Text( PrimitiveExtent { boundary, - depth: state.depth, transform: state.transform_stack.get().transform, }, self.buffer.clone(), diff --git a/wgui/src/widget/mod.rs b/wgui/src/widget/mod.rs index 1f680ea..f83c8e5 100644 --- a/wgui/src/widget/mod.rs +++ b/wgui/src/widget/mod.rs @@ -10,7 +10,7 @@ use crate::{ EventListenerVec, MouseWheelEvent, }, layout::{Layout, LayoutState, WidgetID}, - transform_stack::TransformStack, + stack::{ScissorStack, TransformStack}, }; pub mod div; @@ -100,7 +100,7 @@ pub struct DrawState<'a> { pub layout: &'a Layout, pub primitives: &'a mut Vec, pub transform_stack: &'a mut TransformStack, - pub depth: f32, //TODO: actually use this in shader + pub scissor_stack: &'a mut ScissorStack, } // per-widget draw params @@ -253,7 +253,6 @@ impl WidgetState { ), Vec2::new(transform.dim.x * info.handle_size.x, thickness), ), - depth: state.depth, transform: transform.transform, }, rect_params, @@ -271,7 +270,6 @@ impl WidgetState { ), Vec2::new(thickness, transform.dim.y * info.handle_size.y), ), - depth: state.depth, transform: transform.transform, }, rect_params, diff --git a/wgui/src/widget/rectangle.rs b/wgui/src/widget/rectangle.rs index a1f8eeb..7408d4a 100644 --- a/wgui/src/widget/rectangle.rs +++ b/wgui/src/widget/rectangle.rs @@ -46,7 +46,6 @@ impl WidgetObj for WidgetRectangle { state.primitives.push(drawing::RenderPrimitive::Rectangle( PrimitiveExtent { boundary, - depth: state.depth, transform: state.transform_stack.get().transform, }, drawing::Rectangle { diff --git a/wgui/src/widget/sprite.rs b/wgui/src/widget/sprite.rs index 3e5dd3a..60f76e0 100644 --- a/wgui/src/widget/sprite.rs +++ b/wgui/src/widget/sprite.rs @@ -58,7 +58,6 @@ impl WidgetObj for WidgetSprite { state.primitives.push(drawing::RenderPrimitive::Sprite( PrimitiveExtent { boundary, - depth: state.depth, transform: state.transform_stack.get().transform, }, Some(glyph), @@ -79,12 +78,11 @@ impl WidgetObj for WidgetSprite { state.primitives.push(drawing::RenderPrimitive::Text( PrimitiveExtent { boundary, - depth: state.depth, transform: state.transform_stack.get().transform, }, Rc::new(RefCell::new(buffer)), - )) - }; + )); + } } fn measure( diff --git a/wlx-overlay-s/src/backend/openxr/lines.rs b/wlx-overlay-s/src/backend/openxr/lines.rs index 26b3eb3..2953585 100644 --- a/wlx-overlay-s/src/backend/openxr/lines.rs +++ b/wlx-overlay-s/src/backend/openxr/lines.rs @@ -9,7 +9,7 @@ use std::{ }, }; -use wgui::gfx::{WGfx, pass::WGfxPass, pipeline::WGfxPipeline}; +use wgui::gfx::{WGfx, cmd::WGfxClearMode, pass::WGfxPass, pipeline::WGfxPipeline}; use crate::{ backend::openxr::helpers, @@ -71,6 +71,7 @@ impl LinePool { 0..4, 0..1, vec![set0], + &Default::default(), )?; Ok(Self { @@ -161,7 +162,7 @@ impl LinePool { let mut cmd_buffer = app .gfx .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - cmd_buffer.begin_rendering(tgt)?; + cmd_buffer.begin_rendering(tgt, WGfxClearMode::DontCare)?; cmd_buffer.run_ref(&self.pass)?; cmd_buffer.end_rendering()?; diff --git a/wlx-overlay-s/src/backend/openxr/skybox.rs b/wlx-overlay-s/src/backend/openxr/skybox.rs index 6a0c1b7..bed101d 100644 --- a/wlx-overlay-s/src/backend/openxr/skybox.rs +++ b/wlx-overlay-s/src/backend/openxr/skybox.rs @@ -11,6 +11,7 @@ use vulkano::{ image::view::ImageView, pipeline::graphics::{color_blend::AttachmentBlend, input_assembly::PrimitiveTopology}, }; +use wgui::gfx::cmd::WGfxClearMode; use crate::{ backend::openxr::{helpers::translation_rotation_to_posef, swapchain::SwapchainOpts}, @@ -112,12 +113,13 @@ impl Skybox { 0..4, 0..1, vec![set0, set1], + &Default::default(), )?; let mut cmd_buffer = app .gfx .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - cmd_buffer.begin_rendering(tgt)?; + cmd_buffer.begin_rendering(tgt, WGfxClearMode::DontCare)?; cmd_buffer.run_ref(&pass)?; cmd_buffer.end_rendering()?; @@ -160,12 +162,13 @@ impl Skybox { 0..4, 0..1, vec![], + &Default::default(), )?; let mut cmd_buffer = app .gfx .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - cmd_buffer.begin_rendering(tgt)?; + cmd_buffer.begin_rendering(tgt, WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]))?; cmd_buffer.run_ref(&pass)?; cmd_buffer.end_rendering()?; diff --git a/wlx-overlay-s/src/backend/wayvr/display.rs b/wlx-overlay-s/src/backend/wayvr/display.rs index 29777f2..2e9fb06 100644 --- a/wlx-overlay-s/src/backend/wayvr/display.rs +++ b/wlx-overlay-s/src/backend/wayvr/display.rs @@ -308,7 +308,7 @@ impl Display { } pub fn tick_render(&mut self, renderer: &mut GlesRenderer, time_ms: u64) -> anyhow::Result<()> { - renderer.bind(self.gles_texture.clone())?; + renderer.bind(&mut self.gles_texture)?; let size = Size::from((i32::from(self.width), i32::from(self.height))); let damage: Rectangle = Rectangle::from_size(size); diff --git a/wlx-overlay-s/src/gui/panel/mod.rs b/wlx-overlay-s/src/gui/panel/mod.rs index b8a9b93..fcede7b 100644 --- a/wlx-overlay-s/src/gui/panel/mod.rs +++ b/wlx-overlay-s/src/gui/panel/mod.rs @@ -243,8 +243,15 @@ impl OverlayBackend for GuiPanel { .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit) .unwrap(); // want panic - cmd_buf.begin_rendering(tgt)?; - let primitives = wgui::drawing::draw(&self.layout)?; + cmd_buf.begin_rendering( + tgt, + wgui::gfx::cmd::WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]), + )?; + + let primitives = wgui::drawing::draw(&wgui::drawing::DrawParams { + layout: &self.layout, + debug_draw: false, + })?; self.context .draw(&mut app.wgui_shared, &mut cmd_buf, &primitives)?; cmd_buf.end_rendering()?; diff --git a/wlx-overlay-s/src/overlays/screen/capture.rs b/wlx-overlay-s/src/overlays/screen/capture.rs index 0451f17..957b491 100644 --- a/wlx-overlay-s/src/overlays/screen/capture.rs +++ b/wlx-overlay-s/src/overlays/screen/capture.rs @@ -6,21 +6,22 @@ use vulkano::{ command_buffer::CommandBufferUsage, device::Queue, format::Format, - image::{sampler::Filter, view::ImageView, Image}, + image::{Image, sampler::Filter, view::ImageView}, pipeline::graphics::{color_blend::AttachmentBlend, input_assembly::PrimitiveTopology}, }; -use wgui::gfx::{pass::WGfxPass, pipeline::WGfxPipeline, WGfx}; +use wgui::gfx::{WGfx, cmd::WGfxClearMode, pass::WGfxPass, pipeline::WGfxPipeline}; use wlx_capture::{ - frame::{self as wlx_frame, DrmFormat, FrameFormat, MouseMeta, Transform, WlxFrame}, WlxCapture, + frame::{self as wlx_frame, DrmFormat, FrameFormat, MouseMeta, Transform, WlxFrame}, }; use crate::{ backend::overlay::FrameMeta, config::GeneralConfig, graphics::{ - dmabuf::{fourcc_to_vk, WGfxDmabuf}, - upload_quad_vertices, CommandBuffers, Vert2Uv, + CommandBuffers, Vert2Uv, + dmabuf::{WGfxDmabuf, fourcc_to_vk}, + upload_quad_vertices, }, state::AppState, }; @@ -91,6 +92,7 @@ impl ScreenPipeline { 0..4, 0..1, vec![set0, set1], + &Default::default(), ) } @@ -123,7 +125,14 @@ impl ScreenPipeline { let set0 = pipeline.uniform_sampler(0, view, Filter::Nearest)?; let set1 = pipeline.buffer(1, buf_alpha)?; - let pass = pipeline.create_pass(extentf, buf_vert.clone(), 0..4, 0..1, vec![set0, set1])?; + let pass = pipeline.create_pass( + extentf, + buf_vert.clone(), + 0..4, + 0..1, + vec![set0, set1], + &Default::default(), + )?; cmd_xfer.build_and_execute_now()?; Ok(MousePass { pass, buf_vert }) @@ -145,7 +154,7 @@ impl ScreenPipeline { let mut cmd = app .gfx .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - cmd.begin_rendering(tgt)?; + cmd.begin_rendering(tgt, WGfxClearMode::DontCare)?; cmd.run_ref(&self.pass)?; if let Some(mouse) = capture.mouse.as_ref() { diff --git a/wlx-overlay-s/src/overlays/wayvr.rs b/wlx-overlay-s/src/overlays/wayvr.rs index 032031e..65d5c3c 100644 --- a/wlx-overlay-s/src/overlays/wayvr.rs +++ b/wlx-overlay-s/src/overlays/wayvr.rs @@ -147,6 +147,7 @@ impl WayVRBackend { 0..4, 0..1, vec![set0, set1], + &Default::default(), )?; Ok(Self { @@ -683,7 +684,10 @@ impl OverlayBackend for WayVRBackend { let mut cmd_buffer = app .gfx .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - cmd_buffer.begin_rendering(tgt)?; + cmd_buffer.begin_rendering( + tgt, + wgui::gfx::cmd::WGfxClearMode::Clear([0.0, 0.0, 0.0, 1.0]), + )?; cmd_buffer.run_ref(&self.pass)?; cmd_buffer.end_rendering()?; buf.push(cmd_buffer.build()?); diff --git a/wlx-overlay-s/src/state.rs b/wlx-overlay-s/src/state.rs index 6320854..b661447 100644 --- a/wlx-overlay-s/src/state.rs +++ b/wlx-overlay-s/src/state.rs @@ -96,10 +96,7 @@ impl AppState { toast_sound: toast_sound_wav, wgui_globals: WguiGlobals::new( Box::new(gui::asset::GuiAsset {}), - wgui::globals::Defaults { - dark_mode: true, - text_color: wgui::drawing::Color::new(1.0, 1.0, 1.0, 1.0), - }, + wgui::globals::Defaults::default(), )?, #[cfg(feature = "osc")]