use enum_dispatch::enum_dispatch; use itertools::{Itertools, izip}; use serde::{Deserialize, Serialize}; use std::{fmt, iter}; use crate::node::{CompileError, ConcreteNode, MAX_INPUTS}; use crate::types::{ Dimension, Dimension::*, FloatPrecision::*, ScalarType, ScalarType::*, Type, Type::*, TypeSignature, }; const GEN_F_TYPES: [Type; 4] = [ Scalar(Float(Single)), Vector(Float(Single), D2), Vector(Float(Single), D3), Vector(Float(Single), D4), ]; const GEN_D_TYPES: [Type; 4] = [ Scalar(Float(Double)), Vector(Float(Double), D2), Vector(Float(Double), D3), Vector(Float(Double), D4), ]; const GEN_I_TYPES: [Type; 4] = [ Scalar(Int), Vector(Int, D2), Vector(Int, D3), Vector(Int, D4), ]; const GEN_U_TYPES: [Type; 4] = [ Scalar(UInt), Vector(UInt, D2), Vector(UInt, D3), Vector(UInt, D4), ]; const _GEN_B_TYPES: [Type; 4] = [ Scalar(Bool), Vector(Bool, D2), Vector(Bool, D3), Vector(Bool, D4), ]; const SCALAR_TYPES: [ScalarType; 5] = [Float(Single), Float(Double), Int, UInt, Bool]; const COMPONENT_LABELS: [&str; 4] = ["x", "y", "z", "w"]; pub trait NodeIndex: Sized + fmt::Display { const TITLE: &'static str; fn all() -> impl Iterator; fn pick_node(ui: &mut egui::Ui) -> Option { let mut res: Option = None; ui.menu_button(Self::TITLE, |ui| { for node in Self::all() { if ui.button(format!("{node}")).clicked() { res = Some(node); } } }); res } } /// Helper trait for Nodes with fixed number of inputs and outputs trait FixedNode: fmt::Debug { fn all_signatures(&self) -> Box>; fn compile( &self, f: &mut dyn fmt::Write, signature: TypeSignature, inputs: Vec, outputs: Vec, ) -> Result<(), CompileError> { let mut pairs = signature.outputs.iter().zip(outputs.iter()); let (out_typ, out_name) = pairs.next().expect("no output"); for (typ, name) in pairs { writeln!(f, "{typ} {name};")?; } let func = format!("{self:?}"); let first = func[..1].to_lowercase(); let rest = func[1..].to_string(); let params = inputs.iter().chain(outputs.iter().skip(1)).join(", "); writeln!(f, "{out_typ} {out_name} = {first}{rest}({params});")?; Ok(()) } } impl ConcreteNode for T { fn visible_inputs(&self, connected: &[Option; MAX_INPUTS]) -> Vec> { let signature = self .all_signatures() .into_iter() .find(|sig| sig.matches_inputs(connected)) .unwrap_or_else(|| self.all_signatures().next().expect("need one signature")); signature.inputs.into_iter().map(Some).collect() } fn signature( &self, connected: &[Option; MAX_INPUTS], ) -> Result { self.all_signatures() .find(|sig| sig.matches_inputs(connected)) .ok_or(CompileError::MissingArguments) } fn compile( &self, f: &mut dyn fmt::Write, signature: TypeSignature, inputs: Vec>, outputs: Vec, ) -> Result<(), CompileError> { let inputs: Option> = inputs.into_iter().collect(); if let Some(inputs) = inputs { self.compile(f, signature, inputs, outputs) } else { Err(CompileError::MissingArguments) } } } /* trait ProvideImpl { type Impl = T; } impl ConcreteNode for ProvideImpl { ProvideImpl::Impl::inputs(self) } /// Helper trait for Nodes with a single fixed-type output trait OutputOnlyNode: fmt::Debug { fn output_type(&self) -> Type; fn compile(&self, out_type: Type, output: &str, f: &mut dyn fmt::Write) -> Result<(), CompileError>; } impl ConcreteNode for T { fn inputs(&self) -> usize { 0 } fn outputs(&self) -> usize { 1 } fn signatures_matching(&self, connected: &[Option]) -> Vec { vec![self.signature(connected)] } fn signature(&self, connected: &[Option]) -> TypeSignature { TypeSignature::new([], [self.output_type()]) } fn compile( &self, signature: TypeSignature, inputs: Vec>, outputs: Vec, f: &mut dyn fmt::Write, ) -> Result<(), CompileError> { self.compile(signature.outputs[0], &outputs[0], f) } } */ /// Arithmetic Operations #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum BinArithmetic { Add, Subtract, Multiply, Divide, } fn check_gentype_up(inputs: &[Option]) -> Result, CompileError> { let mut seen: Option = None; for input in inputs { seen = match (seen, input) { (a, None) => a, (None, a) => *a, (Some(a), Some(b)) => Some(Type::upcast_gentype(a, *b)?), } } Ok(seen) } fn check_gentype_down(inputs: &[Option]) -> Result, CompileError> { let mut seen: Option = None; for input in inputs { seen = match (seen, input) { (a, None) => a, (None, Some(b)) => Some(b.scalar()), (Some(a), Some(b)) => Some(b.downcast_gentype(a)?), } } Ok(seen) } fn last_connected(connected: &[Option]) -> Option { connected .iter() .enumerate() .filter(|(_, v)| v.is_some()) .map(|(i, _)| i) .next_back() } impl ConcreteNode for BinArithmetic { fn visible_inputs(&self, connected: &[Option; MAX_INPUTS]) -> Vec> { let typ = check_gentype_up(connected).ok().flatten(); let num = last_connected(connected).map_or(1, |i| i + 1); let inputs = connected.iter().take(num).copied().map(|t| t.or(typ)); if num < MAX_INPUTS { inputs.chain(iter::once(None)).collect() } else { inputs.collect() } } fn signature( &self, connected: &[Option; MAX_INPUTS], ) -> Result { let typ = check_gentype_up(connected)?.ok_or(CompileError::MissingArguments)?; let num = last_connected(connected).map_or(2, |i| i + 2); Ok(TypeSignature { inputs: (0..num).map(|i| connected[i].unwrap_or(typ)).collect(), outputs: Box::new([typ]), }) } fn compile( &self, f: &mut dyn fmt::Write, signature: TypeSignature, inputs: Vec>, outputs: Vec, ) -> Result<(), CompileError> { let out_typ = &signature.outputs[0]; let out_name = &outputs[0]; let sym = match self { Self::Add => " + ", Self::Subtract => " - ", Self::Multiply => " * ", Self::Divide => " / ", }; let expr = inputs.into_iter().flatten().join(sym); writeln!(f, "{out_typ} {out_name} = {expr};")?; Ok(()) } } impl NodeIndex for BinArithmetic { const TITLE: &'static str = "Arithmetic"; fn all() -> impl Iterator { [Self::Add, Self::Subtract, Self::Multiply, Self::Divide].into_iter() } } impl fmt::Display for BinArithmetic { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Add => write!(f, "+ Add"), Self::Subtract => write!(f, "- Subtract"), Self::Multiply => write!(f, "* Multiply"), Self::Divide => write!(f, "/ Divide"), } } } /// 1-1 thru operations #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Thru1 { // trig Radians, Degrees, Sin, Cos, Tan, Asin, Acos, Atan, Sinh, Cosh, Tanh, Asinh, Acosh, Atanh, // exponential Exp, Log, Exp2, Log2, Sqrt, Inverseqrt, // common Abs, Sign, Floor, Trunc, Round, RoundEven, Ceil, Fract, // geometric Normalize, // derivative DFdx, DFdy, Fwidth, } impl Thru1 { pub fn all() -> impl Iterator { [ Self::Abs, Self::Sign, Self::Floor, Self::Trunc, Self::Round, Self::RoundEven, Self::Ceil, Self::Fract, Self::DFdx, Self::DFdy, Self::Fwidth, Self::Sqrt, Self::Inverseqrt, Self::Exp, Self::Log, Self::Exp2, Self::Log2, Self::Radians, Self::Degrees, Self::Sin, Self::Cos, Self::Tan, Self::Asin, Self::Acos, Self::Atan, Self::Sinh, Self::Cosh, Self::Tanh, Self::Asinh, Self::Acosh, Self::Atanh, Self::Normalize, ] .into_iter() } } impl FixedNode for Thru1 { fn all_signatures(&self) -> Box> { Box::new( match self { Self::Abs | Self::Sign => vec![GEN_F_TYPES, GEN_I_TYPES, GEN_D_TYPES], Self::DFdx | Self::DFdy | Self::Fwidth | Self::Exp | Self::Log | Self::Exp2 | Self::Log2 | Self::Radians | Self::Degrees | Self::Sin | Self::Cos | Self::Tan | Self::Asin | Self::Acos | Self::Atan | Self::Sinh | Self::Cosh | Self::Tanh | Self::Asinh | Self::Acosh | Self::Atanh => vec![GEN_F_TYPES], _ => vec![GEN_F_TYPES, GEN_D_TYPES], } .into_iter() .flatten() .map(|t| TypeSignature::new([t], [t])), ) } } /// Modulo #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Pow; impl Pow { pub fn all() -> impl Iterator { iter::once(Pow) } } impl FixedNode for Pow { fn all_signatures(&self) -> Box> { Box::new( GEN_F_TYPES .into_iter() .map(|t| TypeSignature::new([t, t], [t])), ) } } /// Modulo #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Mod; impl Mod { pub fn all() -> impl Iterator { iter::once(Mod) } } impl FixedNode for Mod { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .flat_map(|t| { [ TypeSignature::new([t, t.scalar().into()], [t]), TypeSignature::new([t, t], [t]), ] }) .dedup(), ) } } /// Modf #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Modf; impl Modf { pub fn all() -> impl Iterator { iter::once(Modf) } } impl FixedNode for Modf { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .map(|t| TypeSignature::new([t], [t, t])), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum MinMax { Min, Max, } impl MinMax { pub fn all() -> impl Iterator { [Self::Min, Self::Max].into_iter() } } impl FixedNode for MinMax { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES, GEN_I_TYPES, GEN_U_TYPES] .into_iter() .flatten() .flat_map(|t| { [ TypeSignature::new([t, t.scalar().into()], [t]), TypeSignature::new([t, t], [t]), ] }) .dedup(), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Clamp; impl Clamp { pub fn all() -> impl Iterator { iter::once(Clamp) } } impl FixedNode for Clamp { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES, GEN_I_TYPES, GEN_U_TYPES] .into_iter() .flatten() .flat_map(|t| { [ TypeSignature::new([t, t.scalar().into(), t.scalar().into()], [t]), TypeSignature::new([t, t, t], [t]), ] }) .dedup(), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Mix; impl Mix { pub fn all() -> impl Iterator { iter::once(Self) } } impl FixedNode for Mix { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .flat_map(|t| { let b = match t { Scalar(_) => Scalar(Bool), Vector(_, d) => Vector(Bool, d), _ => unreachable!("mix doesnt exist for matrices"), }; [ TypeSignature::new([t, t, t.scalar().into()], [t]), TypeSignature::new([t, t, t], [t]), TypeSignature::new([t, t, b], [t]), ] }) .dedup(), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Step; impl Step { pub fn all() -> impl Iterator { iter::once(Self) } } impl FixedNode for Step { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .flat_map(|t| { [ TypeSignature::new([t.scalar().into(), t], [t]), TypeSignature::new([t, t], [t]), ] }) .dedup(), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Smoothstep; impl Smoothstep { pub fn all() -> impl Iterator { iter::once(Self) } } impl FixedNode for Smoothstep { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .flat_map(|t| { [ TypeSignature::new([t.scalar().into(), t.scalar().into(), t], [t]), TypeSignature::new([t, t, t], [t]), ] }) .dedup(), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Length; impl Length { pub fn all() -> impl Iterator { iter::once(Self) } } impl FixedNode for Length { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .map(|t| TypeSignature::new([t], [t.scalar().into()])), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum VecVecToScalar { Distance, Dot, } impl VecVecToScalar { pub fn all() -> impl Iterator { [Self::Distance, Self::Dot].into_iter() } } impl FixedNode for VecVecToScalar { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .map(|t| TypeSignature::new([t, t], [t.scalar().into()])), ) } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Cross; impl Cross { pub fn all() -> impl Iterator { iter::once(Self) } } impl FixedNode for Cross { fn all_signatures(&self) -> Box> { Box::new( [GEN_F_TYPES, GEN_D_TYPES] .into_iter() .flatten() .map(|t| TypeSignature::new([t, t], [t])), ) } } #[enum_dispatch(ConcreteNode)] #[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum BuiltinFunction { Thru1(Thru1), Mod(Mod), Modf(Modf), MinMax(MinMax), Clamp(Clamp), Pow(Pow), Mix(Mix), Step(Step), Smoothstep(Smoothstep), Length(Length), VecVecToScalar(VecVecToScalar), Cross(Cross), } impl NodeIndex for BuiltinFunction { const TITLE: &'static str = "Builtin Functions"; fn all() -> impl Iterator { iter::empty() .chain(Thru1::all().map(Self::from)) .chain(Mod::all().map(Self::from)) .chain(Modf::all().map(Self::from)) .chain(MinMax::all().map(Self::from)) .chain(Clamp::all().map(Self::from)) .chain(Mix::all().map(Self::from)) .chain(Step::all().map(Self::from)) .chain(Smoothstep::all().map(Self::from)) .chain(Pow::all().map(Self::from)) .chain(Length::all().map(Self::from)) .chain(VecVecToScalar::all().map(Self::from)) .chain(Cross::all().map(Self::from)) } fn pick_node(ui: &mut egui::Ui) -> Option { let mut res: Option = None; ui.menu_button(Self::TITLE, |ui| { for (title, nodes) in [ ( "Trigonometry", vec![ Self::from(Thru1::Radians), Self::from(Thru1::Degrees), Self::from(Thru1::Sin), Self::from(Thru1::Cos), Self::from(Thru1::Tan), Self::from(Thru1::Asin), Self::from(Thru1::Acos), Self::from(Thru1::Atan), Self::from(Thru1::Sinh), Self::from(Thru1::Cosh), Self::from(Thru1::Tanh), Self::from(Thru1::Asinh), Self::from(Thru1::Acosh), Self::from(Thru1::Atanh), ], ), ( "Exponential", vec![ Self::from(Pow), Self::from(Thru1::Exp), Self::from(Thru1::Log), Self::from(Thru1::Exp2), Self::from(Thru1::Log2), Self::from(Thru1::Sqrt), Self::from(Thru1::Inverseqrt), ], ), ( "Common", vec![ Self::from(Thru1::Abs), Self::from(Thru1::Sign), Self::from(Thru1::Floor), Self::from(Thru1::Trunc), Self::from(Thru1::Round), Self::from(Thru1::RoundEven), Self::from(Thru1::Ceil), Self::from(Thru1::Fract), Self::from(Mod), Self::from(Modf), Self::from(Mix), Self::from(Step), Self::from(Smoothstep), ], ), ( "Geometric", vec![ Self::from(Thru1::Normalize), Self::from(Length), Self::from(VecVecToScalar::Distance), Self::from(VecVecToScalar::Dot), Self::from(Cross), ], ), ] { ui.menu_button(title, |ui| { for node in nodes { if ui.button(format!("{node}")).clicked() { res = Some(node); } } }); } }); res } } impl fmt::Display for BuiltinFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Thru1(x) => fmt::Debug::fmt(x, f), Self::Mod(x) => fmt::Debug::fmt(x, f), Self::Modf(x) => fmt::Debug::fmt(x, f), Self::MinMax(x) => fmt::Debug::fmt(x, f), Self::Clamp(x) => fmt::Debug::fmt(x, f), Self::Mix(x) => fmt::Debug::fmt(x, f), Self::Step(x) => fmt::Debug::fmt(x, f), Self::Smoothstep(x) => fmt::Debug::fmt(x, f), Self::Pow(x) => fmt::Debug::fmt(x, f), Self::Length(x) => fmt::Debug::fmt(x, f), Self::VecVecToScalar(x) => fmt::Debug::fmt(x, f), Self::Cross(x) => fmt::Debug::fmt(x, f), } } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Output; impl FixedNode for Output { fn all_signatures(&self) -> Box> { Box::new( [ TypeSignature::new([Vector(Float(Single), D3)], []), TypeSignature::new([Vector(Float(Single), D4)], []), TypeSignature::new([Scalar(Float(Single))], []), TypeSignature::new([Scalar(Float(Double))], []), TypeSignature::new([Vector(Float(Single), D2)], []), ] .into_iter(), ) } fn compile( &self, f: &mut dyn fmt::Write, signature: TypeSignature, inputs: Vec, _outputs: Vec, ) -> Result<(), CompileError> { match signature.inputs[0] { Vector(_, D2) => writeln!(f, "out_color = vec4({}, 0.0, 1.0);", inputs[0])?, Vector(_, D3) => writeln!(f, "out_color = vec4({}, 1.0);", inputs[0])?, Vector(_, D4) => writeln!(f, "out_color = {};", inputs[0])?, Scalar(_) => writeln!(f, "out_color = vec4(vec3({}), 1.0);", inputs[0])?, _ => unreachable!("invalid output type"), }; Ok(()) } } impl NodeIndex for Output { const TITLE: &'static str = "Output"; fn all() -> impl Iterator { iter::once(Output) } fn pick_node(ui: &mut egui::Ui) -> Option { for node in Self::all() { if ui.button(format!("{node}")).clicked() { return Some(node); } } None } } impl fmt::Display for Output { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Output Color") } } trait Value: fmt::Display { const TYPE: Type; } trait ScalarValue: fmt::Display { type Raw; const SCALAR_TYPE: ScalarType; fn make_widget(val: &mut Self::Raw) -> impl egui::Widget; } impl Value for T { const TYPE: Type = Scalar(Self::SCALAR_TYPE); } trait ValueEditor: Value { fn show_editor(&mut self, ui: &mut egui::Ui) -> egui::Response; } #[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Constant(T); // scalar implementations impl ScalarValue for Constant { type Raw = f32; const SCALAR_TYPE: ScalarType = Float(Single); fn make_widget(val: &mut Self::Raw) -> impl egui::Widget { egui::DragValue::new(val).speed(0.1) } } impl ScalarValue for Constant { type Raw = f64; const SCALAR_TYPE: ScalarType = Float(Double); fn make_widget(val: &mut Self::Raw) -> impl egui::Widget { egui::DragValue::new(val).speed(0.1) } } impl ScalarValue for Constant { type Raw = i32; const SCALAR_TYPE: ScalarType = Int; fn make_widget(val: &mut Self::Raw) -> impl egui::Widget { egui::DragValue::new(val) } } impl ScalarValue for Constant { type Raw = u32; const SCALAR_TYPE: ScalarType = UInt; fn make_widget(val: &mut Self::Raw) -> impl egui::Widget { egui::DragValue::new(val) } } impl ScalarValue for Constant { type Raw = bool; const SCALAR_TYPE: ScalarType = Bool; fn make_widget(val: &mut Self::Raw) -> impl egui::Widget { egui::Checkbox::without_text(val) } } impl fmt::Display for Constant where Constant: ScalarValue, T: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl ValueEditor for Constant where Constant: ScalarValue, T: fmt::Display, { fn show_editor(&mut self, ui: &mut egui::Ui) -> egui::Response { ui.label("value"); ui.add(Self::make_widget(&mut self.0)) } } impl Value for Constant<[T; N]> where Constant: ScalarValue, T: fmt::Display, { const TYPE: Type = Vector(Constant::::SCALAR_TYPE, Dimension::from_const(N)); } impl ValueEditor for Constant<[T; N]> where Constant: ScalarValue, T: fmt::Display, { fn show_editor(&mut self, ui: &mut egui::Ui) -> egui::Response { egui::Grid::new("grid") .num_columns(2) .show(ui, |ui| { for (val, label) in self.0.iter_mut().zip(COMPONENT_LABELS) { ui.label(label); ui.add(Constant::::make_widget(val)); ui.end_row(); } }) .response } } impl fmt::Display for Constant<[T; N]> where Constant<[T; N]>: Value, T: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}({})", Self::TYPE, self.0.iter().map(|v| format!("{}", v)).join(", ") ) } } impl ConcreteNode for Constant where Constant: ValueEditor, { fn visible_inputs(&self, _connected: &[Option; MAX_INPUTS]) -> Vec> { vec![] } fn signature( &self, _connected: &[Option; MAX_INPUTS], ) -> Result { Ok(TypeSignature::new([], [Self::TYPE])) } fn compile( &self, f: &mut dyn fmt::Write, _signature: TypeSignature, _inputs: Vec>, outputs: Vec, ) -> Result<(), CompileError> { let out_typ = Self::TYPE; let out_name = &outputs[0]; writeln!(f, "{out_typ} {out_name} = {};", self)?; Ok(()) } fn show_body(&mut self, ui: &mut egui::Ui) -> egui::Response { self.show_editor(ui) } } #[enum_dispatch(ConcreteNode)] #[derive(Clone, PartialEq, Serialize, Deserialize)] pub enum AnyConstant { Float(Constant), Vec2(Constant<[f32; 2]>), Vec3(Constant<[f32; 3]>), Vec4(Constant<[f32; 4]>), Double(Constant), DVec2(Constant<[f64; 2]>), DVec3(Constant<[f64; 3]>), DVec4(Constant<[f64; 4]>), Int(Constant), IVec2(Constant<[i32; 2]>), IVec3(Constant<[i32; 3]>), IVec4(Constant<[i32; 4]>), UInt(Constant), UVec2(Constant<[u32; 2]>), UVec3(Constant<[u32; 3]>), UVec4(Constant<[u32; 4]>), Bool(Constant), BVec2(Constant<[bool; 2]>), BVec3(Constant<[bool; 3]>), BVec4(Constant<[bool; 4]>), } impl NodeIndex for AnyConstant { const TITLE: &'static str = "Constants"; fn all() -> impl Iterator { [ Self::Float(Default::default()), Self::Vec2(Default::default()), Self::Vec3(Default::default()), Self::Vec4(Default::default()), Self::Double(Default::default()), Self::DVec2(Default::default()), Self::DVec3(Default::default()), Self::DVec4(Default::default()), Self::Int(Default::default()), Self::IVec2(Default::default()), Self::IVec3(Default::default()), Self::IVec4(Default::default()), Self::UInt(Default::default()), Self::UVec2(Default::default()), Self::UVec3(Default::default()), Self::UVec4(Default::default()), Self::Bool(Default::default()), Self::BVec2(Default::default()), Self::BVec3(Default::default()), Self::BVec4(Default::default()), ] .into_iter() } fn pick_node(ui: &mut egui::Ui) -> Option { ui.menu_button(Self::TITLE, |ui| { Type::pick(ui).map(|t| match t { Scalar(Float(Single)) => Self::Float(Default::default()), Vector(Float(Single), D2) => Self::Vec2(Default::default()), Vector(Float(Single), D3) => Self::Vec3(Default::default()), Vector(Float(Single), D4) => Self::Vec4(Default::default()), Scalar(Float(Double)) => Self::Double(Default::default()), Vector(Float(Double), D2) => Self::DVec2(Default::default()), Vector(Float(Double), D3) => Self::DVec3(Default::default()), Vector(Float(Double), D4) => Self::DVec4(Default::default()), Scalar(Int) => Self::Int(Default::default()), Vector(Int, D2) => Self::IVec2(Default::default()), Vector(Int, D3) => Self::IVec3(Default::default()), Vector(Int, D4) => Self::IVec4(Default::default()), Scalar(UInt) => Self::UInt(Default::default()), Vector(UInt, D2) => Self::UVec2(Default::default()), Vector(UInt, D3) => Self::UVec3(Default::default()), Vector(UInt, D4) => Self::UVec4(Default::default()), Scalar(Bool) => Self::Bool(Default::default()), Vector(Bool, D2) => Self::BVec2(Default::default()), Vector(Bool, D3) => Self::BVec3(Default::default()), Vector(Bool, D4) => Self::BVec4(Default::default()), Matrix(_, _, _) => unreachable!(), }) }) .inner .flatten() } } impl fmt::Display for AnyConstant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Float(_) => write!(f, "Float"), Self::Vec2(_) => write!(f, "Vec2"), Self::Vec3(_) => write!(f, "Vec3"), Self::Vec4(_) => write!(f, "Vec4"), Self::Double(_) => write!(f, "Double"), Self::DVec2(_) => write!(f, "DVec2"), Self::DVec3(_) => write!(f, "DVec3"), Self::DVec4(_) => write!(f, "DVec4"), Self::Int(_) => write!(f, "Integer"), Self::IVec2(_) => write!(f, "IVec2"), Self::IVec3(_) => write!(f, "IVec3"), Self::IVec4(_) => write!(f, "IVec4"), Self::UInt(_) => write!(f, "Unsigned Integer"), Self::UVec2(_) => write!(f, "UVec2"), Self::UVec3(_) => write!(f, "UVec3"), Self::UVec4(_) => write!(f, "UVec4"), Self::Bool(_) => write!(f, "Boolean"), Self::BVec2(_) => write!(f, "BVec2"), Self::BVec3(_) => write!(f, "BVec3"), Self::BVec4(_) => write!(f, "BVec4"), } } } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Input { UV, Resolution, Time, } impl ConcreteNode for Input { fn visible_inputs(&self, _connected: &[Option; MAX_INPUTS]) -> Vec> { vec![] } fn signature( &self, _connected: &[Option; MAX_INPUTS], ) -> Result { Ok(TypeSignature::new( [], [match self { Self::UV | Self::Resolution => Vector(Float(Single), D2), Self::Time => Scalar(Float(Single)), }], )) } fn compile( &self, f: &mut dyn fmt::Write, signature: TypeSignature, _inputs: Vec>, outputs: Vec, ) -> Result<(), CompileError> { let out_typ = &signature.outputs[0]; let out_name = &outputs[0]; writeln!( f, "{out_typ} {out_name} = {};", match self { Self::UV => "in_uv", Self::Resolution => "in_resolution", Self::Time => "in_time", } )?; Ok(()) } } impl NodeIndex for Input { const TITLE: &'static str = "Inputs"; fn all() -> impl Iterator { [Self::UV, Self::Resolution, Self::Time].into_iter() } } impl fmt::Display for Input { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::UV => write!(f, "UV Coordinates"), Self::Resolution => write!(f, "Output Resolution"), Self::Time => write!(f, "Time in Seconds"), } } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct SplitVector; impl FixedNode for SplitVector { fn all_signatures(&self) -> Box> { Box::new(SCALAR_TYPES.into_iter().flat_map(|s| { [ TypeSignature::new([Vector(s, D2)], [Scalar(s); 2]), TypeSignature::new([Vector(s, D3)], [Scalar(s); 3]), TypeSignature::new([Vector(s, D4)], [Scalar(s); 4]), ] })) } fn compile( &self, f: &mut dyn fmt::Write, signature: TypeSignature, inputs: Vec, outputs: Vec, ) -> Result<(), CompileError> { let input = &inputs[0]; for (typ, name, component) in izip!( signature.outputs.into_iter(), outputs.into_iter(), COMPONENT_LABELS ) { writeln!(f, "{typ} {name} = {input}.{component};")? } Ok(()) } } impl fmt::Display for SplitVector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Split Vector") } } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct CombineVector; fn without_tail<'a, T>( inputs: impl DoubleEndedIterator>, ) -> Vec<&'a Option> { let mut reversed: Vec<_> = inputs.rev().skip_while(|v| v.is_none()).collect(); reversed.reverse(); reversed } impl ConcreteNode for CombineVector { fn visible_inputs(&self, connected: &[Option; MAX_INPUTS]) -> Vec> { let typ = check_gentype_down(connected).ok().flatten().map(Scalar); let num = last_connected(connected).map_or(1, |i| i + 1); let inputs = connected.iter().take(num).copied().map(|t| t.or(typ)); if num < 4 { inputs.chain(iter::once(None)).collect() } else { inputs.collect() } } fn signature( &self, connected: &[Option; MAX_INPUTS], ) -> Result { let scalar = check_gentype_down(connected)?.ok_or(CompileError::MissingArguments)?; let mut num: usize = 0; for input in without_tail(connected.iter()) { num += if let Some(t) = input { t.num_components() } else { 1 }; } let dim = Dimension::try_from(num).map_err(|_| CompileError::InvalidArguments)?; Ok(TypeSignature { inputs: connected .iter() .map(|v| v.unwrap_or(Scalar(scalar))) .collect(), outputs: Box::new([Vector(scalar, dim)]), }) } fn compile( &self, f: &mut dyn fmt::Write, signature: TypeSignature, inputs: Vec>, outputs: Vec, ) -> Result<(), CompileError> { let out_typ = &signature.outputs[0]; let out_name = &outputs[0]; let params = without_tail(inputs.iter()) .into_iter() .enumerate() .map(|(i, v)| { v.clone() .unwrap_or_else(|| signature.inputs[i].default_value()) }) .join(", "); writeln!(f, "{out_typ} {out_name} = {out_typ}({params});")?; Ok(()) } } impl fmt::Display for CombineVector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Combine into Vector") } } #[enum_dispatch(ConcreteNode)] #[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] pub enum Conversion { SplitVector(SplitVector), CombineVector(CombineVector), } impl NodeIndex for Conversion { const TITLE: &'static str = "Conversion"; fn all() -> impl Iterator { [Self::from(SplitVector), Self::from(CombineVector)].into_iter() } } impl fmt::Display for Conversion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::SplitVector(x) => fmt::Display::fmt(x, f), Self::CombineVector(x) => fmt::Display::fmt(x, f), } } }