Просмотр исходного кода

wallet: make some common gadgets useful and clean up the code

darkfi 2 лет назад
Родитель
Сommit
f4f7a258e9
2 измененных файлов с 215 добавлено и 210 удалено
  1. 212 209
      bin/darkwallet/src/app.rs
  2. 3 1
      bin/darkwallet/src/gfx2.rs

+ 212 - 209
bin/darkwallet/src/app.rs

@@ -196,9 +196,9 @@ impl App {
         let prop = node.get_property("rect").unwrap();
         prop.set_f32(0, 0.).unwrap();
         prop.set_f32(1, 0.).unwrap();
-        let code = vec![Op::LoadVar("sw".to_string())];
+        let code = vec![Op::LoadVar("w".to_string())];
         prop.set_expr(2, code).unwrap();
-        let code = vec![Op::LoadVar("sh".to_string())];
+        let code = vec![Op::LoadVar("h".to_string())];
         prop.set_expr(3, code).unwrap();
         node.set_property_bool("is_visible", true).unwrap();
 
@@ -222,9 +222,9 @@ impl App {
         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())];
+        let code = vec![Op::LoadVar("w".to_string())];
         prop.set_expr(2, code).unwrap();
-        let code = vec![Op::LoadVar("lh".to_string())];
+        let code = vec![Op::LoadVar("h".to_string())];
         prop.set_expr(3, code).unwrap();
 
         // Setup the pimpl
@@ -300,12 +300,163 @@ fn print_type_of<T>(_: &T) {
     println!("{}", std::any::type_name::<T>())
 }
 
+struct OnModify<T> {
+    ex: Arc<smol::Executor<'static>>,
+    node_name: String,
+    node_id: SceneNodeId,
+    me: Weak<T>,
+    tasks: Vec<smol::Task<()>>,
+}
+
+impl<T: Send + Sync + 'static> OnModify<T> {
+    fn new(
+        ex: Arc<smol::Executor<'static>>,
+        node_name: String,
+        node_id: SceneNodeId,
+        me: Weak<T>,
+    ) -> Self {
+        Self { ex, node_name, node_id, me, tasks: vec![] }
+    }
+
+    fn when_change<F>(&mut self, prop: PropertyPtr, f: impl Fn(Arc<T>) -> F + Send + 'static)
+    where
+        F: std::future::Future<Output = ()> + Send + 'static,
+    {
+        let node_name = self.node_name.clone();
+        let node_id = self.node_id;
+        let on_modify_sub = prop.subscribe_modify();
+        let prop_name = prop.name.clone();
+        let me = self.me.clone();
+        let task = self.ex.spawn(async move {
+            loop {
+                let _ = on_modify_sub.receive().await;
+                debug!(target: "app", "Property '{}':{}/'{}' modified", node_name, node_id, prop_name);
+
+                let Some(self_) = me.upgrade() else {
+                    // Should not happen
+                    panic!(
+                        "'{}':{}/'{}' self destroyed before modify_task was stopped!",
+                        node_name, node_id, prop_name
+                    );
+                };
+
+                debug!(target: "app", "property modified");
+                f(self_).await;
+            }
+        });
+        self.tasks.push(task);
+    }
+}
+
+fn eval_rect(rect: PropertyPtr, parent_rect: &Rectangle<f32>) -> Result<()> {
+    if rect.array_len != 4 {
+        return Err(Error::PropertyWrongLen)
+    }
+
+    for i in 0..4 {
+        if !rect.is_expr(i)? {
+            continue
+        }
+
+        let expr = rect.get_expr(i).unwrap();
+
+        let machine = SExprMachine {
+            globals: vec![
+                ("w".to_string(), SExprVal::Float32(parent_rect.w)),
+                ("h".to_string(), SExprVal::Float32(parent_rect.h)),
+            ],
+            stmts: &expr,
+        };
+
+        let v = machine.call()?.as_f32()?;
+        rect.set_cache_f32(i, v).unwrap();
+    }
+    Ok(())
+}
+
+fn read_rect(rect_prop: PropertyPtr) -> Result<Rectangle<f32>> {
+    if rect_prop.array_len != 4 {
+        return Err(Error::PropertyWrongLen)
+    }
+
+    let mut rect = [0.; 4];
+    for i in 0..4 {
+        if rect_prop.is_expr(i)? {
+            rect[i] = rect_prop.get_cached(i)?.as_f32()?;
+        } else {
+            rect[i] = rect_prop.get_f32(i)?;
+        }
+    }
+    Ok(Rectangle::from_array(rect))
+}
+
+fn get_parent_rect(sg: &SceneGraph, node: &SceneNode) -> Option<Rectangle<f32>> {
+    // read our parent
+    if node.parents.is_empty() {
+        info!("RenderLayer {:?} has no parents so skipping", node);
+        return None
+    }
+    if node.parents.len() != 1 {
+        error!("RenderLayer {:?} has too many parents so skipping", node);
+        return None
+    }
+    let parent_id = node.parents[0].id;
+    let parent_node = sg.get_node(parent_id).unwrap();
+    let parent_rect = match parent_node.typ {
+        SceneNodeType::Window => {
+            let Some(screen_size_prop) = parent_node.get_property("screen_size") else {
+                error!(
+                    "RenderLayer {:?} parent node {:?} missing screen_size property",
+                    node, parent_node
+                );
+                return None
+            };
+            let screen_width = screen_size_prop.get_f32(0).unwrap();
+            let screen_height = screen_size_prop.get_f32(1).unwrap();
+
+            let parent_rect = Rectangle { x: 0., y: 0., w: screen_width, h: screen_height };
+            parent_rect
+        }
+        SceneNodeType::RenderLayer => {
+            // get their rect property
+            let Some(parent_rect) = parent_node.get_property("rect") else {
+                error!(
+                    "RenderLayer {:?} parent node {:?} missing rect property",
+                    node, parent_node
+                );
+                return None
+            };
+            // read parent's rect
+            let Ok(parent_rect) = read_rect(parent_rect) else {
+                error!(
+                    "RenderLayer {:?} parent node {:?} malformed rect property",
+                    node, parent_node
+                );
+                return None
+            };
+            parent_rect
+        }
+        _ => {
+            error!(
+                "RenderLayer {:?} parent node {:?} wrong type {:?}",
+                node, parent_node, parent_node.typ
+            );
+            return None
+        }
+    };
+    Some(parent_rect)
+}
+
+struct DrawUpdate {
+    key: u64,
+    draw_calls: Vec<(u64, DrawCall)>,
+}
+
 pub type WindowPtr = Arc<Window>;
 
 pub struct Window {
     node_id: SceneNodeId,
-    resize_task: smol::Task<()>,
-    modify_task: smol::Task<()>,
+    tasks: Vec<smol::Task<()>>,
     screen_size_prop: PropertyPtr,
     render_api: RenderApiPtr,
 }
