mirror of
https://github.com/danbulant/mangui
synced 2026-07-06 11:20:34 +00:00
working render
This commit is contained in:
parent
f85cc62f1f
commit
a953e771da
3 changed files with 65 additions and 40 deletions
61
src/main.rs
61
src/main.rs
|
|
@ -1,6 +1,6 @@
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, Weak};
|
use std::sync::{Arc, RwLock, Weak};
|
||||||
|
|
||||||
use femtovg::renderer::OpenGl;
|
use femtovg::renderer::OpenGl;
|
||||||
use femtovg::{Canvas, Color};
|
use femtovg::{Canvas, Color};
|
||||||
|
|
@ -30,9 +30,10 @@ use crate::nodes::layout::Layout;
|
||||||
|
|
||||||
mod nodes;
|
mod nodes;
|
||||||
|
|
||||||
type GNode = dyn Node<OpenGl>;
|
type TNode<T> = dyn Node<T>;
|
||||||
type SharedGNode = Arc<RwLock<GNode>>;
|
type SharedTNode<T> = Arc<RwLock<TNode<T>>>;
|
||||||
type TaffyMap = PtrWeakKeyHashMap<Weak<RwLock<GNode>>, taffy::node::Node>;
|
type TaffyMap<T> = PtrWeakKeyHashMap<Weak<RwLock<TNode<T>>>, taffy::node::Node>;
|
||||||
|
type CurrentRenderer = OpenGl;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
@ -46,7 +47,7 @@ fn main() {
|
||||||
let mut taffy = Taffy::new();
|
let mut taffy = Taffy::new();
|
||||||
let mut taffy_map = TaffyMap::new();
|
let mut taffy_map = TaffyMap::new();
|
||||||
|
|
||||||
let mut root = Layout::<OpenGl>::new();
|
let mut root = Layout::<CurrentRenderer>::new();
|
||||||
root.style.layout.display = taffy::style::Display::Flex;
|
root.style.layout.display = taffy::style::Display::Flex;
|
||||||
root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
|
root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
|
||||||
root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||||
|
|
@ -61,7 +62,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
color: Color::rgb(255, 0, 0),
|
color: Color::rgb(255, 0, 0),
|
||||||
radius: 0.
|
radius: 10.
|
||||||
})));
|
})));
|
||||||
root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||||
style: Style {
|
style: Style {
|
||||||
|
|
@ -75,13 +76,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
color: Color::rgb(0, 255, 0),
|
color: Color::rgb(0, 255, 0),
|
||||||
radius: 10.
|
radius: 0.
|
||||||
})));
|
})));
|
||||||
let groot: Arc<RwLock<Layout<OpenGl>>> = Arc::new(RwLock::new(root));
|
let groot: Arc<RwLock<Layout<CurrentRenderer>>> = Arc::new(RwLock::new(root));
|
||||||
{
|
{
|
||||||
let clonned = groot.clone();
|
let clonned = groot.clone();
|
||||||
let root = clonned.read().unwrap();
|
let root = clonned.read().unwrap();
|
||||||
let root_style = GNode::style(root.deref());
|
let root_style = TNode::<OpenGl>::style(root.deref());
|
||||||
let root_layout = root_style.layout.to_owned();
|
let root_layout = root_style.layout.to_owned();
|
||||||
let root_node = taffy.new_leaf(root_layout).unwrap();
|
let root_node = taffy.new_leaf(root_layout).unwrap();
|
||||||
|
|
||||||
|
|
@ -90,12 +91,13 @@ fn main() {
|
||||||
|
|
||||||
let mut context = RenderContext {
|
let mut context = RenderContext {
|
||||||
canvas,
|
canvas,
|
||||||
taffy_map,
|
node_layout: taffy_map,
|
||||||
taffy
|
taffy
|
||||||
};
|
};
|
||||||
|
|
||||||
// let mut width: u32 = 0;
|
// let mut width: u32 = 0;
|
||||||
// let mut height: u32 = 0;
|
// let mut height: u32 = 0;
|
||||||
|
let mut should_recompute = true;
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -115,23 +117,33 @@ fn main() {
|
||||||
groot.style.layout.size.height = Dimension::Points(size.height as f32);
|
groot.style.layout.size.height = Dimension::Points(size.height as f32);
|
||||||
drop(groot);
|
drop(groot);
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
|
should_recompute = true;
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Event::RedrawRequested(_) => {
|
Event::RedrawRequested(_) => {
|
||||||
let root: Arc<RwLock<GNode>> = groot.clone();
|
let root: SharedTNode<CurrentRenderer> = groot.clone();
|
||||||
layout_recursively(&root, &mut context);
|
if should_recompute {
|
||||||
let src_nodes = context.taffy_map.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
layout_recursively(&root, &mut context);
|
||||||
context.taffy_map.remove_expired();
|
let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
||||||
let dst_nodes = context.taffy_map.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
context.node_layout.remove_expired();
|
||||||
for src_node in src_nodes {
|
let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
||||||
if !dst_nodes.contains(&src_node) {
|
for src_node in src_nodes {
|
||||||
context.taffy.remove(src_node).unwrap();
|
if !dst_nodes.contains(&src_node) {
|
||||||
dbg!("Removed node", 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);
|
render(&buffer_context, &surface, &window, &mut context, &root);
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -180,13 +192,14 @@ fn render(
|
||||||
buffer_context: &PossiblyCurrentContext,
|
buffer_context: &PossiblyCurrentContext,
|
||||||
surface: &Surface<WindowSurface>,
|
surface: &Surface<WindowSurface>,
|
||||||
window: &Window,
|
window: &Window,
|
||||||
context: &mut RenderContext<OpenGl>,
|
context: &mut RenderContext<CurrentRenderer>,
|
||||||
root_node: &Arc<RwLock<GNode>>
|
root_node: &SharedTNode<CurrentRenderer>
|
||||||
) {
|
) {
|
||||||
// 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();
|
||||||
|
context.canvas.reset();
|
||||||
context.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);
|
||||||
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());
|
context.canvas.clear_rect(0, 0, size.width, size.height, Color::black());
|
||||||
|
|
||||||
// Do the render passes here
|
// Do the render passes here
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,33 @@ pub mod primitives;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use femtovg::{Canvas, Renderer};
|
use femtovg::{Canvas, Renderer, Color};
|
||||||
use femtovg::renderer::OpenGl;
|
|
||||||
use taffy::layout::Layout;
|
use taffy::layout::Layout;
|
||||||
pub use taffy::style::Style as TaffyStyle;
|
pub use taffy::style::Style as TaffyStyle;
|
||||||
use taffy::Taffy;
|
use taffy::Taffy;
|
||||||
use crate::{GNode, TaffyMap, SharedGNode};
|
use crate::TaffyMap;
|
||||||
|
|
||||||
type SharedTNode<T> = Arc<RwLock<dyn Node<T>>>;
|
type SharedTNode<T> = Arc<RwLock<dyn Node<T>>>;
|
||||||
|
|
||||||
pub struct RenderContext<T: Renderer> {
|
pub struct RenderContext<T: Renderer> {
|
||||||
pub canvas: Canvas<T>,
|
pub canvas: Canvas<T>,
|
||||||
pub taffy_map: TaffyMap,
|
pub node_layout: TaffyMap<T>,
|
||||||
pub taffy: Taffy
|
pub taffy: Taffy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Renderer> RenderContext<T> {
|
||||||
|
/// 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)]
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Overflow {
|
pub enum Overflow {
|
||||||
|
|
@ -51,14 +63,14 @@ pub trait Node<T: Renderer>: Debug {
|
||||||
fn render_post_children(&self, _context: &mut RenderContext<T>, _layout: Layout) {}
|
fn render_post_children(&self, _context: &mut RenderContext<T>, _layout: Layout) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_recursively(node: &SharedTNode<OpenGl>, context: &mut RenderContext<OpenGl>) -> taffy::node::Node {
|
pub fn layout_recursively<T: Renderer>(node: &SharedTNode<T>, context: &mut RenderContext<T>) -> taffy::node::Node {
|
||||||
let taffy_node = context.taffy_map.get(node);
|
let taffy_node = context.node_layout.get(node);
|
||||||
let taffy_node = match taffy_node {
|
let taffy_node = match taffy_node {
|
||||||
Some(taffy_node) => taffy_node,
|
Some(taffy_node) => taffy_node,
|
||||||
None => {
|
None => {
|
||||||
let taffy_node = context.taffy.new_leaf(node.read().unwrap().style().layout.to_owned()).unwrap();
|
let taffy_node = context.taffy.new_leaf(node.read().unwrap().style().layout.to_owned()).unwrap();
|
||||||
context.taffy_map.insert(node.clone(), taffy_node);
|
context.node_layout.insert(node.clone(), taffy_node);
|
||||||
context.taffy_map.get(node).unwrap()
|
context.node_layout.get(node).unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -78,21 +90,23 @@ pub fn layout_recursively(node: &SharedTNode<OpenGl>, context: &mut RenderContex
|
||||||
taffy_node
|
taffy_node
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_recursively(node: &SharedGNode, context: &mut RenderContext<OpenGl>) {
|
pub fn render_recursively<T: Renderer>(node: &SharedTNode<T>, context: &mut RenderContext<T>) {
|
||||||
let read_node = node.read().unwrap();
|
let read_node = node.read().unwrap();
|
||||||
let styles = read_node.style();
|
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 layout = *context.taffy.layout(*taffy_node).unwrap();
|
||||||
let sself = node.clone();
|
let sself = node.clone();
|
||||||
context.canvas.save();
|
context.canvas.save();
|
||||||
context.canvas.translate(layout.location.x, layout.location.y);
|
context.canvas.translate(layout.location.x, layout.location.y);
|
||||||
// dbg!(node, layout);
|
// dbg!(node, layout);
|
||||||
|
// dbg!(styles, layout);
|
||||||
|
// dbg!(context.canvas.transform());
|
||||||
match styles.overflow {
|
match styles.overflow {
|
||||||
Overflow::Visible => {},
|
Overflow::Visible => {},
|
||||||
Overflow::Hidden => {
|
Overflow::Hidden => {
|
||||||
context.canvas.scissor(
|
context.canvas.scissor(
|
||||||
layout.location.x,
|
0.,
|
||||||
layout.location.y,
|
0.,
|
||||||
layout.size.width,
|
layout.size.width,
|
||||||
layout.size.height,
|
layout.size.height,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use femtovg::{Color, Paint, Path, Renderer};
|
use femtovg::{Color, Paint, Path, Renderer};
|
||||||
use taffy::geometry::Size;
|
|
||||||
use taffy::layout::Layout;
|
use taffy::layout::Layout;
|
||||||
use taffy::style::Dimension;
|
use crate::nodes::{Node, NodeChildren, RenderContext, Style};
|
||||||
use crate::nodes::{Node, NodeChildren, Overflow, RenderContext, Style, TaffyStyle};
|
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct Rectangle {
|
pub struct Rectangle {
|
||||||
|
|
@ -43,7 +41,7 @@ impl<T: Renderer> Node<T> for Rectangle {
|
||||||
&Paint::color(self.color)
|
&Paint::color(self.color)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
context.canvas.clear_rect(
|
context.fill_rect(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
layout.size.width as u32,
|
layout.size.width as u32,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue