Restructure node crates (#3384)

* Restructure node-graph folder

* Fix wasm compilation

* Move node definitions out of *-types crates

* Cleanup

* Fix warnings

* Fix warnings

* Start adding migrations

* Add migrations and move memo nodes to gcore

* Move nodes/gsvg-render -> rendering

* Replace some hard coded identifiers and fix automatic conversion

* Fix Vec2Value node migration

* Fix formatting

* Add more migrations

* Cleanup features

* Fix core_types::raster import

* Update demo artwork (to make profile ci work)

* Move *-types to node-graph/libraries folder

* Add missing node migrations

* Migrate more nodes

* Remove impure memo node

* More fixes and remove warning

* Migrate context and add a few missing migrations

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert
2025-11-18 11:21:54 +01:00
committed by GitHub
parent 12453d2e61
commit 57b0b9c7ed
193 changed files with 3871 additions and 2720 deletions

View File

@@ -26,5 +26,5 @@ proc-macro-crate = "3.1.0"
proc-macro-error2 = "2"
[dev-dependencies]
graphene-core = { workspace = true }
graphene-core-shaders = { workspace = true }
core-types = { workspace = true }
no-std-types = { workspace = true }

View File

@@ -62,7 +62,7 @@ pub fn derive_buffer_struct_enum(crate_ident: &CrateIdent, item: &ItemEnum) -> R
///
/// This is also largely copied from my (@firestar99) project and adjusted
///
/// [`BufferStruct`]: `graphene_core_shaders::shaders::buffer_struct::BufferStruct`
/// [`BufferStruct`]: `no_std_types::shaders::buffer_struct::BufferStruct`
pub fn derive_buffer_struct_struct(crate_ident: &CrateIdent, item: &ItemStruct) -> Result<TokenStream> {
let gcore_shaders = crate_ident.gcore_shaders()?;
let mod_buffer_struct = quote!(#gcore_shaders::shaders::buffer_struct);

View File

@@ -26,7 +26,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
description,
..
} = parsed;
let graphene_core = crate_ident.gcore()?;
let core_types = crate_ident.gcore()?;
let category = &attributes.category.as_ref().map(|value| quote!(Some(#value))).unwrap_or(quote!(None));
let mod_name = format_ident!("_{}_mod", mod_name);
@@ -68,8 +68,8 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
.map(|field| match &field.ty {
ParsedFieldType::Regular(RegularParsedField { ty, .. }) => ty.clone(),
ParsedFieldType::Node(NodeParsedField { output_type, input_type, .. }) => match parsed.is_async {
true => parse_quote!(&'n impl #graphene_core::Node<'n, #input_type, Output = impl core::future::Future<Output=#output_type>>),
false => parse_quote!(&'n impl #graphene_core::Node<'n, #input_type, Output = #output_type>),
true => parse_quote!(&'n impl #core_types::Node<'n, #input_type, Output = impl core::future::Future<Output=#output_type>>),
false => parse_quote!(&'n impl #core_types::Node<'n, #input_type, Output = #output_type>),
},
})
.collect();
@@ -181,13 +181,13 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
let mut tokens = quote!();
if let Some(min) = number_hard_min {
tokens.extend(quote_spanned! {min.span()=>
let #name = #graphene_core::misc::Clampable::clamp_hard_min(#name, #min);
let #name = #core_types::misc::Clampable::clamp_hard_min(#name, #min);
});
}
if let Some(max) = number_hard_max {
tokens.extend(quote_spanned! {max.span()=>
let #name = #graphene_core::misc::Clampable::clamp_hard_max(#name, #max);
let #name = #core_types::misc::Clampable::clamp_hard_max(#name, #max);
});
}
tokens
@@ -224,13 +224,13 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
// Add Clampable bound if this field uses hard_min or hard_max
if number_hard_min.is_some() || number_hard_max.is_some() {
// The bound applies to the Output type of the future, which is #ty
clampable_clauses.push(quote!(#ty: #graphene_core::misc::Clampable));
clampable_clauses.push(quote!(#ty: #core_types::misc::Clampable));
}
quote!(
#fut_ident: core::future::Future<Output = #ty> + #graphene_core::WasmNotSend + 'n,
for<'all> #all_lifetime_ty: #graphene_core::WasmNotSend,
#name: #graphene_core::Node<'n, #input_type, Output = #fut_ident> + #graphene_core::WasmNotSync
#fut_ident: core::future::Future<Output = #ty> + #core_types::WasmNotSend + 'n,
for<'all> #all_lifetime_ty: #core_types::WasmNotSend,
#name: #core_types::Node<'n, #input_type, Output = #fut_ident> + #core_types::WasmNotSync
)
}
(ParsedFieldType::Node(NodeParsedField { input_type, output_type, .. }), true) => {
@@ -239,8 +239,8 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
future_idents.push(fut_ident.clone());
quote!(
#fut_ident: core::future::Future<Output = #output_type> + #graphene_core::WasmNotSend + 'n,
#name: #graphene_core::Node<'n, #input_type, Output = #fut_ident > + #graphene_core::WasmNotSync
#fut_ident: core::future::Future<Output = #output_type> + #core_types::WasmNotSend + 'n,
#name: #core_types::Node<'n, #input_type, Output = #fut_ident > + #core_types::WasmNotSync
)
}
(ParsedFieldType::Node { .. }, false) => unreachable!("Found node which takes an impl Node<> input but is not async"),
@@ -267,11 +267,11 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
let await_keyword = is_async.then(|| quote!(.await));
let eval_impl = quote! {
type Output = #graphene_core::registry::DynFuture<'n, #output_type>;
type Output = #core_types::registry::DynFuture<'n, #output_type>;
#[inline]
fn eval(&'n self, __input: #input_type) -> Self::Output {
Box::pin(async move {
use #graphene_core::misc::Clampable;
use #core_types::misc::Clampable;
#(#eval_args)*
#(#min_max_args)*
@@ -295,7 +295,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
let properties = &attributes.properties_string.as_ref().map(|value| quote!(Some(#value))).unwrap_or(quote!(None));
let cfg = crate::shader_nodes::modify_cfg(attributes);
let node_input_accessor = generate_node_input_references(parsed, fn_generics, &field_idents, graphene_core, &identifier, &cfg);
let node_input_accessor = generate_node_input_references(parsed, fn_generics, &field_idents, core_types, &identifier, &cfg);
let ShaderTokens { shader_entry_point, gpu_node } = attributes.shader_node.as_ref().map(|n| n.codegen(crate_ident, parsed)).unwrap_or(Ok(ShaderTokens::default()))?;
Ok(quote! {
@@ -306,15 +306,15 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
#cfg
#[automatically_derived]
impl<'n, #(#fn_generics,)* #(#struct_generics,)* #(#future_idents,)*> #graphene_core::Node<'n, #input_type> for #mod_name::#struct_name<#(#struct_generics,)*>
impl<'n, #(#fn_generics,)* #(#struct_generics,)* #(#future_idents,)*> #core_types::Node<'n, #input_type> for #mod_name::#struct_name<#(#struct_generics,)*>
#struct_where_clause
{
#eval_impl
}
#cfg
const fn #identifier() -> #graphene_core::ProtoNodeIdentifier {
#graphene_core::ProtoNodeIdentifier::new(std::concat!(#identifier_path, "::", std::stringify!(#struct_name)))
const fn #identifier() -> #core_types::ProtoNodeIdentifier {
#core_types::ProtoNodeIdentifier::new(std::concat!(#identifier_path, "::", std::stringify!(#struct_name)))
}
#cfg
@@ -329,7 +329,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
#[allow(clippy::module_inception)]
mod #mod_name {
use super::*;
use #graphene_core as gcore;
use #core_types as gcore;
use gcore::{Node, NodeIOTypes, concrete, fn_type, fn_type_fut, future, ProtoNodeIdentifier, WasmNotSync, NodeIO, ContextFeature};
use gcore::value::ClonedNode;
use gcore::ops::TypeNode;
@@ -400,7 +400,7 @@ fn generate_node_input_references(
parsed: &ParsedNodeFn,
fn_generics: &[crate::GenericParam],
field_idents: &[&PatIdent],
graphene_core: &TokenStream2,
core_types: &TokenStream2,
identifier: &Ident,
cfg: &TokenStream2,
) -> TokenStream2 {
@@ -436,9 +436,9 @@ fn generate_node_input_references(
}
});
generated_input_accessor.push(quote! {
impl <#(#used),*> #graphene_core::NodeInputDecleration for #struct_name <#(#fn_generic_params),*> {
impl <#(#used),*> #core_types::NodeInputDecleration for #struct_name <#(#fn_generic_params),*> {
const INDEX: usize = #input_index;
fn identifier() -> #graphene_core::ProtoNodeIdentifier {
fn identifier() -> #core_types::ProtoNodeIdentifier {
#inputs_module_name::IDENTIFIER.clone()
}
type Result = #ty;
@@ -453,7 +453,7 @@ fn generate_node_input_references(
use super::*;
/// The `ProtoNodeIdentifier` of this node without any generics attached to it
pub const IDENTIFIER: #graphene_core::ProtoNodeIdentifier = #identifier();
pub const IDENTIFIER: #core_types::ProtoNodeIdentifier = #identifier();
#(#generated_input_accessor)*
}
}

View File

@@ -5,6 +5,7 @@ use quote::{format_ident, quote};
pub struct CrateIdent {
gcore: syn::Result<TokenStream>,
gcore_shaders: syn::Result<TokenStream>,
raster_types: syn::Result<TokenStream>,
wgpu_executor: syn::Result<TokenStream>,
}
@@ -17,6 +18,10 @@ impl CrateIdent {
self.gcore_shaders.as_ref().map_err(Clone::clone)
}
pub fn raster_types(&self) -> syn::Result<&TokenStream> {
self.raster_types.as_ref().map_err(Clone::clone)
}
pub fn wgpu_executor(&self) -> syn::Result<&TokenStream> {
self.wgpu_executor.as_ref().map_err(Clone::clone)
}
@@ -33,9 +38,15 @@ impl Default for CrateIdent {
Err(e) => Err(syn::Error::new(Span::call_site(), format!("Could not find dependency on `{orig_name}`:\n{e}"))),
};
let gcore = find_crate("graphene-core");
let gcore_shaders = find_crate("graphene-core-shaders").or_else(|eshaders| gcore.clone().map_err(|ecore| syn::Error::new(Span::call_site(), format!("{ecore}\n\nFallback: {eshaders}"))));
let gcore = find_crate("core-types");
let gcore_shaders = find_crate("no-std-types").or_else(|eshaders| gcore.clone().map_err(|ecore| syn::Error::new(Span::call_site(), format!("{ecore}\n\nFallback: {eshaders}"))));
let raster_types = find_crate("raster-types");
let wgpu_executor = find_crate("wgpu-executor");
Self { gcore, gcore_shaders, wgpu_executor }
Self {
gcore,
gcore_shaders,
raster_types,
wgpu_executor,
}
}
}

View File

@@ -110,14 +110,12 @@ fn derive_enum(enum_attributes: &[Attribute], name: Ident, input: syn::DataEnum)
.collect();
let crate_name = {
let crate_name = proc_macro_crate::crate_name("graphene-core-shaders")
.or_else(|_e| proc_macro_crate::crate_name("graphene-core"))
.map_err(|e| {
syn::Error::new(
Span::call_site(),
format!("Failed to find location of 'graphene_core' or 'graphene-core-shaders'. Make sure it is imported as a dependency: {e}"),
)
})?;
let crate_name = proc_macro_crate::crate_name("no-std-types").or_else(|_e| proc_macro_crate::crate_name("core-types")).map_err(|e| {
syn::Error::new(
Span::call_site(),
format!("Failed to find location of 'no-std-types' or 'core-types'. Make sure it is imported as a dependency: {e}"),
)
})?;
match crate_name {
proc_macro_crate::FoundCrate::Itself => quote!(crate),
proc_macro_crate::FoundCrate::Name(name) => {

View File

@@ -804,7 +804,7 @@ mod tests {
#[test]
fn test_basic_node() {
let attr = quote!(category("Math: Arithmetic"), path(graphene_core::TestNode), skip_impl);
let attr = quote!(category("Math: Arithmetic"), path(core_types::TestNode), skip_impl);
let input = quote!(
/// Multi
/// Line
@@ -819,7 +819,7 @@ mod tests {
attributes: NodeFnAttributes {
category: Some(parse_quote!("Math: Arithmetic")),
display_name: None,
path: Some(parse_quote!(graphene_core::TestNode)),
path: Some(parse_quote!(core_types::TestNode)),
skip_impl: true,
properties_string: None,
cfg: None,
@@ -1080,7 +1080,7 @@ mod tests {
#[test]
fn test_number_min_max_range_mode() {
let attr = quote!(category("Math: Arithmetic"), path(graphene_core::TestNode));
let attr = quote!(category("Math: Arithmetic"), path(core_types::TestNode));
let input = quote!(
fn add(
a: f64,
@@ -1100,7 +1100,7 @@ mod tests {
attributes: NodeFnAttributes {
category: Some(parse_quote!("Math: Arithmetic")),
display_name: None,
path: Some(parse_quote!(graphene_core::TestNode)),
path: Some(parse_quote!(core_types::TestNode)),
skip_impl: false,
properties_string: None,
cfg: None,

View File

@@ -182,10 +182,11 @@ impl PerPixelAdjustCodegen<'_> {
fn codegen_gpu_node(&self) -> syn::Result<TokenStream> {
let gcore = self.crate_ident.gcore()?;
let raster_types = self.crate_ident.raster_types()?;
let wgpu_executor = self.crate_ident.wgpu_executor()?;
// adapt fields for gpu node
let raster_gpu: Type = parse_quote!(#gcore::table::Table<#gcore::raster_types::Raster<#gcore::raster_types::GPU>>);
let raster_gpu: Type = parse_quote!(#gcore::table::Table<#raster_types::Raster<#raster_types::GPU>>);
let mut fields = self
.parsed
.fields