@@ -320,20 +471,12 @@ impl Window {
     ) -> Pimpl {
         debug!(target: "app", "Window::new()");
 
-        let screen_size_prop = {
-            let sg = sg.lock().await;
-            let node = sg.get_node(node_id).unwrap();
-            node.get_property("screen_size").unwrap()
-        };
-
-        // Monitor for changes to screen_size or scale properties
-        // If so then trigger draw
-        let scale_sub = {
-            let sg = sg.lock().await;
-            let node = sg.get_node(node_id).unwrap();
-            let prop = node.get_property("scale").unwrap();
-            prop.subscribe_modify()
-        };
+        let scene_graph = sg.lock().await;
+        let node = scene_graph.get_node(node_id).unwrap();
+        let node_name = node.name.clone();
+        let screen_size_prop = node.get_property("screen_size").unwrap();
+        let scale_prop = node.get_property("scale").unwrap();
+        drop(scene_graph);
 
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
             // Start a task monitoring for window resize events
@@ -368,25 +511,22 @@ impl Window {
                 }
             });
 
-            // Modify task needs a Weak<Self>
-            let me2 = me.clone();
-            let modify_task = ex.spawn(async move {
-                loop {
-                    let _ = scale_sub.receive().await;
-                    debug!(target: "app", "Window scale modified");
-
-                    let Some(self_) = me2.upgrade() else {
-                        // Should not happen
-                        panic!("self destroyed before modify_task was stopped!");
-                    };
-
-                    debug!(target: "app", "window property modified");
+            let sg2 = sg.clone();
+            let redraw_fn = move |self_: Arc<Self>| {
+                let sg = sg2.clone();
+                async move {
                     let sg = sg.lock().await;
                     self_.draw(&sg).await;
                 }
-            });
+            };
 
-            Self { node_id, resize_task, modify_task, screen_size_prop, render_api }
+            let mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
+            on_modify.when_change(scale_prop, redraw_fn);
+
+            let mut tasks = on_modify.tasks;
+            tasks.push(resize_task);
+
+            Self { node_id, tasks, screen_size_prop, render_api }
         });
 
         Pimpl::Window(self_)
@@ -415,9 +555,9 @@ impl Window {
                     continue
                 }
             };
