aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-12-25 10:07:06 +0000
committers-ol <s+removethis@s-ol.nu>2025-12-25 10:07:06 +0000
commit958c55f52a0b5c0d928be490ee01731f4b893274 (patch)
treec5baf64fb6e3d528f33b10a492a1b5f635dbbe10 /src
parenttyping working (diff)
downloadnodetoy-958c55f52a0b5c0d928be490ee01731f4b893274.tar.gz
nodetoy-958c55f52a0b5c0d928be490ee01731f4b893274.zip
basic toposorted SSA
Diffstat (limited to 'src')
-rw-r--r--src/main.rs219
-rw-r--r--src/preview.rs17
2 files changed, 53 insertions, 183 deletions
diff --git a/src/main.rs b/src/main.rs
index de5581b..6dafdfd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,7 @@ use egui::{Color32, Id, Ui};
use egui_snarl::{
InPin, InPinId, NodeId, OutPin, OutPinId, Snarl,
ui::{
- AnyPins, NodeLayout, PinInfo, PinPlacement, SnarlStyle, SnarlViewer, SnarlWidget,
+ NodeLayout, PinInfo, PinPlacement, SnarlStyle, SnarlViewer, SnarlWidget,
get_selected_nodes,
},
};
@@ -121,6 +121,41 @@ impl DemoNode {
.collect()
}
+ fn compile_output(pin: OutPinId) -> String {
+ let node_id = pin.node.0;
+ let out_id = pin.output;
+ format!("n{node_id}_o{out_id}")
+ }
+
+ fn get_inputs(&self, node: NodeId, snarl: &Snarl<DemoNode>) -> String {
+ (0..self.inputs())
+ .map(
+ |input| match &*snarl.in_pin(InPinId { node, input }).remotes {
+ [] => "?".to_owned(),
+ [pin] => DemoNode::compile_output(*pin),
+ _ => unreachable!("cannot connect to multiple inputs"),
+ },
+ )
+ .collect::<Vec<_>>()
+ .join(", ")
+ }
+
+ pub fn compile(&self, node: NodeId, snarl: &Snarl<DemoNode>) -> String {
+ let sig = self.get_node_signature(node, snarl);
+ let typ = if sig.outputs.is_empty() {
+ "".to_owned()
+ } else {
+ let output = sig.outputs[0];
+ format!("{output:?}")
+ };
+
+ let node_id = node.0;
+ let name = format!("{self:?}");
+ let inputs = self.get_inputs(node, snarl);
+
+ format!("{typ} n{node_id}_o0 = {name}({inputs});\n")
+ }
+
pub fn get_node_signature(&self, node: NodeId, snarl: &Snarl<DemoNode>) -> TypeSignature {
let connected = self.get_input_types(node, snarl);
self.signature(&connected)
@@ -224,133 +259,6 @@ impl SnarlViewer<DemoNode> for DemoViewer {
}
}
- fn has_dropped_wire_menu(&mut self, _src_pins: AnyPins, _snarl: &mut Snarl<DemoNode>) -> bool {
- false // true
- }
-
- fn show_dropped_wire_menu(
- &mut self,
- _pos: egui::Pos2,
- _ui: &mut Ui,
- _src_pins: AnyPins,
- _snarl: &mut Snarl<DemoNode>,
- ) {
- /*
- // In this demo, we create a context-aware node graph menu, and connect a wire
- // dropped on the fly based on user input to a new node created.
- //
- // In your implementation, you may want to define specifications for each node's
- // pin inputs and outputs and compatibility to make this easier.
-
- type PinCompat = usize;
- const PIN_NUM: PinCompat = 1;
- const PIN_STR: PinCompat = 2;
- const PIN_IMG: PinCompat = 4;
- const PIN_SINK: PinCompat = PIN_NUM | PIN_STR | PIN_IMG;
-
- const fn pin_out_compat(node: &DemoNode) -> PinCompat {
- match node {
- DemoNode::Sink => 0,
- DemoNode::String(_) => PIN_STR,
- DemoNode::ShowImage(_) => PIN_IMG,
- DemoNode::Number(_) | DemoNode::ExprNode(_) => PIN_NUM,
- }
- }
-
- const fn pin_in_compat(node: &DemoNode, pin: usize) -> PinCompat {
- match node {
- DemoNode::Sink => PIN_SINK,
- DemoNode::Number(_) | DemoNode::String(_) => 0,
- DemoNode::ShowImage(_) => PIN_STR,
- DemoNode::ExprNode(_) => {
- if pin == 0 {
- PIN_STR
- } else {
- PIN_NUM
- }
- }
- }
- }
-
- ui.label("Add node");
-
- match src_pins {
- AnyPins::Out(src_pins) => {
- if src_pins.len() != 1 {
- ui.label("Multiple output pins are not supported in this demo");
- return;
- }
-
- let src_pin = src_pins[0];
- let src_out_ty = pin_out_compat(snarl.get_node(src_pin.node).unwrap());
- let dst_in_candidates = [
- ("Sink", (|| DemoNode::Sink) as fn() -> DemoNode, PIN_SINK),
- ("Show Image", || DemoNode::ShowImage(String::new()), PIN_STR),
- ("Expr", || DemoNode::ExprNode(ExprNode::new()), PIN_STR),
- ];
-
- for (name, ctor, in_ty) in dst_in_candidates {
- if src_out_ty & in_ty != 0 && ui.button(name).clicked() {
- // Create new node.
- let new_node = snarl.insert_node(pos, ctor());
- let dst_pin = InPinId {
- node: new_node,
- input: 0,
- };
-
- // Connect the wire.
- snarl.connect(src_pin, dst_pin);
- ui.close();
- }
- }
- }
- AnyPins::In(pins) => {
- let all_src_types = pins.iter().fold(0, |acc, pin| {
- acc | pin_in_compat(snarl.get_node(pin.node).unwrap(), pin.input)
- });
-
- let dst_out_candidates = [
- (
- "Number",
- (|| DemoNode::Number(0.)) as fn() -> DemoNode,
- PIN_NUM,
- ),
- ("String", || DemoNode::String(String::new()), PIN_STR),
- ("Expr", || DemoNode::ExprNode(ExprNode::new()), PIN_NUM),
- ("Show Image", || DemoNode::ShowImage(String::new()), PIN_IMG),
- ];
-
- for (name, ctor, out_ty) in dst_out_candidates {
- if all_src_types & out_ty != 0 && ui.button(name).clicked() {
- // Create new node.
- let new_node = ctor();
- let dst_ty = pin_out_compat(&new_node);
-
- let new_node = snarl.insert_node(pos, new_node);
- let dst_pin = OutPinId {
- node: new_node,
- output: 0,
- };
-
- // Connect the wire.
- for src_pin in pins {
- let src_ty =
- pin_in_compat(snarl.get_node(src_pin.node).unwrap(), src_pin.input);
- if src_ty & dst_ty != 0 {
- // In this demo, input pin MUST be unique ...
- // Therefore here we drop inputs of source input pin.
- snarl.drop_inputs(*src_pin);
- snarl.connect(dst_pin, *src_pin);
- ui.close();
- }
- }
- }
- }
- }
- }
- */
- }
-
fn has_node_menu(&mut self, _node: &DemoNode) -> bool {
true
}
@@ -369,59 +277,6 @@ impl SnarlViewer<DemoNode> for DemoViewer {
ui.close();
}
}
-
- fn has_on_hover_popup(&mut self, _: &DemoNode) -> bool {
- false // true
- }
-
- fn show_on_hover_popup(
- &mut self,
- _node: NodeId,
- _inputs: &[InPin],
- _outputs: &[OutPin],
- _ui: &mut Ui,
- _snarl: &mut Snarl<DemoNode>,
- ) {
- /*
- match snarl[node] {
- DemoNode::Sink => {
- ui.label("Displays anything connected to it");
- }
- DemoNode::Number(_) => {
- ui.label("Outputs integer value");
- }
- DemoNode::String(_) => {
- ui.label("Outputs string value");
- }
- DemoNode::ShowImage(_) => {
- ui.label("Displays image from URL in input");
- }
- DemoNode::ExprNode(_) => {
- ui.label("Evaluates algebraic expression with input for each unique variable name");
- }
- }
- */
- }
-
- fn header_frame(
- &mut self,
- frame: egui::Frame,
- _node: NodeId,
- _inputs: &[InPin],
- _outputs: &[OutPin],
- _snarl: &Snarl<DemoNode>,
- ) -> egui::Frame {
- frame
- /*
- match snarl[node] {
- DemoNode::Sink => frame.fill(egui::Color32::from_rgb(70, 70, 80)),
- DemoNode::Number(_) => frame.fill(egui::Color32::from_rgb(70, 40, 40)),
- DemoNode::String(_) => frame.fill(egui::Color32::from_rgb(40, 70, 40)),
- DemoNode::ShowImage(_) => frame.fill(egui::Color32::from_rgb(40, 40, 70)),
- DemoNode::ExprNode(_) => frame.fill(egui::Color32::from_rgb(70, 66, 40)),
- }
- */
- }
}
pub struct DemoApp {
@@ -541,7 +396,7 @@ impl App for DemoApp {
egui::SidePanel::right("preview").show(ctx, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
egui::Frame::canvas(ui.style()).show(ui, |ui| {
- self.preview.custom_painting(ui);
+ self.preview.custom_painting(ui, &self.snarl);
});
});
});
diff --git a/src/preview.rs b/src/preview.rs
index 33c6b77..94bf128 100644
--- a/src/preview.rs
+++ b/src/preview.rs
@@ -7,6 +7,9 @@ use eframe::{
egui_wgpu::wgpu::util::DeviceExt as _,
egui_wgpu::{self, wgpu},
};
+use egui_snarl::{
+ Snarl, NodeId,
+};
pub struct Custom3d {
angle: f32,
@@ -195,7 +198,7 @@ impl egui_wgpu::CallbackTrait for CustomTriangleCallback {
}
impl Custom3d {
- pub fn custom_painting(&mut self, ui: &mut egui::Ui) {
+ pub fn custom_painting(&mut self, ui: &mut egui::Ui, snarl: &Snarl<crate::DemoNode>) {
let (rect, response) =
ui.allocate_exact_size(egui::Vec2::splat(300.0), egui::Sense::drag());
@@ -204,6 +207,18 @@ impl Custom3d {
rect,
CustomTriangleCallback { angle: self.angle },
));
+
+ if ui.button("compile").clicked() {
+ let mut order = topological_sort::TopologicalSort::<NodeId>::new();
+ for (out, inp) in snarl.wires() {
+ order.add_dependency(out.node, inp.node);
+ }
+
+ // let buf = BufWriter::new(Vec::new());
+ while let Some(id) = order.pop() {
+ info!("{}", snarl[id].compile(id, snarl));
+ }
+ }
}
}