overflow: hidden/scroll scissor support, remove depth

This commit is contained in:
Aleksander
2025-09-25 23:21:11 +02:00
parent 8f75d451e4
commit eb12a6a319
28 changed files with 299 additions and 182 deletions

View File

@@ -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 = &params.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<Vec<RenderPrimitive>> {
pub fn draw(params: &DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
let mut primitives = Vec::<RenderPrimitive>::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)
}