Rename nodes from "Instance ___" -> "Read ___" and "Instance Map" -> "Map Vector" (#3792)

* Rename nodes from "Instance ___" -> "Read ___" and "Instance Map" -> "Map Vector"

* Update leftover references and demo artwork

* Simplify logic

* Fix test
This commit is contained in:
Keavon Chambers
2026-02-20 00:52:36 -08:00
committed by GitHub
parent da278e0264
commit bd1c54907d
15 changed files with 104 additions and 116 deletions

View File

@@ -0,0 +1,43 @@
use core_types::ExtractVarArgs;
use core_types::table::Table;
use core_types::{Ctx, ExtractIndex, ExtractPosition};
use glam::DVec2;
use graphic_types::Vector;
// TODO: Call this "Read Context" once it's fully generic
#[node_macro::node(category("Context"), path(graphene_core::vector))]
fn read_vector(ctx: impl Ctx + ExtractVarArgs) -> Table<Vector> {
let Ok(var_arg) = ctx.vararg(0) else { return Default::default() };
let var_arg = var_arg as &dyn std::any::Any;
var_arg.downcast_ref().cloned().unwrap_or_default()
}
#[node_macro::node(category("Context"), path(core_types::vector))]
async fn read_position(
ctx: impl Ctx + ExtractPosition,
_primary: (),
/// The number of nested loops to traverse outwards (from the innermost loop) to get the position from. The most upstream loop is level 0, and downstream loops add levels.
///
/// In programming terms: inside the double loop `i { j { ... } }`, *Loop Level* 0 = `j` and 1 = `i`. After inserting a third loop `k { ... }`, inside it, levels would be 0 = `k`, 1 = `j`, and 2 = `i`.
loop_level: u32,
) -> DVec2 {
ctx.try_position().and_then(|mut iter| iter.nth(loop_level as usize).or_else(|| iter.last())).unwrap_or(DVec2::ZERO)
}
// TODO: Return u32, u64, or usize instead of f64 after #1621 is resolved and has allowed us to implement automatic type conversion in the node graph for nodes with generic type inputs.
// TODO: (Currently automatic type conversion only works for concrete types, via the Graphene preprocessor and not the full Graphene type system.)
/// Produces the index of the current iteration of a loop by reading from the evaluation context, which is supplied by downstream nodes such as *Instance Repeat*.
///
/// Nested loops can enable 2D or higher-dimensional iteration by using the *Loop Level* parameter to read the index from outer levels of loops.
#[node_macro::node(category("Context"), path(core_types::vector))]
async fn read_index(
ctx: impl Ctx + ExtractIndex,
_primary: (),
/// The number of nested loops to traverse outwards (from the innermost loop) to get the index from. The most upstream loop is level 0, and downstream loops add levels.
///
/// In programming terms: inside the double loop `i { j { ... } }`, *Loop Level* 0 = `j` and 1 = `i`. After inserting a third loop `k { ... }`, inside it, levels would be 0 = `k`, 1 = `j`, and 2 = `i`.
loop_level: u32,
) -> f64 {
ctx.try_index().and_then(|mut iter| iter.nth(loop_level as usize).or_else(|| iter.last())).unwrap_or(0) as f64
}

View File

@@ -1,4 +1,5 @@
pub mod animation;
pub mod context;
pub mod context_modification;
pub mod debug;
pub mod extract_xy;
@@ -8,6 +9,7 @@ pub mod ops;
// Re-export all nodes
pub use animation::*;
pub use context::*;
pub use context_modification::*;
pub use debug::*;
pub use extract_xy::*;

View File

@@ -3,13 +3,14 @@ pub mod render_node;
pub mod text;
#[cfg(feature = "wasm")]
pub mod wasm_application_io;
pub use blending_nodes;
pub use brush_nodes as brush;
pub use core_types::*;
pub use graphene_application_io as application_io;
pub use graphene_core;
pub use graphene_core::debug;
pub use graphic_nodes;
pub use graphic_types::{Artboard, Graphic, Vector};
pub use math_nodes;
pub use path_bool_nodes as path_bool;
pub use raster_nodes;
@@ -75,7 +76,9 @@ pub mod logic {
pub use graphene_core::logic::*;
}
pub use graphene_core::debug;
pub mod context {
pub use graphene_core::context::*;
}
// Re-export graphene_core modules for backward compatibility
pub mod ops {
@@ -91,9 +94,6 @@ pub mod animation {
pub use graphene_core::animation::*;
}
// Re-export at top level for convenience
pub use graphic_types::{Artboard, Graphic, Vector};
/// stop gap solutions until all paths have been replaced with their absolute ones
pub mod renderer {
pub use core_types::math::quad::Quad;

View File

@@ -1,7 +1,6 @@
use core_types::Color;
use core_types::table::{Table, TableRowRef};
use core_types::{CloneVarArgs, Context, Ctx, ExtractAll, ExtractIndex, ExtractPosition, OwnedContextImpl};
use glam::DVec2;
use core_types::{CloneVarArgs, Context, Ctx, ExtractAll, OwnedContextImpl};
use graphic_types::Graphic;
use graphic_types::Vector;
use graphic_types::raster_types::{CPU, Raster};
@@ -83,51 +82,6 @@ async fn instance_repeat<T: Into<Graphic> + Default + Send + Clone + 'static>(
result_table
}
#[node_macro::node(category("Instancing"), path(core_types::vector))]
async fn instance_position(
ctx: impl Ctx + ExtractPosition,
_primary: (),
/// The number of nested loops to traverse outwards (from the innermost loop) to get the position from. The most upstream loop is level 0, and downstream loops add levels.
///
/// In programming terms: inside the double loop `i { j { ... } }`, *Loop Level* 0 = `j` and 1 = `i`. After inserting a third loop `k { ... }`, inside it, levels would be 0 = `k`, 1 = `j`, and 2 = `i`.
loop_level: u32,
) -> DVec2 {
let Some(position_iter) = ctx.try_position() else { return DVec2::ZERO };
let mut last = DVec2::ZERO;
for (i, position) in position_iter.enumerate() {
if i == loop_level as usize {
return position;
}
last = position;
}
last
}
// TODO: Return u32, u64, or usize instead of f64 after #1621 is resolved and has allowed us to implement automatic type conversion in the node graph for nodes with generic type inputs.
// TODO: (Currently automatic type conversion only works for concrete types, via the Graphene preprocessor and not the full Graphene type system.)
/// Produces the index of the current iteration of a loop by reading from the evaluation context, which is supplied by downstream nodes such as *Instance Repeat*.
///
/// Nested loops can enable 2D or higher-dimensional iteration by using the *Loop Level* parameter to read the index from outer levels of loops.
#[node_macro::node(category("Instancing"), path(core_types::vector))]
async fn instance_index(
ctx: impl Ctx + ExtractIndex,
_primary: (),
/// The number of nested loops to traverse outwards (from the innermost loop) to get the index from. The most upstream loop is level 0, and downstream loops add levels.
///
/// In programming terms: inside the double loop `i { j { ... } }`, *Loop Level* 0 = `j` and 1 = `i`. After inserting a third loop `k { ... }`, inside it, levels would be 0 = `k`, 1 = `j`, and 2 = `i`.
loop_level: u32,
) -> f64 {
let Some(index_iter) = ctx.try_index() else { return 0. };
let mut last = 0;
for (i, index) in index_iter.enumerate() {
if i == loop_level as usize {
return index as f64;
}
last = index;
}
last as f64
}
#[cfg(test)]
mod test {
use super::*;
@@ -135,6 +89,7 @@ mod test {
use core_types::Ctx;
use core_types::Node;
use glam::DVec2;
use graphene_core::ReadPositionNode;
use graphene_core::extract_xy::{ExtractXyNode, XY};
use graphic_types::Vector;
use std::future::Future;
@@ -157,13 +112,7 @@ mod test {
let owned = OwnedContextImpl::default().into_context();
let rect = RectangleNode::new(
FutureWrapperNode(()),
ExtractXyNode::new(
InstancePositionNode {
_primary: FutureWrapperNode(()),
loop_level: FutureWrapperNode(0),
},
FutureWrapperNode(XY::Y),
),
ExtractXyNode::new(ReadPositionNode::new(FutureWrapperNode(()), FutureWrapperNode(0)), FutureWrapperNode(XY::Y)),
FutureWrapperNode(2_f64),
FutureWrapperNode(false),
FutureWrapperNode(0_f64),

View File

@@ -5,7 +5,7 @@ use core_types::bounds::{BoundingBox, RenderBoundingBox};
use core_types::registry::types::{Angle, IntegerCount, Length, Multiplier, Percentage, PixelLength, PixelSize, Progression, SeedValue};
use core_types::table::{Table, TableRow, TableRowMut};
use core_types::transform::{Footprint, Transform};
use core_types::{CloneVarArgs, Color, Context, Ctx, ExtractAll, ExtractVarArgs, OwnedContextImpl};
use core_types::{CloneVarArgs, Color, Context, Ctx, ExtractAll, OwnedContextImpl};
use glam::{DAffine2, DVec2};
use graphic_types::Vector;
use graphic_types::raster_types::{CPU, GPU, Raster};
@@ -1325,16 +1325,9 @@ async fn separate_subpaths(_: impl Ctx, content: Table<Vector>) -> Table<Vector>
.collect()
}
// TODO: Call this "Map" once it's fully generic
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
fn instance_vector(ctx: impl Ctx + ExtractVarArgs) -> Table<Vector> {
let Ok(var_arg) = ctx.vararg(0) else { return Default::default() };
let var_arg = var_arg as &dyn std::any::Any;
var_arg.downcast_ref().cloned().unwrap_or_default()
}
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
async fn instance_map(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: Table<Vector>, mapped: impl Node<Context<'static>, Output = Table<Vector>>) -> Table<Vector> {
async fn map_vector(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: Table<Vector>, mapped: impl Node<Context<'static>, Output = Table<Vector>>) -> Table<Vector> {
let mut rows = Vec::new();
for (i, row) in content.into_iter().enumerate() {
@@ -1350,6 +1343,7 @@ async fn instance_map(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: Table<
rows.into_iter().collect()
}
// TODO: Call this "Map" once it's fully generic
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
async fn map_points(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: Table<Vector>, mapped: impl Node<Context<'static>, Output = DVec2>) -> Table<Vector> {
let mut content = content;