Skip to content

Commit 6d669ad

Browse files
authored
Add documentation to many nodes (#3338)
1 parent 055d543 commit 6d669ad

13 files changed

Lines changed: 146 additions & 71 deletions

node-graph/gbrush/src/brush.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,23 @@ pub fn blend_with_mode(background: TableRow<Raster<CPU>>, foreground: TableRow<R
178178
}
179179
}
180180

181+
/// Generates the brush strokes painted with the Brush tool as a raster image.
182+
/// If an input image is supplied, strokes are drawn on top of it, expanding bounds as needed.
181183
#[node_macro::node(category("Raster"))]
182-
async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes: Vec<BrushStroke>, cache: BrushCache) -> Table<Raster<CPU>> {
183-
if image_frame_table.is_empty() {
184-
image_frame_table.push(TableRow::default());
184+
async fn brush(
185+
_: impl Ctx,
186+
/// Optional raster content that may be drawn onto.
187+
mut image: Table<Raster<CPU>>,
188+
/// The list of brush stroke paths drawn by the Brush tool, with each including both its coordinates and styles.
189+
strokes: Vec<BrushStroke>,
190+
/// Internal cache data used to accelerate rendering of the brush content.
191+
cache: BrushCache,
192+
) -> Table<Raster<CPU>> {
193+
if image.is_empty() {
194+
image.push(TableRow::default());
185195
}
186196
// TODO: Find a way to handle more than one row
187-
let table_row = image_frame_table.iter().next().expect("Expected the one row we just pushed").into_cloned();
197+
let table_row = image.iter().next().expect("Expected the one row we just pushed").into_cloned();
188198

189199
let bounds = Table::new_from_row(table_row.clone()).bounding_box(DAffine2::IDENTITY, false);
190200
let [start, end] = if let RenderBoundingBox::Rectangle(rect) = bounds { rect } else { [DVec2::ZERO, DVec2::ZERO] };
@@ -296,13 +306,13 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
296306
actual_image = blend_image_closure(erase_restore_mask, actual_image, |a, b| blend_params.eval((a, b)));
297307
}
298308

299-
let first_row = image_frame_table.iter_mut().next().unwrap();
309+
let first_row = image.iter_mut().next().unwrap();
300310
*first_row.element = actual_image.element;
301311
*first_row.transform = actual_image.transform;
302312
*first_row.alpha_blending = actual_image.alpha_blending;
303313
*first_row.source_node_id = actual_image.source_node_id;
304314

305-
image_frame_table
315+
image
306316
}
307317

308318
pub fn blend_image_closure(foreground: TableRow<Raster<CPU>>, mut background: TableRow<Raster<CPU>>, map_fn: impl Fn(Color, Color) -> Color) -> TableRow<Raster<CPU>> {

node-graph/gcore/src/animation.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@ pub enum AnimationTimeMode {
2222

2323
/// Produces a chosen representation of the current real time and date (in UTC) based on the system clock.
2424
#[node_macro::node(category("Animation"))]
25-
fn real_time(ctx: impl Ctx + ExtractRealTime, _primary: (), mode: RealTimeMode) -> f64 {
25+
fn real_time(
26+
ctx: impl Ctx + ExtractRealTime,
27+
_primary: (),
28+
/// The time and date component to be produced as a number.
29+
component: RealTimeMode,
30+
) -> f64 {
2631
let real_time = ctx.try_real_time().unwrap_or_default();
2732
// TODO: Implement proper conversion using and existing time implementation
28-
match mode {
33+
match component {
2934
RealTimeMode::Utc => real_time,
30-
RealTimeMode::Year => (real_time / DAY / 365.25).floor() + 1970.,
31-
RealTimeMode::Hour => (real_time / 1000. / 3600.).floor() % 24., // TODO: Factor in a chosen timezone
32-
RealTimeMode::Minute => (real_time / 1000. / 60.).floor() % 60., // TODO: Factor in a chosen timezone
35+
RealTimeMode::Year => (real_time / DAY / 365.25).floor() + 1970., // TODO: Factor in a chosen timezone
36+
RealTimeMode::Hour => (real_time / 1000. / 3600.).floor() % 24., // TODO: Factor in a chosen timezone
37+
RealTimeMode::Minute => (real_time / 1000. / 60.).floor() % 60., // TODO: Factor in a chosen timezone
3338

3439
RealTimeMode::Second => (real_time / 1000.).floor() % 60.,
3540
RealTimeMode::Millisecond => real_time % 1000.,
@@ -42,8 +47,7 @@ fn animation_time(ctx: impl Ctx + ExtractAnimationTime) -> f64 {
4247
ctx.try_animation_time().unwrap_or_default()
4348
}
4449

45-
// These nodes require more sophisticated algorithms for giving the correct result
46-
50+
// TODO: These nodes require more sophisticated algorithms for giving the correct result
4751
// #[node_macro::node(category("Animation"))]
4852
// fn month(ctx: impl Ctx + ExtractRealTime) -> f64 {
4953
// ((ctx.try_real_time().unwrap_or_default() / DAY / 365.25 % 1.) * 12.).floor()

node-graph/gcore/src/artboard.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Re
114114
#[node_macro::node(category(""))]
115115
async fn create_artboard<T: Into<Table<Graphic>> + 'n>(
116116
ctx: impl ExtractAll + CloneVarArgs + Ctx,
117+
/// Graphics to include within the artboard.
117118
#[implementations(
118119
Context -> Table<Graphic>,
119120
Context -> Table<Vector>,
@@ -124,10 +125,15 @@ async fn create_artboard<T: Into<Table<Graphic>> + 'n>(
124125
Context -> DAffine2,
125126
)]
126127
content: impl Node<Context<'static>, Output = T>,
128+
/// Name of the artboard, shown in parts of the editor.
127129
label: String,
130+
/// Coordinate of the top-left corner of the artboard within the document.
128131
location: DVec2,
132+
/// Width and height of the artboard within the document. Only integers are valid.
129133
dimensions: DVec2,
134+
/// Color of the artboard background. Only positive integers are valid.
130135
background: Table<Color>,
136+
/// Whether to cut off the contained content that extends outside the artboard, or keep it visible.
131137
clip: bool,
132138
) -> Table<Artboard> {
133139
let location = location.as_ivec2();

node-graph/gcore/src/blending_nodes.rs

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -178,61 +178,78 @@ impl SetClip for Table<GradientStops> {
178178
#[node_macro::node(category("Style"))]
179179
fn blend_mode<T: SetBlendMode>(
180180
_: impl Ctx,
181+
/// The layer stack that will be composited when rendering.
181182
#[implementations(
182183
Table<Graphic>,
183184
Table<Vector>,
184185
Table<Raster<CPU>>,
185186
Table<Color>,
186187
Table<GradientStops>,
187188
)]
188-
mut value: T,
189+
mut content: T,
190+
/// The choice of equation that controls how brightness and color blends between overlapping pixels.
189191
blend_mode: BlendMode,
190192
) -> T {
191193
// TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or TableRow<T>) rather than applying to each row in its own table, which produces the undesired result
192-
value.set_blend_mode(blend_mode);
193-
value
194+
content.set_blend_mode(blend_mode);
195+
content
194196
}
195197

196-
/// Modifies the opacity of the input graphics by multiplying the existing opacity by this percentage. This affects the transparency of the content (together with any above which is clipped to it).
198+
/// Modifies the opacity of the input graphics by multiplying the existing opacity by this percentage.
199+
/// This affects the transparency of the content (together with anything above which is clipped to it).
197200
#[node_macro::node(category("Style"))]
198201
fn opacity<T: MultiplyAlpha>(
199202
_: impl Ctx,
203+
/// The layer stack that will be composited when rendering.
200204
#[implementations(
201205
Table<Graphic>,
202206
Table<Vector>,
203207
Table<Raster<CPU>>,
204208
Table<Color>,
205209
Table<GradientStops>,
206210
)]
207-
mut value: T,
208-
#[default(100.)] opacity: Percentage,
211+
mut content: T,
212+
/// How visible the content should be, including any content clipped to it.
213+
/// Ranges from the default of 100% (fully opaque) to 0% (fully transparent).
214+
#[default(100.)]
215+
opacity: Percentage,
209216
) -> T {
210217
// TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or TableRow<T>) rather than applying to each row in its own table, which produces the undesired result
211-
value.multiply_alpha(opacity / 100.);
212-
value
218+
content.multiply_alpha(opacity / 100.);
219+
content
213220
}
214221

215-
/// Sets each of the blending properties at once. The blend mode determines how overlapping content is composited together. The opacity affects the transparency of the content (together with any above which is clipped to it). The fill affects the transparency of the content itself, without affecting that of content clipped to it. The clip property determines whether the content inherits the alpha of the content beneath it.
222+
/// Sets each of the blending properties at once. The blend mode determines how overlapping content is composited together. The opacity affects the transparency of the content (together with anything above which is clipped to it). The fill affects the transparency of the content itself, without affecting that of content clipped to it. The clip property determines whether the content inherits the alpha of the content beneath it.
216223
#[node_macro::node(category("Style"))]
217224
fn blending<T: SetBlendMode + MultiplyAlpha + MultiplyFill + SetClip>(
218225
_: impl Ctx,
226+
/// The layer stack that will be composited when rendering.
219227
#[implementations(
220228
Table<Graphic>,
221229
Table<Vector>,
222230
Table<Raster<CPU>>,
223231
Table<Color>,
224232
Table<GradientStops>,
225233
)]
226-
mut value: T,
234+
mut content: T,
235+
/// The choice of equation that controls how brightness and color blends between overlapping pixels.
227236
blend_mode: BlendMode,
228-
#[default(100.)] opacity: Percentage,
229-
#[default(100.)] fill: Percentage,
230-
#[default(false)] clip: bool,
237+
/// How visible the content should be, including any content clipped to it.
238+
/// Ranges from the default of 100% (fully opaque) to 0% (fully transparent).
239+
#[default(100.)]
240+
opacity: Percentage,
241+
/// How visible the content should be, independent of any content clipped to it.
242+
/// Ranges from 0% (fully transparent) to 100% (fully opaque).
243+
#[default(100.)]
244+
fill: Percentage,
245+
/// Whether the content inherits the alpha of the content beneath it.
246+
#[default(false)]
247+
clip: bool,
231248
) -> T {
232249
// TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or TableRow<T>) rather than applying to each row in its own table, which produces the undesired result
233-
value.set_blend_mode(blend_mode);
234-
value.multiply_alpha(opacity / 100.);
235-
value.multiply_fill(fill / 100.);
236-
value.set_clip(clip);
237-
value
250+
content.set_blend_mode(blend_mode);
251+
content.multiply_alpha(opacity / 100.);
252+
content.multiply_fill(fill / 100.);
253+
content.set_clip(clip);
254+
content
238255
}

