use crate::raster::adjustments::RedGreenBlue; use crate::raster::BlendMode; use crate::raster::ImageFrame; use crate::registry::types::Percentage; use crate::vector::style::GradientStops; use crate::{Color, Node}; use core::marker::PhantomData; use core::ops::{Add, Div, Mul, Rem, Sub}; use glam::DVec2; use num_traits::Pow; use rand::{Rng, SeedableRng}; #[cfg(target_arch = "spirv")] use spirv_std::num_traits::float::Float; // Add #[node_macro::node(category("Math: Arithmetic"))] fn add, T>( _: (), #[implementations(f64, &f64, f64, &f64, f32, &f32, f32, &f32, u32, &u32, u32, &u32, DVec2, f64, DVec2)] augend: U, #[implementations(f64, f64, &f64, &f64, f32, f32, &f32, &f32, u32, u32, &u32, &u32, DVec2, DVec2, f64)] addend: T, ) -> >::Output { augend + addend } // Subtract #[node_macro::node(category("Math: Arithmetic"))] fn subtract, T>( _: (), #[implementations(f64, &f64, f64, &f64, f32, &f32, f32, &f32, u32, &u32, u32, &u32, DVec2, f64, DVec2)] minuend: U, #[implementations(f64, f64, &f64, &f64, f32, f32, &f32, &f32, u32, u32, &u32, &u32, DVec2, DVec2, f64)] subtrahend: T, ) -> >::Output { minuend - subtrahend } // Multiply #[node_macro::node(category("Math: Arithmetic"))] fn multiply, T>( _: (), #[implementations(f64, &f64, f64, &f64, f32, &f32, f32, &f32, u32, &u32, u32, &u32, DVec2, f64, DVec2)] multiplier: U, #[default(1.)] #[implementations(f64, f64, &f64, &f64, f32, f32, &f32, &f32, u32, u32, &u32, &u32, DVec2, DVec2, f64)] multiplicand: T, ) -> >::Output { multiplier * multiplicand } // Divide #[node_macro::node(category("Math: Arithmetic"))] fn divide, T>( _: (), #[implementations(f64, &f64, f64, &f64, f32, &f32, f32, &f32, u32, &u32, u32, &u32, DVec2, DVec2, f64)] numerator: U, #[default(1.)] #[implementations(f64, f64, &f64, &f64, f32, f32, &f32, &f32, u32, u32, &u32, &u32, DVec2, f64, DVec2)] denominator: T, ) -> >::Output { numerator / denominator } // Modulo #[node_macro::node(category("Math: Arithmetic"))] fn modulo, T>( _: (), #[implementations(f64, &f64, f64, &f64, f32, &f32, f32, &f32, u32, &u32, u32, &u32, DVec2, DVec2, f64)] numerator: U, #[default(2.)] #[implementations(f64, f64, &f64, &f64, f32, f32, &f32, &f32, u32, u32, &u32, &u32, DVec2, f64, DVec2)] modulus: T, ) -> >::Output { numerator % modulus } // Exponent #[node_macro::node(category("Math: Arithmetic"))] fn exponent, T>( _: (), #[implementations(f64, &f64, f64, &f64, f32, &f32, f32, &f32, u32, &u32, u32, &u32)] base: U, #[default(2.)] #[implementations(f64, f64, &f64, &f64, f32, f32, &f32, &f32, u32, u32, &u32, &u32)] power: T, ) -> >::Output { base.pow(power) } // Root #[node_macro::node(category("Math: Arithmetic"))] fn root( _: (), #[default(2.)] #[implementations(f64, f32)] radicand: U, #[default(2.)] #[implementations(f64, f32)] degree: U, ) -> U { if degree == U::from(2.).unwrap() { radicand.sqrt() } else if degree == U::from(3.).unwrap() { radicand.cbrt() } else { radicand.powf(U::from(1.).unwrap() / degree) } } // Logarithm #[node_macro::node(category("Math: Arithmetic"))] fn logarithm( _: (), #[implementations(f64, f32)] value: U, #[default(2.)] #[implementations(f64, f32)] base: U, ) -> U { if base == U::from(2.).unwrap() { value.log2() } else if base == U::from(10.).unwrap() { value.log10() } else if base - U::from(std::f64::consts::E).unwrap() < U::epsilon() * U::from(1e6).unwrap() { value.ln() } else { value.log(base) } } // Sine #[node_macro::node(category("Math: Trig"))] fn sine(_: (), #[implementations(f64, f32)] theta: U) -> U { theta.sin() } // Cosine #[node_macro::node(category("Math: Trig"))] fn cosine(_: (), #[implementations(f64, f32)] theta: U) -> U { theta.cos() } // Tangent #[node_macro::node(category("Math: Trig"))] fn tangent(_: (), #[implementations(f64, f32)] theta: U) -> U { theta.tan() } // Random #[node_macro::node(category("Math: Numeric"))] fn random( _: (), _primary: (), seed: u64, #[implementations(f64, f32)] #[default(0.)] min: U, #[implementations(f64, f32)] #[default(1.)] max: U, ) -> f64 { let mut rng = rand::rngs::StdRng::seed_from_u64(seed); let result = rng.gen::(); let (min, max) = if min < max { (min, max) } else { (max, min) }; let (min, max) = (min.to_f64().unwrap(), max.to_f64().unwrap()); result * (max - min) + min } // Round #[node_macro::node(category("Math: Numeric"))] fn round(_: (), #[implementations(f64, f32)] value: U) -> U { value.round() } // Floor #[node_macro::node(category("Math: Numeric"))] fn floor(_: (), #[implementations(f64, f32)] value: U) -> U { value.floor() } // Ceiling #[node_macro::node(category("Math: Numeric"))] fn ceiling(_: (), #[implementations(f64, f32)] value: U) -> U { value.ceil() } // Absolute Value #[node_macro::node(category("Math: Numeric"))] fn absolute_value(_: (), #[implementations(f64, f32)] value: U) -> U { value.abs() } // Min #[node_macro::node(category("Math: Numeric"))] fn min(_: (), #[implementations(f64, &f64, f32, &f32, u32, &u32, &str)] value: T, #[implementations(f64, &f64, f32, &f32, u32, &u32, &str)] other_value: T) -> T { match value < other_value { true => value, false => other_value, } } // Max #[node_macro::node(category("Math: Numeric"))] fn max(_: (), #[implementations(f64, &f64, f32, &f32, u32, &u32, &str)] value: T, #[implementations(f64, &f64, f32, &f32, u32, &u32, &str)] other_value: T) -> T { match value > other_value { true => value, false => other_value, } } // Equals #[node_macro::node(category("Math: Logic"))] fn equals, T>( _: (), #[implementations(f64, &f64, f32, &f32, u32, &u32, DVec2, &DVec2, &str)] value: T, #[implementations(f64, &f64, f32, &f32, u32, &u32, DVec2, &DVec2, &str)] #[min(100.)] #[max(200.)] other_value: U, ) -> bool { other_value == value } // Logical Or #[node_macro::node(category("Math: Logic"))] fn logical_or(_: (), value: bool, other_value: bool) -> bool { value || other_value } // Logical And #[node_macro::node(category("Math: Logic"))] fn logical_and(_: (), value: bool, other_value: bool) -> bool { value && other_value } // Logical Xor #[node_macro::node(category("Math: Logic"))] fn logical_xor(_: (), value: bool, other_value: bool) -> bool { value ^ other_value } // Logical Not #[node_macro::node(category("Math: Logic"))] fn logical_not(_: (), input: bool) -> bool { !input } // Bool Value #[node_macro::node(category("Value"))] fn bool_value(_: (), _primary: (), #[name("Bool")] bool_value: bool) -> bool { bool_value } // Number Value #[node_macro::node(category("Value"))] fn number_value(_: (), _primary: (), number: f64) -> f64 { number } // Percentage Value #[node_macro::node(category("Value"))] fn percentage_value(_: (), _primary: (), percentage: Percentage) -> f64 { percentage } // Vector2 Value #[node_macro::node(category("Value"))] fn vector2_value(_: (), _primary: (), x: f64, y: f64) -> DVec2 { DVec2::new(x, y) } // Color Value #[node_macro::node(category("Value"))] fn color_value(_: (), _primary: (), #[default(Color::BLACK)] color: Option) -> Option { color } // Gradient Value #[node_macro::node(category("Value"))] fn gradient_value(_: (), _primary: (), gradient: GradientStops) -> GradientStops { gradient } // Color Channel Value #[node_macro::node(category("Value"))] fn color_channel_value(_: (), _primary: (), color_channel: RedGreenBlue) -> RedGreenBlue { color_channel } // Blend Mode Value #[node_macro::node(category("Value"))] fn blend_mode_value(_: (), _primary: (), blend_mode: BlendMode) -> BlendMode { blend_mode } // Size Of #[cfg(feature = "std")] #[node_macro::node(category("Debug"))] fn size_of(_: (), ty: crate::Type) -> Option { ty.size() } // Some #[node_macro::node(category("Debug"))] fn some(_: (), #[implementations(f64, f32, u32, u64, String, Color)] input: T) -> Option { Some(input) } // Unwrap #[node_macro::node(category("Debug"))] fn unwrap(_: (), #[implementations(Option, Option, Option, Option, Option, Option)] input: Option) -> T { input.unwrap_or_default() } // Clone #[node_macro::node(category("Debug"))] fn clone<'i, T: Clone + 'i>(_: (), #[implementations(&ImageFrame)] value: &'i T) -> T { value.clone() } // Identity // TODO: Rename to "Passthrough" /// The identity function returns the input argument unchanged. #[node_macro::node(skip_impl)] fn identity<'i, T: 'i>(value: T) -> T { value } // Type #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct TypeNode Node<'a, I>, I, O>(pub N, pub PhantomData<(I, O)>); impl<'i, N, I: 'i, O: 'i> Node<'i, I> for TypeNode where N: for<'n> Node<'n, I, Output = O>, { type Output = O; fn eval(&'i self, input: I) -> Self::Output { self.0.eval(input) } fn reset(&self) { self.0.reset(); } fn serialize(&self) -> Option> { self.0.serialize() } } impl<'i, N: for<'a> Node<'a, I>, I: 'i> TypeNode>::Output> { pub fn new(node: N) -> Self { Self(node, PhantomData) } } impl<'i, N: for<'a> Node<'a, I> + Clone, I: 'i> Clone for TypeNode>::Output> { fn clone(&self) -> Self { Self(self.0.clone(), self.1) } } impl<'i, N: for<'a> Node<'a, I> + Copy, I: 'i> Copy for TypeNode>::Output> {} // Into pub struct IntoNode { _o: PhantomData, } #[cfg(feature = "alloc")] #[node_macro::old_node_fn(IntoNode<_O>)] async fn into(input: I) -> _O where I: Into<_O> + Sync + Send, { input.into() } #[cfg(test)] mod test { use super::*; use crate::{generic::*, structural::*, value::*}; #[test] pub fn identity_node() { let value = ValueNode(4u32).then(IdentityNode::new()); assert_eq!(value.eval(()), &4); } #[test] pub fn foo() { let fnn = FnNode::new(|(a, b)| (b, a)); assert_eq!(fnn.eval((1u32, 2u32)), (2, 1)); } }