Bladeren bron

wallet: improve RenderApi. now each call is paired with a unique u64 ID which is used to modify the call without knowing its location in the draw tree.

darkfi 2 jaren geleden
bovenliggende
commit
5e1c43af36

+ 1 - 0
bin/darkwallet/Cargo.toml

@@ -35,6 +35,7 @@ easy-parallel = "3.3.1"
 rand = "0.8.5"
 rand = "0.8.5"
 async-lock = "3.4.0"
 async-lock = "3.4.0"
 futures = "0.3.30"
 futures = "0.3.30"
+async-recursion = "1.1.1"
 
 
 #rustpython-vm = "0.3.1"
 #rustpython-vm = "0.3.1"
 
 

+ 307 - 29
bin/darkwallet/src/app.rs

@@ -1,5 +1,7 @@
 use async_lock::Mutex;
 use async_lock::Mutex;
+use async_recursion::async_recursion;
 use futures::{stream::FuturesUnordered, StreamExt};
 use futures::{stream::FuturesUnordered, StreamExt};
+use rand::{rngs::OsRng, Rng};
 use std::{
 use std::{
     sync::{mpsc, Arc, Weak},
     sync::{mpsc, Arc, Weak},
     thread,
     thread,
@@ -8,9 +10,13 @@ use std::{
 use crate::{
 use crate::{
     chatapp,
     chatapp,
     error::{Error, Result},
     error::{Error, Result},
-    expr::Op,
-    gfx2::{GraphicsEvent, RenderApiPtr},
-    prop::{Property, PropertySubType, PropertyType},
+    expr::{Op, SExprMachine, SExprVal},
+    gfx::Rectangle,
+    gfx2::{DrawCall, DrawInstruction, DrawMesh, GraphicsEvent, RenderApiPtr, Vertex},
+    prop::{
+        Property, PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr,
+        PropertySubType, PropertyType, PropertyUint32,
+    },
     pubsub::PublisherPtr,
     pubsub::PublisherPtr,
     scene::{
     scene::{
         MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNode, SceneNodeId, SceneNodeInfo,
         MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNode, SceneNodeId, SceneNodeInfo,
@@ -79,46 +85,87 @@ impl App {
 
 
         sg.link(window_id, SceneGraph::ROOT_ID).unwrap();
         sg.link(window_id, SceneGraph::ROOT_ID).unwrap();
 
 
+        // Testing
+        let node = sg.get_node(window_id).unwrap();
+        node.set_property_f32("scale", 2.).unwrap();
+
+        drop(sg);
+
         self.make_me_a_schema_plox().await;
         self.make_me_a_schema_plox().await;
 
 
         // Access drawable in window node and call draw()
         // Access drawable in window node and call draw()
         self.trigger_redraw().await;
         self.trigger_redraw().await;
-
-        let node = sg.get_node(window_id).unwrap();
-        node.set_property_f32("scale", 2.).unwrap();
     }
     }
 
 
     async fn make_me_a_schema_plox(&self) {
     async fn make_me_a_schema_plox(&self) {
+        // Create a layer called view
         let mut sg = self.sg.lock().await;
         let mut sg = self.sg.lock().await;
         let layer_node_id = chatapp::create_layer(&mut sg, "view");
         let layer_node_id = chatapp::create_layer(&mut sg, "view");
 
 
         // Customize our layer
         // Customize our layer
         let node = sg.get_node(layer_node_id).unwrap();
         let node = sg.get_node(layer_node_id).unwrap();
         let prop = node.get_property("rect").unwrap();
         let prop = node.get_property("rect").unwrap();
-        prop.set_u32(0, 0).unwrap();
-        prop.set_u32(1, 0).unwrap();
-        let code = vec![Op::Float32ToUint32((Box::new(Op::LoadVar("sw".to_string()))))];
+        prop.set_f32(0, 0.).unwrap();
+        prop.set_f32(1, 0.).unwrap();
+        let code = vec![Op::LoadVar("sw".to_string())];
         prop.set_expr(2, code).unwrap();
         prop.set_expr(2, code).unwrap();
-        let code = vec![Op::Float32ToUint32((Box::new(Op::LoadVar("sh".to_string()))))];
+        let code = vec![Op::LoadVar("sh".to_string())];
         prop.set_expr(3, code).unwrap();
         prop.set_expr(3, code).unwrap();
+        node.set_property_bool("is_visible", true).unwrap();
 
 
         // Setup the pimpl
         // Setup the pimpl
         let node_id = node.id;
         let node_id = node.id;
         drop(sg);
         drop(sg);
-        let pimpl = RenderLayer::new().await;
+        let pimpl = RenderLayer::new(self.sg.clone(), node_id).await;
         let mut sg = self.sg.lock().await;
         let mut sg = self.sg.lock().await;
         let node = sg.get_node_mut(node_id).unwrap();
         let node = sg.get_node_mut(node_id).unwrap();
         node.pimpl = pimpl;
         node.pimpl = pimpl;
 
 
         let window_id = sg.lookup_node("/window").unwrap().id;
         let window_id = sg.lookup_node("/window").unwrap().id;
         sg.link(node_id, window_id).unwrap();
         sg.link(node_id, window_id).unwrap();
+
+        // Create a mesh
+        let node_id = chatapp::create_mesh(&mut sg, "bg");
+
+        let node = sg.get_node_mut(node_id).unwrap();
+        let prop = node.get_property("rect").unwrap();
+        prop.set_f32(0, 0.).unwrap();
+        prop.set_f32(1, 0.).unwrap();
+        let code = vec![Op::LoadVar("lw".to_string())];
+        prop.set_expr(2, code).unwrap();
+        let code = vec![Op::LoadVar("lh".to_string())];
+        prop.set_expr(3, code).unwrap();
+
+        // Setup the pimpl
+        let node_id = node.id;
+        let (x1, y1) = (0., 0.);
+        let (x2, y2) = (1., 1.);
+        let verts = vec![
+            // top left
+            Vertex { pos: [x1, y1], color: [1., 0., 0., 1.], uv: [0., 0.] },
+            // top right
+            Vertex { pos: [x2, y1], color: [1., 0., 1., 1.], uv: [1., 0.] },
+            // bottom left
+            Vertex { pos: [x1, y2], color: [0., 0., 1., 1.], uv: [0., 1.] },
+            // bottom right
+            Vertex { pos: [x2, y2], color: [1., 1., 0., 1.], uv: [1., 1.] },
+        ];
+        let indices = vec![0, 2, 1, 1, 2, 3];
+        drop(sg);
+        let pimpl =
+            Mesh::new(self.sg.clone(), node_id, self.render_api.clone(), verts, indices).await;
+        let mut sg = self.sg.lock().await;
+        let node = sg.get_node_mut(node_id).unwrap();
+        node.pimpl = pimpl;
+
+        sg.link(node_id, layer_node_id).unwrap();
     }
     }
 
 
     async fn trigger_redraw(&self) {
     async fn trigger_redraw(&self) {
         let sg = self.sg.lock().await;
         let sg = self.sg.lock().await;
         let window_node = sg.lookup_node("/window").expect("no window attached!");
         let window_node = sg.lookup_node("/window").expect("no window attached!");
         match &window_node.pimpl {
         match &window_node.pimpl {
-            Pimpl::Window(win) => win.draw().await,
+            Pimpl::Window(win) => win.draw(&sg).await,
             _ => panic!("wrong pimpl"),
             _ => panic!("wrong pimpl"),
         }
         }
     }
     }
@@ -137,11 +184,11 @@ fn print_type_of<T>(_: &T) {
 pub type WindowPtr = Arc<Window>;
 pub type WindowPtr = Arc<Window>;
 
 
 pub struct Window {
 pub struct Window {
-    sg: SceneGraphPtr2,
     node_id: SceneNodeId,
     node_id: SceneNodeId,
-    render_api: RenderApiPtr,
     resize_task: smol::Task<()>,
     resize_task: smol::Task<()>,
     modify_task: smol::Task<()>,
     modify_task: smol::Task<()>,
+    screen_size_prop: PropertyPtr,
+    render_api: RenderApiPtr,
 }
 }
 
 
 impl Window {
 impl Window {
@@ -162,7 +209,7 @@ impl Window {
 
 
         // Start a task monitoring for window resize events
         // Start a task monitoring for window resize events
         // which updates screen_size
         // which updates screen_size
-        let ev_sub = event_pub.clone().subscribe();
+        let ev_sub = event_pub.subscribe();
         let screen_size_prop2 = screen_size_prop.clone();
         let screen_size_prop2 = screen_size_prop.clone();
         let resize_task = ex.spawn(async move {
         let resize_task = ex.spawn(async move {
             loop {
             loop {
@@ -211,31 +258,52 @@ impl Window {
                             panic!("self destroyed before modify_task was stopped!");
                             panic!("self destroyed before modify_task was stopped!");
                         };
                         };
 
 
-                        self_.draw().await;
+                        let sg = sg.lock().await;
+                        self_.draw(&sg).await;
                     }
                     }
                 }
                 }
             });
             });
 
 
-            Self { sg, node_id, render_api, resize_task, modify_task }
+            Self { node_id, resize_task, modify_task, screen_size_prop, render_api }
         });
         });
 
 
         Pimpl::Window(self_)
         Pimpl::Window(self_)
     }
     }
 
 
-    async fn draw(&self) {
-        // This should remain locked for the entire draw
-        let sg = self.sg.lock().await;
+    async fn draw(&self, sg: &SceneGraph) {
+        debug!("Window::draw()");
+        // SceneGraph should remain locked for the entire draw
         let self_node = sg.get_node(self.node_id).unwrap();
         let self_node = sg.get_node(self.node_id).unwrap();
 
 
+        let screen_width = self.screen_size_prop.get_f32(0).unwrap();
+        let screen_height = self.screen_size_prop.get_f32(1).unwrap();
+
+        let parent_rect = Rectangle { x: 0., y: 0., w: screen_width, h: screen_height };
+
+        let mut draw_calls = vec![];
+        let mut child_calls = vec![];
         for child_inf in self_node.get_children2() {
         for child_inf in self_node.get_children2() {
             let node = sg.get_node(child_inf.id).unwrap();
             let node = sg.get_node(child_inf.id).unwrap();
+            debug!("Window::draw() calling draw() for node '{}':{}", node.name, node.id);
 
 
-            let sg_ref: &SceneGraph = &sg;
-            match &node.pimpl {
-                //Pimpl::RenderLayer(layer) => layer.draw(sg_ref).await,
-                _ => error!("unhandled pimpl type"),
-            }
+            let dcs = match &node.pimpl {
+                Pimpl::RenderLayer(layer) => layer.draw(sg, &parent_rect).await,
+                _ => {
+                    error!("unhandled pimpl type");
+                    continue
+                }
+            };
+            let Some((dc_key, mut dcs)) = dcs else { continue };
+            draw_calls.append(&mut dcs);
+            child_calls.push(dc_key);
         }
         }
+
+        let root_dc = DrawCall { instrs: vec![], dcs: child_calls };
+        draw_calls.push((0, root_dc));
+        println!("{:?}", draw_calls);
+
+        self.render_api.replace_draw_calls(draw_calls).await;
+        debug!("Window::draw() - replaced draw call");
     }
     }
 }
 }
 
 
@@ -248,14 +316,224 @@ impl Stoppable for Window {
 
 
 pub type RenderLayerPtr = Arc<RenderLayer>;
 pub type RenderLayerPtr = Arc<RenderLayer>;
 
 
-pub struct RenderLayer {}
+pub struct RenderLayer {
+    sg: SceneGraphPtr2,
+    node_id: SceneNodeId,
+
+    dc_key: u64,
+
+    is_visible: PropertyBool,
+    rect: PropertyPtr,
+}
 
 
 impl RenderLayer {
 impl RenderLayer {
-    pub async fn new() -> Pimpl {
-        let self_ = Arc::new(Self {});
+    pub async fn new(sg_ptr: SceneGraphPtr2, node_id: SceneNodeId) -> Pimpl {
+        let sg_ptr2 = sg_ptr.clone();
+        let sg = sg_ptr2.lock().await;
+        let node = sg.get_node(node_id).unwrap();
+
+        let is_visible =
+            PropertyBool::wrap(node, "is_visible", 0).expect("RenderLayer::is_visible");
+        let rect = node.get_property("rect").expect("RenderLayer::rect");
+
+        let self_ = Arc::new(Self { sg: sg_ptr, node_id, dc_key: OsRng.gen(), is_visible, rect });
 
 
         Pimpl::RenderLayer(self_)
         Pimpl::RenderLayer(self_)
     }
     }
 
 
-    pub async fn draw(&self, sg: &SceneGraph) {}
+    fn get_rect(&self, parent_rect: &Rectangle<f32>) -> Result<Rectangle<f32>> {
+        if self.rect.array_len != 4 {
+            return Err(Error::PropertyWrongLen)
+        }
+
+        let mut rect = [0.; 4];
+        for i in 0..4 {
+            if self.rect.is_expr(i)? {
+                let expr = self.rect.get_expr(i).unwrap();
+
+                let machine = SExprMachine {
+                    globals: vec![
+                        ("sw".to_string(), SExprVal::Float32(parent_rect.w)),
+                        ("sh".to_string(), SExprVal::Float32(parent_rect.h)),
+                    ],
+                    stmts: &expr,
+                };
+
+                rect[i] = machine.call()?.as_f32()?;
+            } else {
+                rect[i] = self.rect.get_f32(i)?;
+            }
+        }
+        Ok(Rectangle::from_array(rect))
+    }
+
+    #[async_recursion]
+    pub async fn draw(
+        &self,
+        sg: &SceneGraph,
+        parent_rect: &Rectangle<f32>,
+    ) -> Option<(u64, Vec<(u64, DrawCall)>)> {
+        debug!("RenderLayer::draw()");
+        let node = sg.get_node(self.node_id).unwrap();
+
+        if !self.is_visible.get() {
+            debug!("invisible layer node '{}':{}", node.name, node.id);
+            return None
+        }
+
+        let Ok(rect) = self.get_rect(parent_rect) else {
+            panic!("malformed rect property for node '{}':{}", node.name, node.id)
+        };
+
+        if !parent_rect.includes(&rect) {
+            error!(
+                "layer '{}':{} rect {:?} is not inside parent {:?}",
+                node.name, node.id, rect, parent_rect
+            );
+            return None
+        }
+
+        // Apply viewport
+
+        let mut draw_calls = vec![];
+        let mut child_calls = vec![];
+        for child_inf in node.get_children2() {
+            let node = sg.get_node(child_inf.id).unwrap();
+
+            let dcs = match &node.pimpl {
+                Pimpl::RenderLayer(layer) => layer.draw(&sg, &rect).await,
+                Pimpl::Mesh(mesh) => mesh.draw(&sg, &rect),
+                _ => {
+                    error!("unhandled pimpl type");
+                    continue
+                }
+            };
+            let Some((dc_key, mut dcs)) = dcs else { continue };
+            draw_calls.append(&mut dcs);
+            child_calls.push(dc_key);
+        }
+
+        let dc = DrawCall { instrs: vec![DrawInstruction::ApplyViewport(rect)], dcs: child_calls };
+        draw_calls.push((self.dc_key, dc));
+        Some((self.dc_key, draw_calls))
+    }
+}
+
+pub struct Mesh {
+    render_api: RenderApiPtr,
+    vertex_buffer: miniquad::BufferId,
+    index_buffer: miniquad::BufferId,
+    // Texture
+    num_elements: i32,
+
+    dc_key: u64,
+
+    node_id: SceneNodeId,
+    rect: PropertyPtr,
+}
+
+impl Mesh {
+    pub async fn new(
+        sg: SceneGraphPtr2,
+        node_id: SceneNodeId,
+        render_api: RenderApiPtr,
+        verts: Vec<Vertex>,
+        indices: Vec<u16>,
+    ) -> Pimpl {
+        let num_elements = indices.len() as i32;
+        let vertex_buffer = render_api.new_vertex_buffer(verts).await.unwrap();
+        let index_buffer = render_api.new_index_buffer(indices).await.unwrap();
+
+        let mut sg = sg.lock().await;
+        let node = sg.get_node_mut(node_id).unwrap();
+        let rect = node.get_property("rect").expect("RenderLayer::rect");
+
+        Pimpl::Mesh(Self {
+            render_api,
+            vertex_buffer,
+            index_buffer,
+            num_elements,
+            dc_key: OsRng.gen(),
+            node_id,
+            rect,
+        })
+    }
+
+    // Merge with RenderLayer::get_rect()
+    fn get_rect(&self, parent_rect: &Rectangle<f32>) -> Result<Rectangle<f32>> {
+        if self.rect.array_len != 4 {
+            return Err(Error::PropertyWrongLen)
+        }
+
+        let mut rect = [0.; 4];
+        for i in 0..4 {
+            if self.rect.is_expr(i)? {
+                let expr = self.rect.get_expr(i).unwrap();
+
+                let machine = SExprMachine {
+                    globals: vec![
+                        ("lw".to_string(), SExprVal::Float32(parent_rect.w)),
+                        ("lh".to_string(), SExprVal::Float32(parent_rect.h)),
+                    ],
+                    stmts: &expr,
+                };
+
+                rect[i] = machine.call()?.as_f32()?;
+            } else {
+                rect[i] = self.rect.get_f32(i)?;
+            }
+        }
+        Ok(Rectangle::from_array(rect))
+    }
+
+    pub fn draw(
+        &self,
+        sg: &SceneGraph,
+        parent_rect: &Rectangle<f32>,
+    ) -> Option<(u64, Vec<(u64, DrawCall)>)> {
+        // Only used for debug messages
+        let node = sg.get_node(self.node_id).unwrap();
+
+        let mesh = DrawMesh {
+            vertex_buffer: self.vertex_buffer,
+            index_buffer: self.index_buffer,
+            texture: None,
+            num_elements: self.num_elements,
+        };
+
+        let Ok(rect) = self.get_rect(parent_rect) else {
+            panic!("malformed rect property for node '{}':{}", node.name, node.id)
+        };
+
+        // FIXME: all these rects must be aggregated down the tree
+        let scale_x = rect.w / parent_rect.w;
+        let scale_y = rect.h / parent_rect.h;
+        let model = glam::Mat4::from_translation(glam::Vec3::new(rect.x, rect.y, 0.)) *
+            glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
+
+        Some((
+            self.dc_key,
+            vec![(
+                self.dc_key,
+                DrawCall {
+                    instrs: vec![
+                        DrawInstruction::ApplyMatrix(glam::Mat4::IDENTITY),
+                        DrawInstruction::Draw(mesh),
+                    ],
+                    dcs: vec![],
+                },
+            )],
+        ))
+    }
+}
+
+impl Stoppable for Mesh {
+    async fn stop(self) {
+        // TODO: Delete own draw call
+
+        // Free buffers
+        // Should this be in drop?
+        self.render_api.delete_buffer(self.vertex_buffer);
+        self.render_api.delete_buffer(self.index_buffer);
+    }
 }
 }

+ 6 - 11
bin/darkwallet/src/chatapp.rs

@@ -101,7 +101,7 @@ pub fn create_layer(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
     let mut prop = Property::new("is_visible", PropertyType::Bool, PropertySubType::Null);
     let mut prop = Property::new("is_visible", PropertyType::Bool, PropertySubType::Null);
     node.add_property(prop).unwrap();
     node.add_property(prop).unwrap();
 
 
-    let mut prop = Property::new("rect", PropertyType::Uint32, PropertySubType::Pixel);
+    let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
     prop.set_array_len(4);
     prop.set_array_len(4);
     prop.allow_exprs();
     prop.allow_exprs();
     node.add_property(prop).unwrap();
     node.add_property(prop).unwrap();
@@ -109,11 +109,8 @@ pub fn create_layer(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
     node.id
     node.id
 }
 }
 
 
-fn create_mesh(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId) -> SceneNodeId {
+pub fn create_mesh(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
     let node = sg.add_node(name, SceneNodeType::RenderMesh);
     let node = sg.add_node(name, SceneNodeType::RenderMesh);
-    let mut prop = Property::new("data", PropertyType::Buffer, PropertySubType::Null);
-    prop.set_array_len(2);
-    node.add_property(prop).unwrap();
 
 
     let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
     let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
     prop.set_array_len(4);
     prop.set_array_len(4);
@@ -123,9 +120,7 @@ fn create_mesh(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId) -> S
     let mut prop = Property::new("z_index", PropertyType::Uint32, PropertySubType::Null);
     let mut prop = Property::new("z_index", PropertyType::Uint32, PropertySubType::Null);
     node.add_property(prop).unwrap();
     node.add_property(prop).unwrap();
 
 
-    let node_id = node.id;
-    sg.link(node_id, layer_node_id).unwrap();
-    node_id
+    node.id
 }
 }
 
 
 fn create_text(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId) -> SceneNodeId {
 fn create_text(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId) -> SceneNodeId {
@@ -261,7 +256,7 @@ pub fn setup(sg: &mut SceneGraph) {
 
 
     // Make the black background
     // Make the black background
     // Maybe we should use a RenderPass for this instead
     // Maybe we should use a RenderPass for this instead
-    let node_id = create_mesh(sg, "bg", layer_node_id);
+    let node_id = create_mesh(sg, "bg");
     let node = sg.get_node(node_id).unwrap();
     let node = sg.get_node(node_id).unwrap();
 
 
     let prop = node.get_property("rect").unwrap();
     let prop = node.get_property("rect").unwrap();
@@ -280,7 +275,7 @@ pub fn setup(sg: &mut SceneGraph) {
     prop.set_buf(1, buff.faces).unwrap();
     prop.set_buf(1, buff.faces).unwrap();
 
 
     // Make the chatedit bg
     // Make the chatedit bg
-    let node_id = create_mesh(sg, "chateditbg", layer_node_id);
+    let node_id = create_mesh(sg, "chateditbg");
     let node = sg.get_node(node_id).unwrap();
     let node = sg.get_node(node_id).unwrap();
     let prop = node.get_property("rect").unwrap();
     let prop = node.get_property("rect").unwrap();
 
 
@@ -311,7 +306,7 @@ pub fn setup(sg: &mut SceneGraph) {
     prop.set_buf(1, buff.faces).unwrap();
     prop.set_buf(1, buff.faces).unwrap();
 
 
     // Make the nicktext border
     // Make the nicktext border
-    let node_id = create_mesh(sg, "nickbg", layer_node_id);
+    let node_id = create_mesh(sg, "nickbg");
     let node = sg.get_node(node_id).unwrap();
     let node = sg.get_node(node_id).unwrap();
     let prop = node.get_property("rect").unwrap();
     let prop = node.get_property("rect").unwrap();
     prop.set_f32(0, 0.).unwrap();
     prop.set_f32(0, 0.).unwrap();

+ 16 - 5
bin/darkwallet/src/gfx.rs

@@ -88,7 +88,7 @@ impl<
             + std::cmp::PartialOrd,
             + std::cmp::PartialOrd,
     > Rectangle<T>
     > Rectangle<T>
 {
 {
-    fn from_array(arr: [T; 4]) -> Self {
+    pub fn from_array(arr: [T; 4]) -> Self {
         let mut iter = IntoIter::new(arr);
         let mut iter = IntoIter::new(arr);
         Self {
         Self {
             x: iter.next().unwrap(),
             x: iter.next().unwrap(),
@@ -126,10 +126,21 @@ impl<
     }
     }
 
 
     pub fn contains(&self, point: &Point<T>) -> bool {
     pub fn contains(&self, point: &Point<T>) -> bool {
-        self.x < point.x &&
-            point.x < self.x + self.w &&
-            self.y < point.y &&
-            point.y < self.y + self.h
+        self.x <= point.x &&
+            point.x <= self.x + self.w &&
+            self.y <= point.y &&
+            point.y <= self.y + self.h
+    }
+
+    pub fn top_left(&self) -> Point<T> {
+        Point { x: self.x, y: self.y }
+    }
+    pub fn bottom_right(&self) -> Point<T> {
+        Point { x: self.x + self.w, y: self.y + self.h }
+    }
+
+    pub fn includes(&self, child: &Self) -> bool {
+        self.contains(&child.top_left()) && self.contains(&child.bottom_right())
     }
     }
 }
 }
 
 

+ 31 - 31
bin/darkwallet/src/gfx2.rs

@@ -98,8 +98,8 @@ impl RenderApi {
         let _ = self.method_req.send(method);
         let _ = self.method_req.send(method);
     }
     }
 
 
-    pub async fn replace_draw_call(&self, loc: Vec<usize>, draw_call: DrawCall) {
-        let method = GraphicsMethod::ReplaceDrawCall((loc, draw_call));
+    pub async fn replace_draw_calls(&self, dcs: Vec<(u64, DrawCall)>) {
+        let method = GraphicsMethod::ReplaceDrawCalls(dcs);
 
 
         // Ignore any error
         // Ignore any error
         let _ = self.method_req.send(method);
         let _ = self.method_req.send(method);
@@ -116,7 +116,7 @@ pub struct DrawMesh {
 
 
 #[derive(Debug)]
 #[derive(Debug)]
 pub enum DrawInstruction {
 pub enum DrawInstruction {
-    ApplyViewport(Rectangle<i32>),
+    ApplyViewport(Rectangle<f32>),
     ApplyMatrix(glam::Mat4),
     ApplyMatrix(glam::Mat4),
     Draw(DrawMesh),
     Draw(DrawMesh),
 }
 }
@@ -124,36 +124,42 @@ pub enum DrawInstruction {
 #[derive(Debug)]
 #[derive(Debug)]
 pub struct DrawCall {
 pub struct DrawCall {
     pub instrs: Vec<DrawInstruction>,
     pub instrs: Vec<DrawInstruction>,
-    pub dcs: Vec<DrawCall>,
+    pub dcs: Vec<u64>,
 }
 }
 
 
 struct RenderContext<'a> {
 struct RenderContext<'a> {
     ctx: &'a mut Box<dyn RenderingBackend>,
     ctx: &'a mut Box<dyn RenderingBackend>,
-    root_dc: &'a DrawCall,
+    draw_calls: &'a HashMap<u64, DrawCall>,
     uniforms_data: [u8; 128],
     uniforms_data: [u8; 128],
     white_texture: TextureId,
     white_texture: TextureId,
 }
 }
 
 
 impl<'a> RenderContext<'a> {
 impl<'a> RenderContext<'a> {
     fn draw(&mut self) {
     fn draw(&mut self) {
-        self.draw_call(self.root_dc);
+        debug!(target: "gfx", "RenderContext::draw()");
+        self.draw_call(&self.draw_calls[&0], 0);
     }
     }
 
 
-    fn draw_call(&mut self, draw_call: &DrawCall) {
+    fn draw_call(&mut self, draw_call: &DrawCall, indent: u32) {
+        let ws = " ".repeat(indent as usize * 4);
         for instr in &draw_call.instrs {
         for instr in &draw_call.instrs {
             match instr {
             match instr {
                 DrawInstruction::ApplyViewport(view) => {
                 DrawInstruction::ApplyViewport(view) => {
+                    debug!(target: "gfx", "{}apply_viewport({:?})", ws, view);
+
                     let (_, screen_height) = window::screen_size();
                     let (_, screen_height) = window::screen_size();
 
 
-                    let mut view = view.clone();
-                    view.y = screen_height as i32 - (view.y + view.h);
+                    let view_x = view.x.round() as i32;
+                    let view_y = screen_height - (view.y + view.h);
+                    let view_y = view_y.round() as i32;
+                    let view_w = view.w.round() as i32;
+                    let view_h = view.h.round() as i32;
 
 
-                    //debug!("apply_viewport({:?})", view);
-                    self.ctx.apply_viewport(view.x, view.y, view.w, view.h);
-                    self.ctx.apply_scissor_rect(view.x, view.y, view.w, view.h);
+                    self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
+                    self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
                 }
                 }
                 DrawInstruction::ApplyMatrix(model) => {
                 DrawInstruction::ApplyMatrix(model) => {
-                    //debug!("apply_matrix({:?})", model);
+                    debug!(target: "gfx", "{}apply_matrix({:?})", ws, model);
                     let data: [u8; 64] = unsafe { std::mem::transmute_copy(model) };
                     let data: [u8; 64] = unsafe { std::mem::transmute_copy(model) };
                     self.uniforms_data[64..].copy_from_slice(&data);
                     self.uniforms_data[64..].copy_from_slice(&data);
                     self.ctx.apply_uniforms_from_bytes(
                     self.ctx.apply_uniforms_from_bytes(
@@ -162,7 +168,7 @@ impl<'a> RenderContext<'a> {
                     );
                     );
                 }
                 }
                 DrawInstruction::Draw(mesh) => {
                 DrawInstruction::Draw(mesh) => {
-                    //debug!("draw(mesh)");
+                    debug!(target: "gfx", "{}draw(mesh)", ws);
                     let texture = match mesh.texture {
                     let texture = match mesh.texture {
                         Some(texture) => texture,
                         Some(texture) => texture,
                         None => self.white_texture,
                         None => self.white_texture,
@@ -178,8 +184,9 @@ impl<'a> RenderContext<'a> {
             }
             }
         }
         }
 
 
-        for dc in &draw_call.dcs {
-            self.draw_call(dc);
+        for dc_key in &draw_call.dcs {
+            let dc = &self.draw_calls[dc_key];
+            self.draw_call(dc, indent + 1);
         }
         }
     }
     }
 }
 }
@@ -191,7 +198,7 @@ pub enum GraphicsMethod {
     NewVertexBuffer((Vec<Vertex>, async_channel::Sender<BufferId>)),
     NewVertexBuffer((Vec<Vertex>, async_channel::Sender<BufferId>)),
     NewIndexBuffer((Vec<u16>, async_channel::Sender<BufferId>)),
     NewIndexBuffer((Vec<u16>, async_channel::Sender<BufferId>)),
     DeleteBuffer(BufferId),
     DeleteBuffer(BufferId),
-    ReplaceDrawCall((Vec<usize>, DrawCall)),
+    ReplaceDrawCalls(Vec<(u64, DrawCall)>),
 }
 }
 
 
 #[derive(Debug, Clone)]
 #[derive(Debug, Clone)]
@@ -204,7 +211,7 @@ struct Stage {
     ctx: Box<dyn RenderingBackend>,
     ctx: Box<dyn RenderingBackend>,
     pipeline: Pipeline,
     pipeline: Pipeline,
     white_texture: TextureId,
     white_texture: TextureId,
-    root_dc: DrawCall,
+    draw_calls: HashMap<u64, DrawCall>,
     last_draw_time: Option<Instant>,
     last_draw_time: Option<Instant>,
 
 
     method_rep: mpsc::Receiver<GraphicsMethod>,
     method_rep: mpsc::Receiver<GraphicsMethod>,
@@ -261,7 +268,7 @@ impl Stage {
             ctx,
             ctx,
             pipeline,
             pipeline,
             white_texture,
             white_texture,
-            root_dc: DrawCall { instrs: vec![], dcs: vec![] },
+            draw_calls: HashMap::from([(0, DrawCall { instrs: vec![], dcs: vec![] })]),
             last_draw_time: None,
             last_draw_time: None,
             method_rep,
             method_rep,
             event_pub,
             event_pub,
@@ -308,15 +315,10 @@ impl Stage {
     fn method_delete_buffer(&mut self, buffer: BufferId) {
     fn method_delete_buffer(&mut self, buffer: BufferId) {
         self.ctx.delete_buffer(buffer);
         self.ctx.delete_buffer(buffer);
     }
     }
-    fn method_replace_draw_call(&mut self, mut loc: Vec<usize>, new_dc: DrawCall) {
-        loc.reverse();
-        let mut dc = &mut self.root_dc;
-
-        while let Some(i) = loc.pop() {
-            dc = &mut dc.dcs[i];
+    fn method_replace_draw_calls(&mut self, dcs: Vec<(u64, DrawCall)>) {
+        for (key, val) in dcs {
+            self.draw_calls.insert(key, val);
         }
         }
-
-        std::mem::replace(dc, new_dc);
     }
     }
 }
 }
 
 
@@ -351,9 +353,7 @@ impl EventHandler for Stage {
                     self.method_new_index_buffer(indices, sendr)
                     self.method_new_index_buffer(indices, sendr)
                 }
                 }
                 GraphicsMethod::DeleteBuffer(buffer) => self.method_delete_buffer(buffer),
                 GraphicsMethod::DeleteBuffer(buffer) => self.method_delete_buffer(buffer),
-                GraphicsMethod::ReplaceDrawCall((loc, dc)) => {
-                    self.method_replace_draw_call(loc, dc)
-                }
+                GraphicsMethod::ReplaceDrawCalls(dcs) => self.method_replace_draw_calls(dcs),
             };
             };
         }
         }
     }
     }
@@ -378,7 +378,7 @@ impl EventHandler for Stage {
 
 
         let mut render_ctx = RenderContext {
         let mut render_ctx = RenderContext {
             ctx: &mut self.ctx,
             ctx: &mut self.ctx,
-            root_dc: &self.root_dc,
+            draw_calls: &self.draw_calls,
             uniforms_data,
             uniforms_data,
             white_texture: self.white_texture,
             white_texture: self.white_texture,
         };
         };

+ 6 - 0
bin/darkwallet/src/main.rs

@@ -182,6 +182,12 @@ fn main() {
                 debug!("Event relayer closed");
                 debug!("Event relayer closed");
                 break
                 break
             };
             };
+            // Ignore keys which get stuck
+            match &ev {
+                gfx2::GraphicsEvent::KeyDown((miniquad::KeyCode::LeftShift, _, _)) |
+                gfx2::GraphicsEvent::KeyDown((miniquad::KeyCode::LeftSuper, _, _)) => continue,
+                _ => {}
+            }
             debug!("event: {:?}", ev);
             debug!("event: {:?}", ev);
         }
         }
     });
     });

+ 2 - 0
bin/darkwallet/src/prop/mod.rs

@@ -188,6 +188,8 @@ pub enum ModifyAction {
     Push,
     Push,
 }
 }
 
 
+pub type PropertyPtr = Arc<Property>;
+
 pub struct Property {
 pub struct Property {
     pub name: String,
     pub name: String,
     pub typ: PropertyType,
     pub typ: PropertyType,

+ 3 - 2
bin/darkwallet/src/scene.rs

@@ -623,8 +623,8 @@ impl Signal {
     }
     }
 }
 }
 
 
-type MethodRequestFn = Box<dyn Fn(Vec<u8>, MethodResponseFn) + Send>;
-pub type MethodResponseFn = Box<dyn Fn(Result<Vec<u8>>) + Send>;
+type MethodRequestFn = Box<dyn Fn(Vec<u8>, MethodResponseFn) + Send + Sync>;
+pub type MethodResponseFn = Box<dyn Fn(Result<Vec<u8>>) + Send + Sync>;
 
 
 pub struct Method {
 pub struct Method {
     pub name: String,
     pub name: String,
@@ -639,4 +639,5 @@ pub enum Pimpl {
     ChatView(chatview::ChatViewPtr),
     ChatView(chatview::ChatViewPtr),
     Window(app::WindowPtr),
     Window(app::WindowPtr),
     RenderLayer(app::RenderLayerPtr),
     RenderLayer(app::RenderLayerPtr),
+    Mesh(app::Mesh),
 }
 }