node-graph/gcore/src/context_modification.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ use core::f64;
1111
use glam::{DAffine2, DVec2};
1212
use graphene_core_shaders::color::Color;
1313

14-
/// Node for filtering components of the context based on the specified requirements.
14+
/// Filters out what should be unused components of the context based on the specified requirements.
1515
/// This node is inserted by the compiler to "zero out" unused context components.
1616
#[node_macro::node(category("Internal"))]
1717
async fn context_modification<T>(
1818
ctx: impl Ctx + CloneVarArgs + ExtractAll,
19+
/// The data to pass through, evaluated with the stripped down context.
1920
#[implementations(
2021
Context -> (),
2122
Context -> bool,
@@ -42,6 +43,7 @@ async fn context_modification<T>(
4243
Context -> GradientStops,
4344
)]
4445
value: impl Node<Context<'static>, Output = T>,
46+
/// The parts of the context to keep when evaluating the input value. All other parts are nullified.
4547
features_to_keep: ContextFeatures,
4648
) -> T {
4749
let new_context = OwnedContextImpl::from_flags(ctx, features_to_keep);

node-graph/gcore/src/graphic.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,26 @@ impl BoundingBox for Graphic {
260260
}
261261
}
262262

263+
/// Performs internal editor record-keeping that enables tools to target this network's layer.
264+
/// This node associates the ID of the network's parent layer to every element of output data.
265+
/// This technical detail may be ignored by users, and will be phased out in the future.
263266
#[node_macro::node(category(""))]
264267
async fn source_node_id<I: 'n + Send + Clone>(
265268
_: impl Ctx,
266-
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>, Table<Color>, Table<GradientStops>)] content: Table<I>,
269+
#[implementations(
270+
Table<Artboard>,
271+
Table<Graphic>,
272+
Table<Vector>,
273+
Table<Raster<CPU>>,
274+
Table<Raster<GPU>>,
275+
Table<Color>,
276+
Table<GradientStops>,
277+
)]
278+
content: Table<I>,
267279
node_path: Vec<NodeId>,
268280
) -> Table<I> {
269281
// Get the penultimate element of the node path, or None if the path is too short
270-
// This is used to get the ID of the user-facing parent layer-style node (which encapsulates this internal node).
282+
// This is used to get the ID of the user-facing parent layer node (whose network contains this internal node).
271283
let source_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
272284

273285
let mut content = content;
@@ -297,6 +309,8 @@ async fn extend<I: 'n + Send + Clone>(
297309
}
298310

299311
// TODO: Eventually remove this document upgrade code
312+
/// Performs an obsolete function as part of a migration from an older document format.
313+
/// Users are advised to delete this node and replace it with a new one.
300314
#[node_macro::node(category(""))]
301315
async fn legacy_layer_extend<I: 'n + Send + Clone>(
302316
_: impl Ctx,
@@ -318,7 +332,8 @@ async fn legacy_layer_extend<I: 'n + Send + Clone>(
318332
base
319333
}
320334

321-
/// Places a table of graphical content into an element of a new wrapper graphic table.
335+
/// Nests the input graphical content in a wrapper graphic. This essentially "groups" the input.
336+
/// The inverse of this node is 'Flatten Graphic'.
322337
#[node_macro::node(category("General"))]
323338
async fn wrap_graphic<T: Into<Graphic> + 'n>(
324339
_: impl Ctx,
@@ -441,7 +456,7 @@ async fn flatten_vector(_: impl Ctx, content: Table<Graphic>) -> Table<Vector> {
441456
}
442457

443458
/// Returns the value at the specified index in the collection.
444-
/// If that index has no value, the type's default value is returned.
459+
/// If no value exists at that index, the type's default value is returned.
445460
#[node_macro::node(category("General"))]
446461
fn index_elements<T: AtIndex + Clone + Default>(
447462
_: impl Ctx,

node-graph/gcore/src/logic.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::vector::Vector;
99
use crate::{Context, Ctx};
1010
use glam::{DAffine2, DVec2};
1111

12-
/// Type-asserts a value to be a string, so the automatic type conversion system can convert another type to a string.
12+
/// Type-asserts a value to be a string.
1313
#[node_macro::node(category("Debug"))]
1414
fn to_string(_: impl Ctx, value: String) -> String {
1515
value
@@ -69,8 +69,21 @@ fn string_length(_: impl Ctx, string: String) -> f64 {
6969
string.chars().count() as f64
7070
}
7171

72+
/// Splits a string into a list of substrings based on the specified delimeter.
73+
/// For example, the delimeter "," will split "a,b,c" into the strings "a", "b", and "c".
7274
#[node_macro::node(category("Text"))]
73-
fn string_split(_: impl Ctx, string: String, #[default("\\n")] delimeter: String, #[default(true)] delimeter_escaping: bool) -> Vec<String> {
75+
fn string_split(
76+
_: impl Ctx,
77+
/// The string to split into substrings.
78+
string: String,
79+
/// The character(s) that separate the substrings. These are not included in the outputs.
80+
#[default("\\n")]
81+
delimeter: String,
82+
/// Whether to convert escape sequences found in the delimeter into their corresponding characters:
83+
/// "\n" (newline), "\r" (carriage return), "\t" (tab), "\0" (null), and "\\" (backslash)
84+
#[default(true)]
85+
delimeter_escaping: bool,
86+
) -> Vec<String> {
7487
let delimeter = if delimeter_escaping {
7588
delimeter.replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t").replace("\\0", "\0").replace("\\\\", "\\")
7689
} else {
@@ -124,10 +137,5 @@ async fn switch<T, C: Send + 'n + Clone>(
124137
)]
125138
if_false: impl Node<C, Output = T>,
126139
) -> T {
127-
if condition {
128-
// We can't remove these calls because we only want to evaluate the branch that we actually need
129-
if_true.eval(ctx).await
130-
} else {
131-
if_false.eval(ctx).await
132-
}
140+
if condition { if_true.eval(ctx).await } else { if_false.eval(ctx).await }
133141
}

node-graph/gcore/src/memo.rs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,13 @@ use std::ops::Deref;
77
use std::sync::Arc;
88
use std::sync::Mutex;
99

10-
/// Caches the output of a given Node and acts as a proxy
10+
/// Caches the output of a given node called with a specific input.
1111
///
12-
/// ```text
13-
/// ┌───────────────┐ ┌───────────────┐
14-
/// │ │◄───┤ │◄─── EVAL (START)
15-
/// │ CacheNode │ │ F │
16-
/// │ ├───►│ │───► RESULT (END)
17-
/// ┌───────────────┐ ├───────────────┤ └───────────────┘
18-
/// │ │◄───┤ │
19-
/// │ G │ │ Cached Data │
20-
/// │ ├───►│ │
21-
/// └───────────────┘ └───────────────┘
22-
/// ```
12+
/// A cache miss occurs when the Option is None. In this case, the node evaluates the inner node and memoizes (stores) the result.
2313
///
24-
/// The call from `F` directly reaches the `CacheNode` and the `CacheNode` can decide whether to call `G.eval(input_from_f)`
25-
/// in the event of a cache miss or just return the cached data in the event of a cache hit.
14+
/// A cache hit occurs when the Option is Some and has a stored hash matching the hash of the call argument. In this case, the node returns the cached value without re-evaluating the inner node.
15+
///
16+
/// Currently, only one input-output pair is cached. Subsequent calls with different inputs will overwrite the previous cache.
2617
#[derive(Default)]
2718
pub struct MemoNode<T, CachedNode> {
2819
cache: Arc<Mutex<Option<(u64, T)>>>,
@@ -71,9 +62,8 @@ pub mod memo {
7162
}
7263

7364
/// Caches the output of a given Node and acts as a proxy.
74-
/// In contrast to the regular `MemoNode`. This node ignores all input.
75-
/// Using this node might result in the document not updating properly,
76-
/// use with caution.
65+
/// In contrast to the regular `MemoNode`, this variant ignores all input.
66+
/// This node might result in the document not updating properly. Use with caution!
7767
#[derive(Default)]
7868
pub struct ImpureMemoNode<I, T, CachedNode> {
7969
cache: Arc<Mutex<Option<T>>>,
@@ -86,8 +76,8 @@ where
8676
CachedNode: for<'any_input> Node<'any_input, I>,
8777
for<'a> <CachedNode as Node<'a, I>>::Output: Future<Output = T> + WasmNotSend,
8878
{
89-
// TODO: This should return a reference to the cached cached_value
90-
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty accurate xD
79+
// TODO: This should return a reference to the cached cached_value but that requires a lot of lifetime magic
80+
// TODO: (This was suggested by copilot but is pretty accurate xD)
9181
type Output = DynFuture<'i, T>;
9282
fn eval(&'i self, input: I) -> Self::Output {
9383
if let Some(cached_value) = self.cache.lock().as_ref().unwrap().deref() {

node-graph/gcore/src/ops.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use crate::{ExtractFootprint, Node, transform::Footprint};
44
use std::marker::PhantomData;
55

66
// TODO: Rename to "Passthrough"
7-
/// Passes-through the input value without changing it. This is useful for rerouting wires for organization purposes.
7+
/// Passes-through the input value without changing it.
8+
/// This is useful for rerouting wires for organization purposes.
89
#[node_macro::node(skip_impl)]
910
fn identity<'i, T: 'i + Send>(value: T) -> T {
1011
value

0 commit comments

Comments
 (0)