improved context

This commit is contained in:
Daniel Bulant 2023-10-18 22:09:04 +02:00
parent 7152108017
commit 68cf25da3f
2 changed files with 58 additions and 32 deletions

View file

@ -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<Weak<GNode>, 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<WindowSurface>,
window: &Window,
canvas: &mut Canvas<OpenGl>,
context: &mut RenderContext<OpenGl>,
root_node: &Arc<GNode>,
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");
}

View file

@ -8,7 +8,12 @@ use taffy::style::Style as TaffyStyle;
use taffy::Taffy;
use crate::{GNode, TaffyMap};
pub struct RenderContext<T: Renderer> {
pub(crate) canvas: Canvas<T>,
}
#[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<T> = Vec<Arc<dyn Node<T>>>;
pub trait Node<T: Renderer> {
/// Return style. Usually, you just want self.style.
fn style(&self) -> &Style;
fn children(&self) -> Option<&Vec<Arc<dyn Node<T>>>>;
fn render(&self, canvas: &mut Canvas<T>, layout: &Layout, render_children: &dyn Fn(&mut Canvas<T>) -> ());
/// 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<T>>;
/// 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<T>, layout: &Layout, render_children: &dyn Fn(&mut RenderContext<T>));
}
pub fn render_recursively(selfref: &Arc<GNode>, canvas: &mut Canvas<OpenGl>, taffy_map: &TaffyMap, taffy: &Taffy) {
pub fn render_recursively(selfref: &Arc<GNode>, context: &mut RenderContext<OpenGl>, 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<T: Renderer> Node<T> for RedBoxDemo {
fn children(&self) -> Option<&Vec<Arc<dyn Node<T>>>> {
None
}
fn style(&self) -> &Style {
&self.style
}
fn render(&self, canvas: &mut Canvas<T>, layout: &Layout, _render_children: &dyn Fn(&mut Canvas<T>)) {
canvas.clear_rect(
fn children(&self) -> Option<&NodeChildren<T>> {
None
}
fn render<'a>(&self, context: &mut RenderContext<T>, _layout: &Layout, _render_children: &dyn Fn(&mut RenderContext<T>)) {
context.canvas.clear_rect(
0,
0,
30,