mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
Add documentation to many nodes (#3338)
This commit is contained in:
parent
055d543117
commit
6d669ad734
13 changed files with 146 additions and 71 deletions
|
|
@ -178,13 +178,23 @@ pub fn blend_with_mode(background: TableRow<Raster<CPU>>, foreground: TableRow<R
|
|||
}
|
||||
}
|
||||
|
||||
/// Generates the brush strokes painted with the Brush tool as a raster image.
|
||||
/// If an input image is supplied, strokes are drawn on top of it, expanding bounds as needed.
|
||||
#[node_macro::node(category("Raster"))]
|
||||
async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes: Vec<BrushStroke>, cache: BrushCache) -> Table<Raster<CPU>> {
|
||||
if image_frame_table.is_empty() {
|
||||
image_frame_table.push(TableRow::default());
|
||||
async fn brush(
|
||||
_: impl Ctx,
|
||||
/// Optional raster content that may be drawn onto.
|
||||
mut image: Table<Raster<CPU>>,
|
||||
/// The list of brush stroke paths drawn by the Brush tool, with each including both its coordinates and styles.
|
||||
strokes: Vec<BrushStroke>,
|
||||
/// Internal cache data used to accelerate rendering of the brush content.
|
||||
cache: BrushCache,
|
||||
) -> Table<Raster<CPU>> {
|
||||
if image.is_empty() {
|
||||
image.push(TableRow::default());
|
||||
}
|
||||
// TODO: Find a way to handle more than one row
|
||||
let table_row = image_frame_table.iter().next().expect("Expected the one row we just pushed").into_cloned();
|
||||
let table_row = image.iter().next().expect("Expected the one row we just pushed").into_cloned();
|
||||
|
||||
let bounds = Table::new_from_row(table_row.clone()).bounding_box(DAffine2::IDENTITY, false);
|
||||
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:
|
|||
actual_image = blend_image_closure(erase_restore_mask, actual_image, |a, b| blend_params.eval((a, b)));
|
||||
}
|
||||
|
||||
let first_row = image_frame_table.iter_mut().next().unwrap();
|
||||
let first_row = image.iter_mut().next().unwrap();
|
||||
*first_row.element = actual_image.element;
|
||||
*first_row.transform = actual_image.transform;
|
||||
*first_row.alpha_blending = actual_image.alpha_blending;
|
||||
*first_row.source_node_id = actual_image.source_node_id;
|
||||
|
||||
image_frame_table
|
||||
image
|
||||
}
|
||||
|
||||
pub fn blend_image_closure(foreground: TableRow<Raster<CPU>>, mut background: TableRow<Raster<CPU>>, map_fn: impl Fn(Color, Color) -> Color) -> TableRow<Raster<CPU>> {
|
||||
|
|
|
|||
|
|
@ -22,14 +22,19 @@ pub enum AnimationTimeMode {
|
|||
|
||||
/// Produces a chosen representation of the current real time and date (in UTC) based on the system clock.
|
||||
#[node_macro::node(category("Animation"))]
|
||||
fn real_time(ctx: impl Ctx + ExtractRealTime, _primary: (), mode: RealTimeMode) -> f64 {
|
||||
fn real_time(
|
||||
ctx: impl Ctx + ExtractRealTime,
|
||||
_primary: (),
|
||||
/// The time and date component to be produced as a number.
|
||||
component: RealTimeMode,
|
||||
) -> f64 {
|
||||
let real_time = ctx.try_real_time().unwrap_or_default();
|
||||
// TODO: Implement proper conversion using and existing time implementation
|
||||
match mode {
|
||||
match component {
|
||||
RealTimeMode::Utc => real_time,
|
||||
RealTimeMode::Year => (real_time / DAY / 365.25).floor() + 1970.,
|
||||
RealTimeMode::Hour => (real_time / 1000. / 3600.).floor() % 24., // TODO: Factor in a chosen timezone
|
||||
RealTimeMode::Minute => (real_time / 1000. / 60.).floor() % 60., // TODO: Factor in a chosen timezone
|
||||
RealTimeMode::Year => (real_time / DAY / 365.25).floor() + 1970., // TODO: Factor in a chosen timezone
|
||||
RealTimeMode::Hour => (real_time / 1000. / 3600.).floor() % 24., // TODO: Factor in a chosen timezone
|
||||
RealTimeMode::Minute => (real_time / 1000. / 60.).floor() % 60., // TODO: Factor in a chosen timezone
|
||||
|
||||
RealTimeMode::Second => (real_time / 1000.).floor() % 60.,
|
||||
RealTimeMode::Millisecond => real_time % 1000.,
|
||||
|
|
@ -42,8 +47,7 @@ fn animation_time(ctx: impl Ctx + ExtractAnimationTime) -> f64 {
|
|||
ctx.try_animation_time().unwrap_or_default()
|
||||
}
|
||||
|
||||
// These nodes require more sophisticated algorithms for giving the correct result
|
||||
|
||||
// TODO: These nodes require more sophisticated algorithms for giving the correct result
|
||||
// #[node_macro::node(category("Animation"))]
|
||||
// fn month(ctx: impl Ctx + ExtractRealTime) -> f64 {
|
||||
// ((ctx.try_real_time().unwrap_or_default() / DAY / 365.25 % 1.) * 12.).floor()
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Re
|
|||
#[node_macro::node(category(""))]
|
||||
async fn create_artboard<T: Into<Table<Graphic>> + 'n>(
|
||||
ctx: impl ExtractAll + CloneVarArgs + Ctx,
|
||||
/// Graphics to include within the artboard.
|
||||
#[implementations(
|
||||
Context -> Table<Graphic>,
|
||||
Context -> Table<Vector>,
|
||||
|
|
@ -124,10 +125,15 @@ async fn create_artboard<T: Into<Table<Graphic>> + 'n>(
|
|||
Context -> DAffine2,
|
||||
)]
|
||||
content: impl Node<Context<'static>, Output = T>,
|
||||
/// Name of the artboard, shown in parts of the editor.
|
||||
label: String,
|
||||
/// Coordinate of the top-left corner of the artboard within the document.
|
||||
location: DVec2,
|
||||
/// Width and height of the artboard within the document. Only integers are valid.
|
||||
dimensions: DVec2,
|
||||
/// Color of the artboard background. Only positive integers are valid.
|
||||
background: Table<Color>,
|
||||
/// Whether to cut off the contained content that extends outside the artboard, or keep it visible.
|
||||
clip: bool,
|
||||
) -> Table<Artboard> {
|
||||
let location = location.as_ivec2();
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ impl SetClip for Table<GradientStops> {
|
|||
#[node_macro::node(category("Style"))]
|
||||
fn blend_mode<T: SetBlendMode>(
|
||||
_: impl Ctx,
|
||||
/// The layer stack that will be composited when rendering.
|
||||
#[implementations(
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
|
|
@ -185,18 +186,21 @@ fn blend_mode<T: SetBlendMode>(
|
|||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
)]
|
||||
mut value: T,
|
||||
mut content: T,
|
||||
/// The choice of equation that controls how brightness and color blends between overlapping pixels.
|
||||
blend_mode: BlendMode,
|
||||
) -> T {
|
||||
// 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
|
||||
value.set_blend_mode(blend_mode);
|
||||
value
|
||||
content.set_blend_mode(blend_mode);
|
||||
content
|
||||
}
|
||||
|
||||
/// 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).
|
||||
/// Modifies the opacity of the input graphics by multiplying the existing opacity by this percentage.
|
||||
/// This affects the transparency of the content (together with anything above which is clipped to it).
|
||||
#[node_macro::node(category("Style"))]
|
||||
fn opacity<T: MultiplyAlpha>(
|
||||
_: impl Ctx,
|
||||
/// The layer stack that will be composited when rendering.
|
||||
#[implementations(
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
|
|
@ -204,18 +208,22 @@ fn opacity<T: MultiplyAlpha>(
|
|||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
)]
|
||||
mut value: T,
|
||||
#[default(100.)] opacity: Percentage,
|
||||
mut content: T,
|
||||
/// How visible the content should be, including any content clipped to it.
|
||||
/// Ranges from the default of 100% (fully opaque) to 0% (fully transparent).
|
||||
#[default(100.)]
|
||||
opacity: Percentage,
|
||||
) -> T {
|
||||
// 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
|
||||
value.multiply_alpha(opacity / 100.);
|
||||
value
|
||||
content.multiply_alpha(opacity / 100.);
|
||||
content
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// 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.
|
||||
#[node_macro::node(category("Style"))]
|
||||
fn blending<T: SetBlendMode + MultiplyAlpha + MultiplyFill + SetClip>(
|
||||
_: impl Ctx,
|
||||
/// The layer stack that will be composited when rendering.
|
||||
#[implementations(
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
|
|
@ -223,16 +231,25 @@ fn blending<T: SetBlendMode + MultiplyAlpha + MultiplyFill + SetClip>(
|
|||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
)]
|
||||
mut value: T,
|
||||
mut content: T,
|
||||
/// The choice of equation that controls how brightness and color blends between overlapping pixels.
|
||||
blend_mode: BlendMode,
|
||||
#[default(100.)] opacity: Percentage,
|
||||
#[default(100.)] fill: Percentage,
|
||||
#[default(false)] clip: bool,
|
||||
/// How visible the content should be, including any content clipped to it.
|
||||
/// Ranges from the default of 100% (fully opaque) to 0% (fully transparent).
|
||||
#[default(100.)]
|
||||
opacity: Percentage,
|
||||
/// How visible the content should be, independent of any content clipped to it.
|
||||
/// Ranges from 0% (fully transparent) to 100% (fully opaque).
|
||||
#[default(100.)]
|
||||
fill: Percentage,
|
||||
/// Whether the content inherits the alpha of the content beneath it.
|
||||
#[default(false)]
|
||||
clip: bool,
|
||||
) -> T {
|
||||
// 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
|
||||
value.set_blend_mode(blend_mode);
|
||||
value.multiply_alpha(opacity / 100.);
|
||||
value.multiply_fill(fill / 100.);
|
||||
value.set_clip(clip);
|
||||
value
|
||||
content.set_blend_mode(blend_mode);
|
||||
content.multiply_alpha(opacity / 100.);
|
||||
content.multiply_fill(fill / 100.);
|
||||
content.set_clip(clip);
|
||||
content
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@ use core::f64;
|
|||
use glam::{DAffine2, DVec2};
|
||||
use graphene_core_shaders::color::Color;
|
||||
|
||||
/// Node for filtering components of the context based on the specified requirements.
|
||||
/// Filters out what should be unused components of the context based on the specified requirements.
|
||||
/// This node is inserted by the compiler to "zero out" unused context components.
|
||||
#[node_macro::node(category("Internal"))]
|
||||
async fn context_modification<T>(
|
||||
ctx: impl Ctx + CloneVarArgs + ExtractAll,
|
||||
/// The data to pass through, evaluated with the stripped down context.
|
||||
#[implementations(
|
||||
Context -> (),
|
||||
Context -> bool,
|
||||
|
|
@ -42,6 +43,7 @@ async fn context_modification<T>(
|
|||
Context -> GradientStops,
|
||||
)]
|
||||
value: impl Node<Context<'static>, Output = T>,
|
||||
/// The parts of the context to keep when evaluating the input value. All other parts are nullified.
|
||||
features_to_keep: ContextFeatures,
|
||||
) -> T {
|
||||
let new_context = OwnedContextImpl::from_flags(ctx, features_to_keep);
|
||||
|
|
|
|||
|
|
@ -260,14 +260,26 @@ impl BoundingBox for Graphic {
|
|||
}
|
||||
}
|
||||
|
||||
/// Performs internal editor record-keeping that enables tools to target this network's layer.
|
||||
/// This node associates the ID of the network's parent layer to every element of output data.
|
||||
/// This technical detail may be ignored by users, and will be phased out in the future.
|
||||
#[node_macro::node(category(""))]
|
||||
async fn source_node_id<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>, Table<Color>, Table<GradientStops>)] content: Table<I>,
|
||||
#[implementations(
|
||||
Table<Artboard>,
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
Table<Raster<CPU>>,
|
||||
Table<Raster<GPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
)]
|
||||
content: Table<I>,
|
||||
node_path: Vec<NodeId>,
|
||||
) -> Table<I> {
|
||||
// Get the penultimate element of the node path, or None if the path is too short
|
||||
// This is used to get the ID of the user-facing parent layer-style node (which encapsulates this internal node).
|
||||
// This is used to get the ID of the user-facing parent layer node (whose network contains this internal node).
|
||||
let source_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
||||
|
||||
let mut content = content;
|
||||
|
|
@ -297,6 +309,8 @@ async fn extend<I: 'n + Send + Clone>(
|
|||
}
|
||||
|
||||
// TODO: Eventually remove this document upgrade code
|
||||
/// Performs an obsolete function as part of a migration from an older document format.
|
||||
/// Users are advised to delete this node and replace it with a new one.
|
||||
#[node_macro::node(category(""))]
|
||||
async fn legacy_layer_extend<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
|
|
@ -318,7 +332,8 @@ async fn legacy_layer_extend<I: 'n + Send + Clone>(
|
|||
base
|
||||
}
|
||||
|
||||
/// Places a table of graphical content into an element of a new wrapper graphic table.
|
||||
/// Nests the input graphical content in a wrapper graphic. This essentially "groups" the input.
|
||||
/// The inverse of this node is 'Flatten Graphic'.
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn wrap_graphic<T: Into<Graphic> + 'n>(
|
||||
_: impl Ctx,
|
||||
|
|
@ -441,7 +456,7 @@ async fn flatten_vector(_: impl Ctx, content: Table<Graphic>) -> Table<Vector> {
|
|||
}
|
||||
|
||||
/// Returns the value at the specified index in the collection.
|
||||
/// If that index has no value, the type's default value is returned.
|
||||
/// If no value exists at that index, the type's default value is returned.
|
||||
#[node_macro::node(category("General"))]
|
||||
fn index_elements<T: AtIndex + Clone + Default>(
|
||||
_: impl Ctx,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::vector::Vector;
|
|||
use crate::{Context, Ctx};
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
||||
/// Type-asserts a value to be a string, so the automatic type conversion system can convert another type to a string.
|
||||
/// Type-asserts a value to be a string.
|
||||
#[node_macro::node(category("Debug"))]
|
||||
fn to_string(_: impl Ctx, value: String) -> String {
|
||||
value
|
||||
|
|
@ -69,8 +69,21 @@ fn string_length(_: impl Ctx, string: String) -> f64 {
|
|||
string.chars().count() as f64
|
||||
}
|
||||
|
||||
/// Splits a string into a list of substrings based on the specified delimeter.
|
||||
/// For example, the delimeter "," will split "a,b,c" into the strings "a", "b", and "c".
|
||||
#[node_macro::node(category("Text"))]
|
||||
fn string_split(_: impl Ctx, string: String, #[default("\\n")] delimeter: String, #[default(true)] delimeter_escaping: bool) -> Vec<String> {
|
||||
fn string_split(
|
||||
_: impl Ctx,
|
||||
/// The string to split into substrings.
|
||||
string: String,
|
||||
/// The character(s) that separate the substrings. These are not included in the outputs.
|
||||
#[default("\\n")]
|
||||
delimeter: String,
|
||||
/// Whether to convert escape sequences found in the delimeter into their corresponding characters:
|
||||
/// "\n" (newline), "\r" (carriage return), "\t" (tab), "\0" (null), and "\\" (backslash)
|
||||
#[default(true)]
|
||||
delimeter_escaping: bool,
|
||||
) -> Vec<String> {
|
||||
let delimeter = if delimeter_escaping {
|
||||
delimeter.replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t").replace("\\0", "\0").replace("\\\\", "\\")
|
||||
} else {
|
||||
|
|
@ -124,10 +137,5 @@ async fn switch<T, C: Send + 'n + Clone>(
|
|||
)]
|
||||
if_false: impl Node<C, Output = T>,
|
||||
) -> T {
|
||||
if condition {
|
||||
// We can't remove these calls because we only want to evaluate the branch that we actually need
|
||||
if_true.eval(ctx).await
|
||||
} else {
|
||||
if_false.eval(ctx).await
|
||||
}
|
||||
if condition { if_true.eval(ctx).await } else { if_false.eval(ctx).await }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,22 +7,13 @@ use std::ops::Deref;
|
|||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
/// Caches the output of a given node called with a specific input.
|
||||
///
|
||||
/// ```text
|
||||
/// ┌───────────────┐ ┌───────────────┐
|
||||
/// │ │◄───┤ │◄─── EVAL (START)
|
||||
/// │ CacheNode │ │ F │
|
||||
/// │ ├───►│ │───► RESULT (END)
|
||||
/// ┌───────────────┐ ├───────────────┤ └───────────────┘
|
||||
/// │ │◄───┤ │
|
||||
/// │ G │ │ Cached Data │
|
||||
/// │ ├───►│ │
|
||||
/// └───────────────┘ └───────────────┘
|
||||
/// ```
|
||||
/// A cache miss occurs when the Option is None. In this case, the node evaluates the inner node and memoizes (stores) the result.
|
||||
///
|
||||
/// The call from `F` directly reaches the `CacheNode` and the `CacheNode` can decide whether to call `G.eval(input_from_f)`
|
||||
/// in the event of a cache miss or just return the cached data in the event of a cache hit.
|
||||
/// 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.
|
||||
///
|
||||
/// Currently, only one input-output pair is cached. Subsequent calls with different inputs will overwrite the previous cache.
|
||||
#[derive(Default)]
|
||||
pub struct MemoNode<T, CachedNode> {
|
||||
cache: Arc<Mutex<Option<(u64, T)>>>,
|
||||
|
|
@ -71,9 +62,8 @@ pub mod memo {
|
|||
}
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy.
|
||||
/// In contrast to the regular `MemoNode`. This node ignores all input.
|
||||
/// Using this node might result in the document not updating properly,
|
||||
/// use with caution.
|
||||
/// In contrast to the regular `MemoNode`, this variant ignores all input.
|
||||
/// This node might result in the document not updating properly. Use with caution!
|
||||
#[derive(Default)]
|
||||
pub struct ImpureMemoNode<I, T, CachedNode> {
|
||||
cache: Arc<Mutex<Option<T>>>,
|
||||
|
|
@ -86,8 +76,8 @@ where
|
|||
CachedNode: for<'any_input> Node<'any_input, I>,
|
||||
for<'a> <CachedNode as Node<'a, I>>::Output: Future<Output = T> + WasmNotSend,
|
||||
{
|
||||
// TODO: This should return a reference to the cached cached_value
|
||||
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty accurate xD
|
||||
// TODO: This should return a reference to the cached cached_value but that requires a lot of lifetime magic
|
||||
// TODO: (This was suggested by copilot but is pretty accurate xD)
|
||||
type Output = DynFuture<'i, T>;
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
if let Some(cached_value) = self.cache.lock().as_ref().unwrap().deref() {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use crate::{ExtractFootprint, Node, transform::Footprint};
|
|||
use std::marker::PhantomData;
|
||||
|
||||
// TODO: Rename to "Passthrough"
|
||||
/// Passes-through the input value without changing it. This is useful for rerouting wires for organization purposes.
|
||||
/// Passes-through the input value without changing it.
|
||||
/// This is useful for rerouting wires for organization purposes.
|
||||
#[node_macro::node(skip_impl)]
|
||||
fn identity<'i, T: 'i + Send>(value: T) -> T {
|
||||
value
|
||||
|
|
|
|||
|
|
@ -90,13 +90,15 @@ fn decompose_translation(_: impl Ctx, transform: DAffine2) -> DVec2 {
|
|||
transform.translation
|
||||
}
|
||||
|
||||
/// Extracts the rotation component (in degrees) from the input transform. This, together with the "Decompose Scale" node, also may jointly represent any shear component in the original transform.
|
||||
/// Extracts the rotation component (in degrees) from the input transform.
|
||||
/// This, together with the "Decompose Scale" node, also may jointly represent any shear component in the original transform.
|
||||
#[node_macro::node(category("Math: Transform"))]
|
||||
fn decompose_rotation(_: impl Ctx, transform: DAffine2) -> f64 {
|
||||
transform.decompose_rotation().to_degrees()
|
||||
}
|
||||
|
||||
/// Extracts the scale component from the input transform. This, together with the "Decompose Rotation" node, also may jointly represent any shear component in the original transform.
|
||||
/// Extracts the scale component from the input transform.
|
||||
/// This, together with the "Decompose Rotation" node, also may jointly represent any shear component in the original transform.
|
||||
#[node_macro::node(category("Math: Transform"))]
|
||||
fn decompose_scale(_: impl Ctx, transform: DAffine2) -> DVec2 {
|
||||
transform.decompose_scale()
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ impl CornerRadius for [f64; 4] {
|
|||
}
|
||||
}
|
||||
|
||||
/// Generates a circle shape with a chosen radius.
|
||||
#[node_macro::node(category("Vector: Shape"))]
|
||||
fn circle(
|
||||
_: impl Ctx,
|
||||
|
|
@ -50,6 +51,7 @@ fn circle(
|
|||
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_ellipse(DVec2::splat(-radius), DVec2::splat(radius))))
|
||||
}
|
||||
|
||||
/// Generates an arc shape forming a portion of a circle which may be open, closed, or a pie slice.
|
||||
#[node_macro::node(category("Vector: Shape"))]
|
||||
fn arc(
|
||||
_: impl Ctx,
|
||||
|
|
@ -75,6 +77,7 @@ fn arc(
|
|||
)))
|
||||
}
|
||||
|
||||
/// Generates a spiral shape that winds from an inner to an outer radius.
|
||||
#[node_macro::node(category("Vector: Shape"), properties("spiral_properties"))]
|
||||
fn spiral(
|
||||
_: impl Ctx,
|
||||
|
|
@ -96,6 +99,7 @@ fn spiral(
|
|||
)))
|
||||
}
|
||||
|
||||
/// Generates an ellipse shape (an oval or stretched circle) with the chosen radii.
|
||||
#[node_macro::node(category("Vector: Shape"))]
|
||||
fn ellipse(
|
||||
_: impl Ctx,
|
||||
|
|
@ -123,6 +127,7 @@ fn ellipse(
|
|||
Table::new_from_element(ellipse)
|
||||
}
|
||||
|
||||
/// 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"))]
|
||||
fn rectangle<T: CornerRadius>(
|
||||
_: impl Ctx,
|
||||
|
|
@ -140,6 +145,7 @@ fn rectangle<T: CornerRadius>(
|
|||
corner_radius.generate(DVec2::new(width, height), clamped)
|
||||
}
|
||||
|
||||
/// Generates an regular polygon shape like a triangle, square, pentagon, hexagon, heptagon, octagon, or any higher n-gon.
|
||||
#[node_macro::node(category("Vector: Shape"))]
|
||||
fn regular_polygon<T: AsU64>(
|
||||
_: impl Ctx,
|
||||
|
|
@ -157,6 +163,7 @@ fn regular_polygon<T: AsU64>(
|
|||
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_regular_polygon(DVec2::splat(-radius), points, radius)))
|
||||
}
|
||||
|
||||
/// Generates an n-pointed star shape with inner and outer points at chosen radii from the center.
|
||||
#[node_macro::node(category("Vector: Shape"))]
|
||||
fn star<T: AsU64>(
|
||||
_: impl Ctx,
|
||||
|
|
@ -179,8 +186,18 @@ fn star<T: AsU64>(
|
|||
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_star_polygon(DVec2::splat(-diameter), points, diameter, inner_diameter)))
|
||||
}
|
||||
|
||||
/// Generates a line with endpoints at the two chosen coordinates.
|
||||
#[node_macro::node(category("Vector: Shape"))]
|
||||
fn line(_: impl Ctx, _primary: (), #[default(0., 0.)] start: PixelSize, #[default(100., 100.)] end: PixelSize) -> Table<Vector> {
|
||||
fn line(
|
||||
_: impl Ctx,
|
||||
_primary: (),
|
||||
/// Coordinate of the line's initial endpoint.
|
||||
#[default(0., 0.)]
|
||||
start: PixelSize,
|
||||
/// Coordinate of the line's terminal endpoint.
|
||||
#[default(100., 100.)]
|
||||
end: PixelSize,
|
||||
) -> Table<Vector> {
|
||||
Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_line(start, end)))
|
||||
}
|
||||
|
||||
|
|
@ -198,6 +215,7 @@ impl GridSpacing for DVec2 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Generates a rectangular or isometric grid with the chosen number of columns and rows. Line segments connect the points, forming a vector mesh.
|
||||
#[node_macro::node(category("Vector: Shape"), properties("grid_properties"))]
|
||||
fn grid<T: GridSpacing>(
|
||||
_: impl Ctx,
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ impl Hash for VectorModification {
|
|||
}
|
||||
}
|
||||
|
||||
/// Applies a diff modification to a vector path.
|
||||
/// Applies a differential modification to a vector path, associating changes made by the Pen and Path tools to indices of edited points and segments.
|
||||
#[node_macro::node(category(""))]
|
||||
async fn path_modify(_ctx: impl Ctx, mut vector: Table<Vector>, modification: Box<VectorModification>, node_path: Vec<NodeId>) -> Table<Vector> {
|
||||
if vector.is_empty() {
|
||||
|
|
@ -437,7 +437,7 @@ async fn path_modify(_ctx: impl Ctx, mut vector: Table<Vector>, modification: Bo
|
|||
vector
|
||||
}
|
||||
|
||||
/// Applies the vector path's local transformation to its geometry and resets it to the identity.
|
||||
/// Applies the vector path's local transformation to its geometry and resets the transform to the identity.
|
||||
#[node_macro::node(category("Vector"))]
|
||||
async fn apply_transform(_ctx: impl Ctx, mut vector: Table<Vector>) -> Table<Vector> {
|
||||
for row in vector.iter_mut() {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ impl VectorTableIterMut for Table<Vector> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Uniquely sets the fill and/or stroke style of every vector element to individual colors sampled along a chosen gradient.
|
||||
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector))]
|
||||
async fn assign_colors<T>(
|
||||
_: impl Ctx,
|
||||
|
|
@ -105,6 +106,7 @@ where
|
|||
content
|
||||
}
|
||||
|
||||
/// Applies a fill style to the vector content, giving an appearance to the area within the interior of the geometry.
|
||||
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("fill_properties"))]
|
||||
async fn fill<F: Into<Fill> + 'n + Send, V: VectorTableIterMut + 'n + Send>(
|
||||
_: impl Ctx,
|
||||
|
|
@ -121,6 +123,7 @@ async fn fill<F: Into<Fill> + 'n + Send, V: VectorTableIterMut + 'n + Send>(
|
|||
)]
|
||||
mut content: V,
|
||||
/// The fill to paint the path with.
|
||||
#[default(Color::BLACK)]
|
||||
#[implementations(
|
||||
Fill,
|
||||
Table<Color>,
|
||||
|
|
@ -131,7 +134,6 @@ async fn fill<F: Into<Fill> + 'n + Send, V: VectorTableIterMut + 'n + Send>(
|
|||
Table<GradientStops>,
|
||||
Gradient,
|
||||
)]
|
||||
#[default(Color::BLACK)]
|
||||
fill: F,
|
||||
_backup_color: Table<Color>,
|
||||
_backup_gradient: Gradient,
|
||||
|
|
@ -144,7 +146,7 @@ async fn fill<F: Into<Fill> + 'n + Send, V: VectorTableIterMut + 'n + Send>(
|
|||
content
|
||||
}
|
||||
|
||||
/// Applies a stroke style to the vector contained in the input.
|
||||
/// Applies a stroke style to the vector content, giving an appearance to the area within the outline of the geometry.
|
||||
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("stroke_properties"))]
|
||||
async fn stroke<V>(
|
||||
_: impl Ctx,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue