Node graph improvements (#855)

* Selecting multiple nodes

* Improve logs

* Log bad types in dyn any

* Add (broken) node links

* New topological sort

* Fix reorder ids function

* Input and output node

* Add nodes that operate on images

* Fixups

* Show node parameters together with layer properties

* New nodes don't crash editor

* Fix tests

* Node positions backend

* Generate node graph on value change

* Add expose input message

* Fix tests

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2022-11-17 23:36:23 +00:00
committed by GitHub
parent 5fe7aba85d
commit 6cd0dbdcd0
23 changed files with 734 additions and 331 deletions

View File

@@ -28,12 +28,19 @@ fn merge_ids(a: u64, b: u64) -> u64 {
hasher.finish()
}
#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DocumentNodeMetadata {
pub position: (i32, i32),
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DocumentNode {
pub name: String,
pub inputs: Vec<NodeInput>,
pub implementation: DocumentNodeImplementation,
pub metadata: DocumentNodeMetadata,
}
impl DocumentNode {
@@ -54,7 +61,7 @@ impl DocumentNode {
let first = self.inputs.remove(0);
if let DocumentNodeImplementation::Unresolved(fqn) = self.implementation {
let (input, mut args) = match first {
NodeInput::Value(tagged_value) => {
NodeInput::Value { tagged_value, .. } => {
assert_eq!(self.inputs.len(), 0);
(ProtoNodeInput::None, ConstructionArgs::Value(tagged_value.to_value()))
}
@@ -63,7 +70,7 @@ impl DocumentNode {
};
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network)), "recieved non resolved parameter");
assert!(
!self.inputs.iter().any(|input| matches!(input, NodeInput::Value(_))),
!self.inputs.iter().any(|input| matches!(input, NodeInput::Value { .. })),
"recieved value as parameter. inupts: {:#?}, construction_args: {:#?}",
&self.inputs,
&args
@@ -90,7 +97,7 @@ impl DocumentNode {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NodeInput {
Node(NodeId),
Value(value::TaggedValue),
Value { tagged_value: value::TaggedValue, exposed: bool },
Network,
}
@@ -100,13 +107,20 @@ impl NodeInput {
*self = NodeInput::Node(f(*id))
}
}
pub fn is_exposed(&self) -> bool {
if let NodeInput::Value { exposed, .. } = self {
*exposed
} else {
true
}
}
}
impl PartialEq for NodeInput {
fn eq(&self, other: &Self) -> bool {
match (&self, &other) {
(Self::Node(n1), Self::Node(n2)) => n1 == n2,
(Self::Value(v1), Self::Value(v2)) => v1 == v2,
(Self::Value { tagged_value: v1, .. }, Self::Value { tagged_value: v2, .. }) => v1 == v2,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
@@ -169,13 +183,14 @@ impl NodeNetwork {
let network_input = self.nodes.get_mut(network_input).unwrap();
network_input.populate_first_network_input(node, *offset);
}
NodeInput::Value(value) => {
let name = format!("Value: {:?}", value.clone().to_value());
NodeInput::Value { tagged_value, exposed } => {
let name = format!("Value: {:?}", tagged_value.clone().to_value());
let new_id = map_ids(id, gen_id());
let value_node = DocumentNode {
name: name.clone(),
inputs: vec![NodeInput::Value(value)],
inputs: vec![NodeInput::Value { tagged_value, exposed }],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic])),
metadata: DocumentNodeMetadata::default(),
};
assert!(!self.nodes.contains_key(&new_id));
self.nodes.insert(new_id, value_node);
@@ -235,17 +250,19 @@ mod test {
(
0,
DocumentNode {
name: "cons".into(),
name: "Cons".into(),
inputs: vec![NodeInput::Network, NodeInput::Network],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
(
1,
DocumentNode {
name: "add".into(),
name: "Add".into(),
inputs: vec![NodeInput::Node(0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
]
@@ -265,17 +282,19 @@ mod test {
(
1,
DocumentNode {
name: "cons".into(),
name: "Cons".into(),
inputs: vec![NodeInput::Network, NodeInput::Network],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
(
2,
DocumentNode {
name: "add".into(),
name: "Add".into(),
inputs: vec![NodeInput::Node(1)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
]
@@ -294,8 +313,15 @@ mod test {
1,
DocumentNode {
name: "Inc".into(),
inputs: vec![NodeInput::Network, NodeInput::Value(value::TaggedValue::U32(2))],
inputs: vec![
NodeInput::Network,
NodeInput::Value {
tagged_value: value::TaggedValue::U32(2),
exposed: false,
},
],
implementation: DocumentNodeImplementation::Network(add_network()),
metadata: DocumentNodeMetadata::default(),
},
)]
.into_iter()
@@ -312,9 +338,10 @@ mod test {
#[test]
fn resolve_proto_node_add() {
let document_node = DocumentNode {
name: "cons".into(),
name: "Cons".into(),
inputs: vec![NodeInput::Network, NodeInput::Node(0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
metadata: DocumentNodeMetadata::default(),
};
let proto_node = document_node.resolve_proto_node();
@@ -380,30 +407,37 @@ mod test {
name: "Inc".into(),
inputs: vec![NodeInput::Node(11)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
(
10,
DocumentNode {
name: "cons".into(),
name: "Cons".into(),
inputs: vec![NodeInput::Network, NodeInput::Node(14)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::structural::ConsNode", &[Type::Generic, Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
(
14,
DocumentNode {
name: "Value: 2".into(),
inputs: vec![NodeInput::Value(value::TaggedValue::U32(2))],
inputs: vec![NodeInput::Value {
tagged_value: value::TaggedValue::U32(2),
exposed: false,
}],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
(
11,
DocumentNode {
name: "add".into(),
name: "Add".into(),
inputs: vec![NodeInput::Node(10)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Generic, Type::Generic])),
metadata: DocumentNodeMetadata::default(),
},
),
]