-            let Some((dc_key, mut dcs)) = dcs else { continue };
-            draw_calls.append(&mut dcs);
-            child_calls.push(dc_key);
+            let Some(mut draw_update) = dcs else { continue };
+            draw_calls.append(&mut draw_update.draw_calls);
+            child_calls.push(draw_update.key);
         }
 
         let root_dc = DrawCall { instrs: vec![], dcs: child_calls };
@@ -439,7 +579,7 @@ pub type RenderLayerPtr = Arc<RenderLayer>;
 pub struct RenderLayer {
     sg: SceneGraphPtr2,
     node_id: SceneNodeId,
-    modify_task: smol::Task<()>,
+    tasks: Vec<smol::Task<()>>,
     render_api: RenderApiPtr,
 
     dc_key: u64,
@@ -459,6 +599,7 @@ impl RenderLayer {
     ) -> Pimpl {
         let sg = sg_ptr.lock().await;
         let node = sg.get_node(node_id).unwrap();
+        let node_name = node.name.clone();
 
         let is_visible =
             PropertyBool::wrap(node, "is_visible", 0).expect("RenderLayer::is_visible");
@@ -470,27 +611,13 @@ impl RenderLayer {
         let rect_sub = rect.subscribe_modify();
 
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
-            let me2 = me.clone();
-            // Modify task needs a Weak<Self>
-            let modify_task = ex.spawn(async move {
-                loop {
-                    let _ = rect_sub.receive().await;
-                    debug!(target: "app", "Layer rect modified");
-
-                    let Some(self_) = me2.upgrade() else {
-                        // Should not happen
-                        panic!("self destroyed before modify_task was stopped!");
-                    };
-
-                    debug!(target: "app", "layer rect property modified");
-                    self_.redraw().await;
-                }
-            });
+            let mut on_modify = OnModify::new(ex.clone(), node_name, node_id, me.clone());
+            on_modify.when_change(rect.clone(), Self::redraw);
 
             Self {
                 sg: sg_ptr,
                 node_id,
-                modify_task,
+                tasks: on_modify.tasks,
                 render_api,
                 dc_key: OsRng.gen(),
                 is_visible,
@@ -502,120 +629,24 @@ impl RenderLayer {
         Pimpl::RenderLayer(self_)
     }
 
-    async fn redraw(&self) {
+    async fn redraw(self: Arc<Self>) {
         let sg = self.sg.lock().await;
-        // read our parent
         let node = sg.get_node(self.node_id).unwrap();
-        if node.parents.is_empty() {
-            info!("RenderLayer {:?} has no parents so skipping", node);
-            return
-        }
-        if node.parents.len() != 1 {
-            error!("RenderLayer {:?} has too many parents so skipping", node);
-            return
-        }
-        let parent_id = node.parents[0].id;
-        let parent_node = sg.get_node(parent_id).unwrap();
-        let parent_rect = match parent_node.typ {
-            SceneNodeType::Window => {
-                let Some(screen_size_prop) = parent_node.get_property("screen_size") else {
-                    error!(
-                        "RenderLayer {:?} parent node {:?} missing screen_size property",
-                        node, parent_node
-                    );
-                    return
-                };
-                let screen_width = screen_size_prop.get_f32(0).unwrap();
-                let screen_height = screen_size_prop.get_f32(1).unwrap();
 
-                let parent_rect = Rectangle { x: 0., y: 0., w: screen_width, h: screen_height };
-                parent_rect
-            }
-            SceneNodeType::RenderLayer => {
-                // get their rect property
-                let Some(parent_rect) = parent_node.get_property("rect") else {
-                    error!(
-                        "RenderLayer {:?} parent node {:?} missing rect property",
-                        node, parent_node
-                    );
-                    return
-                };
-                // read parent's rect
-                let Ok(parent_rect) = Self::read_rect(parent_rect) else {
-                    error!(
-                        "RenderLayer {:?} parent node {:?} malformed rect property",
-                        node, parent_node
-                    );
-                    return
-                };
-                parent_rect
-            }
-            _ => {
-                error!(
-                    "RenderLayer {:?} parent node {:?} wrong type {:?}",
-                    node, parent_node, parent_node.typ
-                );
-                return
-            }
+        let Some(parent_rect) = get_parent_rect(&sg, node) else {
+            return;
         };
-        let Some((_, dcs)) = self.draw(&sg, &parent_rect).await else {
+
+        let Some(draw_update) = self.draw(&sg, &parent_rect).await else {
             error!("RenderLayer {:?} failed to draw", node);
             return;
         };
-        self.render_api.replace_draw_calls(dcs).await;
+        self.render_api.replace_draw_calls(draw_update.draw_calls).await;
         debug!("replace draw calls done");
     }
 
-    fn read_rect(rect_prop: PropertyPtr) -> Result<Rectangle<f32>> {
-        if rect_prop.array_len != 4 {
-            return Err(Error::PropertyWrongLen)
-        }
-
-        let mut rect = [0.; 4];
-        for i in 0..4 {
-            if rect_prop.is_expr(i)? {
-                rect[i] = rect_prop.get_cached(i)?.as_f32()?;
-            } else {
-                rect[i] = rect_prop.get_f32(i)?;
-            }
-        }
-        Ok(Rectangle::from_array(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![
-                        ("sw".to_string(), SExprVal::Float32(parent_rect.w)),
-                        ("sh".to_string(), SExprVal::Float32(parent_rect.h)),
-                    ],
-                    stmts: &expr,
-                };
-
-                let v = machine.call()?.as_f32()?;
-                self.rect.set_cache_f32(i, v).unwrap();
-                rect[i] = v;
-            } 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)>)> {
+    pub async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle<f32>) -> Option<DrawUpdate> {
         debug!(target: "app", "RenderLayer::draw()");
         let node = sg.get_node(self.node_id).unwrap();
 
@@ -624,8 +655,12 @@ impl RenderLayer {
             return None
         }
 
-        let Ok(mut rect) = self.get_rect(parent_rect) else {
-            panic!("malformed rect property for node '{}':{}", node.name, node.id)
+        if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {
+            panic!("Node {:?} bad rect property: {}", node, err);
+        }
+
+        let Ok(mut rect) = read_rect(self.rect.clone()) else {
+            panic!("Node {:?} bad rect property", node);
         };
 
         rect.x += parent_rect.x;
@@ -658,14 +693,14 @@ impl RenderLayer {
                     continue
                 }
             };
-            let Some((dc_key, mut dcs)) = dcs else { continue };
-            draw_calls.append(&mut dcs);
-            child_calls.push(dc_key);
+            let Some(mut draw_update) = dcs else { continue };
+            draw_calls.append(&mut draw_update.draw_calls);
+            child_calls.push(draw_update.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))
+        Some(DrawUpdate { key: self.dc_key, draw_calls })
     }
 }
 
@@ -713,40 +748,7 @@ impl Mesh {
         })
     }
 
-    // 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,
-                };
-
-                let v = machine.call()?.as_f32()?;
-                self.rect.set_cache_f32(i, v).unwrap();
-                rect[i] = v;
-            } 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)>)> {
+    pub fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle<f32>) -> Option<DrawUpdate> {
         debug!(target: "app", "Mesh::draw()");
         // Only used for debug messages
         let node = sg.get_node(self.node_id).unwrap();
@@ -758,8 +760,12 @@ impl Mesh {
             num_elements: self.num_elements,
         };
 
-        let Ok(mut rect) = self.get_rect(parent_rect) else {
-            panic!("malformed rect property for node '{}':{}", node.name, node.id)
+        if let Err(err) = eval_rect(self.rect.clone(), parent_rect) {
+            panic!("Node {:?} bad rect property: {}", node, err);
+        }
+
+        let Ok(mut rect) = read_rect(self.rect.clone()) else {
+            panic!("Node {:?} bad rect property", node);
         };
 
         rect.x += parent_rect.x;
@@ -772,19 +778,16 @@ impl Mesh {
         let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
             glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
 
-        Some((
-            self.dc_key,
-            vec![(
+        Some(DrawUpdate {
+            key: self.dc_key,
+            draw_calls: vec![(
                 self.dc_key,
                 DrawCall {
-                    instrs: vec![
-                        DrawInstruction::ApplyMatrix(model),
-                        DrawInstruction::Draw(mesh),
-                    ],
+                    instrs: vec![DrawInstruction::ApplyMatrix(model), DrawInstruction::Draw(mesh)],
                     dcs: vec![],
                 },
             )],
-        ))
+        })
     }
 }
 

+ 3 - 1
bin/darkwallet/src/gfx2.rs

@@ -33,6 +33,7 @@ use crate::{
     shader,
 };
 
+// This is very noisy so suppress output by default
 const DEBUG_RENDER: bool = false;
 
 #[derive(Debug, SerialEncodable, SerialDecodable)]
@@ -149,7 +150,8 @@ impl<'a> RenderContext<'a> {
     }
 
     fn draw_call(&mut self, draw_call: &DrawCall, indent: u32) {
-        let ws = " ".repeat(indent as usize * 4);
+        let ws = if DEBUG_RENDER { " ".repeat(indent as usize * 4) } else { String::new() };
+
         for instr in &draw_call.instrs {
             match instr {
                 DrawInstruction::ApplyViewport(view) => {