mirror of
https://github.com/danbulant/mangui
synced 2026-07-05 10:50:35 +00:00
improved context
This commit is contained in:
parent
7152108017
commit
68cf25da3f
2 changed files with 58 additions and 32 deletions
33
src/main.rs
33
src/main.rs
|
|
@ -1,10 +1,9 @@
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
use femtovg::renderer::OpenGl;
|
use femtovg::renderer::OpenGl;
|
||||||
use femtovg::{Canvas, Color, Renderer};
|
use femtovg::{Canvas, Color};
|
||||||
use glutin::surface::Surface;
|
use glutin::surface::Surface;
|
||||||
use glutin::{context::PossiblyCurrentContext, display::Display};
|
use glutin::{context::PossiblyCurrentContext, display::Display};
|
||||||
use glutin_winit::DisplayBuilder;
|
use glutin_winit::DisplayBuilder;
|
||||||
|
|
@ -23,7 +22,7 @@ use glutin::{
|
||||||
};
|
};
|
||||||
use taffy::Taffy;
|
use taffy::Taffy;
|
||||||
use weak_table::PtrWeakKeyHashMap;
|
use weak_table::PtrWeakKeyHashMap;
|
||||||
use crate::nodes::{Node, render_recursively};
|
use crate::nodes::{Node, render_recursively, RenderContext};
|
||||||
|
|
||||||
mod nodes;
|
mod nodes;
|
||||||
|
|
||||||
|
|
@ -32,12 +31,12 @@ type TaffyMap = PtrWeakKeyHashMap<Weak<GNode>, taffy::node::Node>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
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 _) }
|
let renderer = unsafe { OpenGl::new_from_function_cstr(|s| gl_display.get_proc_address(s) as *const _) }
|
||||||
.expect("Cannot create renderer");
|
.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 = Taffy::new();
|
||||||
let mut taffy_map = TaffyMap::new();
|
let mut taffy_map = TaffyMap::new();
|
||||||
|
|
@ -48,6 +47,10 @@ fn main() {
|
||||||
|
|
||||||
taffy_map.insert(root.clone(), root_node);
|
taffy_map.insert(root.clone(), root_node);
|
||||||
|
|
||||||
|
let mut context = RenderContext {
|
||||||
|
canvas
|
||||||
|
};
|
||||||
|
|
||||||
event_loop.run(move |event, _target, control_flow| match event {
|
event_loop.run(move |event, _target, control_flow| match event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => match event {
|
||||||
// WindowEvent::CursorMoved { position, .. } => {
|
// WindowEvent::CursorMoved { position, .. } => {
|
||||||
|
|
@ -57,13 +60,13 @@ fn main() {
|
||||||
WindowEvent::Resized(size) => {
|
WindowEvent::Resized(size) => {
|
||||||
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
|
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
|
||||||
let height: NonZeroU32 = NonZeroU32::new(size.height).unwrap();
|
let height: NonZeroU32 = NonZeroU32::new(size.height).unwrap();
|
||||||
surface.resize(&context, width, height);
|
surface.resize(&buffer_context, width, height);
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Event::RedrawRequested(_) => {
|
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(
|
fn render(
|
||||||
context: &PossiblyCurrentContext,
|
buffer_context: &PossiblyCurrentContext,
|
||||||
surface: &Surface<WindowSurface>,
|
surface: &Surface<WindowSurface>,
|
||||||
window: &Window,
|
window: &Window,
|
||||||
canvas: &mut Canvas<OpenGl>,
|
context: &mut RenderContext<OpenGl>,
|
||||||
root_node: &Arc<GNode>,
|
root_node: &Arc<GNode>,
|
||||||
taffy_map: &TaffyMap,
|
taffy_map: &TaffyMap,
|
||||||
taffy: &Taffy
|
taffy: &Taffy
|
||||||
) {
|
) {
|
||||||
// Make sure the canvas has the right size:
|
// Make sure the canvas has the right size:
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
canvas.set_size(size.width, size.height, window.scale_factor() as f32);
|
context.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?
|
context.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.clear_rect(0, 0, size.width, size.height, Color::black());
|
||||||
|
|
||||||
// Do the render passes here
|
// 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
|
// Tell renderer to execute all drawing commands
|
||||||
canvas.flush();
|
context.canvas.flush();
|
||||||
// Display what we've just rendered
|
// 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");
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,12 @@ use taffy::style::Style as TaffyStyle;
|
||||||
use taffy::Taffy;
|
use taffy::Taffy;
|
||||||
use crate::{GNode, TaffyMap};
|
use crate::{GNode, TaffyMap};
|
||||||
|
|
||||||
|
pub struct RenderContext<T: Renderer> {
|
||||||
|
pub(crate) canvas: Canvas<T>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[non_exhaustive]
|
||||||
pub enum Overflow {
|
pub enum Overflow {
|
||||||
#[default]
|
#[default]
|
||||||
/// Content is not clipped and may be rendered outside the element's box
|
/// Content is not clipped and may be rendered outside the element's box
|
||||||
|
|
@ -25,26 +30,44 @@ pub struct Style {
|
||||||
pub overflow: Overflow
|
pub overflow: Overflow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeChildren<T> = Vec<Arc<dyn Node<T>>>;
|
||||||
|
|
||||||
pub trait Node<T: Renderer> {
|
pub trait Node<T: Renderer> {
|
||||||
|
/// Return style. Usually, you just want self.style.
|
||||||
fn style(&self) -> &Style;
|
fn style(&self) -> &Style;
|
||||||
fn children(&self) -> Option<&Vec<Arc<dyn Node<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 render(&self, canvas: &mut Canvas<T>, layout: &Layout, render_children: &dyn Fn(&mut Canvas<T>) -> ());
|
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 node = taffy_map.get(selfref).unwrap();
|
||||||
let layout = taffy.layout(*node).unwrap();
|
let layout = taffy.layout(*node).unwrap();
|
||||||
let sself = selfref.clone();
|
let sself = selfref.clone();
|
||||||
canvas.save_with(move |mut canvas| {
|
context.canvas.save();
|
||||||
canvas.translate(layout.location.x, layout.location.y);
|
context.canvas.translate(layout.location.x, layout.location.y);
|
||||||
sself.render(&mut canvas, &layout, & (|canvas| {
|
match styles.overflow {
|
||||||
if let Some(children) = sself.children() {
|
Overflow::Visible => {},
|
||||||
for child in children {
|
Overflow::Hidden => {
|
||||||
render_recursively(child, canvas, taffy_map, taffy);
|
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 {
|
pub struct RedBoxDemo {
|
||||||
|
|
@ -69,14 +92,14 @@ impl RedBoxDemo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Renderer> Node<T> for RedBoxDemo {
|
impl<T: Renderer> Node<T> for RedBoxDemo {
|
||||||
fn children(&self) -> Option<&Vec<Arc<dyn Node<T>>>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
fn style(&self) -> &Style {
|
fn style(&self) -> &Style {
|
||||||
&self.style
|
&self.style
|
||||||
}
|
}
|
||||||
fn render(&self, canvas: &mut Canvas<T>, layout: &Layout, _render_children: &dyn Fn(&mut Canvas<T>)) {
|
fn children(&self) -> Option<&NodeChildren<T>> {
|
||||||
canvas.clear_rect(
|
None
|
||||||
|
}
|
||||||
|
fn render<'a>(&self, context: &mut RenderContext<T>, _layout: &Layout, _render_children: &dyn Fn(&mut RenderContext<T>)) {
|
||||||
|
context.canvas.clear_rect(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
30,
|
30,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue