diff --git a/src/main.rs b/src/main.rs index 103897b..cb2665c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::num::NonZeroU32; use std::ops::Deref; -use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, Weak}; +use std::sync::{Arc, RwLock, Weak}; use femtovg::renderer::OpenGl; use femtovg::{Canvas, Color}; @@ -30,9 +30,10 @@ use crate::nodes::layout::Layout; mod nodes; -type GNode = dyn Node; -type SharedGNode = Arc>; -type TaffyMap = PtrWeakKeyHashMap>, taffy::node::Node>; +type TNode = dyn Node; +type SharedTNode = Arc>>; +type TaffyMap = PtrWeakKeyHashMap>>, taffy::node::Node>; +type CurrentRenderer = OpenGl; fn main() { let event_loop = EventLoop::new(); @@ -46,7 +47,7 @@ fn main() { let mut taffy = Taffy::new(); let mut taffy_map = TaffyMap::new(); - let mut root = Layout::::new(); + let mut root = Layout::::new(); root.style.layout.display = taffy::style::Display::Flex; root.style.layout.flex_direction = taffy::style::FlexDirection::Row; root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle { @@ -61,7 +62,7 @@ fn main() { } }, color: Color::rgb(255, 0, 0), - radius: 0. + radius: 10. }))); root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle { style: Style { @@ -75,13 +76,13 @@ fn main() { } }, color: Color::rgb(0, 255, 0), - radius: 10. + radius: 0. }))); - let groot: Arc>> = Arc::new(RwLock::new(root)); + let groot: Arc>> = Arc::new(RwLock::new(root)); { let clonned = groot.clone(); let root = clonned.read().unwrap(); - let root_style = GNode::style(root.deref()); + let root_style = TNode::::style(root.deref()); let root_layout = root_style.layout.to_owned(); let root_node = taffy.new_leaf(root_layout).unwrap(); @@ -90,12 +91,13 @@ fn main() { let mut context = RenderContext { canvas, - taffy_map, + node_layout: taffy_map, taffy }; // let mut width: u32 = 0; // let mut height: u32 = 0; + let mut should_recompute = true; event_loop.run(move |event, _target, control_flow| match event { Event::WindowEvent { event, .. } => match event { @@ -115,23 +117,33 @@ fn main() { groot.style.layout.size.height = Dimension::Points(size.height as f32); drop(groot); window.request_redraw(); + should_recompute = true; }, _ => {} }, Event::RedrawRequested(_) => { - let root: Arc> = groot.clone(); - layout_recursively(&root, &mut context); - let src_nodes = context.taffy_map.values().map(|v| v.to_owned()).collect::>(); - context.taffy_map.remove_expired(); - let dst_nodes = context.taffy_map.values().map(|v| v.to_owned()).collect::>(); - for src_node in src_nodes { - if !dst_nodes.contains(&src_node) { - context.taffy.remove(src_node).unwrap(); - dbg!("Removed node", src_node); + let root: SharedTNode = groot.clone(); + if should_recompute { + layout_recursively(&root, &mut context); + let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::>(); + context.node_layout.remove_expired(); + let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::>(); + for src_node in src_nodes { + if !dst_nodes.contains(&src_node) { + context.taffy.remove(src_node).unwrap(); + dbg!("Removed node", src_node); + } } + for (node, taffy_node) in context.node_layout.iter() { + let node = node.read().unwrap(); + let node_style = node.style(); + context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap(); + } + context.taffy.compute_layout(*context.node_layout.get(&root).unwrap(), Size::MAX_CONTENT).unwrap(); + should_recompute = false; + // dbg!("recomputed"); } - context.taffy.compute_layout(*context.taffy_map.get(&root).unwrap(), Size::MAX_CONTENT).unwrap(); - dbg!(&root); + // dbg!(&root); render(&buffer_context, &surface, &window, &mut context, &root); }, _ => {} @@ -180,13 +192,14 @@ fn render( buffer_context: &PossiblyCurrentContext, surface: &Surface, window: &Window, - context: &mut RenderContext, - root_node: &Arc> + context: &mut RenderContext, + root_node: &SharedTNode ) { // Make sure the canvas has the right size: let size = window.inner_size(); + context.canvas.reset(); context.canvas.set_size(size.width, size.height, window.scale_factor() as f32); - context.canvas.scale(1., -1.); // layout is bottom to top, canvas is top to bottom, this might make it easier? + // context.canvas.scale(1., -1.); // layout is bottom to top, canvas is top to bottom, this might make it easier? context.canvas.clear_rect(0, 0, size.width, size.height, Color::black()); // Do the render passes here diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index 311c760..50dd21e 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -3,21 +3,33 @@ pub mod primitives; use std::fmt::Debug; use std::sync::{Arc, RwLock}; -use femtovg::{Canvas, Renderer}; -use femtovg::renderer::OpenGl; +use femtovg::{Canvas, Renderer, Color}; use taffy::layout::Layout; pub use taffy::style::Style as TaffyStyle; use taffy::Taffy; -use crate::{GNode, TaffyMap, SharedGNode}; +use crate::TaffyMap; type SharedTNode = Arc>>; pub struct RenderContext { pub canvas: Canvas, - pub taffy_map: TaffyMap, + pub node_layout: TaffyMap, pub taffy: Taffy } +impl RenderContext { + /// Fills a rectangle area with the specified color, using the current transform of the canvas. + /// Rotation WILL break this, this is mostly for simple scaling and translation. + fn fill_rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: Color) { + let transform = self.canvas.transform(); + let x = transform[0] * x as f32 + transform[2] * y as f32 + transform[4]; + let y = transform[1] * x as f32 + transform[3] * y as f32 + transform[5]; + let width = transform[0] * width as f32 + transform[2] * height as f32; + let height = transform[1] * width as f32 + transform[3] * height as f32; + self.canvas.clear_rect(x as u32, y as u32, width as u32, height as u32, color); + } +} + #[derive(Copy, Clone, Default, Debug)] #[non_exhaustive] pub enum Overflow { @@ -51,14 +63,14 @@ pub trait Node: Debug { fn render_post_children(&self, _context: &mut RenderContext, _layout: Layout) {} } -pub fn layout_recursively(node: &SharedTNode, context: &mut RenderContext) -> taffy::node::Node { - let taffy_node = context.taffy_map.get(node); +pub fn layout_recursively(node: &SharedTNode, context: &mut RenderContext) -> taffy::node::Node { + let taffy_node = context.node_layout.get(node); let taffy_node = match taffy_node { Some(taffy_node) => taffy_node, None => { let taffy_node = context.taffy.new_leaf(node.read().unwrap().style().layout.to_owned()).unwrap(); - context.taffy_map.insert(node.clone(), taffy_node); - context.taffy_map.get(node).unwrap() + context.node_layout.insert(node.clone(), taffy_node); + context.node_layout.get(node).unwrap() } }; @@ -78,21 +90,23 @@ pub fn layout_recursively(node: &SharedTNode, context: &mut RenderContex taffy_node } -pub fn render_recursively(node: &SharedGNode, context: &mut RenderContext) { +pub fn render_recursively(node: &SharedTNode, context: &mut RenderContext) { let read_node = node.read().unwrap(); let styles = read_node.style(); - let taffy_node = context.taffy_map.get(node).unwrap(); + let taffy_node = context.node_layout.get(node).unwrap(); let layout = *context.taffy.layout(*taffy_node).unwrap(); let sself = node.clone(); context.canvas.save(); context.canvas.translate(layout.location.x, layout.location.y); // dbg!(node, layout); + // dbg!(styles, layout); + // dbg!(context.canvas.transform()); match styles.overflow { Overflow::Visible => {}, Overflow::Hidden => { context.canvas.scissor( - layout.location.x, - layout.location.y, + 0., + 0., layout.size.width, layout.size.height, ); diff --git a/src/nodes/primitives.rs b/src/nodes/primitives.rs index 2806588..b22248c 100644 --- a/src/nodes/primitives.rs +++ b/src/nodes/primitives.rs @@ -1,8 +1,6 @@ use femtovg::{Color, Paint, Path, Renderer}; -use taffy::geometry::Size; use taffy::layout::Layout; -use taffy::style::Dimension; -use crate::nodes::{Node, NodeChildren, Overflow, RenderContext, Style, TaffyStyle}; +use crate::nodes::{Node, NodeChildren, RenderContext, Style}; #[derive(Clone, Default, Debug)] pub struct Rectangle { @@ -43,7 +41,7 @@ impl Node for Rectangle { &Paint::color(self.color) ); } else { - context.canvas.clear_rect( + context.fill_rect( 0, 0, layout.size.width as u32,