Merge branch 'master' into spiral-node

This commit is contained in:
0SlowPoke0 2025-07-03 16:45:33 +05:30 committed by GitHub
commit a9327ee33d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 313 additions and 150 deletions

38
Cargo.lock generated
View file

@ -2195,8 +2195,10 @@ dependencies = [
"glam", "glam",
"graph-craft", "graph-craft",
"graphene-application-io", "graphene-application-io",
"graphene-brush",
"graphene-core", "graphene-core",
"graphene-path-bool", "graphene-path-bool",
"graphene-raster-nodes",
"graphene-svg-renderer", "graphene-svg-renderer",
"iai-callgrind", "iai-callgrind",
"js-sys", "js-sys",
@ -2228,6 +2230,19 @@ dependencies = [
"wgpu", "wgpu",
] ]
[[package]]
name = "graphene-brush"
version = "0.1.0"
dependencies = [
"dyn-any",
"glam",
"graphene-core",
"graphene-raster-nodes",
"node-macro",
"serde",
"tokio",
]
[[package]] [[package]]
name = "graphene-cli" name = "graphene-cli"
version = "0.1.0" version = "0.1.0"
@ -2305,6 +2320,27 @@ dependencies = [
"specta", "specta",
] ]
[[package]]
name = "graphene-raster-nodes"
version = "0.1.0"
dependencies = [
"bezier-rs",
"bytemuck",
"dyn-any",
"fastnoise-lite",
"futures",
"glam",
"graphene-core",
"image",
"ndarray",
"node-macro",
"rand 0.9.0",
"rand_chacha 0.9.0",
"serde",
"specta",
"tokio",
]
[[package]] [[package]]
name = "graphene-std" name = "graphene-std"
version = "0.1.0" version = "0.1.0"
@ -2317,9 +2353,11 @@ dependencies = [
"glam", "glam",
"graph-craft", "graph-craft",
"graphene-application-io", "graphene-application-io",
"graphene-brush",
"graphene-core", "graphene-core",
"graphene-math-nodes", "graphene-math-nodes",
"graphene-path-bool", "graphene-path-bool",
"graphene-raster-nodes",
"graphene-svg-renderer", "graphene-svg-renderer",
"image", "image",
"log", "log",

View file

@ -5,12 +5,14 @@ members = [
"frontend/wasm", "frontend/wasm",
"frontend/src-tauri", "frontend/src-tauri",
"node-graph/gapplication-io", "node-graph/gapplication-io",
"node-graph/gbrush",
"node-graph/gcore", "node-graph/gcore",
"node-graph/gstd", "node-graph/gstd",
"node-graph/gmath-nodes", "node-graph/gmath-nodes",
"node-graph/gpath-bool", "node-graph/gpath-bool",
"node-graph/graph-craft", "node-graph/graph-craft",
"node-graph/graphene-cli", "node-graph/graphene-cli",
"node-graph/graster-nodes",
"node-graph/gsvg-renderer", "node-graph/gsvg-renderer",
"node-graph/interpreted-executor", "node-graph/interpreted-executor",
"node-graph/node-macro", "node-graph/node-macro",
@ -24,12 +26,14 @@ members = [
default-members = [ default-members = [
"editor", "editor",
"frontend/wasm", "frontend/wasm",
"node-graph/gbrush",
"node-graph/gcore", "node-graph/gcore",
"node-graph/gstd", "node-graph/gstd",
"node-graph/gmath-nodes", "node-graph/gmath-nodes",
"node-graph/gpath-bool", "node-graph/gpath-bool",
"node-graph/graph-craft", "node-graph/graph-craft",
"node-graph/graphene-cli", "node-graph/graphene-cli",
"node-graph/graster-nodes",
"node-graph/gsvg-renderer", "node-graph/gsvg-renderer",
"node-graph/interpreted-executor", "node-graph/interpreted-executor",
"node-graph/node-macro", "node-graph/node-macro",
@ -44,10 +48,12 @@ preprocessor = { path = "node-graph/preprocessor"}
math-parser = { path = "libraries/math-parser" } math-parser = { path = "libraries/math-parser" }
path-bool = { path = "libraries/path-bool" } path-bool = { path = "libraries/path-bool" }
graphene-application-io = { path = "node-graph/gapplication-io" } graphene-application-io = { path = "node-graph/gapplication-io" }
graphene-brush = { path = "node-graph/gbrush" }
graphene-core = { path = "node-graph/gcore" } graphene-core = { path = "node-graph/gcore" }
graphene-math-nodes = { path = "node-graph/gmath-nodes" } graphene-math-nodes = { path = "node-graph/gmath-nodes" }
graphene-path-bool = { path = "node-graph/gpath-bool" } graphene-path-bool = { path = "node-graph/gpath-bool" }
graph-craft = { path = "node-graph/graph-craft" } graph-craft = { path = "node-graph/graph-craft" }
graphene-raster-nodes = { path = "node-graph/graster-nodes" }
graphene-std = { path = "node-graph/gstd" } graphene-std = { path = "node-graph/gstd" }
graphene-svg-renderer = { path = "node-graph/gsvg-renderer" } graphene-svg-renderer = { path = "node-graph/gsvg-renderer" }
interpreted-executor = { path = "node-graph/interpreted-executor" } interpreted-executor = { path = "node-graph/interpreted-executor" }
@ -147,6 +153,7 @@ half = { version = "2.4.1", default-features = false, features = ["bytemuck", "s
tinyvec = { version = "1" } tinyvec = { version = "1" }
criterion = { version = "0.5", features = ["html_reports"] } criterion = { version = "0.5", features = ["html_reports"] }
iai-callgrind = { version = "0.12.3" } iai-callgrind = { version = "0.12.3" }
ndarray = "0.16.1"
[profile.dev] [profile.dev]
opt-level = 1 opt-level = 1

View file

@ -6,12 +6,12 @@ use bezier_rs::Subpath;
use glam::{DAffine2, DVec2, IVec2}; use glam::{DAffine2, DVec2, IVec2};
use graph_craft::document::NodeId; use graph_craft::document::NodeId;
use graphene_std::Artboard; use graphene_std::Artboard;
use graphene_std::brush::brush_stroke::BrushStroke;
use graphene_std::raster::BlendMode; use graphene_std::raster::BlendMode;
use graphene_std::raster_types::{CPU, RasterDataTable}; use graphene_std::raster_types::{CPU, RasterDataTable};
use graphene_std::text::{Font, TypesettingConfig}; use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::PointId; use graphene_std::vector::PointId;
use graphene_std::vector::VectorModificationType; use graphene_std::vector::VectorModificationType;
use graphene_std::vector::brush_stroke::BrushStroke;
use graphene_std::vector::style::{Fill, Stroke}; use graphene_std::vector::style::{Fill, Stroke};
#[impl_message(Message, DocumentMessage, GraphOperation)] #[impl_message(Message, DocumentMessage, GraphOperation)]

View file

@ -9,10 +9,10 @@ use graph_craft::concrete;
use graph_craft::document::value::TaggedValue; use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput}; use graph_craft::document::{NodeId, NodeInput};
use graphene_std::Artboard; use graphene_std::Artboard;
use graphene_std::brush::brush_stroke::BrushStroke;
use graphene_std::raster::BlendMode; use graphene_std::raster::BlendMode;
use graphene_std::raster_types::{CPU, RasterDataTable}; use graphene_std::raster_types::{CPU, RasterDataTable};
use graphene_std::text::{Font, TypesettingConfig}; use graphene_std::text::{Font, TypesettingConfig};
use graphene_std::vector::brush_stroke::BrushStroke;
use graphene_std::vector::style::{Fill, Stroke}; use graphene_std::vector::style::{Fill, Stroke};
use graphene_std::vector::{PointId, VectorModificationType}; use graphene_std::vector::{PointId, VectorModificationType};
use graphene_std::vector::{VectorData, VectorDataTable}; use graphene_std::vector::{VectorData, VectorDataTable};

View file

@ -16,8 +16,8 @@ use graph_craft::ProtoNodeIdentifier;
use graph_craft::concrete; use graph_craft::concrete;
use graph_craft::document::value::*; use graph_craft::document::value::*;
use graph_craft::document::*; use graph_craft::document::*;
use graphene_std::brush::brush_cache::BrushCache;
use graphene_std::extract_xy::XY; use graphene_std::extract_xy::XY;
use graphene_std::raster::brush_cache::BrushCache;
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
use graphene_std::raster_types::{CPU, RasterDataTable}; use graphene_std::raster_types::{CPU, RasterDataTable};
use graphene_std::text::{Font, TypesettingConfig}; use graphene_std::text::{Font, TypesettingConfig};
@ -1032,7 +1032,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
nodes: vec![DocumentNode { nodes: vec![DocumentNode {
inputs: vec![ inputs: vec![
NodeInput::network(concrete!(RasterDataTable<CPU>), 0), NodeInput::network(concrete!(RasterDataTable<CPU>), 0),
NodeInput::network(concrete!(Vec<graphene_std::vector::brush_stroke::BrushStroke>), 1), NodeInput::network(concrete!(Vec<brush::brush_stroke::BrushStroke>), 1),
NodeInput::network(concrete!(BrushCache), 2), NodeInput::network(concrete!(BrushCache), 2),
], ],
manual_composition: Some(concrete!(Context)), manual_composition: Some(concrete!(Context)),

View file

@ -25,6 +25,7 @@ const REPLACEMENTS: &[(&str, &str)] = &[
("graphene_core::ConstructArtboardNode", "graphene_core::graphic_element::ToArtboardNode"), ("graphene_core::ConstructArtboardNode", "graphene_core::graphic_element::ToArtboardNode"),
("graphene_core::ToGraphicElementNode", "graphene_core::graphic_element::ToElementNode"), ("graphene_core::ToGraphicElementNode", "graphene_core::graphic_element::ToElementNode"),
("graphene_core::ToGraphicGroupNode", "graphene_core::graphic_element::ToGroupNode"), ("graphene_core::ToGraphicGroupNode", "graphene_core::graphic_element::ToGroupNode"),
// math_nodes
("graphene_core::ops::MathNode", "graphene_math_nodes::MathNode"), ("graphene_core::ops::MathNode", "graphene_math_nodes::MathNode"),
("graphene_core::ops::AddNode", "graphene_math_nodes::AddNode"), ("graphene_core::ops::AddNode", "graphene_math_nodes::AddNode"),
("graphene_core::ops::SubtractNode", "graphene_math_nodes::SubtractNode"), ("graphene_core::ops::SubtractNode", "graphene_math_nodes::SubtractNode"),
@ -65,43 +66,72 @@ const REPLACEMENTS: &[(&str, &str)] = &[
("graphene_core::ops::GradientValueNode", "graphene_math_nodes::GradientValueNode"), ("graphene_core::ops::GradientValueNode", "graphene_math_nodes::GradientValueNode"),
("graphene_core::ops::StringValueNode", "graphene_math_nodes::StringValueNode"), ("graphene_core::ops::StringValueNode", "graphene_math_nodes::StringValueNode"),
("graphene_core::ops::DotProductNode", "graphene_math_nodes::DotProductNode"), ("graphene_core::ops::DotProductNode", "graphene_math_nodes::DotProductNode"),
// debug
("graphene_core::ops::SizeOfNode", "graphene_core::debug::SizeOfNode"), ("graphene_core::ops::SizeOfNode", "graphene_core::debug::SizeOfNode"),
("graphene_core::ops::SomeNode", "graphene_core::debug::SomeNode"), ("graphene_core::ops::SomeNode", "graphene_core::debug::SomeNode"),
("graphene_core::ops::UnwrapNode", "graphene_core::debug::UnwrapNode"), ("graphene_core::ops::UnwrapNode", "graphene_core::debug::UnwrapNode"),
("graphene_core::ops::CloneNode", "graphene_core::debug::CloneNode"), ("graphene_core::ops::CloneNode", "graphene_core::debug::CloneNode"),
// ???
("graphene_core::ops::ExtractXyNode", "graphene_core::extract_xy::ExtractXyNode"), ("graphene_core::ops::ExtractXyNode", "graphene_core::extract_xy::ExtractXyNode"),
("graphene_core::logic::LogicAndNode", "graphene_core::ops::LogicAndNode"), ("graphene_core::logic::LogicAndNode", "graphene_core::ops::LogicAndNode"),
("graphene_core::logic::LogicNotNode", "graphene_core::ops::LogicNotNode"), ("graphene_core::logic::LogicNotNode", "graphene_core::ops::LogicNotNode"),
("graphene_core::logic::LogicOrNode", "graphene_core::ops::LogicOrNode"), ("graphene_core::logic::LogicOrNode", "graphene_core::ops::LogicOrNode"),
("graphene_core::ops::ConstructVector2", "graphene_core::ops::CoordinateValueNode"), ("graphene_core::ops::ConstructVector2", "graphene_core::ops::CoordinateValueNode"),
("graphene_core::ops::Vector2ValueNode", "graphene_core::ops::CoordinateValueNode"), ("graphene_core::ops::Vector2ValueNode", "graphene_core::ops::CoordinateValueNode"),
("graphene_core::raster::BlackAndWhiteNode", "graphene_core::raster::adjustments::BlackAndWhiteNode"),
("graphene_core::raster::BlendNode", "graphene_core::raster::adjustments::BlendNode"),
("graphene_core::raster::BlendModeNode", "graphene_core::blending_nodes::BlendModeNode"), ("graphene_core::raster::BlendModeNode", "graphene_core::blending_nodes::BlendModeNode"),
("graphene_core::raster::OpacityNode", "graphene_core::blending_nodes::OpacityNode"), ("graphene_core::raster::OpacityNode", "graphene_core::blending_nodes::OpacityNode"),
("graphene_core::raster::BlendingNode", "graphene_core::blending_nodes::BlendingNode"), ("graphene_core::raster::BlendingNode", "graphene_core::blending_nodes::BlendingNode"),
("graphene_core::raster::ChannelMixerNode", "graphene_core::raster::adjustments::ChannelMixerNode"),
("graphene_core::raster::adjustments::ColorOverlayNode", "graphene_core::raster::adjustments::ColorOverlayNode"),
("graphene_core::raster::ExposureNode", "graphene_core::raster::adjustments::ExposureNode"),
("graphene_core::raster::ExtractChannelNode", "graphene_core::raster::adjustments::ExtractChannelNode"),
("graphene_core::raster::GradientMapNode", "graphene_core::raster::adjustments::GradientMapNode"),
("graphene_core::raster::HueSaturationNode", "graphene_core::raster::adjustments::HueSaturationNode"),
("graphene_core::vector::GenerateHandlesNode", "graphene_core::vector::AutoTangentsNode"), ("graphene_core::vector::GenerateHandlesNode", "graphene_core::vector::AutoTangentsNode"),
("graphene_core::vector::RemoveHandlesNode", "graphene_core::vector::AutoTangentsNode"), ("graphene_core::vector::RemoveHandlesNode", "graphene_core::vector::AutoTangentsNode"),
("graphene_core::raster::InvertNode", "graphene_core::raster::adjustments::InvertNode"), // raster::adjustments
("graphene_core::raster::InvertRGBNode", "graphene_core::raster::adjustments::InvertNode"), ("graphene_core::raster::adjustments::LuminanceNode", "graphene_raster_nodes::adjustments::LuminanceNode"),
("graphene_core::raster::LevelsNode", "graphene_core::raster::adjustments::LevelsNode"), ("graphene_core::raster::LuminanceNode", "graphene_raster_nodes::adjustments::LuminanceNode"),
("graphene_core::raster::LuminanceNode", "graphene_core::raster::adjustments::LuminanceNode"), ("graphene_core::raster::adjustments::ExtractChannelNode", "graphene_raster_nodes::adjustments::ExtractChannelNode"),
("graphene_core::raster::ExtractOpaqueNode", "graphene_core::raster::adjustments::MakeOpaqueNode"), ("graphene_core::raster::ExtractChannelNode", "graphene_raster_nodes::adjustments::ExtractChannelNode"),
("graphene_core::raster::PosterizeNode", "graphene_core::raster::adjustments::PosterizeNode"), ("graphene_core::raster::adjustments::MakeOpaqueNode", "graphene_raster_nodes::adjustments::MakeOpaqueNode"),
("graphene_core::raster::ThresholdNode", "graphene_core::raster::adjustments::ThresholdNode"), ("graphene_core::raster::ExtractOpaqueNode", "graphene_raster_nodes::adjustments::MakeOpaqueNode"),
("graphene_core::raster::VibranceNode", "graphene_core::raster::adjustments::VibranceNode"), (
"graphene_core::raster::adjustments::BrightnessContrastNode",
"graphene_raster_nodes::adjustments::BrightnessContrastNode",
),
("graphene_core::raster::adjustments::LevelsNode", "graphene_raster_nodes::adjustments::LevelsNode"),
("graphene_core::raster::LevelsNode", "graphene_raster_nodes::adjustments::LevelsNode"),
("graphene_core::raster::adjustments::BlackAndWhiteNode", "graphene_raster_nodes::adjustments::BlackAndWhiteNode"),
("graphene_core::raster::BlackAndWhiteNode", "graphene_raster_nodes::adjustments::BlackAndWhiteNode"),
("graphene_core::raster::adjustments::HueSaturationNode", "graphene_raster_nodes::adjustments::HueSaturationNode"),
("graphene_core::raster::HueSaturationNode", "graphene_raster_nodes::adjustments::HueSaturationNode"),
("graphene_core::raster::adjustments::InvertNode", "graphene_raster_nodes::adjustments::InvertNode"),
("graphene_core::raster::InvertNode", "graphene_raster_nodes::adjustments::InvertNode"),
("graphene_core::raster::InvertRGBNode", "graphene_raster_nodes::adjustments::InvertNode"),
("graphene_core::raster::adjustments::ThresholdNode", "graphene_raster_nodes::adjustments::ThresholdNode"),
("graphene_core::raster::ThresholdNode", "graphene_raster_nodes::adjustments::ThresholdNode"),
("graphene_core::raster::adjustments::BlendNode", "graphene_raster_nodes::adjustments::BlendNode"),
("graphene_core::raster::BlendNode", "graphene_raster_nodes::adjustments::BlendNode"),
("graphene_core::raster::BlendColorPairNode", "graphene_raster_nodes::adjustments::BlendColorPairNode"),
("graphene_core::raster::adjustments::BlendColorsNode", "graphene_raster_nodes::adjustments::BlendColorsNode"),
("graphene_core::raster::BlendColorsNode", "graphene_raster_nodes::adjustments::BlendColorsNode"),
("graphene_core::raster::adjustments::GradientMapNode", "graphene_raster_nodes::adjustments::GradientMapNode"),
("graphene_core::raster::GradientMapNode", "graphene_raster_nodes::adjustments::GradientMapNode"),
("graphene_core::raster::adjustments::VibranceNode", "graphene_raster_nodes::adjustments::VibranceNode"),
("graphene_core::raster::VibranceNode", "graphene_raster_nodes::adjustments::VibranceNode"),
("graphene_core::raster::adjustments::ChannelMixerNode", "graphene_raster_nodes::adjustments::ChannelMixerNode"),
("graphene_core::raster::ChannelMixerNode", "graphene_raster_nodes::adjustments::ChannelMixerNode"),
("graphene_core::raster::adjustments::SelectiveColorNode", "graphene_raster_nodes::adjustments::SelectiveColorNode"),
("graphene_core::raster::adjustments::PosterizeNode", "graphene_raster_nodes::adjustments::PosterizeNode"),
("graphene_core::raster::PosterizeNode", "graphene_raster_nodes::adjustments::PosterizeNode"),
("graphene_core::raster::adjustments::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"),
("graphene_core::raster::ExposureNode", "graphene_raster_nodes::adjustments::ExposureNode"),
("graphene_core::raster::adjustments::GenerateCurvesNode", "graphene_raster_nodes::generate_curves::GenerateCurvesNode"),
("graphene_core::raster::adjustments::ColorOverlayNode", "graphene_raster_nodes::generate_curves::ColorOverlayNode"),
// text
("graphene_core::text::TextGeneratorNode", "graphene_core::text::TextNode"), ("graphene_core::text::TextGeneratorNode", "graphene_core::text::TextNode"),
// transform
("graphene_core::transform::SetTransformNode", "graphene_core::transform_nodes::ReplaceTransformNode"), ("graphene_core::transform::SetTransformNode", "graphene_core::transform_nodes::ReplaceTransformNode"),
("graphene_core::transform::ReplaceTransformNode", "graphene_core::transform_nodes::ReplaceTransformNode"), ("graphene_core::transform::ReplaceTransformNode", "graphene_core::transform_nodes::ReplaceTransformNode"),
("graphene_core::transform::TransformNode", "graphene_core::transform_nodes::TransformNode"), ("graphene_core::transform::TransformNode", "graphene_core::transform_nodes::TransformNode"),
("graphene_core::transform::BoundlessFootprintNode", "graphene_core::transform_nodes::BoundlessFootprintNode"), ("graphene_core::transform::BoundlessFootprintNode", "graphene_core::transform_nodes::BoundlessFootprintNode"),
("graphene_core::transform::FreezeRealTimeNode", "graphene_core::transform_nodes::FreezeRealTimeNode"), ("graphene_core::transform::FreezeRealTimeNode", "graphene_core::transform_nodes::FreezeRealTimeNode"),
// ???
("graphene_core::vector::SplinesFromPointsNode", "graphene_core::vector::SplineNode"), ("graphene_core::vector::SplinesFromPointsNode", "graphene_core::vector::SplineNode"),
("graphene_core::vector::generator_nodes::EllipseGenerator", "graphene_core::vector::generator_nodes::EllipseNode"), ("graphene_core::vector::generator_nodes::EllipseGenerator", "graphene_core::vector::generator_nodes::EllipseNode"),
("graphene_core::vector::generator_nodes::LineGenerator", "graphene_core::vector::generator_nodes::LineNode"), ("graphene_core::vector::generator_nodes::LineGenerator", "graphene_core::vector::generator_nodes::LineNode"),
@ -117,6 +147,10 @@ const REPLACEMENTS: &[(&str, &str)] = &[
("graphene_std::raster::MaskImageNode", "graphene_std::raster::MaskNode"), ("graphene_std::raster::MaskImageNode", "graphene_std::raster::MaskNode"),
("graphene_core::vector::FlattenVectorElementsNode", "graphene_core::vector::FlattenPathNode"), ("graphene_core::vector::FlattenVectorElementsNode", "graphene_core::vector::FlattenPathNode"),
("graphene_std::vector::BooleanOperationNode", "graphene_path_bool::BooleanOperationNode"), ("graphene_std::vector::BooleanOperationNode", "graphene_path_bool::BooleanOperationNode"),
// brush
("graphene_std::brush::BrushStampGeneratorNode", "graphene_brush::brush::BrushStampGeneratorNode"),
("graphene_std::brush::BlitNode", "graphene_brush::brush::BlitNode"),
("graphene_std::brush::BrushNode", "graphene_brush::brush::BrushNode"),
]; ];
pub fn document_migration_string_preprocessing(document_serialized_content: String) -> String { pub fn document_migration_string_preprocessing(document_serialized_content: String) -> String {

View file

@ -8,8 +8,8 @@ use crate::messages::tool::common_functionality::color_selector::{ToolColorOptio
use graph_craft::document::NodeId; use graph_craft::document::NodeId;
use graph_craft::document::value::TaggedValue; use graph_craft::document::value::TaggedValue;
use graphene_std::Color; use graphene_std::Color;
use graphene_std::brush::brush_stroke::{BrushInputSample, BrushStroke, BrushStyle};
use graphene_std::raster::BlendMode; use graphene_std::raster::BlendMode;
use graphene_std::vector::brush_stroke::{BrushInputSample, BrushStroke, BrushStyle};
const BRUSH_MAX_SIZE: f64 = 5000.; const BRUSH_MAX_SIZE: f64 = 5000.;

View file

@ -0,0 +1,28 @@
[package]
name = "graphene-brush"
version = "0.1.0"
edition = "2024"
description = "graphene brush"
authors = ["Graphite Authors <contact@graphite.rs>"]
license = "MIT OR Apache-2.0"
[features]
default = ["serde"]
serde = ["dep:serde"]
[dependencies]
# Local dependencies
dyn-any = { workspace = true }
graphene-core = { workspace = true }
graphene-raster-nodes = { workspace = true }
node-macro = { workspace = true }
# Workspace dependencies
glam = { workspace = true }
# Optional workspace dependencies
serde = { workspace = true, optional = true, features = ["derive"] }
[dev-dependencies]
# Workspace dependencies
tokio = { workspace = true }

View file

@ -1,19 +1,21 @@
use crate::raster::{empty_image, extend_image_to_bounds}; use crate::brush_cache::BrushCache;
use crate::brush_stroke::{BrushStroke, BrushStyle};
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
use graph_craft::generic::FnNode; use graphene_core::blending::BlendMode;
use graph_craft::proto::FutureWrapperNode;
use graphene_core::bounds::BoundingBox; use graphene_core::bounds::BoundingBox;
use graphene_core::color::{Alpha, Color, Pixel, Sample};
use graphene_core::generic::FnNode;
use graphene_core::instances::Instance; use graphene_core::instances::Instance;
use graphene_core::math::bbox::{AxisAlignedBbox, Bbox}; use graphene_core::math::bbox::{AxisAlignedBbox, Bbox};
use graphene_core::raster::adjustments::blend_colors; use graphene_core::raster::BitmapMut;
use graphene_core::raster::brush_cache::BrushCache;
use graphene_core::raster::image::Image; use graphene_core::raster::image::Image;
use graphene_core::raster::{Alpha, BitmapMut, BlendMode, Color, Pixel, Sample};
use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::raster_types::{CPU, Raster, RasterDataTable};
use graphene_core::registry::FutureWrapperNode;
use graphene_core::transform::Transform; use graphene_core::transform::Transform;
use graphene_core::value::ClonedNode; use graphene_core::value::ClonedNode;
use graphene_core::vector::brush_stroke::{BrushStroke, BrushStyle}; use graphene_core::{Ctx, Node};
use graphene_core::{Ctx, GraphicElement, Node}; use graphene_raster_nodes::adjustments::blend_colors;
use graphene_raster_nodes::std_nodes::{empty_image, extend_image_to_bounds};
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct BrushStampGenerator<P: Pixel + Alpha> { pub struct BrushStampGenerator<P: Pixel + Alpha> {
@ -50,7 +52,7 @@ impl<P: Pixel + Alpha> Sample for BrushStampGenerator<P> {
return None; return None;
}; };
use graphene_core::raster::Channel; use graphene_core::color::Channel;
Some(self.color.multiplied_alpha(P::AlphaChannel::from_linear(result))) Some(self.color.multiplied_alpha(P::AlphaChannel::from_linear(result)))
} }
} }
@ -78,7 +80,6 @@ fn brush_stamp_generator(#[unit(" px")] diameter: f64, color: Color, hardness: f
fn blit<BlendFn>(mut target: RasterDataTable<CPU>, texture: Raster<CPU>, positions: Vec<DVec2>, blend_mode: BlendFn) -> RasterDataTable<CPU> fn blit<BlendFn>(mut target: RasterDataTable<CPU>, texture: Raster<CPU>, positions: Vec<DVec2>, blend_mode: BlendFn) -> RasterDataTable<CPU>
where where
BlendFn: for<'any_input> Node<'any_input, (Color, Color), Output = Color>, BlendFn: for<'any_input> Node<'any_input, (Color, Color), Output = Color>,
GraphicElement: From<Raster<CPU>>,
{ {
if positions.is_empty() { if positions.is_empty() {
return target; return target;
@ -239,7 +240,6 @@ async fn brush(_: impl Ctx, mut image_frame_table: RasterDataTable<CPU>, strokes
let target = core::mem::take(&mut brush_plan.first_stroke_texture); let target = core::mem::take(&mut brush_plan.first_stroke_texture);
extend_image_to_bounds((), target.to_table(), stroke_to_layer) extend_image_to_bounds((), target.to_table(), stroke_to_layer)
} else { } else {
use crate::raster::empty_image;
empty_image((), stroke_to_layer, Color::TRANSPARENT) empty_image((), stroke_to_layer, Color::TRANSPARENT)
// EmptyImageNode::new(CopiedNode::new(stroke_to_layer), CopiedNode::new(Color::TRANSPARENT)).eval(()) // EmptyImageNode::new(CopiedNode::new(stroke_to_layer), CopiedNode::new(Color::TRANSPARENT)).eval(())
}; };
@ -393,7 +393,7 @@ mod test {
(), (),
RasterDataTable::<CPU>::new(Raster::new_cpu(Image::<Color>::default())), RasterDataTable::<CPU>::new(Raster::new_cpu(Image::<Color>::default())),
vec![BrushStroke { vec![BrushStroke {
trace: vec![crate::vector::brush_stroke::BrushInputSample { position: DVec2::ZERO }], trace: vec![crate::brush_stroke::BrushInputSample { position: DVec2::ZERO }],
style: BrushStyle { style: BrushStyle {
color: Color::BLACK, color: Color::BLACK,
diameter: 20., diameter: 20.,

View file

@ -1,9 +1,9 @@
use crate::instances::Instance; use crate::brush_stroke::BrushStroke;
use crate::raster_types::CPU; use crate::brush_stroke::BrushStyle;
use crate::raster_types::Raster;
use crate::vector::brush_stroke::BrushStroke;
use crate::vector::brush_stroke::BrushStyle;
use dyn_any::DynAny; use dyn_any::DynAny;
use graphene_core::instances::Instance;
use graphene_core::raster_types::CPU;
use graphene_core::raster_types::Raster;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use std::sync::Arc; use std::sync::Arc;
@ -15,11 +15,11 @@ struct BrushCacheImpl {
prev_input: Vec<BrushStroke>, prev_input: Vec<BrushStroke>,
// The strokes that have been fully processed and blended into the background. // The strokes that have been fully processed and blended into the background.
#[serde(deserialize_with = "crate::graphene_core::raster::image::migrate_image_frame_instance")] #[serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame_instance")]
background: Instance<Raster<CPU>>, background: Instance<Raster<CPU>>,
#[serde(deserialize_with = "crate::graphene_core::raster::image::migrate_image_frame_instance")] #[serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame_instance")]
blended_image: Instance<Raster<CPU>>, blended_image: Instance<Raster<CPU>>,
#[serde(deserialize_with = "crate::graphene_core::raster::image::migrate_image_frame_instance")] #[serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame_instance")]
last_stroke_texture: Instance<Raster<CPU>>, last_stroke_texture: Instance<Raster<CPU>>,
// A cache for brush textures. // A cache for brush textures.

View file

@ -1,8 +1,8 @@
use crate::Color;
use crate::math::bbox::AxisAlignedBbox;
use crate::raster::BlendMode;
use dyn_any::DynAny; use dyn_any::DynAny;
use glam::DVec2; use glam::DVec2;
use graphene_core::blending::BlendMode;
use graphene_core::color::Color;
use graphene_core::math::bbox::AxisAlignedBbox;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
/// The style of a brush. /// The style of a brush.

View file

@ -0,0 +1,3 @@
pub mod brush;
pub mod brush_cache;
pub mod brush_stroke;

View file

@ -12,13 +12,9 @@ pub mod color {
pub use super::*; pub use super::*;
} }
pub mod adjustments;
pub mod brush_cache;
pub mod curve;
pub mod image; pub mod image;
pub use self::image::Image; pub use self::image::Image;
pub use adjustments::*;
pub trait Bitmap { pub trait Bitmap {
type Pixel: Pixel; type Pixel: Pixel;

View file

@ -1,5 +1,4 @@
pub mod algorithms; pub mod algorithms;
pub mod brush_stroke;
pub mod click_target; pub mod click_target;
pub mod generator_nodes; pub mod generator_nodes;
pub mod misc; pub mod misc;

View file

@ -17,8 +17,10 @@ loading = ["serde_json"]
dyn-any = { workspace = true } dyn-any = { workspace = true }
graphene-core = { workspace = true } graphene-core = { workspace = true }
graphene-path-bool = { workspace = true } graphene-path-bool = { workspace = true }
graphene-brush = { workspace = true }
graphene-application-io = { workspace = true } graphene-application-io = { workspace = true }
graphene-svg-renderer = { workspace = true } graphene-svg-renderer = { workspace = true }
graphene-raster-nodes = { workspace = true }
# Workspace dependencies # Workspace dependencies
log = { workspace = true } log = { workspace = true }

View file

@ -5,8 +5,8 @@ use dyn_any::DynAny;
pub use dyn_any::StaticType; pub use dyn_any::StaticType;
pub use glam::{DAffine2, DVec2, IVec2, UVec2}; pub use glam::{DAffine2, DVec2, IVec2, UVec2};
use graphene_application_io::SurfaceFrame; use graphene_application_io::SurfaceFrame;
use graphene_core::raster::brush_cache::BrushCache; use graphene_brush::brush_cache::BrushCache;
use graphene_core::raster::{BlendMode, LuminanceCalculation}; use graphene_brush::brush_stroke::BrushStroke;
use graphene_core::raster_types::CPU; use graphene_core::raster_types::CPU;
use graphene_core::transform::ReferencePoint; use graphene_core::transform::ReferencePoint;
use graphene_core::uuid::NodeId; use graphene_core::uuid::NodeId;
@ -209,29 +209,29 @@ tagged_value! {
#[serde(alias = "GradientPositions")] // TODO: Eventually remove this alias document upgrade code #[serde(alias = "GradientPositions")] // TODO: Eventually remove this alias document upgrade code
GradientStops(graphene_core::vector::style::GradientStops), GradientStops(graphene_core::vector::style::GradientStops),
Font(graphene_core::text::Font), Font(graphene_core::text::Font),
BrushStrokes(Vec<graphene_core::vector::brush_stroke::BrushStroke>), BrushStrokes(Vec<BrushStroke>),
BrushCache(BrushCache), BrushCache(BrushCache),
DocumentNode(DocumentNode), DocumentNode(DocumentNode),
Curve(graphene_core::raster::curve::Curve), Curve(graphene_raster_nodes::curve::Curve),
Footprint(graphene_core::transform::Footprint), Footprint(graphene_core::transform::Footprint),
VectorModification(Box<graphene_core::vector::VectorModification>), VectorModification(Box<graphene_core::vector::VectorModification>),
FontCache(Arc<graphene_core::text::FontCache>), FontCache(Arc<graphene_core::text::FontCache>),
// ========== // ==========
// ENUM TYPES // ENUM TYPES
// ========== // ==========
BlendMode(BlendMode), BlendMode(graphene_core::blending::BlendMode),
LuminanceCalculation(LuminanceCalculation), LuminanceCalculation(graphene_raster_nodes::adjustments::LuminanceCalculation),
XY(graphene_core::extract_xy::XY), XY(graphene_core::extract_xy::XY),
RedGreenBlue(graphene_core::raster::RedGreenBlue), RedGreenBlue(graphene_raster_nodes::adjustments::RedGreenBlue),
RedGreenBlueAlpha(graphene_core::raster::RedGreenBlueAlpha), RedGreenBlueAlpha(graphene_raster_nodes::adjustments::RedGreenBlueAlpha),
RealTimeMode(graphene_core::animation::RealTimeMode), RealTimeMode(graphene_core::animation::RealTimeMode),
NoiseType(graphene_core::raster::NoiseType), NoiseType(graphene_raster_nodes::adjustments::NoiseType),
FractalType(graphene_core::raster::FractalType), FractalType(graphene_raster_nodes::adjustments::FractalType),
CellularDistanceFunction(graphene_core::raster::CellularDistanceFunction), CellularDistanceFunction(graphene_raster_nodes::adjustments::CellularDistanceFunction),
CellularReturnType(graphene_core::raster::CellularReturnType), CellularReturnType(graphene_raster_nodes::adjustments::CellularReturnType),
DomainWarpType(graphene_core::raster::DomainWarpType), DomainWarpType(graphene_raster_nodes::adjustments::DomainWarpType),
RelativeAbsolute(graphene_core::raster::RelativeAbsolute), RelativeAbsolute(graphene_raster_nodes::adjustments::RelativeAbsolute),
SelectiveColorChoice(graphene_core::raster::SelectiveColorChoice), SelectiveColorChoice(graphene_raster_nodes::adjustments::SelectiveColorChoice),
GridType(graphene_core::vector::misc::GridType), GridType(graphene_core::vector::misc::GridType),
ArcType(graphene_core::vector::misc::ArcType), ArcType(graphene_core::vector::misc::ArcType),
MergeByDistanceAlgorithm(graphene_core::vector::misc::MergeByDistanceAlgorithm), MergeByDistanceAlgorithm(graphene_core::vector::misc::MergeByDistanceAlgorithm),

View file

@ -0,0 +1,35 @@
[package]
name = "graphene-raster-nodes"
version = "0.1.0"
edition = "2024"
description = "graphene raster data format"
authors = ["Graphite Authors <contact@graphite.rs>"]
license = "MIT OR Apache-2.0"
[features]
default = ["serde"]
serde = ["dep:serde"]
[dependencies]
# Local dependencies
dyn-any = { workspace = true }
graphene-core = { workspace = true }
node-macro = { workspace = true }
# Workspace dependencies
glam = { workspace = true }
specta = { workspace = true }
image = { workspace = true }
bytemuck = { workspace = true }
ndarray = { workspace = true }
bezier-rs = { workspace = true }
rand = { workspace = true }
rand_chacha = { workspace = true }
fastnoise-lite = { workspace = true }
# Optional workspace dependencies
serde = { workspace = true, optional = true, features = ["derive"] }
[dev-dependencies]
tokio = { workspace = true }
futures = { workspace = true }

View file

@ -1,16 +1,16 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use crate::GraphicElement; use crate::curve::CubicSplines;
use crate::blending::BlendMode;
use crate::raster::curve::{CubicSplines, CurveManipulatorGroup};
use crate::raster::curve::{Curve, ValueMapperNode};
use crate::raster::image::Image;
use crate::raster::{Channel, Color, Pixel};
use crate::raster_types::{CPU, Raster, RasterDataTable};
use crate::registry::types::{Angle, Percentage, SignedPercentage};
use crate::vector::style::GradientStops;
use crate::{Ctx, Node};
use dyn_any::DynAny; use dyn_any::DynAny;
use graphene_core::Node;
use graphene_core::blending::BlendMode;
use graphene_core::color::Color;
use graphene_core::color::Pixel;
use graphene_core::context::Ctx;
use graphene_core::gradient::GradientStops;
use graphene_core::raster::image::Image;
use graphene_core::raster_types::{CPU, Raster, RasterDataTable};
use graphene_core::registry::types::{Angle, Percentage, SignedPercentage};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt::Debug; use std::fmt::Debug;
@ -576,10 +576,7 @@ impl Adjust<Color> for GradientStops {
} }
} }
} }
impl Adjust<Color> for RasterDataTable<CPU> impl Adjust<Color> for RasterDataTable<CPU> {
where
GraphicElement: From<Image<Color>>,
{
fn adjust(&mut self, map_fn: impl Fn(&Color) -> Color) { fn adjust(&mut self, map_fn: impl Fn(&Color) -> Color) {
for instance in self.instance_mut_iter() { for instance in self.instance_mut_iter() {
for c in instance.instance.data_mut().data.iter_mut() { for c in instance.instance.data_mut().data.iter_mut() {
@ -1130,48 +1127,6 @@ async fn exposure<T: Adjust<Color>>(
input input
} }
const WINDOW_SIZE: usize = 1024;
#[node_macro::node(category(""))]
fn generate_curves<C: Channel + crate::raster::Linear>(_: impl Ctx, curve: Curve, #[implementations(f32, f64)] _target_format: C) -> ValueMapperNode<C> {
use bezier_rs::{Bezier, TValue};
let [mut pos, mut param]: [[f32; 2]; 2] = [[0.; 2], curve.first_handle];
let mut lut = vec![C::from_f64(0.); WINDOW_SIZE];
let end = CurveManipulatorGroup {
anchor: [1.; 2],
handles: [curve.last_handle, [0.; 2]],
};
for sample in curve.manipulator_groups.iter().chain(std::iter::once(&end)) {
let [x0, y0, x1, y1, x2, y2, x3, y3] = [pos[0], pos[1], param[0], param[1], sample.handles[0][0], sample.handles[0][1], sample.anchor[0], sample.anchor[1]].map(f64::from);
let bezier = Bezier::from_cubic_coordinates(x0, y0, x1, y1, x2, y2, x3, y3);
let [left, right] = [pos[0], sample.anchor[0]].map(|c| c.clamp(0., 1.));
let lut_index_left: usize = (left * (lut.len() - 1) as f32).floor() as _;
let lut_index_right: usize = (right * (lut.len() - 1) as f32).ceil() as _;
for index in lut_index_left..=lut_index_right {
let x = index as f64 / (lut.len() - 1) as f64;
let y = if x <= x0 {
y0
} else if x >= x3 {
y3
} else {
bezier.find_tvalues_for_x(x)
.next()
.map(|t| bezier.evaluate(TValue::Parametric(t.clamp(0., 1.))).y)
// Fall back to a very bad approximation if Bezier-rs fails
.unwrap_or_else(|| (x - x0) / (x3 - x0) * (y3 - y0) + y0)
};
lut[index] = C::from_f64(y);
}
pos = sample.anchor;
param = sample.handles[1];
}
ValueMapperNode::new(lut)
}
#[node_macro::node(category("Raster: Adjustment"))] #[node_macro::node(category("Raster: Adjustment"))]
fn color_overlay<T: Adjust<Color>>( fn color_overlay<T: Adjust<Color>>(
_: impl Ctx, _: impl Ctx,
@ -1224,10 +1179,10 @@ fn color_overlay<T: Adjust<Color>>(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::Color; use graphene_core::blending::BlendMode;
use crate::blending::BlendMode; use graphene_core::color::Color;
use crate::raster::image::Image; use graphene_core::raster::image::Image;
use crate::raster_types::{Raster, RasterDataTable}; use graphene_core::raster_types::{Raster, RasterDataTable};
#[tokio::test] #[tokio::test]
async fn color_overlay_multiply() { async fn color_overlay_multiply() {

View file

@ -1,6 +1,7 @@
use super::{Channel, Linear, LuminanceMut};
use crate::Node;
use dyn_any::{DynAny, StaticType, StaticTypeSized}; use dyn_any::{DynAny, StaticType, StaticTypeSized};
use graphene_core::Node;
use graphene_core::color::{Channel, Linear, LuminanceMut};
use std::hash::{Hash, Hasher};
use std::ops::{Add, Mul, Sub}; use std::ops::{Add, Mul, Sub};
#[derive(Debug, Clone, PartialEq, DynAny, specta::Type, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, DynAny, specta::Type, serde::Serialize, serde::Deserialize)]
@ -23,8 +24,8 @@ impl Default for Curve {
} }
} }
impl std::hash::Hash for Curve { impl Hash for Curve {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.manipulator_groups.hash(state); self.manipulator_groups.hash(state);
[self.first_handle, self.last_handle].iter().flatten().for_each(|f| f.to_bits().hash(state)); [self.first_handle, self.last_handle].iter().flatten().for_each(|f| f.to_bits().hash(state));
} }
@ -36,8 +37,8 @@ pub struct CurveManipulatorGroup {
pub handles: [[f32; 2]; 2], pub handles: [[f32; 2]; 2],
} }
impl std::hash::Hash for CurveManipulatorGroup { impl Hash for CurveManipulatorGroup {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
for c in self.handles.iter().chain([&self.anchor]).flatten() { for c in self.handles.iter().chain([&self.anchor]).flatten() {
c.to_bits().hash(state); c.to_bits().hash(state);
} }

View file

@ -1,7 +1,7 @@
use graph_craft::proto::types::Percentage; use graphene_core::context::Ctx;
use graphene_core::Ctx;
use graphene_core::raster::image::Image; use graphene_core::raster::image::Image;
use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::raster_types::{CPU, Raster, RasterDataTable};
use graphene_core::registry::types::Percentage;
use image::{DynamicImage, GenericImage, GenericImageView, GrayImage, ImageBuffer, Luma, Rgba, RgbaImage}; use image::{DynamicImage, GenericImage, GenericImageView, GrayImage, ImageBuffer, Luma, Rgba, RgbaImage};
use ndarray::{Array2, ArrayBase, Dim, OwnedRepr}; use ndarray::{Array2, ArrayBase, Dim, OwnedRepr};
use std::cmp::{max, min}; use std::cmp::{max, min};
@ -15,7 +15,7 @@ async fn dehaze(_: impl Ctx, image_frame: RasterDataTable<CPU>, strength: Percen
// Prepare the image data for processing // Prepare the image data for processing
let image_data = bytemuck::cast_vec(image.data.clone()); let image_data = bytemuck::cast_vec(image.data.clone());
let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, image_data).expect("Failed to convert internal image format into image-rs data type."); let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, image_data).expect("Failed to convert internal image format into image-rs data type.");
let dynamic_image: image::DynamicImage = image_buffer.into(); let dynamic_image: DynamicImage = image_buffer.into();
// Run the dehaze algorithm // Run the dehaze algorithm
let dehazed_dynamic_image = dehaze_image(dynamic_image, strength / 100.); let dehazed_dynamic_image = dehaze_image(dynamic_image, strength / 100.);

View file

@ -1,8 +1,9 @@
use graph_craft::proto::types::PixelLength; use graphene_core::color::Color;
use graphene_core::context::Ctx;
use graphene_core::raster::image::Image; use graphene_core::raster::image::Image;
use graphene_core::raster::{Bitmap, BitmapMut}; use graphene_core::raster::{Bitmap, BitmapMut};
use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::raster_types::{CPU, Raster, RasterDataTable};
use graphene_core::{Color, Ctx}; use graphene_core::registry::types::PixelLength;
/// Blurs the image with a Gaussian or blur kernel filter. /// Blurs the image with a Gaussian or blur kernel filter.
#[node_macro::node(category("Raster: Filter"))] #[node_macro::node(category("Raster: Filter"))]

View file

@ -0,0 +1,46 @@
//! requires bezier-rs
use crate::curve::{Curve, CurveManipulatorGroup, ValueMapperNode};
use bezier_rs::{Bezier, TValue};
use graphene_core::color::{Channel, Linear};
use graphene_core::context::Ctx;
const WINDOW_SIZE: usize = 1024;
#[node_macro::node(category(""))]
fn generate_curves<C: Channel + Linear>(_: impl Ctx, curve: Curve, #[implementations(f32, f64)] _target_format: C) -> ValueMapperNode<C> {
let [mut pos, mut param]: [[f32; 2]; 2] = [[0.; 2], curve.first_handle];
let mut lut = vec![C::from_f64(0.); WINDOW_SIZE];
let end = CurveManipulatorGroup {
anchor: [1.; 2],
handles: [curve.last_handle, [0.; 2]],
};
for sample in curve.manipulator_groups.iter().chain(std::iter::once(&end)) {
let [x0, y0, x1, y1, x2, y2, x3, y3] = [pos[0], pos[1], param[0], param[1], sample.handles[0][0], sample.handles[0][1], sample.anchor[0], sample.anchor[1]].map(f64::from);
let bezier = Bezier::from_cubic_coordinates(x0, y0, x1, y1, x2, y2, x3, y3);
let [left, right] = [pos[0], sample.anchor[0]].map(|c| c.clamp(0., 1.));
let lut_index_left: usize = (left * (lut.len() - 1) as f32).floor() as _;
let lut_index_right: usize = (right * (lut.len() - 1) as f32).ceil() as _;
for index in lut_index_left..=lut_index_right {
let x = index as f64 / (lut.len() - 1) as f64;
let y = if x <= x0 {
y0
} else if x >= x3 {
y3
} else {
bezier.find_tvalues_for_x(x)
.next()
.map(|t| bezier.evaluate(TValue::Parametric(t.clamp(0., 1.))).y)
// Fall back to a very bad approximation if Bezier-rs fails
.unwrap_or_else(|| (x - x0) / (x3 - x0) * (y3 - y0) + y0)
};
lut[index] = C::from_f64(y);
}
pos = sample.anchor;
param = sample.handles[1];
}
ValueMapperNode::new(lut)
}

View file

@ -1,5 +1,6 @@
use graphene_core::color::Color;
use graphene_core::context::Ctx;
use graphene_core::raster_types::{CPU, RasterDataTable}; use graphene_core::raster_types::{CPU, RasterDataTable};
use graphene_core::{Color, Ctx};
#[node_macro::node(category("Color"))] #[node_macro::node(category("Color"))]
async fn image_color_palette( async fn image_color_palette(

View file

@ -0,0 +1,7 @@
pub mod adjustments;
pub mod curve;
pub mod dehaze;
pub mod filter;
pub mod generate_curves;
pub mod image_color_palette;
pub mod std_nodes;

View file

@ -1,12 +1,17 @@
use crate::adjustments::{CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, NoiseType};
use dyn_any::DynAny; use dyn_any::DynAny;
use fastnoise_lite; use fastnoise_lite;
use glam::{DAffine2, DVec2, Vec2}; use glam::{DAffine2, DVec2, Vec2};
use graphene_core::blending::AlphaBlending;
use graphene_core::color::Color;
use graphene_core::color::{Alpha, AlphaMut, Channel, LinearChannel, Luminance, RGBMut};
use graphene_core::context::{Ctx, ExtractFootprint};
use graphene_core::instances::Instance; use graphene_core::instances::Instance;
use graphene_core::math::bbox::Bbox; use graphene_core::math::bbox::Bbox;
pub use graphene_core::raster::*; use graphene_core::raster::image::Image;
use graphene_core::raster::{Bitmap, BitmapMut};
use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::raster_types::{CPU, Raster, RasterDataTable};
use graphene_core::transform::Transform; use graphene_core::transform::Transform;
use graphene_core::{Ctx, ExtractFootprint};
use rand::prelude::*; use rand::prelude::*;
use rand_chacha::ChaCha8Rng; use rand_chacha::ChaCha8Rng;
use std::fmt::Debug; use std::fmt::Debug;
@ -25,7 +30,7 @@ impl From<std::io::Error> for Error {
} }
#[node_macro::node(category("Debug: Raster"))] #[node_macro::node(category("Debug: Raster"))]
fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: RasterDataTable<CPU>) -> RasterDataTable<CPU> { pub fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: RasterDataTable<CPU>) -> RasterDataTable<CPU> {
let mut result_table = RasterDataTable::default(); let mut result_table = RasterDataTable::default();
for mut image_frame_instance in image_frame.instance_iter() { for mut image_frame_instance in image_frame.instance_iter() {
@ -92,7 +97,7 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: RasterDa
} }
#[node_macro::node(category("Raster: Channels"))] #[node_macro::node(category("Raster: Channels"))]
fn combine_channels( pub fn combine_channels(
_: impl Ctx, _: impl Ctx,
_primary: (), _primary: (),
#[expose] red: RasterDataTable<CPU>, #[expose] red: RasterDataTable<CPU>,
@ -181,7 +186,7 @@ fn combine_channels(
} }
#[node_macro::node(category("Raster"))] #[node_macro::node(category("Raster"))]
fn mask( pub fn mask(
_: impl Ctx, _: impl Ctx,
/// The image to be masked. /// The image to be masked.
image: RasterDataTable<CPU>, image: RasterDataTable<CPU>,
@ -301,13 +306,13 @@ pub fn empty_image(_: impl Ctx, transform: DAffine2, color: Color) -> RasterData
/// Constructs a raster image. /// Constructs a raster image.
#[node_macro::node(category(""))] #[node_macro::node(category(""))]
fn image_value(_: impl Ctx, _primary: (), image: RasterDataTable<CPU>) -> RasterDataTable<CPU> { pub fn image_value(_: impl Ctx, _primary: (), image: RasterDataTable<CPU>) -> RasterDataTable<CPU> {
image image
} }
#[node_macro::node(category("Raster: Pattern"))] #[node_macro::node(category("Raster: Pattern"))]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn noise_pattern( pub fn noise_pattern(
ctx: impl ExtractFootprint + Ctx, ctx: impl ExtractFootprint + Ctx,
_primary: (), _primary: (),
clip: bool, clip: bool,
@ -463,7 +468,7 @@ fn noise_pattern(
} }
#[node_macro::node(category("Raster: Pattern"))] #[node_macro::node(category("Raster: Pattern"))]
fn mandelbrot(ctx: impl ExtractFootprint + Send) -> RasterDataTable<CPU> { pub fn mandelbrot(ctx: impl ExtractFootprint + Send) -> RasterDataTable<CPU> {
let footprint = ctx.footprint(); let footprint = ctx.footprint();
let viewport_bounds = footprint.viewport_bounds_in_local_space(); let viewport_bounds = footprint.viewport_bounds_in_local_space();

View file

@ -32,6 +32,8 @@ graphene-path-bool = { workspace = true }
graphene-math-nodes = { workspace = true } graphene-math-nodes = { workspace = true }
graphene-svg-renderer = { workspace = true } graphene-svg-renderer = { workspace = true }
graphene-application-io = { workspace = true } graphene-application-io = { workspace = true }
graphene-raster-nodes = { workspace = true }
graphene-brush = { workspace = true }
# Workspace dependencies # Workspace dependencies
fastnoise-lite = { workspace = true } fastnoise-lite = { workspace = true }

View file

@ -1,23 +1,26 @@
pub mod any; pub mod any;
pub mod brush;
pub mod dehaze;
pub mod filter;
pub mod http; pub mod http;
pub mod image_color_palette;
pub mod raster;
pub mod text; pub mod text;
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
pub mod wasm_application_io; pub mod wasm_application_io;
pub use graphene_application_io as application_io; pub use graphene_application_io as application_io;
pub use graphene_brush as brush;
pub use graphene_core::vector; pub use graphene_core::vector;
pub use graphene_core::*; pub use graphene_core::*;
pub use graphene_math_nodes as math_nodes; pub use graphene_math_nodes as math_nodes;
pub use graphene_path_bool as path_bool; pub use graphene_path_bool as path_bool;
pub use graphene_raster_nodes as raster_nodes;
/// stop gap solution until all `Quad` and `Rect` paths have been replaced with their absolute ones /// stop gap solutions until all paths have been replaced with their absolute ones
pub mod renderer { pub mod renderer {
pub use graphene_core::math::quad::Quad; pub use graphene_core::math::quad::Quad;
pub use graphene_core::math::rect::Rect; pub use graphene_core::math::rect::Rect;
pub use graphene_svg_renderer::*; pub use graphene_svg_renderer::*;
} }
pub mod raster {
pub use graphene_core::raster::*;
pub use graphene_raster_nodes::adjustments::*;
pub use graphene_raster_nodes::*;
}