From 68cf25da3f781eb0cd481a0b46863e5ae6d4ab2f Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Wed, 18 Oct 2023 22:09:04 +0200 Subject: [PATCH] improved context --- src/main.rs | 33 +++++++++++++++------------- src/nodes/mod.rs | 57 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7d6c983..6dbd50e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,9 @@ use std::num::NonZeroU32; use std::ops::Deref; -use std::rc::Rc; use std::sync::{Arc, Weak}; use femtovg::renderer::OpenGl; -use femtovg::{Canvas, Color, Renderer}; +use femtovg::{Canvas, Color}; use glutin::surface::Surface; use glutin::{context::PossiblyCurrentContext, display::Display}; use glutin_winit::DisplayBuilder; @@ -23,7 +22,7 @@ use glutin::{ }; use taffy::Taffy; use weak_table::PtrWeakKeyHashMap; -use crate::nodes::{Node, render_recursively}; +use crate::nodes::{Node, render_recursively, RenderContext}; mod nodes; @@ -32,12 +31,12 @@ type TaffyMap = PtrWeakKeyHashMap, taffy::node::Node>; fn main() { let event_loop = EventLoop::new(); - let (context, gl_display, window, surface) = create_window(&event_loop); + let (buffer_context, gl_display, window, surface) = create_window(&event_loop); let renderer = unsafe { OpenGl::new_from_function_cstr(|s| gl_display.get_proc_address(s) as *const _) } .expect("Cannot create renderer"); - let mut canvas = Canvas::new(renderer).expect("Cannot create canvas"); + let canvas = Canvas::new(renderer).expect("Cannot create canvas"); let mut taffy = Taffy::new(); let mut taffy_map = TaffyMap::new(); @@ -48,6 +47,10 @@ fn main() { taffy_map.insert(root.clone(), root_node); + let mut context = RenderContext { + canvas + }; + event_loop.run(move |event, _target, control_flow| match event { Event::WindowEvent { event, .. } => match event { // WindowEvent::CursorMoved { position, .. } => { @@ -57,13 +60,13 @@ fn main() { WindowEvent::Resized(size) => { let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap(); let height: NonZeroU32 = NonZeroU32::new(size.height).unwrap(); - surface.resize(&context, width, height); + surface.resize(&buffer_context, width, height); window.request_redraw(); }, _ => {} }, Event::RedrawRequested(_) => { - render(&context, &surface, &window, &mut canvas, &root, &taffy_map, &taffy); + render(&buffer_context, &surface, &window, &mut context, &root, &taffy_map, &taffy); }, _ => {} }) @@ -108,25 +111,25 @@ fn create_window(event_loop: &EventLoop<()>) -> (PossiblyCurrentContext, Display } fn render( - context: &PossiblyCurrentContext, + buffer_context: &PossiblyCurrentContext, surface: &Surface, window: &Window, - canvas: &mut Canvas, + context: &mut RenderContext, root_node: &Arc, taffy_map: &TaffyMap, taffy: &Taffy ) { // Make sure the canvas has the right size: let size = window.inner_size(); - canvas.set_size(size.width, size.height, window.scale_factor() as f32); - canvas.scale(1., -1.); // layout is bottom to top, canvas is top to bottom, this might make it easier? - canvas.clear_rect(0, 0, size.width, size.height, Color::black()); + 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.clear_rect(0, 0, size.width, size.height, Color::black()); // Do the render passes here - render_recursively(root_node, canvas, taffy_map, taffy); + render_recursively(root_node, context, taffy_map, taffy); // Tell renderer to execute all drawing commands - canvas.flush(); + context.canvas.flush(); // Display what we've just rendered - surface.swap_buffers(context).expect("Could not swap buffers"); + surface.swap_buffers(buffer_context).expect("Could not swap buffers"); } \ No newline at end of file diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index aa07867..eba9d6b 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -8,7 +8,12 @@ use taffy::style::Style as TaffyStyle; use taffy::Taffy; use crate::{GNode, TaffyMap}; +pub struct RenderContext { + pub(crate) canvas: Canvas, +} + #[derive(Copy, Clone, Default)] +#[non_exhaustive] pub enum Overflow { #[default] /// Content is not clipped and may be rendered outside the element's box @@ -25,26 +30,44 @@ pub struct Style { pub overflow: Overflow } +type NodeChildren = Vec>>; + pub trait Node { + /// Return style. Usually, you just want self.style. fn style(&self) -> &Style; - fn children(&self) -> Option<&Vec>>>; - fn render(&self, canvas: &mut Canvas, layout: &Layout, render_children: &dyn Fn(&mut Canvas) -> ()); + /// Returns the children of the node. If the node has no children, return None (empty Vec also works, None is mainly for nodes without children support). + fn children(&self) -> Option<&NodeChildren>; + /// Render the node and its children. render_children gets ['children'] and calls this function there as well. When drawing, the canvas is translated to the node's location. + /// Canvas considers 0, 0 to be top left corner (for location after layouting happens) + fn render(&self, context: &mut RenderContext, layout: &Layout, render_children: &dyn Fn(&mut RenderContext)); } -pub fn render_recursively(selfref: &Arc, canvas: &mut Canvas, taffy_map: &TaffyMap, taffy: &Taffy) { +pub fn render_recursively(selfref: &Arc, context: &mut RenderContext, taffy_map: &TaffyMap, taffy: &Taffy) { + let styles = selfref.style(); let node = taffy_map.get(selfref).unwrap(); let layout = taffy.layout(*node).unwrap(); let sself = selfref.clone(); - canvas.save_with(move |mut canvas| { - canvas.translate(layout.location.x, layout.location.y); - sself.render(&mut canvas, &layout, & (|canvas| { - if let Some(children) = sself.children() { - for child in children { - render_recursively(child, canvas, taffy_map, taffy); - } + context.canvas.save(); + context.canvas.translate(layout.location.x, layout.location.y); + match styles.overflow { + Overflow::Visible => {}, + Overflow::Hidden => { + context.canvas.scissor( + layout.location.x, + layout.location.y, + layout.size.width, + layout.size.height, + ); + } + } + sself.render(context, layout, & (|context| { + if let Some(children) = sself.children() { + for child in children { + render_recursively(child, context, taffy_map, taffy); } - })); - }); + } + })); + context.canvas.restore(); } pub struct RedBoxDemo { @@ -69,14 +92,14 @@ impl RedBoxDemo { } impl Node for RedBoxDemo { - fn children(&self) -> Option<&Vec>>> { - None - } fn style(&self) -> &Style { &self.style } - fn render(&self, canvas: &mut Canvas, layout: &Layout, _render_children: &dyn Fn(&mut Canvas)) { - canvas.clear_rect( + fn children(&self) -> Option<&NodeChildren> { + None + } + fn render<'a>(&self, context: &mut RenderContext, _layout: &Layout, _render_children: &dyn Fn(&mut RenderContext)) { + context.canvas.clear_rect( 0, 0, 30,