Drop unread index bounds from fold kernels and mark re-addressing nodes ModifyIndex

This commit is contained in:
Dennis Kobert
2026-08-25 11:05:38 +00:00
parent 9cf037e992
commit ff99f3605c
12 changed files with 46 additions and 44 deletions
+1 -1
View File
@@ -149,5 +149,5 @@ fn read_index(
) -> f64 { ) -> f64 {
// The chain's innermost entry is the consuming wire's own lane from the // The chain's innermost entry is the consuming wire's own lane from the
// decompose-and-promote split; the loops the reader counts sit above it. // decompose-and-promote split; the loops the reader counts sit above it.
ctx.try_index().and_then(|mut iter| iter.nth(loop_level as usize + 1).or_else(|| iter.last())).unwrap_or(0) as f64 ctx.try_index().and_then(|mut iter| iter.nth(loop_level as usize + 1)).unwrap_or(0) as f64
} }
+3 -3
View File
@@ -1,5 +1,5 @@
use core_types::arena::ArenaCell; use core_types::arena::ArenaCell;
use core_types::context::{Ctx, CtxSnapshot, DeriveCtx, ExtractAll, ExtractIndex, InjectIndex}; use core_types::context::{Ctx, CtxSnapshot, DeriveCtx, ExtractAll, ModifyIndex};
use core_types::frame_table::{FrameTable, Lookup}; use core_types::frame_table::{FrameTable, Lookup};
use core_types::gpoll::{Finality, GPoll}; use core_types::gpoll::{Finality, GPoll};
use core_types::graphene_hash::CacheHash; use core_types::graphene_hash::CacheHash;
@@ -31,7 +31,7 @@ pub struct MemoLevel {
/// materialization of the content instead of re-evaluating it per lane. /// materialization of the content instead of re-evaluating it per lane.
#[node_macro::node(category("General"), path(graphene_core::memo))] #[node_macro::node(category("General"), path(graphene_core::memo))]
fn memoize<'e>( fn memoize<'e>(
ctx: impl Ctx + CacheHash + DeriveCtx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy, ctx: impl Ctx + CacheHash + DeriveCtx + ExtractArena<'e> + ModifyIndex + Copy,
#[data] cache: Arc<Mutex<Option<MemoLevel>>>, #[data] cache: Arc<Mutex<Option<MemoLevel>>>,
content: impl Node<Context<'_>, Output = RecordValue<'e>>, content: impl Node<Context<'_>, Output = RecordValue<'e>>,
) -> GPoll<RecordValue<'e>> { ) -> GPoll<RecordValue<'e>> {
@@ -188,7 +188,7 @@ type MonitorValue = Arc<Mutex<Option<IORecord<CtxSnapshot, RecordCapture>>>>;
/// The Monitor node is used by the editor to access the data flowing through it. /// The Monitor node is used by the editor to access the data flowing through it.
#[node_macro::node(category(""), path(graphene_core::memo), serialize(serialize_monitor), properties("monitor_properties"))] #[node_macro::node(category(""), path(graphene_core::memo), serialize(serialize_monitor), properties("monitor_properties"))]
fn monitor<'e>( fn monitor<'e>(
ctx: impl Ctx + DeriveCtx + ExtractAll + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy, ctx: impl Ctx + DeriveCtx + ExtractAll + ExtractArena<'e> + ModifyIndex + Copy,
#[data] io: MonitorValue, #[data] io: MonitorValue,
content: impl Node<Context<'_>, Output = RecordValue<'e>>, content: impl Node<Context<'_>, Output = RecordValue<'e>>,
) -> GPoll<RecordValue<'e>> { ) -> GPoll<RecordValue<'e>> {
+5 -5
View File
@@ -7,7 +7,7 @@
use core_types::Ctx; use core_types::Ctx;
use core_types::attribute::{Attr, EditorLayerPath, Opacity, RemoveAttr, Transform}; use core_types::attribute::{Attr, EditorLayerPath, Opacity, RemoveAttr, Transform};
use core_types::context::{DeriveCtx, ExtractIndex, ExtractIndices, IndexLink, InjectIndex}; use core_types::context::{DeriveCtx, ExtractIndex, ExtractIndices, IndexLink, InjectIndex, ModifyIndex};
use core_types::extent::{ExtentIn, LevelIn, ListIn, ValueIn}; use core_types::extent::{ExtentIn, LevelIn, ListIn, ValueIn};
use core_types::gpoll::{ErrorKind, Extent, GPoll, GraphError, Interrupt, Level}; use core_types::gpoll::{ErrorKind, Extent, GPoll, GraphError, Interrupt, Level};
use core_types::node::Lane; use core_types::node::Lane;
@@ -63,12 +63,12 @@ fn repeat_opacity(ctx: impl Ctx + ExtractIndex, element: f64, count: u32) -> ILi
} }
#[node_macro::node(category("Test"))] #[node_macro::node(category("Test"))]
fn sum(_: impl Ctx + ExtractIndex + InjectIndex + Copy, items: IList<f64>) -> f64 { fn sum(_: impl Ctx, items: IList<f64>) -> f64 {
items.into_iter().sum() items.into_iter().sum()
} }
#[node_macro::node(category("Test"))] #[node_macro::node(category("Test"))]
fn sum_nested(_: impl Ctx + ExtractIndex + InjectIndex + Copy, items: IList<IList<f64>>) -> f64 { fn sum_nested(_: impl Ctx, items: IList<IList<f64>>) -> f64 {
items.into_iter().sum() items.into_iter().sum()
} }
@@ -196,7 +196,7 @@ fn resolve_index(index: f64, total: u64) -> Option<u64> {
/// the omitted index read one lane further. An out-of-range index passes the /// the omitted index read one lane further. An out-of-range index passes the
/// level through unchanged. /// level through unchanged.
#[node_macro::node(category("Test"), extent(omit_element_extent))] #[node_macro::node(category("Test"), extent(omit_element_extent))]
fn omit_element<T>(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, content: impl Node<Context<'_>, Output = T>, index: f64) -> Result<T, Interrupt> { fn omit_element<T>(ctx: impl Ctx + ModifyIndex + Copy, content: impl Node<Context<'_>, Output = T>, index: f64) -> Result<T, Interrupt> {
let total = match content.extent(ctx, Level::Total) { let total = match content.extent(ctx, Level::Total) {
GPoll::Final(Extent::Exactly(count)) => count as u64, GPoll::Final(Extent::Exactly(count)) => count as u64,
GPoll::Pending => return Err(Interrupt::Pending), GPoll::Pending => return Err(Interrupt::Pending),
@@ -225,7 +225,7 @@ fn omit_element_extent(content: ExtentIn<'_>, index: ValueIn<'_, f64>, level: Le
/// Rank-model Index Elements: a one-lane level holding the item at the index /// Rank-model Index Elements: a one-lane level holding the item at the index
/// with its attributes, or an empty level when the index is out of range. /// with its attributes, or an empty level when the index is out of range.
#[node_macro::node(category("Test"), extent(index_elements_extent))] #[node_macro::node(category("Test"), extent(index_elements_extent))]
fn index_elements<T>(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, content: impl Node<Context<'_>, Output = T>, index: f64) -> Result<T, Interrupt> { fn index_elements<T>(ctx: impl Ctx + ModifyIndex + Copy, content: impl Node<Context<'_>, Output = T>, index: f64) -> Result<T, Interrupt> {
let total = match content.extent(ctx, Level::Total) { let total = match content.extent(ctx, Level::Total) {
GPoll::Final(Extent::Exactly(count)) => count as u64, GPoll::Final(Extent::Exactly(count)) => count as u64,
GPoll::Pending => return Err(Interrupt::Pending), GPoll::Pending => return Err(Interrupt::Pending),
+2 -2
View File
@@ -2,7 +2,7 @@ use core_types::attribute::{Attr, Background, Clip, Dimensions, Location};
use core_types::extent::{ExtentIn, LevelIn, ValueIn}; use core_types::extent::{ExtentIn, LevelIn, ValueIn};
use core_types::gpoll::{Extent, GPoll, Interrupt}; use core_types::gpoll::{Extent, GPoll, Interrupt};
use core_types::transform::TransformMut; use core_types::transform::TransformMut;
use core_types::{Color, Ctx, DeriveCtx, ExtractIndex, InjectIndex, ModifyFootprint}; use core_types::{Color, Ctx, DeriveCtx, ModifyFootprint};
use glam::DVec2; use glam::DVec2;
use graphic_types::Artboard; use graphic_types::Artboard;
use graphic_types::graphic::Graphic; use graphic_types::graphic::Graphic;
@@ -22,7 +22,7 @@ fn translate_footprint_extent(content: ExtentIn<'_>, _offset: ValueIn<'_, DVec2>
/// Constructs an artboard element with the given content and metadata stored as attributes. /// Constructs an artboard element with the given content and metadata stored as attributes.
#[node_macro::node(category(""))] #[node_macro::node(category(""))]
pub fn create_artboard( pub fn create_artboard(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
/// Graphics to include within the artboard. /// Graphics to include within the artboard.
content: IList<Graphic>, content: IList<Graphic>,
/// Coordinate of the top-left corner of the artboard within the document. /// Coordinate of the top-left corner of the artboard within the document.
+9 -9
View File
@@ -5,7 +5,7 @@ use core_types::gpoll::{Extent, GPoll, GraphError, Interrupt, Level};
use core_types::list::List; use core_types::list::List;
use core_types::registry::types::{Angle, SignedInteger}; use core_types::registry::types::{Angle, SignedInteger};
use core_types::uuid::NodeId; use core_types::uuid::NodeId;
use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM, CacheHash, Color, Ctx, DeriveCtx, ExtractIndex, InjectIndex}; use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM, CacheHash, Color, Ctx, DeriveCtx, ExtractIndex, InjectIndex, ModifyIndex};
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
use graphic_types::graphic::{Graphic, IntoGraphicList}; use graphic_types::graphic::{Graphic, IntoGraphicList};
use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, Artboard, Vector}; use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, Artboard, Vector};
@@ -27,7 +27,7 @@ fn resolve_index(index: f64, total: u64) -> Option<u64> {
/// attributes, or an empty level when the index is out of range. /// attributes, or an empty level when the index is out of range.
#[node_macro::node(category("General"), extent(index_elements_extent))] #[node_macro::node(category("General"), extent(index_elements_extent))]
pub fn index_elements<T>( pub fn index_elements<T>(
ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, ctx: impl Ctx + ModifyIndex + Copy,
/// The list of data. /// The list of data.
list: impl Node<Context<'_>, Output = T>, list: impl Node<Context<'_>, Output = T>,
/// The index of the item to retrieve, starting from 0 for the first item. Negative indices count backwards from the end of the list, starting from -1 for the last item. /// The index of the item to retrieve, starting from 0 for the first item. Negative indices count backwards from the end of the list, starting from -1 for the last item.
@@ -60,7 +60,7 @@ fn index_elements_extent(list: ExtentIn<'_>, index: ValueIn<'_, f64>, level: Lev
/// If no value exists at that index, the list is returned unchanged. /// If no value exists at that index, the list is returned unchanged.
#[node_macro::node(category("General"), extent(omit_element_extent))] #[node_macro::node(category("General"), extent(omit_element_extent))]
pub fn omit_element<T>( pub fn omit_element<T>(
ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, ctx: impl Ctx + ModifyIndex + Copy,
/// The list of data. /// The list of data.
list: impl Node<Context<'_>, Output = T>, list: impl Node<Context<'_>, Output = T>,
/// The index of the item to remove, starting from 0 for the first item. Negative indices count backwards from the end of the list, starting from -1 for the last item. /// The index of the item to remove, starting from 0 for the first item. Negative indices count backwards from the end of the list, starting from -1 for the last item.
@@ -96,7 +96,7 @@ fn omit_element_extent(list: ExtentIn<'_>, index: ValueIn<'_, f64>, level: Level
/// If no value exists at that index, the element type's default is returned. /// If no value exists at that index, the element type's default is returned.
#[node_macro::node(category("General"))] #[node_macro::node(category("General"))]
pub fn extract_element<T: Clone + Default + Send + Sync + CacheHash + 'static>( pub fn extract_element<T: Clone + Default + Send + Sync + CacheHash + 'static>(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
/// The `List` of data to extract from. /// The `List` of data to extract from.
#[implementations(String, f64, NodeId, Color, GradientStops, Vector, Raster<CPU>, Graphic, Artboard)] #[implementations(String, f64, NodeId, Color, GradientStops, Vector, Raster<CPU>, Graphic, Artboard)]
list: IList<T>, list: IList<T>,
@@ -455,7 +455,7 @@ pub fn legacy_layer_extend<T: Send + Clone>(
/// The inverse of this node is 'Flatten Graphic'. /// The inverse of this node is 'Flatten Graphic'.
#[node_macro::node(category("General"), extent(wrap_graphic_extent))] #[node_macro::node(category("General"), extent(wrap_graphic_extent))]
pub fn wrap_graphic<T: Clone + Send + Sync + core_types::CacheHash + 'static>( pub fn wrap_graphic<T: Clone + Send + Sync + core_types::CacheHash + 'static>(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
#[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] content: IList<T>, #[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] content: IList<T>,
) -> Result<IList<Graphic>, Interrupt> { ) -> Result<IList<Graphic>, Interrupt> {
// SAFETY: a materialized input's frames are arena-resident. // SAFETY: a materialized input's frames are arena-resident.
@@ -525,7 +525,7 @@ pub fn to_graphic_element<T: Into<Graphic> + Clone + Send + Sync + core_types::C
/// graphic identifier. /// graphic identifier.
#[node_macro::node(category(""), extent(wrap_graphic_extent))] #[node_macro::node(category(""), extent(wrap_graphic_extent))]
pub fn to_graphic_typed<T: Clone + Send + Sync + core_types::CacheHash + 'static>( pub fn to_graphic_typed<T: Clone + Send + Sync + core_types::CacheHash + 'static>(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
#[implementations(Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] content: IList<T>, #[implementations(Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] content: IList<T>,
) -> Result<IList<Graphic>, Interrupt> { ) -> Result<IList<Graphic>, Interrupt> {
// SAFETY: a materialized input's frames are arena-resident. // SAFETY: a materialized input's frames are arena-resident.
@@ -539,7 +539,7 @@ pub fn to_graphic_typed<T: Clone + Send + Sync + core_types::CacheHash + 'static
/// An unconnected content input carries the unit, which renders as nothing like /// An unconnected content input carries the unit, which renders as nothing like
/// the pre-flip empty list. Registered under the to graphic identifier. /// the pre-flip empty list. Registered under the to graphic identifier.
#[node_macro::node(category(""), extent(to_graphic_unit_extent))] #[node_macro::node(category(""), extent(to_graphic_unit_extent))]
pub fn to_graphic_unit(_: impl Ctx + ExtractIndex + InjectIndex + Copy, _content: ()) -> Result<IList<Graphic>, Interrupt> { pub fn to_graphic_unit(_: impl Ctx, _content: ()) -> Result<IList<Graphic>, Interrupt> {
Err(core_types::gpoll::GraphError::past_end().into()) Err(core_types::gpoll::GraphError::past_end().into())
} }
@@ -553,7 +553,7 @@ fn to_graphic_unit_extent(_content: core_types::extent::ValueIn<'_, ()>, _level:
/// the last legacy consumer. /// the last legacy consumer.
#[node_macro::node(category(""))] #[node_macro::node(category(""))]
pub fn level_to_list<T: Clone + Send + Sync + CacheHash + 'static>( pub fn level_to_list<T: Clone + Send + Sync + CacheHash + 'static>(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
#[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] value: IList<T>, #[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] value: IList<T>,
_converter: (), _converter: (),
) -> List<T> { ) -> List<T> {
@@ -650,7 +650,7 @@ pub fn flatten_gradient<T: IntoGraphicList>(_: impl Ctx, #[implementations(List<
/// Constructs a gradient from a `Color[]`, where the colors are evenly distributed as gradient stops across the range from 0 to 1. /// Constructs a gradient from a `Color[]`, where the colors are evenly distributed as gradient stops across the range from 0 to 1.
#[node_macro::node(category("Color"))] #[node_macro::node(category("Color"))]
fn colors_to_gradient(_: impl Ctx + ExtractIndex + InjectIndex + Copy, colors: IList<Color>) -> GradientStops { fn colors_to_gradient(_: impl Ctx, colors: IList<Color>) -> GradientStops {
let stop = |position: f64, color: Color| GradientStop { position, midpoint: 0.5, color }; let stop = |position: f64, color: Color| GradientStop { position, midpoint: 0.5, color };
match colors.len() { match colors.len() {
0 => GradientStops::new(vec![stop(0., Color::BLACK), stop(1., Color::BLACK)]), 0 => GradientStops::new(vec![stop(0., Color::BLACK), stop(1., Color::BLACK)]),
+2 -2
View File
@@ -115,7 +115,7 @@ fn flatten_extent(content: ListIn<'_, Graphic>, fully_flatten: ValueIn<'_, bool>
/// Rank-model Wrap: the content level as one group element on a one-lane /// Rank-model Wrap: the content level as one group element on a one-lane
/// level, the inverse of flatten's one-level descent. /// level, the inverse of flatten's one-level descent.
#[node_macro::node(category("Test"), extent(wrap_extent))] #[node_macro::node(category("Test"), extent(wrap_extent))]
fn wrap(_: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<Graphic>) -> Result<IList<Graphic>, Interrupt> { fn wrap(_: impl Ctx, content: IList<Graphic>) -> Result<IList<Graphic>, Interrupt> {
// SAFETY: a materialized input's frames are arena-resident. // SAFETY: a materialized input's frames are arena-resident.
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) }; let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
Ok(Graphic::Group(core_types::record::Group { Ok(Graphic::Group(core_types::record::Group {
@@ -132,7 +132,7 @@ fn wrap_extent(_content: ListIn<'_, Graphic>, _level: LevelIn) -> GPoll<Extent>
/// Rank-model colors-to-gradient: the color level folds into one gradient /// Rank-model colors-to-gradient: the color level folds into one gradient
/// with evenly spaced stops. /// with evenly spaced stops.
#[node_macro::node(category("Test"))] #[node_macro::node(category("Test"))]
fn to_gradient(_: impl Ctx + ExtractIndex + InjectIndex + Copy, colors: IList<Color>) -> GradientStops { fn to_gradient(_: impl Ctx, colors: IList<Color>) -> GradientStops {
let stop = |position: f64, color: Color| GradientStop { position, midpoint: 0.5, color }; let stop = |position: f64, color: Color| GradientStop { position, midpoint: 0.5, color };
match colors.len() { match colors.len() {
0 => GradientStops::new(vec![stop(0., Color::BLACK), stop(1., Color::BLACK)]), 0 => GradientStops::new(vec![stop(0., Color::BLACK), stop(1., Color::BLACK)]),
@@ -14,7 +14,9 @@ use core_types::runtime::SourceFuture;
use core_types::transform::Footprint; use core_types::transform::Footprint;
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use core_types::{ATTR_TRANSFORM, WasmNotSend}; use core_types::{ATTR_TRANSFORM, WasmNotSend};
use core_types::{Color, Ctx, ExtractIndex, InjectIndex}; use core_types::{Color, Ctx};
#[cfg(target_family = "wasm")]
use graphic_types::ATTR_EDITOR_MERGED_LAYERS;
pub use graph_craft::application_io::resource::{Resource, ResourceHash}; pub use graph_craft::application_io::resource::{Resource, ResourceHash};
pub use graph_craft::application_io::*; pub use graph_craft::application_io::*;
pub use graph_craft::document::value::RenderOutputType; pub use graph_craft::document::value::RenderOutputType;
@@ -128,7 +130,7 @@ fn string_to_bytes(_: impl Ctx, string: String) -> Arc<[u8]> {
/// Converts extracted raw RGBA pixel data from an input image. Each pixel becomes 4 sequential bytes. Useful for transmission over HTTP or writing to files. /// Converts extracted raw RGBA pixel data from an input image. Each pixel becomes 4 sequential bytes. Useful for transmission over HTTP or writing to files.
#[node_macro::node(category("Web Request"), name("Image to Bytes"))] #[node_macro::node(category("Web Request"), name("Image to Bytes"))]
fn image_to_bytes(_: impl Ctx + ExtractIndex + InjectIndex + Copy, image: IList<Raster<CPU>>) -> Arc<[u8]> { fn image_to_bytes(_: impl Ctx, image: IList<Raster<CPU>>) -> Arc<[u8]> {
if image.is_empty() { if image.is_empty() {
return Arc::from(Vec::new()); return Arc::from(Vec::new());
} }
+2 -2
View File
@@ -1,7 +1,7 @@
//! Not immediately shader compatible due to needing [`GradientStops`] as a param, which needs [`Vec`] //! Not immediately shader compatible due to needing [`GradientStops`] as a param, which needs [`Vec`]
use crate::adjust::Adjust; use crate::adjust::Adjust;
use core_types::{Color, Ctx, ExtractIndex, InjectIndex}; use core_types::{Color, Ctx};
use raster_types::{CPU, Raster}; use raster_types::{CPU, Raster};
use vector_types::GradientStops; use vector_types::GradientStops;
@@ -10,7 +10,7 @@ use vector_types::GradientStops;
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Gradient%20settings%20(Photoshop%206.0) // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Gradient%20settings%20(Photoshop%206.0)
#[node_macro::node(category("Raster: Adjustment"))] #[node_macro::node(category("Raster: Adjustment"))]
fn gradient_map<T: Adjust<Color> + Clone + Send + Sync + core_types::CacheHash + 'static>( fn gradient_map<T: Adjust<Color> + Clone + Send + Sync + core_types::CacheHash + 'static>(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
#[implementations( #[implementations(
Raster<CPU>, Raster<CPU>,
Color, Color,
+2 -2
View File
@@ -229,7 +229,7 @@ fn combine_channels_extent(
#[node_macro::node(category("Raster"))] #[node_macro::node(category("Raster"))]
pub fn mask( pub fn mask(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
/// The image to be masked. /// The image to be masked.
(mut image, lane_transform): (Raster<CPU>, Attr<TransformAttr>), (mut image, lane_transform): (Raster<CPU>, Attr<TransformAttr>),
/// The stencil to be used for masking. /// The stencil to be used for masking.
@@ -331,7 +331,7 @@ pub fn empty_image_core(transform: DAffine2, color: Color) -> Raster<CPU> {
} }
#[node_macro::node(category("Debug"))] #[node_macro::node(category("Debug"))]
pub fn empty_image(_: impl Ctx + ExtractIndex + InjectIndex + Copy, transform: DAffine2, color: IList<Color>) -> (Raster<CPU>, Attr<TransformAttr>) { pub fn empty_image(_: impl Ctx, transform: DAffine2, color: IList<Color>) -> (Raster<CPU>, Attr<TransformAttr>) {
let color = match color.len() { let color = match color.len() {
0 => Color::WHITE, 0 => Color::WHITE,
_ => color.get(0), _ => color.get(0),
@@ -4,7 +4,7 @@ use core_types::color::Color;
use core_types::extent::{ExtentIn, LevelIn, ValueIn}; use core_types::extent::{ExtentIn, LevelIn, ValueIn};
use core_types::gpoll::{Extent, GPoll, Interrupt}; use core_types::gpoll::{Extent, GPoll, Interrupt};
use core_types::transform::{ApplyTransform, ScaleType, Transform}; use core_types::transform::{ApplyTransform, ScaleType, Transform};
use core_types::{CacheHash, Context, Ctx, DeriveCtx, ExtractIndex, InjectFootprint, InjectIndex, ModifyFootprint}; use core_types::{CacheHash, Context, Ctx, DeriveCtx, InjectFootprint, ModifyFootprint};
use glam::{DAffine2, DMat2, DVec2}; use glam::{DAffine2, DMat2, DVec2};
use graphic_types::Graphic; use graphic_types::Graphic;
use graphic_types::Vector; use graphic_types::Vector;
@@ -98,7 +98,7 @@ fn replace_transform<T>(_: impl Ctx + InjectFootprint, (element, _content_transf
/// Obtains the transform of the first lane of the input wire, if present. /// Obtains the transform of the first lane of the input wire, if present.
#[node_macro::node(category("Math: Transform"), path(core_types::vector))] #[node_macro::node(category("Math: Transform"), path(core_types::vector))]
fn extract_transform<T: Clone + Send + Sync + CacheHash + 'static>( fn extract_transform<T: Clone + Send + Sync + CacheHash + 'static>(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
#[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops)] content: IList<T>, #[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops)] content: IList<T>,
) -> DAffine2 { ) -> DAffine2 {
match content.len() { match content.len() {
@@ -1,5 +1,5 @@
use core_types::registry::types::{Angle, PixelLength, PixelSize}; use core_types::registry::types::{Angle, PixelLength, PixelSize};
use core_types::{CacheHash, Ctx, ExtractIndex, InjectIndex}; use core_types::{CacheHash, Ctx};
use dyn_any::DynAny; use dyn_any::DynAny;
use glam::DVec2; use glam::DVec2;
use graphic_types::Vector; use graphic_types::Vector;
@@ -135,7 +135,7 @@ fn ellipse(
/// Generates a rectangle shape with the chosen width and height. It may also have rounded corners if desired. /// Generates a rectangle shape with the chosen width and height. It may also have rounded corners if desired.
#[node_macro::node(category("Vector: Shape"), properties("rectangle_properties"))] #[node_macro::node(category("Vector: Shape"), properties("rectangle_properties"))]
fn rectangle( fn rectangle(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
_primary: (), _primary: (),
#[unit(" px")] #[unit(" px")]
#[default(100)] #[default(100)]
+12 -12
View File
@@ -924,7 +924,7 @@ fn extrude(_: impl Ctx, mut source: Vector, direction: DVec2, joining_algorithm:
} }
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector))] #[node_macro::node(category("Vector: Modifier"), path(core_types::vector))]
fn box_warp(_: impl Ctx + ExtractIndex + InjectIndex + Copy, (vector, transform): (Vector, Attr<TransformAttr>), #[expose] rectangle: IList<Vector>) -> (Vector, Attr<TransformAttr>) { fn box_warp(_: impl Ctx, (vector, transform): (Vector, Attr<TransformAttr>), #[expose] rectangle: IList<Vector>) -> (Vector, Attr<TransformAttr>) {
if rectangle.is_empty() { if rectangle.is_empty() {
return (vector, Attr(*transform)); return (vector, Attr(*transform));
} }
@@ -1283,7 +1283,7 @@ fn bounding_box(_: impl Ctx, vector: Vector) -> Vector {
} }
#[node_macro::node(category("Vector: Measure"), path(core_types::vector))] #[node_macro::node(category("Vector: Measure"), path(core_types::vector))]
fn dimensions(_: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<Vector>) -> DVec2 { fn dimensions(_: impl Ctx, content: IList<Vector>) -> DVec2 {
(0..content.len()) (0..content.len())
.filter_map(|index| content.element_ref(index).bounding_box_with_transform(content.lane(index).attr::<TransformAttr>())) .filter_map(|index| content.element_ref(index).bounding_box_with_transform(content.lane(index).attr::<TransformAttr>()))
.reduce(|[acc_top_left, acc_bottom_right], [top_left, bottom_right]| [acc_top_left.min(top_left), acc_bottom_right.max(bottom_right)]) .reduce(|[acc_top_left, acc_bottom_right], [top_left, bottom_right]| [acc_top_left.min(top_left), acc_bottom_right.max(bottom_right)])
@@ -1704,7 +1704,7 @@ fn separate_subpaths_extent(content: ListIn<'_, Vector>, level: LevelIn) -> GPol
/// Determines if the subpath at the given index (across all vector element subpaths) is closed, meaning its ends are connected together forming a loop. /// Determines if the subpath at the given index (across all vector element subpaths) is closed, meaning its ends are connected together forming a loop.
#[node_macro::node(name("Path is Closed"), category("Vector: Measure"), path(core_types::vector))] #[node_macro::node(name("Path is Closed"), category("Vector: Measure"), path(core_types::vector))]
fn path_is_closed( fn path_is_closed(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
/// The vector content whose subpaths are inspected. /// The vector content whose subpaths are inspected.
content: IList<Vector>, content: IList<Vector>,
/// The index of the subpath to check, counting across subpaths in all vector elements. /// The index of the subpath to check, counting across subpaths in all vector elements.
@@ -2274,7 +2274,7 @@ fn cut_segments(_: impl Ctx, mut content: Vector) -> Vector {
/// If multiple subpaths make up the path, the whole number part of the progression value selects the subpath and the decimal part determines the position along it. /// If multiple subpaths make up the path, the whole number part of the progression value selects the subpath and the decimal part determines the position along it.
#[node_macro::node(name("Position on Path"), category("Vector: Measure"), path(graphene_core::vector))] #[node_macro::node(name("Position on Path"), category("Vector: Measure"), path(graphene_core::vector))]
fn position_on_path( fn position_on_path(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
/// The path to traverse. /// The path to traverse.
content: IList<Vector>, content: IList<Vector>,
/// The factor from the start to the end of the path, 0–1 for one subpath, 1–2 for a second subpath, and so on. /// The factor from the start to the end of the path, 0–1 for one subpath, 1–2 for a second subpath, and so on.
@@ -2312,7 +2312,7 @@ fn position_on_path(
/// If multiple subpaths make up the path, the whole number part of the progression value selects the subpath and the decimal part determines the position along it. /// If multiple subpaths make up the path, the whole number part of the progression value selects the subpath and the decimal part determines the position along it.
#[node_macro::node(name("Tangent on Path"), category("Vector: Measure"), path(graphene_core::vector))] #[node_macro::node(name("Tangent on Path"), category("Vector: Measure"), path(graphene_core::vector))]
fn tangent_on_path( fn tangent_on_path(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
/// The path to traverse. /// The path to traverse.
content: IList<Vector>, content: IList<Vector>,
/// The factor from the start to the end of the path, 0–1 for one subpath, 1–2 for a second subpath, and so on. /// The factor from the start to the end of the path, 0–1 for one subpath, 1–2 for a second subpath, and so on.
@@ -3584,7 +3584,7 @@ fn close_path(_: impl Ctx, mut source: Vector) -> Vector {
} }
#[node_macro::node(category("Vector: Measure"), path(core_types::vector))] #[node_macro::node(category("Vector: Measure"), path(core_types::vector))]
fn point_inside(_: impl Ctx + ExtractIndex + InjectIndex + Copy, source: IList<Vector>, point: DVec2) -> bool { fn point_inside(_: impl Ctx, source: IList<Vector>, point: DVec2) -> bool {
(0..source.len()).any(|index| { (0..source.len()).any(|index| {
let transform: DAffine2 = source.lane(index).attr::<TransformAttr>(); let transform: DAffine2 = source.lane(index).attr::<TransformAttr>();
source.element_ref(index).check_point_inside_shape(transform, point) source.element_ref(index).check_point_inside_shape(transform, point)
@@ -3595,14 +3595,14 @@ fn point_inside(_: impl Ctx + ExtractIndex + InjectIndex + Copy, source: IList<V
// TODO: (Currently automatic type conversion only works for concrete types, via the Graphene preprocessor and not the full Graphene type system.) // TODO: (Currently automatic type conversion only works for concrete types, via the Graphene preprocessor and not the full Graphene type system.)
#[node_macro::node(category("General"), path(graphene_core::vector))] #[node_macro::node(category("General"), path(graphene_core::vector))]
fn count_elements<T: Clone + Send + Sync + CacheHash + 'static>( fn count_elements<T: Clone + Send + Sync + CacheHash + 'static>(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
#[implementations(Graphic, Artboard, Vector, Raster<CPU>, Color, GradientStops, String)] content: IList<T>, #[implementations(Graphic, Artboard, Vector, Raster<CPU>, Color, GradientStops, String)] content: IList<T>,
) -> f64 { ) -> f64 {
content.len() as f64 content.len() as f64
} }
#[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))]
fn count_points(_: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<Vector>) -> f64 { fn count_points(_: impl Ctx, content: IList<Vector>) -> f64 {
(0..content.len()).map(|index| content.element_ref(index).point_domain.positions().len() as f64).sum() (0..content.len()).map(|index| content.element_ref(index).point_domain.positions().len() as f64).sum()
} }
@@ -3610,7 +3610,7 @@ fn count_points(_: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<
/// If no value exists at that index, the position (0, 0) is returned. /// If no value exists at that index, the position (0, 0) is returned.
#[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))]
fn index_points( fn index_points(
_: impl Ctx + ExtractIndex + InjectIndex + Copy, _: impl Ctx,
/// The vector element or elements containing the anchor points to be retrieved. /// The vector element or elements containing the anchor points to be retrieved.
content: IList<Vector>, content: IList<Vector>,
/// The index of the points to retrieve, starting from 0 for the first point. Negative indices count backwards from the end, starting from -1 for the last item. /// The index of the points to retrieve, starting from 0 for the first point. Negative indices count backwards from the end, starting from -1 for the last item.
@@ -3644,7 +3644,7 @@ fn index_points(
} }
#[node_macro::node(category("Vector: Measure"), path(core_types::vector))] #[node_macro::node(category("Vector: Measure"), path(core_types::vector))]
fn path_length(_: impl Ctx + ExtractIndex + InjectIndex + Copy, source: IList<Vector>) -> f64 { fn path_length(_: impl Ctx, source: IList<Vector>) -> f64 {
(0..source.len()) (0..source.len())
.map(|index| { .map(|index| {
let transform: DAffine2 = source.lane(index).attr::<TransformAttr>(); let transform: DAffine2 = source.lane(index).attr::<TransformAttr>();
@@ -3664,7 +3664,7 @@ fn path_length(_: impl Ctx + ExtractIndex + InjectIndex + Copy, source: IList<Ve
#[node_macro::node(category("Vector: Measure"), path(core_types::vector))] #[node_macro::node(category("Vector: Measure"), path(core_types::vector))]
// The legacy form reset the footprint before evaluating; the nullification // The legacy form reset the footprint before evaluating; the nullification
// pass now strips it upstream since this node declares no footprint feature. // pass now strips it upstream since this node declares no footprint feature.
fn area(_: impl Ctx + ExtractIndex + InjectIndex + Copy, vector: IList<Vector>) -> Result<f64, Interrupt> { fn area(_: impl Ctx, vector: IList<Vector>) -> Result<f64, Interrupt> {
Ok((0..vector.len()) Ok((0..vector.len())
.map(|index| { .map(|index| {
let transform: DAffine2 = vector.lane(index).attr::<TransformAttr>(); let transform: DAffine2 = vector.lane(index).attr::<TransformAttr>();
@@ -3676,7 +3676,7 @@ fn area(_: impl Ctx + ExtractIndex + InjectIndex + Copy, vector: IList<Vector>)
#[node_macro::node(category("Vector: Measure"), path(core_types::vector))] #[node_macro::node(category("Vector: Measure"), path(core_types::vector))]
// The footprint reset moved to the nullification pass, as in `area`. // The footprint reset moved to the nullification pass, as in `area`.
fn centroid(_: impl Ctx + ExtractIndex + InjectIndex + Copy, vector: IList<Vector>, centroid_type: CentroidType) -> Result<DVec2, Interrupt> { fn centroid(_: impl Ctx, vector: IList<Vector>, centroid_type: CentroidType) -> Result<DVec2, Interrupt> {
if vector.is_empty() { if vector.is_empty() {
return Ok(DVec2::ZERO); return Ok(DVec2::ZERO);
} }