diff --git a/Cargo.lock b/Cargo.lock index b297a14e8d..0c9d490848 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,6 +185,7 @@ version = "0.1.0" dependencies = [ "async-trait", "dyn-any", + "serde", "spirv-std", ] diff --git a/node-graph/gcore/Cargo.toml b/node-graph/gcore/Cargo.toml index 9457fb97c5..ec5dd413ad 100644 --- a/node-graph/gcore/Cargo.toml +++ b/node-graph/gcore/Cargo.toml @@ -20,3 +20,4 @@ dyn-any = {path = "../../libraries/dyn-any", features = ["derive"], optional = t spirv-std = { git = "https://github.com/EmbarkStudios/rust-gpu", features = ["glam"] , optional = true} async-trait = {version = "0.1", optional = true} +serde = "1.0" diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index e08b7a5bef..a63bc47c54 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -11,6 +11,7 @@ use async_trait::async_trait; pub mod generic; pub mod ops; //pub mod structural; +pub mod raster; pub mod value; pub trait Node<'n> { diff --git a/node-graph/gcore/src/raster.rs b/node-graph/gcore/src/raster.rs new file mode 100644 index 0000000000..2654710527 --- /dev/null +++ b/node-graph/gcore/src/raster.rs @@ -0,0 +1,18 @@ +use core::marker::PhantomData; + +use crate::Node; + +use self::color::Color; + +pub mod color; + +pub struct GrayscaleNode<'n, N: Node<'n, Output = Color>>(pub N, PhantomData<&'n ()>); + +impl<'n, N: Node<'n, Output = Color>> Node<'n> for GrayscaleNode<'n, N> { + type Output = Color; + fn eval(&'n self) -> Color { + let color = self.0.eval(); + let avg = (color.r() + color.g() + color.b()) / 3.0; + Color::from_rgbaf32(avg, avg, avg, color.a()).expect("Grayscale node created an invalid color") + } +} diff --git a/node-graph/gcore/src/raster/color.rs b/node-graph/gcore/src/raster/color.rs new file mode 100644 index 0000000000..0b4fe2fd1f --- /dev/null +++ b/node-graph/gcore/src/raster/color.rs @@ -0,0 +1,173 @@ +use serde::{Deserialize, Serialize}; + +/// Structure that represents a color. +/// Internally alpha is stored as `f32` that ranges from `0.0` (transparent) to `1.0` (opaque). +/// The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`, +/// the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)] +pub struct Color { + red: f32, + green: f32, + blue: f32, + alpha: f32, +} + +impl Color { + pub const BLACK: Color = Color::from_unsafe(0., 0., 0.); + pub const WHITE: Color = Color::from_unsafe(1., 1., 1.); + pub const RED: Color = Color::from_unsafe(1., 0., 0.); + pub const GREEN: Color = Color::from_unsafe(0., 1., 0.); + pub const BLUE: Color = Color::from_unsafe(0., 0., 1.); + + /// Returns `Some(Color)` if `red`, `green`, `blue` and `alpha` have a valid value. Negative numbers (including `-0.0`), NaN, and infinity are not valid values and return `None`. + /// Alpha values greater than `1.0` are not valid. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgbaf32(0.3, 0.14, 0.15, 0.92).unwrap(); + /// assert!(color.components() == (0.3, 0.14, 0.15, 0.92)); + /// + /// let color = Color::from_rgbaf32(1.0, 1.0, 1.0, f32::NAN); + /// assert!(color == None); + /// ``` + pub fn from_rgbaf32(red: f32, green: f32, blue: f32, alpha: f32) -> Option { + if alpha > 1. || [red, green, blue, alpha].iter().any(|c| c.is_sign_negative() || !c.is_finite()) { + return None; + } + Some(Color { red, green, blue, alpha }) + } + + /// Return an opaque `Color` from given `f32` RGB channels. + pub const fn from_unsafe(red: f32, green: f32, blue: f32) -> Color { + Color { red, green, blue, alpha: 1. } + } + + /// Return an opaque SDR `Color` given RGB channels from `0` to `255`. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgb8(0x72, 0x67, 0x62); + /// let color2 = Color::from_rgba8(0x72, 0x67, 0x62, 0xFF); + /// assert!(color == color2) + /// ``` + pub fn from_rgb8(red: u8, green: u8, blue: u8) -> Color { + Color::from_rgba8(red, green, blue, 255) + } + + /// Return an SDR `Color` given RGBA channels from `0` to `255`. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgba8(0x72, 0x67, 0x62, 0x61); + /// ``` + pub fn from_rgba8(red: u8, green: u8, blue: u8, alpha: u8) -> Color { + let map_range = |int_color| int_color as f32 / 255.0; + Color { + red: map_range(red), + green: map_range(green), + blue: map_range(blue), + alpha: map_range(alpha), + } + } + + /// Return the `red` component. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap(); + /// assert!(color.r() == 0.114); + /// ``` + pub fn r(&self) -> f32 { + self.red + } + + /// Return the `green` component. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap(); + /// assert!(color.g() == 0.103); + /// ``` + pub fn g(&self) -> f32 { + self.green + } + + /// Return the `blue` component. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap(); + /// assert!(color.b() == 0.98); + /// ``` + pub fn b(&self) -> f32 { + self.blue + } + + /// Return the `alpha` component without checking its expected `0.0` to `1.0` range. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap(); + /// assert!(color.a() == 0.97); + /// ``` + pub fn a(&self) -> f32 { + self.alpha + } + + /// Return the all components as a tuple, first component is red, followed by green, followed by blue, followed by alpha. + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap(); + /// assert!(color.components() == (0.114, 0.103, 0.98, 0.97)); + /// ``` + pub fn components(&self) -> (f32, f32, f32, f32) { + (self.red, self.green, self.blue, self.alpha) + } + + // TODO: Readd formatting + + /// Creates a color from a 8-character RGBA hex string (without a # prefix). + /// + /// # Examples + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgba_str("7C67FA61").unwrap(); + /// ``` + pub fn from_rgba_str(color_str: &str) -> Option { + if color_str.len() != 8 { + return None; + } + let r = u8::from_str_radix(&color_str[0..2], 16).ok()?; + let g = u8::from_str_radix(&color_str[2..4], 16).ok()?; + let b = u8::from_str_radix(&color_str[4..6], 16).ok()?; + let a = u8::from_str_radix(&color_str[6..8], 16).ok()?; + + Some(Color::from_rgba8(r, g, b, a)) + } + + /// Creates a color from a 6-character RGB hex string (without a # prefix). + /// ``` + /// use graphene_core::raster::color::Color; + /// let color = Color::from_rgb_str("7C67FA").unwrap(); + /// ``` + pub fn from_rgb_str(color_str: &str) -> Option { + if color_str.len() != 6 { + return None; + } + let r = u8::from_str_radix(&color_str[0..2], 16).ok()?; + let g = u8::from_str_radix(&color_str[2..4], 16).ok()?; + let b = u8::from_str_radix(&color_str[4..6], 16).ok()?; + + Some(Color::from_rgb8(r, g, b)) + } +} diff --git a/node-graph/gstd/file.rs b/node-graph/gstd/file.rs deleted file mode 100644 index 3be2bcb9f8..0000000000 --- a/node-graph/gstd/file.rs +++ /dev/null @@ -1,22 +0,0 @@ -# [cfg (target_arch = "spirv")]pub mod gpu { -# [repr (C )]pub struct PushConsts { - n : u32 , node : u32 , - } - use super :: * ; - use spirv_std :: glam :: UVec3 ; - # [allow (unused )]# [spirv (compute (threads (64)))]pub fn "add"(# [spirv (global_invocation_id )]global_id : UVec3 , # [spirv (storage_buffer , descriptor_set = 0, binding = 0)]a : & [u32 ], # [spirv (storage_buffer , descriptor_set = 0, binding = 1)]y : & mut [u32 ], # [spirv (push_constant )]push_consts : & PushConsts , ){ - fn node_graph (input : u32 )-> u32 { - let n0 = graphene_core :: value :: ValueNode :: new (input ); - let n1 = graphene_core :: value :: ValueNode :: new (1u32); - let n2 = graphene_core :: ops :: AddNode :: new ((& n0 , & n1 )); - n2 . eval () - } - let gid = global_id . x as usize ; - if global_id . x < push_consts . n { - y [gid ]= node_graph (a [gid ]); - - } - - } - -} diff --git a/node-graph/gstd/src/lib.rs b/node-graph/gstd/src/lib.rs index 791b73039f..ae80bfa10a 100644 --- a/node-graph/gstd/src/lib.rs +++ b/node-graph/gstd/src/lib.rs @@ -6,7 +6,7 @@ pub mod memo; pub use graphene_core::*; -use dyn_any::{downcast_ref, DynAny, StaticType}; +use dyn_any::DynAny; pub type DynNode<'n, T> = &'n (dyn Node<'n, Output = T> + 'n); pub type DynAnyNode<'n> = &'n (dyn Node<'n, Output = &'n dyn DynAny<'n>> + 'n); diff --git a/node-graph/gstd/src/main.rs b/node-graph/gstd/src/main.rs index bb802a9e9e..c8f70f91ae 100644 --- a/node-graph/gstd/src/main.rs +++ b/node-graph/gstd/src/main.rs @@ -1,15 +1,15 @@ -use borrow_stack::BorrowStack; //#![feature(generic_associated_types)] -use dyn_any::{DynAny, StaticType}; -use graphene_std::value::{AnyRefNode, AnyValueNode, StorageNode, ValueNode}; -use graphene_std::*; +// use borrow_stack::BorrowStack; +// use dyn_any::{DynAny, StaticType}; +// use graphene_std::value::{AnyRefNode, AnyValueNode, StorageNode, ValueNode}; +// use graphene_std::*; /*fn mul(#[dyn_any(default)] a: f32, b: f32) -> f32 { a * b }*/ mod mul { - use dyn_any::{downcast_ref, DynAny, StaticType}; + use dyn_any::downcast_ref; use graphene_std::{DynAnyNode, DynNode, DynamicInput, Node}; pub struct MulNodeInput<'n> { pub a: &'n f32, @@ -28,7 +28,7 @@ mod mul { impl<'n> Node<'n> for MulNodeAnyProxy<'n> { type Output = MulNodeInput<'n>; fn eval(&'n self) -> >::Output { - let a = self.a.unwrap().eval(); + // let a = self.a.unwrap().eval(); let a: &f32 = self.a.map(|v| downcast_ref(v.eval()).unwrap()).unwrap_or(&1.); /*let b: &f32 = self .b @@ -55,7 +55,7 @@ mod mul { //pub(crate) use new; impl<'n> DynamicInput<'n> for MulNodeAnyProxy<'n> { - fn set_kwarg_by_name(&mut self, name: &str, value: DynAnyNode<'n>) { + fn set_kwarg_by_name(&mut self, _name: &str, _value: DynAnyNode<'n>) { todo!() } fn set_arg_by_index(&mut self, index: usize, value: DynAnyNode<'n>) { @@ -68,29 +68,29 @@ mod mul { } } } -type SNode<'n> = dyn Node<'n, Output = &'n dyn DynAny<'n>>; +// type SNode<'n> = dyn Node<'n, Output = &'n dyn DynAny<'n>>; -struct NodeStore<'n>(borrow_stack::FixedSizeStack<'n, Box>>); +// struct NodeStore<'n>(borrow_stack::FixedSizeStack<'n, Box>>); -impl<'n> NodeStore<'n> { - fn len(&self) -> usize { - self.0.len() - } +// impl<'n> NodeStore<'n> { +// fn len(&self) -> usize { +// self.0.len() +// } - fn push(&'n mut self, f: fn(&'n [Box]) -> Box>) { - unsafe { self.0.push(f(self.0.get())) }; - } +// fn push(&'n mut self, f: fn(&'n [Box]) -> Box>) { +// unsafe { self.0.push(f(self.0.get())) }; +// } - /*fn get_index(&'n self, index: usize) -> &'n SNode<'n> { - assert!(index < self.0.len()); - &unsafe { self.0.get()[index] } - }*/ -} +// /*fn get_index(&'n self, index: usize) -> &'n SNode<'n> { +// assert!(index < self.0.len()); +// &unsafe { self.0.get()[index] } +// }*/ +// } fn main() { use graphene_std::*; use quote::quote; - use syn::parse::Parse; + // use syn::parse::Parse; let nodes = vec![ NodeKind::Input, NodeKind::Value(syn::parse_quote!(1u32)), @@ -99,7 +99,7 @@ fn main() { //println!("{}", node_graph(1)); - let nodegraph = NodeGraph { + let _nodegraph = NodeGraph { nodes, input: syn::Type::Verbatim(quote! {u32}), output: syn::Type::Verbatim(quote! {u32}), diff --git a/node-graph/gstd/src/value.rs b/node-graph/gstd/src/value.rs index 9759075dc4..e399054337 100644 --- a/node-graph/gstd/src/value.rs +++ b/node-graph/gstd/src/value.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; pub use graphene_core::value::*; use graphene_core::Node; -use dyn_any::{DynAny, StaticType, StaticTypeSized}; +use dyn_any::DynAny; pub struct AnyRefNode<'n, N: Node<'n>>(N, PhantomData<&'n ()>); diff --git a/node-graph/proc-macro/src/lib.rs b/node-graph/proc-macro/src/lib.rs index a56629a503..c26b7e78c1 100644 --- a/node-graph/proc-macro/src/lib.rs +++ b/node-graph/proc-macro/src/lib.rs @@ -51,7 +51,7 @@ fn generate_to_string(parsed: ItemFn, string: String) -> TokenStream { let types = extract_arg_types(fn_args); let types = types.iter().map(|t| t.to_token_stream()).collect::>(); let idents = idents.iter().map(|t| t.to_token_stream()).collect::>(); - let const_idents = idents + let _const_idents = idents .iter() .map(|t| { let name = t.to_string().to_uppercase();