mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 15:28:04 +08:00
Downscale Images to document resolution (#1077)
* Add DownscaleNode * Add lambda (call argument) input type + fix caching * Add comment explaining Lambda input * Automatically insert cache node after downscale node * Implement sparse hashing of images
This commit is contained in:
@@ -69,6 +69,7 @@ impl DocumentNode {
|
||||
(ProtoNodeInput::Node(node_id, lambda), ConstructionArgs::Nodes(vec![]))
|
||||
}
|
||||
NodeInput::Network(ty) => (ProtoNodeInput::Network(ty), ConstructionArgs::Nodes(vec![])),
|
||||
NodeInput::ShortCircut(ty) => (ProtoNodeInput::ShortCircut(ty), ConstructionArgs::Nodes(vec![])),
|
||||
};
|
||||
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network(_))), "recieved non resolved parameter");
|
||||
assert!(
|
||||
@@ -121,12 +122,52 @@ impl DocumentNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the possible inputs to a node.
|
||||
/// # ShortCircuting
|
||||
/// In Graphite nodes are functions and by default, these are composed into a single function
|
||||
/// by inserting Compose nodes.
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
/// ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
/// │ │◄──────────────┤ │◄───────────────┤ │
|
||||
/// │ A │ │ B │ │ C │
|
||||
/// │ ├──────────────►│ ├───────────────►│ │
|
||||
/// └─────────────────┘ └──────────────────┘ └──────────────────┘
|
||||
///
|
||||
///
|
||||
///
|
||||
/// This is equivalent to calling c(b(a(input))) when evaluating c with input ( `c.eval(input)`)
|
||||
/// But sometimes we might want to have a little more control over the order of execution.
|
||||
/// This is why we allow nodes to opt out of the input forwarding by consuming the input directly.
|
||||
///
|
||||
///
|
||||
///
|
||||
/// ┌─────────────────────┐ ┌─────────────┐
|
||||
/// │ │◄───────────────┤ │
|
||||
/// │ Cache Node │ │ C │
|
||||
/// │ ├───────────────►│ │
|
||||
/// ┌──────────────────┐ ├─────────────────────┤ └─────────────┘
|
||||
/// │ │◄──────────────┤ │
|
||||
/// │ A │ │ * Cached Node │
|
||||
/// │ ├──────────────►│ │
|
||||
/// └──────────────────┘ └─────────────────────┘
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
/// In this case the Cache node actually consumes it's input and then manually forwards it to it's parameter
|
||||
/// Node. This is necessary because the Cache Node needs to short-circut the actual node evaluation
|
||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum NodeInput {
|
||||
Node { node_id: NodeId, output_index: usize, lambda: bool },
|
||||
Value { tagged_value: crate::document::value::TaggedValue, exposed: bool },
|
||||
Network(Type),
|
||||
// A short circuting input represents an input that is not resolved through function composition but
|
||||
// actually consuming the provided input instead of passing it to its predecessor
|
||||
ShortCircut(Type),
|
||||
}
|
||||
|
||||
impl NodeInput {
|
||||
@@ -153,6 +194,7 @@ impl NodeInput {
|
||||
NodeInput::Node { .. } => true,
|
||||
NodeInput::Value { exposed, .. } => *exposed,
|
||||
NodeInput::Network(_) => false,
|
||||
NodeInput::ShortCircut(_) => false,
|
||||
}
|
||||
}
|
||||
pub fn ty(&self) -> Type {
|
||||
@@ -160,6 +202,7 @@ impl NodeInput {
|
||||
NodeInput::Node { .. } => unreachable!("ty() called on NodeInput::Node"),
|
||||
NodeInput::Value { tagged_value, .. } => tagged_value.ty(),
|
||||
NodeInput::Network(ty) => ty.clone(),
|
||||
NodeInput::ShortCircut(ty) => ty.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,6 +440,7 @@ impl NodeNetwork {
|
||||
self.inputs[index] = *network_input;
|
||||
}
|
||||
}
|
||||
NodeInput::ShortCircut(_) => (),
|
||||
}
|
||||
}
|
||||
node.implementation = DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into());
|
||||
|
||||
@@ -44,6 +44,7 @@ impl core::fmt::Display for ProtoNetwork {
|
||||
match &node.input {
|
||||
ProtoNodeInput::None => f.write_str("None")?,
|
||||
ProtoNodeInput::Network(ty) => f.write_fmt(format_args!("Network (type = {:?})", ty))?,
|
||||
ProtoNodeInput::ShortCircut(ty) => f.write_fmt(format_args!("Lambda (type = {:?})", ty))?,
|
||||
ProtoNodeInput::Node(_, _) => f.write_str("Node")?,
|
||||
}
|
||||
f.write_str("\n")?;
|
||||
@@ -116,11 +117,19 @@ pub struct ProtoNode {
|
||||
pub identifier: NodeIdentifier,
|
||||
}
|
||||
|
||||
/// A ProtoNodeInput represents the input of a node in a ProtoNetwork.
|
||||
/// For documentation on the meaning of the variants, see the documentation of the `NodeInput` enum
|
||||
/// in the `document` module
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum ProtoNodeInput {
|
||||
None,
|
||||
Network(Type),
|
||||
// the bool indicates whether to treat the node as lambda node
|
||||
/// A ShortCircut input represents an input that is not resolved through function composition but
|
||||
/// actually consuming the provided input instead of passing it to its predecessor
|
||||
ShortCircut(Type),
|
||||
/// the bool indicates whether to treat the node as lambda node.
|
||||
/// When treating it as a lambda, only the node that is connected itself is fed as input.
|
||||
/// Otherwise, the the entire network of which the node is the output is fed as input.
|
||||
Node(NodeId, bool),
|
||||
}
|
||||
|
||||
@@ -142,6 +151,10 @@ impl ProtoNode {
|
||||
self.construction_args.hash(&mut hasher);
|
||||
match self.input {
|
||||
ProtoNodeInput::None => "none".hash(&mut hasher),
|
||||
ProtoNodeInput::ShortCircut(ref ty) => {
|
||||
"lambda".hash(&mut hasher);
|
||||
ty.hash(&mut hasher);
|
||||
}
|
||||
ProtoNodeInput::Network(ref ty) => {
|
||||
"network".hash(&mut hasher);
|
||||
ty.hash(&mut hasher);
|
||||
@@ -422,6 +435,7 @@ impl TypingContext {
|
||||
// Get the node input type from the proto node declaration
|
||||
let input = match node.input {
|
||||
ProtoNodeInput::None => concrete!(()),
|
||||
ProtoNodeInput::ShortCircut(ref ty) => ty.clone(),
|
||||
ProtoNodeInput::Network(ref ty) => ty.clone(),
|
||||
ProtoNodeInput::Node(id, _) => {
|
||||
let input = self
|
||||
|
||||
Reference in New Issue
Block a user