mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Restructure node crates (#3384)
* Restructure node-graph folder * Fix wasm compilation * Move node definitions out of *-types crates * Cleanup * Fix warnings * Fix warnings * Start adding migrations * Add migrations and move memo nodes to gcore * Move nodes/gsvg-render -> rendering * Replace some hard coded identifiers and fix automatic conversion * Fix Vec2Value node migration * Fix formatting * Add more migrations * Cleanup features * Fix core_types::raster import * Update demo artwork (to make profile ci work) * Move *-types to node-graph/libraries folder * Add missing node migrations * Migrate more nodes * Remove impure memo node * More fixes and remove warning * Migrate context and add a few missing migrations --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
452
Cargo.lock
generated
452
Cargo.lock
generated
@@ -506,6 +506,18 @@ version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
||||
|
||||
[[package]]
|
||||
name = "blending-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"glam",
|
||||
"graphic-types",
|
||||
"node-macro",
|
||||
"serde",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
@@ -552,6 +564,20 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brush-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"node-macro",
|
||||
"raster-nodes",
|
||||
"raster-types",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.7.7"
|
||||
@@ -1025,6 +1051,37 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitflags 2.9.3",
|
||||
"bytemuck",
|
||||
"ctor",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"image",
|
||||
"kurbo 0.12.0",
|
||||
"log",
|
||||
"lyon_geom",
|
||||
"no-std-types",
|
||||
"node-macro",
|
||||
"num-traits",
|
||||
"parley",
|
||||
"petgraph 0.7.1",
|
||||
"polycool",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"skrifa 0.36.0",
|
||||
"specta",
|
||||
"tinyvec",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core_maths"
|
||||
version = "0.1.1"
|
||||
@@ -2048,25 +2105,28 @@ dependencies = [
|
||||
name = "graph-craft"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"brush-nodes",
|
||||
"core-types",
|
||||
"criterion",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graph-craft",
|
||||
"graphene-application-io",
|
||||
"graphene-brush",
|
||||
"graphene-core",
|
||||
"graphene-path-bool",
|
||||
"graphene-raster-nodes",
|
||||
"graphene-svg-renderer",
|
||||
"graphic-types",
|
||||
"iai-callgrind",
|
||||
"js-sys",
|
||||
"log",
|
||||
"path-bool-nodes",
|
||||
"pretty_assertions",
|
||||
"raster-nodes",
|
||||
"rendering",
|
||||
"reqwest",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"specta",
|
||||
"text-nodes",
|
||||
"tokio",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@@ -2079,28 +2139,17 @@ dependencies = [
|
||||
name = "graphene-application-io"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"log",
|
||||
"serde",
|
||||
"text-nodes",
|
||||
"vector-types",
|
||||
"web-sys",
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-brush"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"graphene-raster-nodes",
|
||||
"node-macro",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-cli"
|
||||
version = "0.1.0"
|
||||
@@ -2110,7 +2159,6 @@ dependencies = [
|
||||
"fern",
|
||||
"futures",
|
||||
"graph-craft",
|
||||
"graphene-core",
|
||||
"graphene-std",
|
||||
"interpreted-executor",
|
||||
"log",
|
||||
@@ -2124,120 +2172,16 @@ dependencies = [
|
||||
name = "graphene-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitflags 2.9.3",
|
||||
"bytemuck",
|
||||
"ctor",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphene-core-shaders",
|
||||
"image",
|
||||
"kurbo 0.12.0",
|
||||
"graphic-types",
|
||||
"log",
|
||||
"lyon_geom",
|
||||
"node-macro",
|
||||
"num-traits",
|
||||
"parley",
|
||||
"petgraph 0.7.1",
|
||||
"polycool",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"raster-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"skrifa 0.36.0",
|
||||
"specta",
|
||||
"tinyvec",
|
||||
"tokio",
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-core-shaders"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"half",
|
||||
"log",
|
||||
"node-macro",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"serde",
|
||||
"specta",
|
||||
"spirv-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-math-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"log",
|
||||
"math-parser",
|
||||
"node-macro",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-path-bool"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"log",
|
||||
"node-macro",
|
||||
"path-bool",
|
||||
"serde",
|
||||
"specta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-raster-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"dyn-any",
|
||||
"fastnoise-lite",
|
||||
"futures",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"graphene-core-shaders",
|
||||
"graphene-raster-nodes-shaders",
|
||||
"image",
|
||||
"kurbo 0.12.0",
|
||||
"ndarray",
|
||||
"node-macro",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"serde",
|
||||
"specta",
|
||||
"spirv-std",
|
||||
"tokio",
|
||||
"wgpu-executor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-raster-nodes-shaders"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo-gpu",
|
||||
"env_logger",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-raster-nodes-shaders-entrypoint"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"graphene-raster-nodes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2245,21 +2189,29 @@ name = "graphene-std"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"blending-nodes",
|
||||
"brush-nodes",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graph-craft",
|
||||
"graphene-application-io",
|
||||
"graphene-brush",
|
||||
"graphene-core",
|
||||
"graphene-math-nodes",
|
||||
"graphene-path-bool",
|
||||
"graphene-raster-nodes",
|
||||
"graphene-svg-renderer",
|
||||
"graphic-nodes",
|
||||
"graphic-types",
|
||||
"image",
|
||||
"log",
|
||||
"math-nodes",
|
||||
"node-macro",
|
||||
"path-bool-nodes",
|
||||
"raster-nodes",
|
||||
"rendering",
|
||||
"reqwest",
|
||||
"text-nodes",
|
||||
"tokio",
|
||||
"transform-nodes",
|
||||
"vector-nodes",
|
||||
"vector-types",
|
||||
"vello",
|
||||
"vello_encoding",
|
||||
"wasm-bindgen",
|
||||
@@ -2269,19 +2221,32 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-svg-renderer"
|
||||
name = "graphic-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"kurbo 0.12.0",
|
||||
"log",
|
||||
"num-traits",
|
||||
"graphic-types",
|
||||
"node-macro",
|
||||
"raster-types",
|
||||
"serde",
|
||||
"usvg 0.45.1",
|
||||
"vello",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphic-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"node-macro",
|
||||
"raster-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"specta",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2962,17 +2927,18 @@ dependencies = [
|
||||
name = "interpreted-executor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"criterion",
|
||||
"dyn-any",
|
||||
"futures",
|
||||
"glam",
|
||||
"graph-craft",
|
||||
"graphene-core",
|
||||
"graphene-path-bool",
|
||||
"graphene-std",
|
||||
"iai-callgrind",
|
||||
"log",
|
||||
"once_cell",
|
||||
"path-bool-nodes",
|
||||
"preprocessor",
|
||||
"serde",
|
||||
"wgpu-executor",
|
||||
@@ -3347,6 +3313,19 @@ dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "math-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"glam",
|
||||
"log",
|
||||
"math-parser",
|
||||
"node-macro",
|
||||
"rand 0.9.2",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "math-parser"
|
||||
version = "0.0.0"
|
||||
@@ -3603,14 +3582,33 @@ dependencies = [
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "no-std-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"half",
|
||||
"log",
|
||||
"node-macro",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"serde",
|
||||
"specta",
|
||||
"spirv-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "node-macro"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"convert_case 0.8.0",
|
||||
"graphene-core",
|
||||
"graphene-core-shaders",
|
||||
"core-types",
|
||||
"indoc",
|
||||
"no-std-types",
|
||||
"proc-macro-crate",
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
@@ -4074,6 +4072,22 @@ dependencies = [
|
||||
"svg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "path-bool-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphic-types",
|
||||
"log",
|
||||
"node-macro",
|
||||
"path-bool",
|
||||
"serde",
|
||||
"specta",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.3"
|
||||
@@ -4604,6 +4618,68 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
|
||||
|
||||
[[package]]
|
||||
name = "raster-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"fastnoise-lite",
|
||||
"futures",
|
||||
"glam",
|
||||
"image",
|
||||
"kurbo 0.12.0",
|
||||
"ndarray",
|
||||
"no-std-types",
|
||||
"node-macro",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"raster-nodes-shaders",
|
||||
"raster-types",
|
||||
"serde",
|
||||
"specta",
|
||||
"spirv-std",
|
||||
"tokio",
|
||||
"vector-types",
|
||||
"wgpu-executor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raster-nodes-shaders"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo-gpu",
|
||||
"env_logger",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raster-nodes-shaders-entrypoint"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"raster-nodes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raster-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytemuck",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"image",
|
||||
"node-macro",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"specta",
|
||||
"wgpu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rav1e"
|
||||
version = "0.7.1"
|
||||
@@ -4786,6 +4862,24 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "rendering"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"graphic-types",
|
||||
"kurbo 0.12.0",
|
||||
"log",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"usvg 0.45.1",
|
||||
"vector-types",
|
||||
"vello",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.23"
|
||||
@@ -5744,6 +5838,21 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"log",
|
||||
"node-macro",
|
||||
"parley",
|
||||
"serde",
|
||||
"skrifa 0.36.0",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@@ -6124,6 +6233,18 @@ dependencies = [
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "transform-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"glam",
|
||||
"graphic-types",
|
||||
"node-macro",
|
||||
"serde",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.5"
|
||||
@@ -6408,6 +6529,48 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vector-nodes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"futures",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"graphic-types",
|
||||
"kurbo 0.12.0",
|
||||
"log",
|
||||
"node-macro",
|
||||
"rand 0.9.2",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"tokio",
|
||||
"vector-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vector-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.3",
|
||||
"bytemuck",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"kurbo 0.12.0",
|
||||
"log",
|
||||
"lyon_geom",
|
||||
"node-macro",
|
||||
"num-traits",
|
||||
"petgraph 0.7.1",
|
||||
"polycool",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"specta",
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vello"
|
||||
version = "0.6.0"
|
||||
@@ -6831,13 +6994,14 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytemuck",
|
||||
"core-types",
|
||||
"dyn-any",
|
||||
"futures",
|
||||
"glam",
|
||||
"graphene-application-io",
|
||||
"graphene-core",
|
||||
"graphene-svg-renderer",
|
||||
"node-macro",
|
||||
"raster-types",
|
||||
"rendering",
|
||||
"vello",
|
||||
"web-sys",
|
||||
"wgpu",
|
||||
|
||||
93
Cargo.toml
93
Cargo.toml
@@ -12,19 +12,28 @@ members = [
|
||||
"libraries/dyn-any",
|
||||
"libraries/path-bool",
|
||||
"libraries/math-parser",
|
||||
"node-graph/gapplication-io",
|
||||
"node-graph/gbrush",
|
||||
"node-graph/gcore",
|
||||
"node-graph/gcore-shaders",
|
||||
"node-graph/gmath-nodes",
|
||||
"node-graph/gpath-bool",
|
||||
"node-graph/libraries/application-io",
|
||||
"node-graph/libraries/core-types",
|
||||
"node-graph/libraries/no-std-types",
|
||||
"node-graph/libraries/raster-types",
|
||||
"node-graph/libraries/vector-types",
|
||||
"node-graph/libraries/graphic-types",
|
||||
"node-graph/libraries/rendering",
|
||||
"node-graph/nodes/blending",
|
||||
"node-graph/nodes/brush",
|
||||
"node-graph/nodes/gcore",
|
||||
"node-graph/nodes/graphic",
|
||||
"node-graph/nodes/math",
|
||||
"node-graph/nodes/path-bool",
|
||||
"node-graph/nodes/raster",
|
||||
"node-graph/nodes/raster/shaders",
|
||||
"node-graph/nodes/raster/shaders/entrypoint",
|
||||
"node-graph/nodes/text",
|
||||
"node-graph/nodes/transform",
|
||||
"node-graph/nodes/vector",
|
||||
"node-graph/graph-craft",
|
||||
"node-graph/graphene-cli",
|
||||
"node-graph/graster-nodes",
|
||||
"node-graph/graster-nodes/shaders",
|
||||
"node-graph/graster-nodes/shaders/entrypoint",
|
||||
"node-graph/gstd",
|
||||
"node-graph/gsvg-renderer",
|
||||
"node-graph/nodes/gstd",
|
||||
"node-graph/interpreted-executor",
|
||||
"node-graph/node-macro",
|
||||
"node-graph/preprocessor",
|
||||
@@ -37,18 +46,27 @@ default-members = [
|
||||
"libraries/dyn-any",
|
||||
"libraries/path-bool",
|
||||
"libraries/math-parser",
|
||||
"node-graph/gapplication-io",
|
||||
"node-graph/gbrush",
|
||||
"node-graph/gcore",
|
||||
"node-graph/gcore-shaders",
|
||||
"node-graph/graster-nodes/shaders",
|
||||
"node-graph/gmath-nodes",
|
||||
"node-graph/gpath-bool",
|
||||
"node-graph/libraries/application-io",
|
||||
"node-graph/libraries/core-types",
|
||||
"node-graph/libraries/no-std-types",
|
||||
"node-graph/libraries/raster-types",
|
||||
"node-graph/libraries/vector-types",
|
||||
"node-graph/libraries/graphic-types",
|
||||
"node-graph/libraries/rendering",
|
||||
"node-graph/nodes/blending",
|
||||
"node-graph/nodes/brush",
|
||||
"node-graph/nodes/gcore",
|
||||
"node-graph/nodes/graphic",
|
||||
"node-graph/nodes/math",
|
||||
"node-graph/nodes/path-bool",
|
||||
"node-graph/nodes/raster",
|
||||
"node-graph/nodes/raster/shaders",
|
||||
"node-graph/nodes/text",
|
||||
"node-graph/nodes/transform",
|
||||
"node-graph/nodes/vector",
|
||||
"node-graph/graph-craft",
|
||||
"node-graph/graphene-cli",
|
||||
"node-graph/graster-nodes",
|
||||
"node-graph/gstd",
|
||||
"node-graph/gsvg-renderer",
|
||||
"node-graph/nodes/gstd",
|
||||
"node-graph/interpreted-executor",
|
||||
"node-graph/node-macro",
|
||||
"node-graph/preprocessor",
|
||||
@@ -70,16 +88,25 @@ dyn-any = { path = "libraries/dyn-any", features = [
|
||||
preprocessor = { path = "node-graph/preprocessor" }
|
||||
math-parser = { path = "libraries/math-parser" }
|
||||
path-bool = { path = "libraries/path-bool" }
|
||||
graphene-application-io = { path = "node-graph/gapplication-io" }
|
||||
graphene-brush = { path = "node-graph/gbrush" }
|
||||
graphene-core = { path = "node-graph/gcore" }
|
||||
graphene-core-shaders = { path = "node-graph/gcore-shaders" }
|
||||
graphene-math-nodes = { path = "node-graph/gmath-nodes" }
|
||||
graphene-path-bool = { path = "node-graph/gpath-bool" }
|
||||
graphene-application-io = { path = "node-graph/libraries/application-io" }
|
||||
core-types = { path = "node-graph/libraries/core-types" }
|
||||
no-std-types = { path = "node-graph/libraries/no-std-types" }
|
||||
raster-types = { path = "node-graph/libraries/raster-types" }
|
||||
vector-types = { path = "node-graph/libraries/vector-types" }
|
||||
graphic-types = { path = "node-graph/libraries/graphic-types" }
|
||||
rendering = { path = "node-graph/libraries/rendering" }
|
||||
brush-nodes = { path = "node-graph/nodes/brush" }
|
||||
blending-nodes = { path = "node-graph/nodes/blending" }
|
||||
graphene-core = { path = "node-graph/nodes/gcore" }
|
||||
graphic-nodes = { path = "node-graph/nodes/graphic" }
|
||||
text-nodes = { path = "node-graph/nodes/text" }
|
||||
transform-nodes = { path = "node-graph/nodes/transform" }
|
||||
vector-nodes = { path = "node-graph/nodes/vector" }
|
||||
math-nodes = { path = "node-graph/nodes/math" }
|
||||
path-bool-nodes = { path = "node-graph/nodes/path-bool" }
|
||||
graph-craft = { path = "node-graph/graph-craft" }
|
||||
graphene-raster-nodes = { path = "node-graph/graster-nodes" }
|
||||
graphene-std = { path = "node-graph/gstd" }
|
||||
graphene-svg-renderer = { path = "node-graph/gsvg-renderer" }
|
||||
raster-nodes = { path = "node-graph/nodes/raster" }
|
||||
graphene-std = { path = "node-graph/nodes/gstd" }
|
||||
interpreted-executor = { path = "node-graph/interpreted-executor" }
|
||||
node-macro = { path = "node-graph/node-macro" }
|
||||
wgpu-executor = { path = "node-graph/wgpu-executor" }
|
||||
@@ -209,9 +236,8 @@ unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spir
|
||||
opt-level = 1
|
||||
|
||||
[profile.dev.package]
|
||||
graphite-editor = { opt-level = 1 }
|
||||
graphene-core-shaders = { opt-level = 1 }
|
||||
graphene-std = { opt-level = 1 }
|
||||
no-std-types = { opt-level = 1 }
|
||||
core-types= { opt-level = 1 }
|
||||
interpreted-executor = { opt-level = 1 } # This is a mitigation for https://github.com/rustwasm/wasm-pack/issues/981 which is needed because the node_registry function is too large
|
||||
graphite-proc-macros = { opt-level = 1 }
|
||||
image = { opt-level = 2 }
|
||||
@@ -219,6 +245,7 @@ rustc-hash = { opt-level = 3 }
|
||||
serde_derive = { opt-level = 1 }
|
||||
specta-macros = { opt-level = 1 }
|
||||
syn = { opt-level = 1 }
|
||||
node-macro = { opt-level = 2 }
|
||||
|
||||
[profile.release]
|
||||
lto = "thin"
|
||||
|
||||
2
demo-artwork/changing-seasons.graphite
generated
2
demo-artwork/changing-seasons.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/isometric-fountain.graphite
generated
2
demo-artwork/isometric-fountain.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/painted-dreams.graphite
generated
2
demo-artwork/painted-dreams.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/parametric-dunescape.graphite
generated
2
demo-artwork/parametric-dunescape.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/procedural-string-lights.graphite
generated
2
demo-artwork/procedural-string-lights.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/red-dress.graphite
generated
2
demo-artwork/red-dress.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/valley-of-spires.graphite
generated
2
demo-artwork/valley-of-spires.graphite
generated
File diff suppressed because one or more lines are too long
@@ -15,7 +15,6 @@ gpu = ["graphite-editor/gpu", "graphene-std/shader-nodes"]
|
||||
# Local dependencies
|
||||
graphite-editor = { path = "../../editor", features = [
|
||||
"gpu",
|
||||
"vello",
|
||||
] }
|
||||
graphene-std = { workspace = true }
|
||||
graph-craft = { workspace = true }
|
||||
|
||||
@@ -11,18 +11,16 @@ repository = "https://github.com/GraphiteEditor/Graphite"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[features]
|
||||
default = ["wasm"]
|
||||
default = ["wasm", "gpu" ]
|
||||
wasm = ["wasm-bindgen", "graphene-std/wasm"]
|
||||
gpu = ["interpreted-executor/gpu", "wgpu-executor"]
|
||||
resvg = ["graphene-std/resvg"]
|
||||
vello = ["graphene-std/vello", "resvg"]
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
graphite-proc-macros = { workspace = true }
|
||||
graph-craft = { workspace = true }
|
||||
interpreted-executor = { workspace = true }
|
||||
graphene-std = { workspace = true } # NOTE: `graphene-core` should not be added here because `graphene-std` re-exports its contents
|
||||
graphene-std = { workspace = true } # NOTE: `core-types` should not be added here because `graphene-std` re-exports its contents
|
||||
preprocessor = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
@@ -59,8 +57,3 @@ env_logger = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[lints.rust]
|
||||
# TODO: figure out why we check these features when they do not exist
|
||||
unexpected_cfgs = { level = "warn", check-cfg = [
|
||||
'cfg(feature, values("resvg", "vello"))',
|
||||
] }
|
||||
|
||||
@@ -449,7 +449,7 @@ impl TableRowLayout for Vector {
|
||||
|
||||
table_rows.push(vec![
|
||||
TextLabel::new("Upstream Nested Layers").narrow(true).widget_holder(),
|
||||
TextLabel::new(if self.upstream_nested_layers.is_some() {
|
||||
TextLabel::new(if self.upstream_data.is_some() {
|
||||
"Yes (this preserves references to its upstream nested layers for editing by tools)"
|
||||
} else {
|
||||
"No (this doesn't preserve references to its upstream nested layers for editing by tools)"
|
||||
|
||||
@@ -881,24 +881,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Memoize Impure",
|
||||
category: "Debug",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
input_metadata: vec![("Image", "TODO").into()],
|
||||
output_names: vec!["Image".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
#[cfg(feature = "gpu")]
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Create GPU Surface",
|
||||
@@ -915,7 +897,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
@@ -986,7 +968,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
DocumentNode {
|
||||
call_argument: generic!(T),
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
@@ -1073,7 +1055,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
// category: "Raster: Adjustment",
|
||||
// node_template: NodeTemplate {
|
||||
// document_node: DocumentNode {
|
||||
// implementation: DocumentNodeImplementation::proto("graphene_core::raster::CurvesNode"),
|
||||
// implementation: DocumentNodeImplementation::proto("core_types::raster::CurvesNode"),
|
||||
// inputs: vec![
|
||||
// NodeInput::value(TaggedValue::Raster(Default::default()), true),
|
||||
// NodeInput::value(TaggedValue::Curve(Default::default()), false),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -150,10 +150,7 @@ impl NodeGraphExecutor {
|
||||
viewport,
|
||||
scale: viewport_scale,
|
||||
time,
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
export_format: graphene_std::application_io::ExportFormat::Raster,
|
||||
#[cfg(not(any(feature = "resvg", feature = "vello")))]
|
||||
export_format: graphene_std::application_io::ExportFormat::Svg,
|
||||
render_mode: document.render_mode,
|
||||
hide_artboards: false,
|
||||
for_export: false,
|
||||
|
||||
@@ -302,7 +302,7 @@ impl NodeRuntime {
|
||||
self.monitor_nodes = proto_network
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|(_, node)| node.identifier == "graphene_core::memo::MonitorNode".into())
|
||||
.filter(|(_, node)| node.identifier == graphene_std::memo::monitor::IDENTIFIER)
|
||||
.map(|(_, node)| node.original_location.path.clone().unwrap_or_default())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ crate-type = ["cdylib", "rlib"]
|
||||
# Local dependencies
|
||||
editor = { path = "../../editor", package = "graphite-editor", features = [
|
||||
"gpu",
|
||||
"resvg",
|
||||
"vello",
|
||||
] }
|
||||
graphene-std = { workspace = true }
|
||||
|
||||
|
||||
@@ -1,625 +0,0 @@
|
||||
use crate::blending::AlphaBlending;
|
||||
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use crate::gradient::GradientStops;
|
||||
use crate::raster_types::{CPU, GPU, Raster};
|
||||
use crate::table::{Table, TableRow};
|
||||
use crate::uuid::NodeId;
|
||||
use crate::vector::Vector;
|
||||
use crate::{Artboard, Color, Ctx};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::hash::Hash;
|
||||
|
||||
/// The possible forms of graphical content that can be rendered by the Render node into either an image or SVG syntax.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Graphic {
|
||||
Graphic(Table<Graphic>),
|
||||
Vector(Table<Vector>),
|
||||
RasterCPU(Table<Raster<CPU>>),
|
||||
RasterGPU(Table<Raster<GPU>>),
|
||||
Color(Table<Color>),
|
||||
Gradient(Table<GradientStops>),
|
||||
}
|
||||
|
||||
impl Default for Graphic {
|
||||
fn default() -> Self {
|
||||
Self::Graphic(Table::new())
|
||||
}
|
||||
}
|
||||
|
||||
// Graphic
|
||||
impl From<Table<Graphic>> for Graphic {
|
||||
fn from(graphic: Table<Graphic>) -> Self {
|
||||
Graphic::Graphic(graphic)
|
||||
}
|
||||
}
|
||||
|
||||
// Vector
|
||||
impl From<Vector> for Graphic {
|
||||
fn from(vector: Vector) -> Self {
|
||||
Graphic::Vector(Table::new_from_element(vector))
|
||||
}
|
||||
}
|
||||
impl From<Table<Vector>> for Graphic {
|
||||
fn from(vector: Table<Vector>) -> Self {
|
||||
Graphic::Vector(vector)
|
||||
}
|
||||
}
|
||||
impl From<Vector> for Table<Graphic> {
|
||||
fn from(vector: Vector) -> Self {
|
||||
Table::new_from_element(Graphic::Vector(Table::new_from_element(vector)))
|
||||
}
|
||||
}
|
||||
impl From<Table<Vector>> for Table<Graphic> {
|
||||
fn from(vector: Table<Vector>) -> Self {
|
||||
Table::new_from_element(Graphic::Vector(vector))
|
||||
}
|
||||
}
|
||||
|
||||
// Raster<CPU>
|
||||
impl From<Raster<CPU>> for Graphic {
|
||||
fn from(raster: Raster<CPU>) -> Self {
|
||||
Graphic::RasterCPU(Table::new_from_element(raster))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<CPU>>> for Graphic {
|
||||
fn from(raster: Table<Raster<CPU>>) -> Self {
|
||||
Graphic::RasterCPU(raster)
|
||||
}
|
||||
}
|
||||
impl From<Raster<CPU>> for Table<Graphic> {
|
||||
fn from(raster: Raster<CPU>) -> Self {
|
||||
Table::new_from_element(Graphic::RasterCPU(Table::new_from_element(raster)))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<CPU>>> for Table<Graphic> {
|
||||
fn from(raster: Table<Raster<CPU>>) -> Self {
|
||||
Table::new_from_element(Graphic::RasterCPU(raster))
|
||||
}
|
||||
}
|
||||
|
||||
// Raster<GPU>
|
||||
impl From<Raster<GPU>> for Graphic {
|
||||
fn from(raster: Raster<GPU>) -> Self {
|
||||
Graphic::RasterGPU(Table::new_from_element(raster))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<GPU>>> for Graphic {
|
||||
fn from(raster: Table<Raster<GPU>>) -> Self {
|
||||
Graphic::RasterGPU(raster)
|
||||
}
|
||||
}
|
||||
impl From<Raster<GPU>> for Table<Graphic> {
|
||||
fn from(raster: Raster<GPU>) -> Self {
|
||||
Table::new_from_element(Graphic::RasterGPU(Table::new_from_element(raster)))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<GPU>>> for Table<Graphic> {
|
||||
fn from(raster: Table<Raster<GPU>>) -> Self {
|
||||
Table::new_from_element(Graphic::RasterGPU(raster))
|
||||
}
|
||||
}
|
||||
|
||||
// Color
|
||||
impl From<Color> for Graphic {
|
||||
fn from(color: Color) -> Self {
|
||||
Graphic::Color(Table::new_from_element(color))
|
||||
}
|
||||
}
|
||||
impl From<Table<Color>> for Graphic {
|
||||
fn from(color: Table<Color>) -> Self {
|
||||
Graphic::Color(color)
|
||||
}
|
||||
}
|
||||
impl From<Color> for Table<Graphic> {
|
||||
fn from(color: Color) -> Self {
|
||||
Table::new_from_element(Graphic::Color(Table::new_from_element(color)))
|
||||
}
|
||||
}
|
||||
impl From<Table<Color>> for Table<Graphic> {
|
||||
fn from(color: Table<Color>) -> Self {
|
||||
Table::new_from_element(Graphic::Color(color))
|
||||
}
|
||||
}
|
||||
|
||||
// Option<Color>
|
||||
impl From<Option<Color>> for Graphic {
|
||||
fn from(color: Option<Color>) -> Self {
|
||||
if let Some(color) = color {
|
||||
Graphic::Color(Table::new_from_element(color))
|
||||
} else {
|
||||
Graphic::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<Option<Color>> for Table<Graphic> {
|
||||
fn from(color: Option<Color>) -> Self {
|
||||
if let Some(color) = color {
|
||||
Table::new_from_element(Graphic::Color(Table::new_from_element(color)))
|
||||
} else {
|
||||
Table::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<Table<Color>> for Option<Color> {
|
||||
fn from(color: Table<Color>) -> Self {
|
||||
color.into_iter().next().map(|row| row.element)
|
||||
}
|
||||
}
|
||||
|
||||
// GradientStops
|
||||
impl From<GradientStops> for Graphic {
|
||||
fn from(gradient: GradientStops) -> Self {
|
||||
Graphic::Gradient(Table::new_from_element(gradient))
|
||||
}
|
||||
}
|
||||
impl From<Table<GradientStops>> for Graphic {
|
||||
fn from(gradient: Table<GradientStops>) -> Self {
|
||||
Graphic::Gradient(gradient)
|
||||
}
|
||||
}
|
||||
impl From<GradientStops> for Table<Graphic> {
|
||||
fn from(gradient: GradientStops) -> Self {
|
||||
Table::new_from_element(Graphic::Gradient(Table::new_from_element(gradient)))
|
||||
}
|
||||
}
|
||||
impl From<Table<GradientStops>> for Table<Graphic> {
|
||||
fn from(gradient: Table<GradientStops>) -> Self {
|
||||
Table::new_from_element(Graphic::Gradient(gradient))
|
||||
}
|
||||
}
|
||||
|
||||
// DAffine2
|
||||
impl From<DAffine2> for Graphic {
|
||||
fn from(_: DAffine2) -> Self {
|
||||
Graphic::default()
|
||||
}
|
||||
}
|
||||
impl From<DAffine2> for Table<Graphic> {
|
||||
fn from(_: DAffine2) -> Self {
|
||||
Table::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Graphic {
|
||||
pub fn as_graphic(&self) -> Option<&Table<Graphic>> {
|
||||
match self {
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_graphic_mut(&mut self) -> Option<&mut Table<Graphic>> {
|
||||
match self {
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector(&self) -> Option<&Table<Vector>> {
|
||||
match self {
|
||||
Graphic::Vector(vector) => Some(vector),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector_mut(&mut self) -> Option<&mut Table<Vector>> {
|
||||
match self {
|
||||
Graphic::Vector(vector) => Some(vector),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster(&self) -> Option<&Table<Raster<CPU>>> {
|
||||
match self {
|
||||
Graphic::RasterCPU(raster) => Some(raster),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster_mut(&mut self) -> Option<&mut Table<Raster<CPU>>> {
|
||||
match self {
|
||||
Graphic::RasterCPU(raster) => Some(raster),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn had_clip_enabled(&self) -> bool {
|
||||
match self {
|
||||
Graphic::Vector(vector) => vector.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Graphic(graphic) => graphic.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::RasterCPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::RasterGPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Color(color) => color.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Gradient(gradient) => gradient.iter().all(|row| row.alpha_blending.clip),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_reduce_to_clip_path(&self) -> bool {
|
||||
match self {
|
||||
Graphic::Vector(vector) => vector.iter().all(|row| {
|
||||
let style = &row.element.style;
|
||||
let alpha_blending = &row.alpha_blending;
|
||||
(alpha_blending.opacity > 1. - f32::EPSILON) && style.fill().is_opaque() && style.stroke().is_none_or(|stroke| !stroke.has_renderable_stroke())
|
||||
}),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundingBox for Graphic {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||
match self {
|
||||
Graphic::Vector(vector) => vector.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterCPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterGPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
Graphic::Graphic(graphic) => graphic.bounding_box(transform, include_stroke),
|
||||
Graphic::Color(color) => color.bounding_box(transform, include_stroke),
|
||||
Graphic::Gradient(gradient) => gradient.bounding_box(transform, include_stroke),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
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 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;
|
||||
for row in content.iter_mut() {
|
||||
*row.source_node_id = source_node_id;
|
||||
}
|
||||
|
||||
content
|
||||
}
|
||||
|
||||
/// Joins two tables of the same type, extending the base table with the rows of the new table.
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn extend<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
/// The table whose rows will appear at the start of the extended table.
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>, Table<Color>, Table<GradientStops>)]
|
||||
base: Table<I>,
|
||||
/// The table whose rows will appear at the end of the extended table.
|
||||
#[expose]
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>, Table<Color>, Table<GradientStops>)]
|
||||
new: Table<I>,
|
||||
) -> Table<I> {
|
||||
let mut base = base;
|
||||
base.extend(new);
|
||||
|
||||
base
|
||||
}
|
||||
|
||||
// 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,
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>, Table<Color>, Table<GradientStops>)] base: Table<I>,
|
||||
#[expose]
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>, Table<Color>, Table<GradientStops>)]
|
||||
new: Table<I>,
|
||||
nested_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).
|
||||
let source_node_id = nested_node_path.get(nested_node_path.len().wrapping_sub(2)).copied();
|
||||
|
||||
let mut base = base;
|
||||
for row in new.into_iter() {
|
||||
base.push(TableRow { source_node_id, ..row });
|
||||
}
|
||||
|
||||
base
|
||||
}
|
||||
|
||||
/// 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,
|
||||
#[implementations(
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
Table<Raster<CPU>>,
|
||||
Table<Raster<GPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
DAffine2,
|
||||
)]
|
||||
content: T,
|
||||
) -> Table<Graphic> {
|
||||
Table::new_from_element(content.into())
|
||||
}
|
||||
|
||||
/// Converts a table of graphical content into a graphic table by placing it into an element of a new wrapper graphic table.
|
||||
/// If it is already a graphic table, it is not wrapped again. Use the 'Wrap Graphic' node if wrapping is always desired.
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn to_graphic<T: Into<Table<Graphic>> + 'n>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
Table<Raster<CPU>>,
|
||||
Table<Raster<GPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
)]
|
||||
content: T,
|
||||
) -> Table<Graphic> {
|
||||
content.into()
|
||||
}
|
||||
|
||||
/// Removes a level of nesting from a graphic table, or all nesting if "Fully Flatten" is enabled.
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn flatten_graphic(_: impl Ctx, content: Table<Graphic>, fully_flatten: bool) -> Table<Graphic> {
|
||||
// TODO: Avoid mutable reference, instead return a new Table<Graphic>?
|
||||
fn flatten_table(output_graphic_table: &mut Table<Graphic>, current_graphic_table: Table<Graphic>, fully_flatten: bool, recursion_depth: usize) {
|
||||
for current_row in current_graphic_table.iter() {
|
||||
let current_element = current_row.element.clone();
|
||||
let reference = *current_row.source_node_id;
|
||||
|
||||
let recurse = fully_flatten || recursion_depth == 0;
|
||||
|
||||
match current_element {
|
||||
// If we're allowed to recurse, flatten any graphics we encounter
|
||||
Graphic::Graphic(mut current_element) if recurse => {
|
||||
// Apply the parent graphic's transform to all child elements
|
||||
for graphic in current_element.iter_mut() {
|
||||
*graphic.transform = *current_row.transform * *graphic.transform;
|
||||
}
|
||||
|
||||
flatten_table(output_graphic_table, current_element, fully_flatten, recursion_depth + 1);
|
||||
}
|
||||
// Push any leaf Graphic elements we encounter, which can be either Graphic table elements beyond the recursion depth, or table elements other than Graphic tables
|
||||
_ => {
|
||||
output_graphic_table.push(TableRow {
|
||||
element: current_element,
|
||||
transform: *current_row.transform,
|
||||
alpha_blending: *current_row.alpha_blending,
|
||||
source_node_id: reference,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = Table::new();
|
||||
flatten_table(&mut output, content, fully_flatten, 0);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Converts a graphic table into a vector table by deeply flattening any vector content it contains, and discarding any non-vector content.
|
||||
#[node_macro::node(category("Vector"))]
|
||||
async fn flatten_vector(_: impl Ctx, content: Table<Graphic>) -> Table<Vector> {
|
||||
// TODO: Avoid mutable reference, instead return a new Table<Graphic>?
|
||||
fn flatten_table(output_vector_table: &mut Table<Vector>, current_graphic_table: Table<Graphic>) {
|
||||
for current_graphic_row in current_graphic_table.iter() {
|
||||
let current_graphic = current_graphic_row.element.clone();
|
||||
let source_node_id = *current_graphic_row.source_node_id;
|
||||
|
||||
match current_graphic {
|
||||
// If we're allowed to recurse, flatten any tables we encounter
|
||||
Graphic::Graphic(mut current_graphic_table) => {
|
||||
// Apply the parent graphic's transform to all child elements
|
||||
for graphic in current_graphic_table.iter_mut() {
|
||||
*graphic.transform = *current_graphic_row.transform * *graphic.transform;
|
||||
}
|
||||
|
||||
flatten_table(output_vector_table, current_graphic_table);
|
||||
}
|
||||
// Push any leaf Vector elements we encounter
|
||||
Graphic::Vector(vector_table) => {
|
||||
for current_vector_row in vector_table.iter() {
|
||||
output_vector_table.push(TableRow {
|
||||
element: current_vector_row.element.clone(),
|
||||
transform: *current_graphic_row.transform * *current_vector_row.transform,
|
||||
alpha_blending: AlphaBlending {
|
||||
blend_mode: current_vector_row.alpha_blending.blend_mode,
|
||||
opacity: current_graphic_row.alpha_blending.opacity * current_vector_row.alpha_blending.opacity,
|
||||
fill: current_vector_row.alpha_blending.fill,
|
||||
clip: current_vector_row.alpha_blending.clip,
|
||||
},
|
||||
source_node_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = Table::new();
|
||||
flatten_table(&mut output, content);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Returns the value at the specified index in the collection.
|
||||
/// 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,
|
||||
/// The collection of data, such as a list or table.
|
||||
#[implementations(
|
||||
Vec<f64>,
|
||||
Vec<u32>,
|
||||
Vec<u64>,
|
||||
Vec<DVec2>,
|
||||
Vec<String>,
|
||||
Table<Artboard>,
|
||||
Table<Graphic>,
|
||||
Table<Vector>,
|
||||
Table<Raster<CPU>>,
|
||||
Table<Raster<GPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
)]
|
||||
collection: T,
|
||||
/// The index of the item to retrieve, starting from 0 for the first item.
|
||||
index: u32,
|
||||
) -> T::Output
|
||||
where
|
||||
T::Output: Clone + Default,
|
||||
{
|
||||
collection.at_index(index as usize).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub trait AtIndex {
|
||||
type Output;
|
||||
fn at_index(&self, index: usize) -> Option<Self::Output>;
|
||||
}
|
||||
impl<T: Clone> AtIndex for Vec<T> {
|
||||
type Output = T;
|
||||
|
||||
fn at_index(&self, index: usize) -> Option<Self::Output> {
|
||||
self.get(index).cloned()
|
||||
}
|
||||
}
|
||||
impl<T: Clone> AtIndex for Table<T> {
|
||||
type Output = Table<T>;
|
||||
|
||||
fn at_index(&self, index: usize) -> Option<Self::Output> {
|
||||
let mut result_table = Self::default();
|
||||
if let Some(row) = self.iter().nth(index) {
|
||||
result_table.push(row.into_cloned());
|
||||
Some(result_table)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_graphic<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Graphic>, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OldGraphicGroup {
|
||||
elements: Vec<(Graphic, Option<NodeId>)>,
|
||||
transform: DAffine2,
|
||||
alpha_blending: AlphaBlending,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GraphicGroup {
|
||||
elements: Vec<(Graphic, Option<NodeId>)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OlderTable<T> {
|
||||
id: Vec<u64>,
|
||||
#[serde(alias = "instances", alias = "instance")]
|
||||
element: Vec<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OldTable<T> {
|
||||
id: Vec<u64>,
|
||||
#[serde(alias = "instances", alias = "instance")]
|
||||
element: Vec<T>,
|
||||
transform: Vec<DAffine2>,
|
||||
alpha_blending: Vec<AlphaBlending>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum GraphicFormat {
|
||||
OldGraphicGroup(OldGraphicGroup),
|
||||
OlderTableOldGraphicGroup(OlderTable<OldGraphicGroup>),
|
||||
OldTableOldGraphicGroup(OldTable<OldGraphicGroup>),
|
||||
OldTableGraphicGroup(OldTable<GraphicGroup>),
|
||||
Table(serde_json::Value),
|
||||
}
|
||||
|
||||
Ok(match GraphicFormat::deserialize(deserializer)? {
|
||||
GraphicFormat::OldGraphicGroup(old) => {
|
||||
let mut graphic_table = Table::new();
|
||||
for (graphic, source_node_id) in old.elements {
|
||||
graphic_table.push(TableRow {
|
||||
element: graphic,
|
||||
transform: old.transform,
|
||||
alpha_blending: old.alpha_blending,
|
||||
source_node_id,
|
||||
});
|
||||
}
|
||||
graphic_table
|
||||
}
|
||||
GraphicFormat::OlderTableOldGraphicGroup(old) => old
|
||||
.element
|
||||
.into_iter()
|
||||
.flat_map(|element| {
|
||||
element.elements.into_iter().map(move |(graphic, source_node_id)| TableRow {
|
||||
element: graphic,
|
||||
transform: element.transform,
|
||||
alpha_blending: element.alpha_blending,
|
||||
source_node_id,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
GraphicFormat::OldTableOldGraphicGroup(old) => old
|
||||
.element
|
||||
.into_iter()
|
||||
.flat_map(|element| {
|
||||
element.elements.into_iter().map(move |(graphic, source_node_id)| TableRow {
|
||||
element: graphic,
|
||||
transform: element.transform,
|
||||
alpha_blending: element.alpha_blending,
|
||||
source_node_id,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
GraphicFormat::OldTableGraphicGroup(old) => old
|
||||
.element
|
||||
.into_iter()
|
||||
.flat_map(|element| {
|
||||
element.elements.into_iter().map(move |(graphic, source_node_id)| TableRow {
|
||||
element: graphic,
|
||||
transform: Default::default(),
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
GraphicFormat::Table(value) => {
|
||||
// Try to deserialize as either table format
|
||||
if let Ok(old_table) = serde_json::from_value::<Table<GraphicGroup>>(value.clone()) {
|
||||
let mut graphic_table = Table::new();
|
||||
for row in old_table.iter() {
|
||||
for (graphic, source_node_id) in &row.element.elements {
|
||||
graphic_table.push(TableRow {
|
||||
element: graphic.clone(),
|
||||
transform: *row.transform,
|
||||
alpha_blending: *row.alpha_blending,
|
||||
source_node_id: *source_node_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
graphic_table
|
||||
} else if let Ok(new_table) = serde_json::from_value::<Table<Graphic>>(value) {
|
||||
new_table
|
||||
} else {
|
||||
return Err(serde::de::Error::custom("Failed to deserialize Table<Graphic>"));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
use crate::{Node, WasmNotSend};
|
||||
use dyn_any::DynFuture;
|
||||
use std::future::Future;
|
||||
use std::hash::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// Caches the output of a given node called with a specific input.
|
||||
///
|
||||
/// A cache miss occurs when the Option is None. In this case, the node evaluates the inner node and memoizes (stores) the result.
|
||||
///
|
||||
/// 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)>>>,
|
||||
node: CachedNode,
|
||||
}
|
||||
impl<'i, I: Hash + 'i, T: 'i + Clone + WasmNotSend, CachedNode: 'i> Node<'i, I> for MemoNode<T, CachedNode>
|
||||
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
|
||||
type Output = DynFuture<'i, T>;
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
input.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
if let Some(data) = self.cache.lock().as_ref().unwrap().as_ref().and_then(|data| (data.0 == hash).then_some(data.1.clone())) {
|
||||
Box::pin(async move { data })
|
||||
} else {
|
||||
let fut = self.node.eval(input);
|
||||
let cache = self.cache.clone();
|
||||
Box::pin(async move {
|
||||
let value = fut.await;
|
||||
*cache.lock().unwrap() = Some((hash, value.clone()));
|
||||
value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
self.cache.lock().unwrap().take();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, CachedNode> MemoNode<T, CachedNode> {
|
||||
pub fn new(node: CachedNode) -> MemoNode<T, CachedNode> {
|
||||
MemoNode { cache: Default::default(), node }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::module_inception)]
|
||||
pub mod memo {
|
||||
pub const IDENTIFIER: crate::ProtoNodeIdentifier = crate::ProtoNodeIdentifier::new("graphene_core::memo::MemoNode");
|
||||
}
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy.
|
||||
/// 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>>>,
|
||||
node: CachedNode,
|
||||
_phantom: std::marker::PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<'i, I: 'i, T: 'i + Clone + WasmNotSend, CachedNode: 'i> Node<'i, I> for ImpureMemoNode<I, T, CachedNode>
|
||||
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
|
||||
// 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() {
|
||||
let data = cached_value.clone();
|
||||
Box::pin(async move { data })
|
||||
} else {
|
||||
let fut = self.node.eval(input);
|
||||
let cache = self.cache.clone();
|
||||
Box::pin(async move {
|
||||
let value = fut.await;
|
||||
*cache.lock().unwrap() = Some(value.clone());
|
||||
value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
self.cache.lock().unwrap().take();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I, CachedNode> ImpureMemoNode<I, T, CachedNode> {
|
||||
pub fn new(node: CachedNode) -> ImpureMemoNode<I, T, CachedNode> {
|
||||
ImpureMemoNode {
|
||||
cache: Default::default(),
|
||||
node,
|
||||
_phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod impure_memo {
|
||||
pub const IDENTIFIER: crate::ProtoNodeIdentifier = crate::ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode");
|
||||
}
|
||||
|
||||
/// Stores both what a node was called with and what it returned.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IORecord<I, O> {
|
||||
pub input: I,
|
||||
pub output: O,
|
||||
}
|
||||
|
||||
/// Caches the output of the last graph evaluation for introspection
|
||||
#[derive(Default)]
|
||||
pub struct MonitorNode<I, T, N> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
io: Arc<Mutex<Option<Arc<IORecord<I, T>>>>>,
|
||||
node: N,
|
||||
}
|
||||
|
||||
impl<'i, T, I, N> Node<'i, I> for MonitorNode<I, T, N>
|
||||
where
|
||||
I: Clone + 'static + Send + Sync,
|
||||
T: Clone + 'static + Send + Sync,
|
||||
for<'a> N: Node<'a, I, Output: Future<Output = T> + WasmNotSend> + 'i,
|
||||
{
|
||||
type Output = DynFuture<'i, T>;
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
let io = self.io.clone();
|
||||
let output_fut = self.node.eval(input.clone());
|
||||
Box::pin(async move {
|
||||
let output = output_fut.await;
|
||||
*io.lock().unwrap() = Some(Arc::new(IORecord { input, output: output.clone() }));
|
||||
output
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize(&self) -> Option<Arc<dyn std::any::Any + Send + Sync>> {
|
||||
let io = self.io.lock().unwrap();
|
||||
(io).as_ref().map(|output| output.clone() as Arc<dyn std::any::Any + Send + Sync>)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T, N> MonitorNode<I, T, N> {
|
||||
pub fn new(node: N) -> MonitorNode<I, T, N> {
|
||||
MonitorNode { io: Arc::new(Mutex::new(None)), node }
|
||||
}
|
||||
}
|
||||
|
||||
pub mod monitor {
|
||||
pub const IDENTIFIER: crate::ProtoNodeIdentifier = crate::ProtoNodeIdentifier::new("graphene_core::memo::MonitorNode");
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct MemoHash<T: Hash> {
|
||||
hash: u64,
|
||||
value: Arc<T>,
|
||||
}
|
||||
|
||||
impl<'de, T: serde::Deserialize<'de> + Hash> serde::Deserialize<'de> for MemoHash<T> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(|value| Self::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash + serde::Serialize> serde::Serialize for MemoHash<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.value.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> MemoHash<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
let hash = Self::calc_hash(&value);
|
||||
Self { hash, value: value.into() }
|
||||
}
|
||||
pub fn new_with_hash(value: T, hash: u64) -> Self {
|
||||
Self { hash, value: value.into() }
|
||||
}
|
||||
|
||||
fn calc_hash(data: &T) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
data.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
pub fn inner_mut(&mut self) -> MemoHashGuard<'_, T> {
|
||||
MemoHashGuard { inner: self }
|
||||
}
|
||||
pub fn into_inner(self) -> Arc<T> {
|
||||
self.value
|
||||
}
|
||||
pub fn hash_code(&self) -> u64 {
|
||||
self.hash
|
||||
}
|
||||
}
|
||||
impl<T: Hash> From<T> for MemoHash<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> Hash for MemoHash<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.hash.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> Deref for MemoHash<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MemoHashGuard<'a, T: Hash> {
|
||||
inner: &'a mut MemoHash<T>,
|
||||
}
|
||||
|
||||
impl<T: Hash> Drop for MemoHashGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
let hash = MemoHash::<T>::calc_hash(&self.inner.value);
|
||||
self.inner.hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> Deref for MemoHashGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash + Clone> std::ops::DerefMut for MemoHashGuard<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
Arc::make_mut(&mut self.inner.value)
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
use crate::gradient::GradientStops;
|
||||
use crate::raster_types::{CPU, GPU, Raster};
|
||||
use crate::table::Table;
|
||||
use crate::vector::Vector;
|
||||
use crate::{Artboard, Color, Graphic};
|
||||
|
||||
pub trait RenderComplexity {
|
||||
fn render_complexity(&self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RenderComplexity> RenderComplexity for Table<T> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
self.iter().map(|row| row.element.render_complexity()).fold(0, usize::saturating_add)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Artboard {
|
||||
fn render_complexity(&self) -> usize {
|
||||
self.content.render_complexity()
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Graphic {
|
||||
fn render_complexity(&self) -> usize {
|
||||
match self {
|
||||
Self::Graphic(table) => table.render_complexity(),
|
||||
Self::Vector(table) => table.render_complexity(),
|
||||
Self::RasterCPU(table) => table.render_complexity(),
|
||||
Self::RasterGPU(table) => table.render_complexity(),
|
||||
Self::Color(table) => table.render_complexity(),
|
||||
Self::Gradient(table) => table.render_complexity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Vector {
|
||||
fn render_complexity(&self) -> usize {
|
||||
self.segment_domain.ids().len()
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Raster<CPU> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
(self.width * self.height / 500) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Raster<GPU> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
// GPU textures currently can't have a thumbnail
|
||||
usize::MAX
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Color {
|
||||
fn render_complexity(&self) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for GradientStops {
|
||||
fn render_complexity(&self) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
@@ -5,22 +5,24 @@ edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[features]
|
||||
default = ["dealloc_nodes"]
|
||||
dealloc_nodes = ["graphene-core/dealloc_nodes"]
|
||||
default = ["dealloc_nodes", "wgpu"]
|
||||
dealloc_nodes = ["core-types/dealloc_nodes"]
|
||||
wgpu = ["wgpu-executor"]
|
||||
tokio = ["dep:tokio"]
|
||||
wayland = []
|
||||
loading = ["serde_json"]
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
dyn-any = { workspace = true }
|
||||
core-types = { workspace = true }
|
||||
path-bool-nodes = { workspace = true }
|
||||
brush-nodes = { workspace = true }
|
||||
graphene-core = { workspace = true }
|
||||
graphene-path-bool = { workspace = true }
|
||||
graphene-brush = { workspace = true }
|
||||
graphene-application-io = { workspace = true }
|
||||
graphene-svg-renderer = { workspace = true }
|
||||
graphene-raster-nodes = { workspace = true }
|
||||
rendering = { workspace = true }
|
||||
raster-nodes = { workspace = true }
|
||||
graphic-types = { workspace = true }
|
||||
text-nodes = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
log = { workspace = true }
|
||||
|
||||
@@ -2,12 +2,12 @@ pub mod value;
|
||||
|
||||
use crate::document::value::TaggedValue;
|
||||
use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode};
|
||||
use core_types::memo::MemoHashGuard;
|
||||
pub use core_types::uuid::NodeId;
|
||||
pub use core_types::uuid::generate_uuid;
|
||||
use core_types::{Context, ContextDependencies, Cow, MemoHash, ProtoNodeIdentifier, Type};
|
||||
use dyn_any::DynAny;
|
||||
use glam::IVec2;
|
||||
use graphene_core::memo::MemoHashGuard;
|
||||
pub use graphene_core::uuid::NodeId;
|
||||
pub use graphene_core::uuid::generate_uuid;
|
||||
use graphene_core::{Context, ContextDependencies, Cow, MemoHash, ProtoNodeIdentifier, Type};
|
||||
use log::Metadata;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
use std::collections::HashMap;
|
||||
@@ -318,7 +318,7 @@ pub enum DocumentNodeImplementation {
|
||||
|
||||
impl Default for DocumentNodeImplementation {
|
||||
fn default() -> Self {
|
||||
Self::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode"))
|
||||
Self::ProtoNode(graphene_core::ops::identity::IDENTIFIER)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,7 +475,7 @@ pub struct OldNodeNetwork {
|
||||
#[serde(alias = "outputs", deserialize_with = "deserialize_exports")] // TODO: Eventually remove this alias document upgrade code
|
||||
pub exports: Vec<NodeInput>,
|
||||
/// The list of all nodes in this network.
|
||||
//cfg_attr(feature = "serde", #[serde(serialize_with = "graphene_core::vector::serialize_hashmap", deserialize_with = "graphene_core::vector::deserialize_hashmap"))]
|
||||
//cfg_attr(feature = "serde", #[serde(serialize_with = "core_types::vector::serialize_hashmap", deserialize_with = "core_types::vector::deserialize_hashmap"))]
|
||||
pub nodes: HashMap<NodeId, OldDocumentNode>,
|
||||
/// Indicates whether the network is currently rendered with a particular node that is previewed, and if so, which connection should be restored when the preview ends.
|
||||
#[serde(default)]
|
||||
@@ -488,7 +488,7 @@ pub struct OldNodeNetwork {
|
||||
|
||||
/// A network may expose nodes as constants which can by used by other nodes using a `NodeInput::Scope(key)`.
|
||||
#[serde(default)]
|
||||
//cfg_attr(feature = "serde", #[serde(serialize_with = "graphene_core::vector::serialize_hashmap", deserialize_with = "graphene_core::vector::deserialize_hashmap"))]
|
||||
//cfg_attr(feature = "serde", #[serde(serialize_with = "core_types::vector::serialize_hashmap", deserialize_with = "core_types::vector::deserialize_hashmap"))]
|
||||
pub scope_injections: HashMap<String, (NodeId, Type)>,
|
||||
}
|
||||
|
||||
@@ -520,11 +520,17 @@ pub struct NodeNetwork {
|
||||
// TODO: Instead of storing import types in each NodeInput::Import connection, the types are stored here. This is similar to how types need to be defined for parameters when creating a function in Rust.
|
||||
// pub import_types: Vec<Type>,
|
||||
/// The list of all nodes in this network.
|
||||
#[serde(serialize_with = "graphene_core::vector::serialize_hashmap", deserialize_with = "graphene_core::vector::deserialize_hashmap")]
|
||||
#[serde(
|
||||
serialize_with = "graphic_types::vector_types::vector::serialize_hashmap",
|
||||
deserialize_with = "graphic_types::vector_types::vector::deserialize_hashmap"
|
||||
)]
|
||||
pub nodes: FxHashMap<NodeId, DocumentNode>,
|
||||
/// A network may expose nodes as constants which can by used by other nodes using a `NodeInput::Scope(key)`.
|
||||
#[serde(default)]
|
||||
#[serde(serialize_with = "graphene_core::vector::serialize_hashmap", deserialize_with = "graphene_core::vector::deserialize_hashmap")]
|
||||
#[serde(
|
||||
serialize_with = "graphic_types::vector_types::vector::serialize_hashmap",
|
||||
deserialize_with = "graphic_types::vector_types::vector::deserialize_hashmap"
|
||||
)]
|
||||
pub scope_injections: FxHashMap<String, (NodeId, Type)>,
|
||||
#[serde(skip)]
|
||||
pub generated: bool,
|
||||
@@ -773,7 +779,7 @@ impl NodeNetwork {
|
||||
};
|
||||
|
||||
// If the node is hidden, replace it with an identity node
|
||||
let identity_node = DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into());
|
||||
let identity_node = DocumentNodeImplementation::ProtoNode(graphene_core::ops::identity::IDENTIFIER);
|
||||
if !node.visible && node.implementation != identity_node {
|
||||
node.implementation = identity_node;
|
||||
|
||||
@@ -787,7 +793,7 @@ impl NodeNetwork {
|
||||
let path = node.original_location.path.clone().unwrap_or_default();
|
||||
|
||||
// Replace value inputs with dedicated value nodes
|
||||
if node.implementation != DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()) {
|
||||
if node.implementation != DocumentNodeImplementation::ProtoNode("core_types::value::ClonedNode".into()) {
|
||||
Self::replace_value_inputs_with_nodes(&mut node.inputs, &mut self.nodes, &path, gen_id, map_ids, id);
|
||||
}
|
||||
|
||||
@@ -923,7 +929,7 @@ impl NodeNetwork {
|
||||
merged_node_id,
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::Value { tagged_value, exposed }],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::value::ClonedNode".into()),
|
||||
original_location,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -989,7 +995,7 @@ impl NodeNetwork {
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|(_, node)| {
|
||||
matches!(&node.implementation, DocumentNodeImplementation::ProtoNode(ident) if ident == &ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode"))
|
||||
matches!(&node.implementation, DocumentNodeImplementation::ProtoNode(ident) if ident == &graphene_core::ops::identity::IDENTIFIER)
|
||||
&& node.inputs.len() == 1
|
||||
&& matches!(node.inputs[0], NodeInput::Node { .. })
|
||||
})
|
||||
@@ -1022,7 +1028,7 @@ impl NodeNetwork {
|
||||
assert_eq!(output_index, 0);
|
||||
// TODO: check if we can read lambda checking?
|
||||
let mut input_node = self.nodes.remove(&node_id).unwrap();
|
||||
node.implementation = DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into());
|
||||
node.implementation = DocumentNodeImplementation::ProtoNode("core_types::value::ClonedNode".into());
|
||||
if let Some(input) = input_node.inputs.get_mut(0) {
|
||||
*input = match &input {
|
||||
NodeInput::Node { .. } => NodeInput::import(generic!(T), 0),
|
||||
@@ -1139,7 +1145,7 @@ mod test {
|
||||
NodeId(0),
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::import(concrete!(u32), 0), NodeInput::import(concrete!(u32), 1)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::structural::ConsNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::structural::ConsNode".into()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
@@ -1147,7 +1153,7 @@ mod test {
|
||||
NodeId(1),
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::ops::AddPairNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::ops::AddPairNode".into()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
@@ -1169,7 +1175,7 @@ mod test {
|
||||
NodeId(1),
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::import(concrete!(u32), 0), NodeInput::import(concrete!(u32), 1)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::structural::ConsNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::structural::ConsNode".into()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
@@ -1177,7 +1183,7 @@ mod test {
|
||||
NodeId(2),
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::ops::AddPairNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::ops::AddPairNode".into()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
@@ -1193,7 +1199,7 @@ mod test {
|
||||
fn extract_node() {
|
||||
let id_node = DocumentNode {
|
||||
inputs: vec![],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_core::ops::identity::IDENTIFIER),
|
||||
..Default::default()
|
||||
};
|
||||
// TODO: Extend test cases to test nested network
|
||||
@@ -1250,13 +1256,13 @@ mod test {
|
||||
let document_node = DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
call_argument: concrete!(u32),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::structural::ConsNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::structural::ConsNode".into()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let proto_node = document_node.resolve_proto_node();
|
||||
let reference = ProtoNode {
|
||||
identifier: "graphene_core::structural::ConsNode".into(),
|
||||
identifier: "core_types::structural::ConsNode".into(),
|
||||
call_argument: concrete!(u32),
|
||||
construction_args: ConstructionArgs::Nodes(vec![NodeId(0)]),
|
||||
..Default::default()
|
||||
@@ -1273,7 +1279,7 @@ mod test {
|
||||
(
|
||||
NodeId(10),
|
||||
ProtoNode {
|
||||
identifier: "graphene_core::structural::ConsNode".into(),
|
||||
identifier: "core_types::structural::ConsNode".into(),
|
||||
call_argument: concrete!(u32),
|
||||
construction_args: ConstructionArgs::Nodes(vec![NodeId(14)]),
|
||||
original_location: OriginalLocation {
|
||||
@@ -1289,7 +1295,7 @@ mod test {
|
||||
(
|
||||
NodeId(11),
|
||||
ProtoNode {
|
||||
identifier: "graphene_core::ops::AddPairNode".into(),
|
||||
identifier: "core_types::ops::AddPairNode".into(),
|
||||
call_argument: concrete!(Context),
|
||||
construction_args: ConstructionArgs::Nodes(vec![NodeId(10)]),
|
||||
original_location: OriginalLocation {
|
||||
@@ -1304,8 +1310,8 @@ mod test {
|
||||
(
|
||||
NodeId(14),
|
||||
ProtoNode {
|
||||
identifier: "graphene_core::value::ClonedNode".into(),
|
||||
call_argument: concrete!(graphene_core::Context),
|
||||
identifier: "core_types::value::ClonedNode".into(),
|
||||
call_argument: concrete!(core_types::Context),
|
||||
construction_args: ConstructionArgs::Value(TaggedValue::U32(2).into()),
|
||||
original_location: OriginalLocation {
|
||||
path: Some(vec![NodeId(1), NodeId(4)]),
|
||||
@@ -1338,7 +1344,7 @@ mod test {
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(14), 0)],
|
||||
call_argument: concrete!(u32),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::structural::ConsNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::structural::ConsNode".into()),
|
||||
original_location: OriginalLocation {
|
||||
path: Some(vec![NodeId(1), NodeId(0)]),
|
||||
inputs_source: [(Source { node: vec![NodeId(1)], index: 1 }, 1)].into(),
|
||||
@@ -1352,7 +1358,7 @@ mod test {
|
||||
NodeId(14),
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::value(TaggedValue::U32(2), false)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::value::ClonedNode".into()),
|
||||
original_location: OriginalLocation {
|
||||
path: Some(vec![NodeId(1), NodeId(4)]),
|
||||
inputs_source: HashMap::new(),
|
||||
@@ -1366,7 +1372,7 @@ mod test {
|
||||
NodeId(11),
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(10), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::ops::AddPairNode".into()),
|
||||
implementation: DocumentNodeImplementation::ProtoNode("core_types::ops::AddPairNode".into()),
|
||||
original_location: OriginalLocation {
|
||||
path: Some(vec![NodeId(1), NodeId(1)]),
|
||||
inputs_source: HashMap::new(),
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
use super::DocumentNode;
|
||||
use crate::proto::{Any as DAny, FutureAny};
|
||||
use crate::wasm_application_io::WasmEditorApi;
|
||||
use brush_nodes::brush_cache::BrushCache;
|
||||
use brush_nodes::brush_stroke::BrushStroke;
|
||||
use core_types::table::Table;
|
||||
use core_types::uuid::NodeId;
|
||||
use core_types::{Color, ContextFeatures, MemoHash, Node, Type};
|
||||
use dyn_any::DynAny;
|
||||
pub use dyn_any::StaticType;
|
||||
use glam::{Affine2, Vec2};
|
||||
pub use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||
use graphene_application_io::{ImageTexture, SurfaceFrame};
|
||||
use graphene_brush::brush_cache::BrushCache;
|
||||
use graphene_brush::brush_stroke::BrushStroke;
|
||||
use graphene_core::raster::Image;
|
||||
use graphene_core::raster_types::{CPU, Raster};
|
||||
use graphene_core::table::Table;
|
||||
use graphene_core::transform::ReferencePoint;
|
||||
use graphene_core::uuid::NodeId;
|
||||
use graphene_core::vector::Vector;
|
||||
use graphene_core::vector::style::Fill;
|
||||
use graphene_core::vector::style::GradientStops;
|
||||
use graphene_core::{Artboard, Color, ContextFeatures, Graphic, MemoHash, Node, Type};
|
||||
use graphene_svg_renderer::RenderMetadata;
|
||||
use graphic_types::Artboard;
|
||||
use graphic_types::Graphic;
|
||||
use graphic_types::Vector;
|
||||
use graphic_types::raster_types::Image;
|
||||
use graphic_types::raster_types::{CPU, Raster};
|
||||
use graphic_types::vector_types::vector;
|
||||
use graphic_types::vector_types::vector::ReferencePoint;
|
||||
use graphic_types::vector_types::vector::style::Fill;
|
||||
use graphic_types::vector_types::vector::style::GradientStops;
|
||||
use rendering::RenderMetadata;
|
||||
use std::fmt::Display;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
@@ -76,7 +79,7 @@ macro_rules! tagged_value {
|
||||
Self::EditorApi(x) => Arc::new(x),
|
||||
}
|
||||
}
|
||||
/// Creates a graphene_core::Type::Concrete(TypeDescriptor { .. }) with the type of the value inside the tagged value
|
||||
/// Creates a core_types::Type::Concrete(TypeDescriptor { .. }) with the type of the value inside the tagged value
|
||||
pub fn ty(&self) -> Type {
|
||||
match self {
|
||||
Self::None => concrete!(()),
|
||||
@@ -186,19 +189,19 @@ tagged_value! {
|
||||
// TABLE TYPES
|
||||
// ===========
|
||||
GraphicUnused(Graphic), // TODO: This is unused but removing it causes `cargo test` to infinitely recurse its type solving; figure out why and then remove this
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphene_core::vector::migrate_vector"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphic_types::migrations::migrate_vector"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[serde(alias = "VectorData")]
|
||||
Vector(Table<Vector>),
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphic_types::raster_types::image::migrate_image_frame"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[serde(alias = "ImageFrame", alias = "RasterData", alias = "Image")]
|
||||
Raster(Table<Raster<CPU>>),
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphene_core::graphic::migrate_graphic"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphic_types::graphic::migrate_graphic"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[serde(alias = "GraphicGroup", alias = "Group")]
|
||||
Graphic(Table<Graphic>),
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphene_core::artboard::migrate_artboard"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphic_types::artboard::migrate_artboard"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[serde(alias = "ArtboardGroup")]
|
||||
Artboard(Table<Artboard>),
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "graphene_core::misc::migrate_color"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[cfg_attr(target_family = "wasm", serde(deserialize_with = "core_types::misc::migrate_color"))] // TODO: Eventually remove this migration document upgrade code
|
||||
#[serde(alias = "ColorTable", alias = "OptionalColor")]
|
||||
Color(Table<Color>),
|
||||
GradientTable(Table<GradientStops>),
|
||||
@@ -210,52 +213,52 @@ tagged_value! {
|
||||
#[serde(alias = "IVec2", alias = "UVec2")]
|
||||
DVec2(DVec2),
|
||||
DAffine2(DAffine2),
|
||||
Stroke(graphene_core::vector::style::Stroke),
|
||||
Gradient(graphene_core::vector::style::Gradient),
|
||||
Stroke(graphic_types::vector_types::vector::style::Stroke),
|
||||
Gradient(graphic_types::vector_types::vector::style::Gradient),
|
||||
#[serde(alias = "GradientPositions")] // TODO: Eventually remove this alias document upgrade code
|
||||
GradientStops(GradientStops),
|
||||
Font(graphene_core::text::Font),
|
||||
Font(text_nodes::Font),
|
||||
BrushStrokes(Vec<BrushStroke>),
|
||||
BrushCache(BrushCache),
|
||||
DocumentNode(DocumentNode),
|
||||
ContextFeatures(ContextFeatures),
|
||||
Curve(graphene_raster_nodes::curve::Curve),
|
||||
Footprint(graphene_core::transform::Footprint),
|
||||
VectorModification(Box<graphene_core::vector::VectorModification>),
|
||||
Curve(raster_nodes::curve::Curve),
|
||||
Footprint(core_types::transform::Footprint),
|
||||
VectorModification(Box<vector::VectorModification>),
|
||||
// ==========
|
||||
// ENUM TYPES
|
||||
// ==========
|
||||
Fill(graphene_core::vector::style::Fill),
|
||||
BlendMode(graphene_core::blending::BlendMode),
|
||||
LuminanceCalculation(graphene_raster_nodes::adjustments::LuminanceCalculation),
|
||||
Fill(vector::style::Fill),
|
||||
BlendMode(core_types::blending::BlendMode),
|
||||
LuminanceCalculation(raster_nodes::adjustments::LuminanceCalculation),
|
||||
XY(graphene_core::extract_xy::XY),
|
||||
RedGreenBlue(graphene_raster_nodes::adjustments::RedGreenBlue),
|
||||
RedGreenBlueAlpha(graphene_raster_nodes::adjustments::RedGreenBlueAlpha),
|
||||
RedGreenBlue(raster_nodes::adjustments::RedGreenBlue),
|
||||
RedGreenBlueAlpha(raster_nodes::adjustments::RedGreenBlueAlpha),
|
||||
RealTimeMode(graphene_core::animation::RealTimeMode),
|
||||
NoiseType(graphene_raster_nodes::adjustments::NoiseType),
|
||||
FractalType(graphene_raster_nodes::adjustments::FractalType),
|
||||
CellularDistanceFunction(graphene_raster_nodes::adjustments::CellularDistanceFunction),
|
||||
CellularReturnType(graphene_raster_nodes::adjustments::CellularReturnType),
|
||||
DomainWarpType(graphene_raster_nodes::adjustments::DomainWarpType),
|
||||
RelativeAbsolute(graphene_raster_nodes::adjustments::RelativeAbsolute),
|
||||
SelectiveColorChoice(graphene_raster_nodes::adjustments::SelectiveColorChoice),
|
||||
GridType(graphene_core::vector::misc::GridType),
|
||||
ArcType(graphene_core::vector::misc::ArcType),
|
||||
MergeByDistanceAlgorithm(graphene_core::vector::misc::MergeByDistanceAlgorithm),
|
||||
PointSpacingType(graphene_core::vector::misc::PointSpacingType),
|
||||
SpiralType(graphene_core::vector::misc::SpiralType),
|
||||
NoiseType(raster_nodes::adjustments::NoiseType),
|
||||
FractalType(raster_nodes::adjustments::FractalType),
|
||||
CellularDistanceFunction(raster_nodes::adjustments::CellularDistanceFunction),
|
||||
CellularReturnType(raster_nodes::adjustments::CellularReturnType),
|
||||
DomainWarpType(raster_nodes::adjustments::DomainWarpType),
|
||||
RelativeAbsolute(raster_nodes::adjustments::RelativeAbsolute),
|
||||
SelectiveColorChoice(raster_nodes::adjustments::SelectiveColorChoice),
|
||||
GridType(vector::misc::GridType),
|
||||
ArcType(vector::misc::ArcType),
|
||||
MergeByDistanceAlgorithm(vector::misc::MergeByDistanceAlgorithm),
|
||||
PointSpacingType(vector::misc::PointSpacingType),
|
||||
SpiralType(vector::misc::SpiralType),
|
||||
#[serde(alias = "LineCap")]
|
||||
StrokeCap(graphene_core::vector::style::StrokeCap),
|
||||
StrokeCap(vector::style::StrokeCap),
|
||||
#[serde(alias = "LineJoin")]
|
||||
StrokeJoin(graphene_core::vector::style::StrokeJoin),
|
||||
StrokeAlign(graphene_core::vector::style::StrokeAlign),
|
||||
PaintOrder(graphene_core::vector::style::PaintOrder),
|
||||
FillType(graphene_core::vector::style::FillType),
|
||||
GradientType(graphene_core::vector::style::GradientType),
|
||||
ReferencePoint(graphene_core::transform::ReferencePoint),
|
||||
CentroidType(graphene_core::vector::misc::CentroidType),
|
||||
BooleanOperation(graphene_path_bool::BooleanOperation),
|
||||
TextAlign(graphene_core::text::TextAlign),
|
||||
StrokeJoin(vector::style::StrokeJoin),
|
||||
StrokeAlign(vector::style::StrokeAlign),
|
||||
PaintOrder(vector::style::PaintOrder),
|
||||
FillType(vector::style::FillType),
|
||||
GradientType(vector::style::GradientType),
|
||||
ReferencePoint(vector::ReferencePoint),
|
||||
CentroidType(vector::misc::CentroidType),
|
||||
BooleanOperation(path_bool_nodes::BooleanOperation),
|
||||
TextAlign(text_nodes::TextAlign),
|
||||
}
|
||||
|
||||
impl TaggedValue {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate graphene_core;
|
||||
extern crate core_types;
|
||||
|
||||
pub use graphene_core::{ProtoNodeIdentifier, Type, TypeDescriptor, concrete, generic};
|
||||
pub use core_types::{ProtoNodeIdentifier, Type, TypeDescriptor, concrete, generic};
|
||||
|
||||
pub mod document;
|
||||
pub mod graphene_compiler;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::document::value::TaggedValue;
|
||||
use crate::document::{InlineRust, value};
|
||||
use crate::document::{NodeId, OriginalLocation};
|
||||
pub use graphene_core::registry::*;
|
||||
use graphene_core::*;
|
||||
pub use core_types::registry::*;
|
||||
use core_types::*;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@@ -139,7 +139,7 @@ pub struct ProtoNode {
|
||||
impl Default for ProtoNode {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
identifier: ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode"),
|
||||
identifier: graphene_core::ops::identity::IDENTIFIER,
|
||||
construction_args: ConstructionArgs::Value(value::TaggedValue::U32(0).into()),
|
||||
call_argument: concrete!(()),
|
||||
original_location: OriginalLocation::default(),
|
||||
@@ -175,7 +175,7 @@ impl ProtoNode {
|
||||
_ => 2,
|
||||
};
|
||||
Self {
|
||||
identifier: ProtoNodeIdentifier::new("graphene_core::value::ClonedNode"),
|
||||
identifier: ProtoNodeIdentifier::new("core_types::value::ClonedNode"),
|
||||
construction_args: value,
|
||||
call_argument: concrete!(Context),
|
||||
original_location: OriginalLocation {
|
||||
@@ -340,7 +340,7 @@ impl ProtoNetwork {
|
||||
ProtoNode {
|
||||
construction_args: ConstructionArgs::Value(MemoHash::new(TaggedValue::ContextFeatures(context_deps))),
|
||||
call_argument: concrete!(Context),
|
||||
identifier: ProtoNodeIdentifier::new("graphene_core::value::ClonedNode"),
|
||||
identifier: ProtoNodeIdentifier::new("core_types::value::ClonedNode"),
|
||||
original_location: OriginalLocation {
|
||||
path: path.clone(),
|
||||
..Default::default()
|
||||
|
||||
@@ -9,12 +9,10 @@ license = "MIT OR Apache-2.0"
|
||||
[features]
|
||||
default = ["wgpu"]
|
||||
wgpu = ["wgpu-executor", "gpu", "graphene-std/wgpu"]
|
||||
wayland = ["graphene-std/wayland"]
|
||||
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "wgpu-executor"]
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
graphene-core = { workspace = true }
|
||||
graphene-std = { workspace = true }
|
||||
interpreted-executor = { workspace = true }
|
||||
graph-craft = { workspace = true, features = ["loading"] }
|
||||
|
||||
@@ -6,8 +6,8 @@ use graph_craft::graphene_compiler::{Compiler, Executor};
|
||||
use graph_craft::proto::ProtoNetwork;
|
||||
use graph_craft::util::load_network;
|
||||
use graph_craft::wasm_application_io::EditorPreferences;
|
||||
use graphene_core::text::FontCache;
|
||||
use graphene_std::application_io::{ApplicationIo, NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||
use graphene_std::text_nodes::FontCache;
|
||||
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||
use interpreted_executor::util::wrap_network_in_scope;
|
||||
@@ -168,8 +168,7 @@ fn fix_nodes(network: &mut NodeNetwork) {
|
||||
// https://github.com/GraphiteEditor/Graphite/blob/d68f91ccca69e90e6d2df78d544d36cd1aaf348e/editor/src/messages/portfolio/portfolio_message_handler.rs#L535
|
||||
// Since the CLI doesn't have the document node definitions, a less robust method of just patching the inputs is used.
|
||||
DocumentNodeImplementation::ProtoNode(proto_node_identifier)
|
||||
if (proto_node_identifier.name.starts_with("graphene_core::ConstructLayerNode") || proto_node_identifier.name.starts_with("graphene_core::AddArtboardNode"))
|
||||
&& node.inputs.len() < 3 =>
|
||||
if (proto_node_identifier.name.starts_with("core_types::ConstructLayerNode") || proto_node_identifier.name.starts_with("core_types::AddArtboardNode")) && node.inputs.len() < 3 =>
|
||||
{
|
||||
node.inputs.push(NodeInput::Reflection(DocumentNodeMetadata::DocumentNodePath));
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#![no_std]
|
||||
pub use graphene_raster_nodes::*;
|
||||
@@ -1,26 +0,0 @@
|
||||
pub mod any;
|
||||
pub mod render_node;
|
||||
pub mod text;
|
||||
#[cfg(feature = "wasm")]
|
||||
pub mod wasm_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::*;
|
||||
pub use graphene_math_nodes as math_nodes;
|
||||
pub use graphene_path_bool as path_bool;
|
||||
pub use graphene_raster_nodes as raster_nodes;
|
||||
|
||||
/// stop gap solutions until all paths have been replaced with their absolute ones
|
||||
pub mod renderer {
|
||||
pub use graphene_core::math::quad::Quad;
|
||||
pub use graphene_core::math::rect::Rect;
|
||||
pub use graphene_svg_renderer::*;
|
||||
}
|
||||
|
||||
pub mod raster {
|
||||
pub use graphene_core::raster::*;
|
||||
pub use graphene_raster_nodes::adjustments::*;
|
||||
pub use graphene_raster_nodes::*;
|
||||
}
|
||||
@@ -12,9 +12,10 @@ gpu = ["graphene-std/gpu", "graphene-std/wgpu"]
|
||||
# Local dependencies
|
||||
graphene-std = { workspace = true }
|
||||
graph-craft = { workspace = true }
|
||||
wgpu-executor = { workspace = true }
|
||||
graphene-core = { workspace = true }
|
||||
graphene-path-bool = { workspace = true }
|
||||
wgpu-executor = { workspace = true }
|
||||
core-types = { workspace = true }
|
||||
path-bool-nodes = { workspace = true }
|
||||
dyn-any = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
|
||||
@@ -4,8 +4,9 @@ pub mod util;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core_types::*;
|
||||
use futures::executor::block_on;
|
||||
use graphene_core::*;
|
||||
use graphene_core::ops::identity;
|
||||
|
||||
#[test]
|
||||
fn double_number() {
|
||||
@@ -21,7 +22,7 @@ mod tests {
|
||||
DocumentNode {
|
||||
inputs: vec![],
|
||||
call_argument: concrete!(u32),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(identity::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
@@ -30,7 +31,7 @@ mod tests {
|
||||
NodeId(1),
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(0), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::AddNode")),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("core_types::ops::AddNode")),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
|
||||
@@ -3,15 +3,7 @@ use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::DocumentNode;
|
||||
use graph_craft::document::value::RenderOutput;
|
||||
use graph_craft::proto::{NodeConstructor, TypeErasedBox};
|
||||
use graphene_core::raster::color::Color;
|
||||
use graphene_core::raster::*;
|
||||
#[cfg(feature = "gpu")]
|
||||
use graphene_core::raster_types::GPU;
|
||||
use graphene_core::raster_types::{CPU, Raster};
|
||||
use graphene_core::{Artboard, concrete};
|
||||
use graphene_core::{Cow, ProtoNodeIdentifier};
|
||||
use graphene_core::{NodeIO, NodeIOTypes};
|
||||
use graphene_core::{fn_type_fut, future};
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::Context;
|
||||
use graphene_std::Graphic;
|
||||
#[cfg(feature = "gpu")]
|
||||
@@ -20,7 +12,13 @@ use graphene_std::any::DynAnyNode;
|
||||
use graphene_std::application_io::{ImageTexture, SurfaceFrame};
|
||||
use graphene_std::brush::brush_cache::BrushCache;
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::concrete;
|
||||
use graphene_std::gradient::GradientStops;
|
||||
#[cfg(feature = "gpu")]
|
||||
use graphene_std::raster::GPU;
|
||||
use graphene_std::raster::color::Color;
|
||||
use graphene_std::raster::*;
|
||||
use graphene_std::raster::{CPU, Raster};
|
||||
use graphene_std::render_node::RenderIntermediate;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::transform::Footprint;
|
||||
@@ -29,6 +27,9 @@ use graphene_std::vector::Vector;
|
||||
use graphene_std::wasm_application_io::WasmEditorApi;
|
||||
#[cfg(feature = "gpu")]
|
||||
use graphene_std::wasm_application_io::WasmSurfaceHandle;
|
||||
use graphene_std::{Cow, ProtoNodeIdentifier};
|
||||
use graphene_std::{NodeIO, NodeIOTypes};
|
||||
use graphene_std::{fn_type_fut, future};
|
||||
use node_registry_macros::{async_node, convert_node, into_node};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
@@ -49,10 +50,10 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
into_node!(from: Table<Raster<CPU>>, to: Table<Raster<CPU>>),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>),
|
||||
into_node!(from: Table<Vector>, to: Table<Graphic>),
|
||||
into_node!(from: Table<Raster<CPU>>, to: Table<Graphic>),
|
||||
convert_node!(from: Table<Vector>, to: Table<Graphic>),
|
||||
convert_node!(from: Table<Raster<CPU>>, to: Table<Graphic>),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: Table<Raster<GPU>>, to: Table<Graphic>),
|
||||
convert_node!(from: Table<Raster<GPU>>, to: Table<Graphic>),
|
||||
// into_node!(from: Table<Raster<CPU>>, to: Table<Raster<SRGBA8>>),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: &WasmEditorApi, to: &WgpuExecutor),
|
||||
@@ -93,17 +94,17 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => BlendMode]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_path_bool::BooleanOperation]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Fill]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeCap]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeJoin]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::PaintOrder]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeAlign]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Stroke]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Gradient]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::path_bool::BooleanOperation]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Fill]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::StrokeCap]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::StrokeJoin]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::PaintOrder]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::StrokeAlign]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Stroke]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Gradient]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GradientStops]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<graphene_core::uuid::NodeId>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Box<graphene_core::vector::VectorModification>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<graphene_std::uuid::NodeId>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Box<graphene_std::vector::VectorModification>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::CentroidType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::PointSpacingType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Option<f64>]),
|
||||
@@ -112,18 +113,18 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => [f64; 4]]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<NodeId>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Graphic]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::text::Font]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::text::Font]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<BrushStroke>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => BrushCache]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => DocumentNode]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::curve::Curve]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::transform::Footprint]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::blending::BlendMode]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::Footprint]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::blending::BlendMode]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::LuminanceCalculation]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::extract_xy::XY]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::extract_xy::XY]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::RedGreenBlue]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::RedGreenBlueAlpha]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::animation::RealTimeMode]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::animation::RealTimeMode]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::NoiseType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::FractalType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::CellularDistanceFunction]),
|
||||
@@ -131,15 +132,15 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::DomainWarpType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::RelativeAbsolute]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::SelectiveColorChoice]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::GridType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::ArcType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::MergeByDistanceAlgorithm]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::PointSpacingType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::FillType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::GradientType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::transform::ReferencePoint]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::CentroidType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::text::TextAlign]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::GridType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::ArcType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::MergeByDistanceAlgorithm]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::PointSpacingType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::FillType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::GradientType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::CentroidType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::text::TextAlign]),
|
||||
// Context nullification
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => &WasmEditorApi, Context => graphene_std::ContextFeatures]),
|
||||
@@ -193,23 +194,23 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Graphic]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => glam::f32::Vec2]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => glam::f32::Affine2]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Stroke]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Gradient]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::text::Font]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Stroke]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Gradient]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::text::Font]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Vec<BrushStroke>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => BrushCache]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => DocumentNode]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::ContextFeatures]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::curve::Curve]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::transform::Footprint]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Box<graphene_core::vector::VectorModification>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Fill]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::blending::BlendMode]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::transform::Footprint]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Box<graphene_std::vector::VectorModification>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Fill]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::blending::BlendMode]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::LuminanceCalculation]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::extract_xy::XY]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::extract_xy::XY]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::RedGreenBlue]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::RedGreenBlueAlpha]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::animation::RealTimeMode]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::animation::RealTimeMode]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::NoiseType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::FractalType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::CellularDistanceFunction]),
|
||||
@@ -217,35 +218,21 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::DomainWarpType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::RelativeAbsolute]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::SelectiveColorChoice]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::GridType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::ArcType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::MergeByDistanceAlgorithm]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::PointSpacingType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeCap]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeJoin]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeAlign]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::PaintOrder]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::FillType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::style::GradientType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::transform::ReferencePoint]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::CentroidType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_path_bool::BooleanOperation]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::text::TextAlign]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::GridType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::ArcType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::MergeByDistanceAlgorithm]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::PointSpacingType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::StrokeCap]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::StrokeJoin]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::StrokeAlign]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::PaintOrder]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::FillType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::style::GradientType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::CentroidType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => path_bool_nodes::BooleanOperation]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::text::TextAlign]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RenderIntermediate]),
|
||||
// =================
|
||||
// IMPURE MEMO NODES
|
||||
// =================
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Artboard>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Graphic>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Vector>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<CPU>>]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Color>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<GradientStops>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Option<WgpuSurface>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||
// =======================
|
||||
// CREATE GPU SURFACE NODE
|
||||
// =======================
|
||||
@@ -295,7 +282,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
|
||||
let mut map: HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> = HashMap::new();
|
||||
|
||||
for (id, entry) in graphene_core::registry::NODE_REGISTRY.lock().unwrap().iter() {
|
||||
for (id, entry) in graphene_std::registry::NODE_REGISTRY.lock().unwrap().iter() {
|
||||
for (constructor, types) in entry.iter() {
|
||||
map.entry(id.clone()).or_default().insert(types.clone(), *constructor);
|
||||
}
|
||||
@@ -362,7 +349,7 @@ mod node_registry_macros {
|
||||
ProtoNodeIdentifier::new(concat!["graphene_core::ops::IntoNode<", stringify!($to), ">"]),
|
||||
|mut args| {
|
||||
Box::pin(async move {
|
||||
let node = graphene_core::ops::IntoNode::new(
|
||||
let node = graphene_std::ops::IntoNode::new(
|
||||
graphene_std::any::downcast_node::<Context, $from>(args.pop().unwrap()),
|
||||
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>)),
|
||||
);
|
||||
@@ -371,7 +358,7 @@ mod node_registry_macros {
|
||||
})
|
||||
},
|
||||
{
|
||||
let node = graphene_core::ops::IntoNode::new(
|
||||
let node = graphene_std::ops::IntoNode::new(
|
||||
graphene_std::any::PanicNode::<Context, core::pin::Pin<Box<dyn core::future::Future<Output = $from> + Send>>>::new(),
|
||||
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>)),
|
||||
);
|
||||
@@ -412,7 +399,7 @@ mod node_registry_macros {
|
||||
|mut args| {
|
||||
Box::pin(async move {
|
||||
let mut args = args.drain(..);
|
||||
let node = graphene_core::ops::ConvertNode::new(
|
||||
let node = graphene_std::ops::ConvertNode::new(
|
||||
graphene_std::any::downcast_node::<Context, $from>(args.next().expect("Convert node did not get first argument")),
|
||||
graphene_std::any::downcast_node::<Context, $convert>(args.next().expect("Convert node did not get converter argument")),
|
||||
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>))
|
||||
@@ -422,7 +409,8 @@ mod node_registry_macros {
|
||||
})
|
||||
},
|
||||
{
|
||||
let node = graphene_core::ops::ConvertNode::new(
|
||||
let node = graphene_std::ops::ConvertNode::new(
|
||||
|
||||
graphene_std::any::PanicNode::<Context, core::pin::Pin<Box<dyn core::future::Future<Output = $from> + Send>>>::new(),
|
||||
graphene_std::any::PanicNode::<Context, core::pin::Pin<Box<dyn core::future::Future<Output = $convert> + Send>>>::new(),
|
||||
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>))
|
||||
|
||||
@@ -43,7 +43,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc<WasmEdito
|
||||
},
|
||||
DocumentNode {
|
||||
call_argument: concrete!(Context),
|
||||
inputs: vec![NodeInput::import(graphene_core::Type::Fn(Box::new(concrete!(Context)), Box::new(generic!(T))), 0)],
|
||||
inputs: vec![NodeInput::import(core_types::Type::Fn(Box::new(concrete!(Context)), Box::new(generic!(T))), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render_intermediate::IDENTIFIER),
|
||||
context_features: graphene_std::ContextDependencies {
|
||||
extract: ContextFeatures::VARARGS,
|
||||
|
||||
@@ -13,7 +13,9 @@ wgpu = ["dep:wgpu"]
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
dyn-any = { workspace = true }
|
||||
graphene-core = { workspace = true }
|
||||
core-types = { workspace = true }
|
||||
vector-types = { workspace = true }
|
||||
text-nodes = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
glam = { workspace = true }
|
||||
@@ -1,8 +1,6 @@
|
||||
use core_types::transform::Footprint;
|
||||
use dyn_any::{DynAny, StaticType, StaticTypeSized};
|
||||
use glam::{DAffine2, UVec2};
|
||||
use graphene_core::text::FontCache;
|
||||
use graphene_core::transform::Footprint;
|
||||
use graphene_core::vector::style::RenderMode;
|
||||
use std::fmt::Debug;
|
||||
use std::future::Future;
|
||||
use std::hash::{Hash, Hasher};
|
||||
@@ -10,6 +8,8 @@ use std::pin::Pin;
|
||||
use std::ptr::addr_of;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use text_nodes::FontCache;
|
||||
use vector_types::vector::style::RenderMode;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
pub struct SurfaceId(pub u64);
|
||||
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "graphene-core"
|
||||
name = "core-types"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "API definitions for Graphene"
|
||||
description = "Core types and traits for Graphene node system"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -10,12 +10,11 @@ license = "MIT OR Apache-2.0"
|
||||
default = ["serde"]
|
||||
nightly = []
|
||||
type_id_logging = []
|
||||
wgpu = ["dep:wgpu"]
|
||||
dealloc_nodes = []
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
graphene-core-shaders = { workspace = true, features = ["std"] }
|
||||
no-std-types = { workspace = true, features = ["std"] }
|
||||
|
||||
# Workspace dependencies
|
||||
bitflags = { workspace = true }
|
||||
@@ -43,7 +42,6 @@ polycool = { workspace = true }
|
||||
|
||||
# Optional workspace dependencies
|
||||
serde = { workspace = true, optional = true }
|
||||
wgpu = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# Workspace dependencies
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Color, gradient::GradientStops};
|
||||
use crate::Color;
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
||||
@@ -33,8 +33,3 @@ impl BoundingBox for Color {
|
||||
RenderBoundingBox::Infinite
|
||||
}
|
||||
}
|
||||
impl BoundingBox for GradientStops {
|
||||
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> RenderBoundingBox {
|
||||
RenderBoundingBox::Infinite
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::raster::Color;
|
||||
use crate::Color;
|
||||
|
||||
// RENDERING
|
||||
pub const LAYER_OUTLINE_STROKE_COLOR: Color = Color::BLACK;
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::transform::Footprint;
|
||||
pub use graphene_core_shaders::context::{ArcCtx, Ctx};
|
||||
pub use no_std_types::context::{ArcCtx, Ctx};
|
||||
use std::any::Any;
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::{Hash, Hasher};
|
||||
@@ -1,51 +1,34 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod animation;
|
||||
pub mod artboard;
|
||||
pub mod blending_nodes;
|
||||
pub mod bounds;
|
||||
pub mod consts;
|
||||
pub mod context;
|
||||
pub mod context_modification;
|
||||
pub mod debug;
|
||||
pub mod extract_xy;
|
||||
pub mod generic;
|
||||
pub mod gradient;
|
||||
pub mod graphic;
|
||||
pub mod logic;
|
||||
pub mod math;
|
||||
pub mod memo;
|
||||
pub mod misc;
|
||||
pub mod ops;
|
||||
pub mod raster;
|
||||
pub mod raster_types;
|
||||
pub mod registry;
|
||||
pub mod render_complexity;
|
||||
pub mod subpath;
|
||||
pub mod table;
|
||||
pub mod text;
|
||||
pub mod transform;
|
||||
pub mod transform_nodes;
|
||||
pub mod uuid;
|
||||
pub mod value;
|
||||
pub mod vector;
|
||||
|
||||
pub use crate as graphene_core;
|
||||
pub use artboard::Artboard;
|
||||
pub use crate as core_types;
|
||||
pub use blending::*;
|
||||
pub use color::Color;
|
||||
pub use context::*;
|
||||
pub use ctor;
|
||||
pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync};
|
||||
pub use graphene_core_shaders::AsU32;
|
||||
pub use graphene_core_shaders::blending;
|
||||
pub use graphene_core_shaders::choice_type;
|
||||
pub use graphene_core_shaders::color;
|
||||
pub use graphene_core_shaders::shaders;
|
||||
pub use graphic::Graphic;
|
||||
pub use memo::MemoHash;
|
||||
pub use no_std_types::AsU32;
|
||||
pub use no_std_types::blending;
|
||||
pub use no_std_types::choice_type;
|
||||
pub use no_std_types::color;
|
||||
pub use no_std_types::shaders;
|
||||
pub use num_traits;
|
||||
pub use specta;
|
||||
use std::any::TypeId;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
@@ -1,5 +1,4 @@
|
||||
pub mod bbox;
|
||||
pub mod math_ext;
|
||||
pub mod polynomial;
|
||||
pub mod quad;
|
||||
pub mod rect;
|
||||
105
node-graph/libraries/core-types/src/memo.rs
Normal file
105
node-graph/libraries/core-types/src/memo.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
use std::hash::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Stores both what a node was called with and what it returned.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IORecord<I, O> {
|
||||
pub input: I,
|
||||
pub output: O,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct MemoHash<T: Hash> {
|
||||
hash: u64,
|
||||
value: Arc<T>,
|
||||
}
|
||||
|
||||
impl<'de, T: serde::Deserialize<'de> + Hash> serde::Deserialize<'de> for MemoHash<T> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(|value| Self::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash + serde::Serialize> serde::Serialize for MemoHash<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.value.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> MemoHash<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
let hash = Self::calc_hash(&value);
|
||||
Self { hash, value: value.into() }
|
||||
}
|
||||
pub fn new_with_hash(value: T, hash: u64) -> Self {
|
||||
Self { hash, value: value.into() }
|
||||
}
|
||||
|
||||
fn calc_hash(data: &T) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
data.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
pub fn inner_mut(&mut self) -> MemoHashGuard<'_, T> {
|
||||
MemoHashGuard { inner: self }
|
||||
}
|
||||
pub fn into_inner(self) -> Arc<T> {
|
||||
self.value
|
||||
}
|
||||
pub fn hash_code(&self) -> u64 {
|
||||
self.hash
|
||||
}
|
||||
}
|
||||
impl<T: Hash> From<T> for MemoHash<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> Hash for MemoHash<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.hash.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> Deref for MemoHash<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MemoHashGuard<'a, T: Hash> {
|
||||
inner: &'a mut MemoHash<T>,
|
||||
}
|
||||
|
||||
impl<T: Hash> Drop for MemoHashGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
let hash = MemoHash::<T>::calc_hash(&self.inner.value);
|
||||
self.inner.hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> Deref for MemoHashGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash + Clone> std::ops::DerefMut for MemoHashGuard<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
Arc::make_mut(&mut self.inner.value)
|
||||
}
|
||||
}
|
||||
@@ -62,9 +62,9 @@ impl Clampable for DVec2 {
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_color<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<crate::table::Table<graphene_core_shaders::color::Color>, D::Error> {
|
||||
pub fn migrate_color<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<crate::table::Table<no_std_types::color::Color>, D::Error> {
|
||||
use crate::table::Table;
|
||||
use graphene_core_shaders::color::Color;
|
||||
use no_std_types::color::Color;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
@@ -1,16 +1,11 @@
|
||||
use graphene_core_shaders::Ctx;
|
||||
|
||||
use crate::{ExtractFootprint, Node, transform::Footprint};
|
||||
use crate::{
|
||||
Node,
|
||||
table::{Table, TableRow},
|
||||
transform::Footprint,
|
||||
};
|
||||
use std::future::Future;
|
||||
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.
|
||||
#[node_macro::node(skip_impl)]
|
||||
fn identity<'i, T: 'i + Send>(value: T) -> T {
|
||||
value
|
||||
}
|
||||
|
||||
// Type
|
||||
// TODO: Document this
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
@@ -44,11 +39,6 @@ impl<'i, N: for<'a> Node<'a, I> + Clone, I: 'i> Clone for TypeNode<N, I, <N as N
|
||||
}
|
||||
impl<'i, N: for<'a> Node<'a, I> + Copy, I: 'i> Copy for TypeNode<N, I, <N as Node<'i, I>>::Output> {}
|
||||
|
||||
#[node_macro::node(skip_impl)]
|
||||
fn into<'i, T: 'i + Send + Into<O>, O: 'i + Send>(_: impl Ctx, value: T, _out_ty: PhantomData<O>) -> O {
|
||||
value.into()
|
||||
}
|
||||
|
||||
/// The [`Convert`] trait allows for conversion between Rust primitive numeric types.
|
||||
/// Because number casting is lossy, we cannot use the normal [`Into`] trait like we do for other types.
|
||||
pub trait Convert<T, C>: Sized {
|
||||
@@ -65,6 +55,27 @@ impl<T: ToString + Send> Convert<String, ()> for T {
|
||||
}
|
||||
}
|
||||
|
||||
// trait mentioning inner type in args
|
||||
pub trait TableConvert<U> {
|
||||
fn convert_row(self) -> U;
|
||||
}
|
||||
|
||||
//
|
||||
impl<U, T: TableConvert<U> + Send> Convert<Table<U>, ()> for Table<T> {
|
||||
async fn convert(self, _: Footprint, _: ()) -> Table<U> {
|
||||
let table: Table<U> = self
|
||||
.into_iter()
|
||||
.map(|row| TableRow {
|
||||
element: row.element.convert_row(),
|
||||
transform: row.transform,
|
||||
alpha_blending: row.alpha_blending,
|
||||
source_node_id: row.source_node_id,
|
||||
})
|
||||
.collect();
|
||||
table
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the [`Convert`] trait for conversion between the cartesian product of Rust's primitive numeric types.
|
||||
macro_rules! impl_convert {
|
||||
($from:ty, $to:ty) => {
|
||||
@@ -105,18 +116,3 @@ impl_convert!(i128);
|
||||
impl_convert!(u128);
|
||||
impl_convert!(isize);
|
||||
impl_convert!(usize);
|
||||
|
||||
#[node_macro::node(skip_impl)]
|
||||
async fn convert<'i, T: 'i + Send + Convert<O, C>, O: 'i + Send, C: 'i + Send>(ctx: impl Ctx + ExtractFootprint, value: T, converter: C, _out_ty: PhantomData<O>) -> O {
|
||||
value.convert(*ctx.try_footprint().unwrap_or(&Footprint::DEFAULT), converter).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn identity_node() {
|
||||
assert_eq!(identity(&4), &4);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ use std::ops::Deref;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{LazyLock, Mutex};
|
||||
|
||||
pub use graphene_core_shaders::registry::types;
|
||||
pub use no_std_types::registry::types;
|
||||
|
||||
// Translation struct between macro and definition
|
||||
#[derive(Clone, Debug)]
|
||||
21
node-graph/libraries/core-types/src/render_complexity.rs
Normal file
21
node-graph/libraries/core-types/src/render_complexity.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Raster types moved to raster-types crate
|
||||
use crate::Color;
|
||||
use crate::table::Table;
|
||||
|
||||
pub trait RenderComplexity {
|
||||
fn render_complexity(&self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RenderComplexity> RenderComplexity for Table<T> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
self.iter().map(|row| row.element.render_complexity()).fold(0, usize::saturating_add)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Color {
|
||||
fn render_complexity(&self) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
@@ -315,3 +315,10 @@ pub struct TableRowMut<'a, T> {
|
||||
pub alpha_blending: &'a mut AlphaBlending,
|
||||
pub source_node_id: &'a mut Option<NodeId>,
|
||||
}
|
||||
|
||||
// Conversion from Table<Color> to Option<Color> - extracts first element
|
||||
impl From<Table<crate::Color>> for Option<crate::Color> {
|
||||
fn from(table: Table<crate::Color>) -> Self {
|
||||
table.iter().nth(0).map(|row| row.element).copied()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
use crate::Artboard;
|
||||
use crate::math::bbox::AxisAlignedBbox;
|
||||
pub use crate::vector::ReferencePoint;
|
||||
use core::f64;
|
||||
use glam::{DAffine2, DMat2, DVec2, UVec2};
|
||||
|
||||
@@ -54,16 +52,6 @@ impl<T: Transform> Transform for &T {
|
||||
}
|
||||
}
|
||||
|
||||
// Implementations for Artboard
|
||||
impl Transform for Artboard {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
DAffine2::from_translation(self.location.as_dvec2())
|
||||
}
|
||||
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
||||
self.location.as_dvec2() + self.dimensions.as_dvec2() * pivot
|
||||
}
|
||||
}
|
||||
|
||||
// Implementations for DAffine2
|
||||
impl Transform for DAffine2 {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
@@ -173,22 +173,22 @@ fn migrate_type_descriptor_names<'de, D: serde::Deserializer<'de>>(deserializer:
|
||||
let name = String::deserialize(deserializer)?;
|
||||
let name = match name.as_str() {
|
||||
"f32" => "f64".to_string(),
|
||||
"graphene_core::transform::Footprint" => "std::option::Option<std::sync::Arc<graphene_core::context::OwnedContextImpl>>".to_string(),
|
||||
"graphene_core::graphic_element::GraphicGroup" => "graphene_core::table::Table<graphene_core::graphic::Graphic>".to_string(),
|
||||
"graphene_core::raster::image::ImageFrame<Color>"
|
||||
| "graphene_core::raster::image::ImageFrame<graphene_core::raster::color::Color>"
|
||||
| "graphene_core::instances::Instances<graphene_core::raster::image::ImageFrame<Color>>"
|
||||
| "graphene_core::instances::Instances<graphene_core::raster::image::ImageFrame<graphene_core::raster::color::Color>>"
|
||||
| "graphene_core::instances::Instances<graphene_core::raster::image::Image<graphene_core::raster::color::Color>>" => {
|
||||
"graphene_core::table::Table<graphene_core::raster::image::Image<graphene_core::raster::color::Color>>".to_string()
|
||||
"grahpene_core::transform::Footprint" => "std::option::Option<std::sync::Arc<grahpene_core::context::OwnedContextImpl>>".to_string(),
|
||||
"grahpene_core::graphic_element::GraphicGroup" => "grahpene_core::table::Table<grahpene_core::graphic_types::Graphic>".to_string(),
|
||||
"grahpene_core::raster::image::ImageFrame<Color>"
|
||||
| "grahpene_core::raster::image::ImageFrame<grahpene_core::raster::color::Color>"
|
||||
| "grahpene_core::instances::Instances<grahpene_core::raster::image::ImageFrame<Color>>"
|
||||
| "grahpene_core::instances::Instances<grahpene_core::raster::image::ImageFrame<grahpene_core::raster::color::Color>>"
|
||||
| "grahpene_core::instances::Instances<grahpene_core::raster::image::Image<grahpene_core::raster::color::Color>>" => {
|
||||
"grahpene_core::table::Table<grahpene_core::raster::image::Image<grahpene_core::raster::color::Color>>".to_string()
|
||||
}
|
||||
"graphene_core::vector::vector_data::VectorData"
|
||||
| "graphene_core::instances::Instances<graphene_core::vector::vector_data::VectorData>"
|
||||
| "graphene_core::table::Table<graphene_core::vector::vector_data::VectorData>"
|
||||
| "graphene_core::table::Table<graphene_core::vector::vector_data::Vector>" => "graphene_core::table::Table<graphene_core::vector::vector_types::Vector>".to_string(),
|
||||
"graphene_core::instances::Instances<graphene_core::graphic_element::Artboard>" => "graphene_core::table::Table<graphene_core::artboard::Artboard>".to_string(),
|
||||
"graphene_core::vector::vector_data::modification::VectorModification" => "graphene_core::vector::vector_modification::VectorModification".to_string(),
|
||||
"graphene_core::table::Table<graphene_core::graphic_element::Graphic>" => "graphene_core::table::Table<graphene_core::graphic::Graphic>".to_string(),
|
||||
"grahpene_core::vector::vector_data::VectorData"
|
||||
| "grahpene_core::instances::Instances<grahpene_core::vector::vector_data::VectorData>"
|
||||
| "grahpene_core::table::Table<grahpene_core::vector::vector_data::VectorData>"
|
||||
| "grahpene_core::table::Table<grahpene_core::vector::vector_data::Vector>" => "grahpene_core::table::Table<grahpene_core::vector::vector_types::Vector>".to_string(),
|
||||
"grahpene_core::instances::Instances<grahpene_core::graphic_element::Artboard>" => "grahpene_core::table::Table<grahpene_core::artboard::Artboard>".to_string(),
|
||||
"grahpene_core::vector::vector_data::modification::VectorModification" => "grahpene_core::vector::vector_modification::VectorModification".to_string(),
|
||||
"grahpene_core::table::Table<grahpene_core::graphic_element::Graphic>" => "grahpene_core::table::Table<grahpene_core::graphic_types::Graphic>".to_string(),
|
||||
_ => name,
|
||||
};
|
||||
|
||||
26
node-graph/libraries/graphic-types/Cargo.toml
Normal file
26
node-graph/libraries/graphic-types/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "graphic-types"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "Graphic types for Graphene - combines vector types with core infrastructure"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
core-types = { workspace = true }
|
||||
raster-types = { workspace = true, features = ["wgpu"] }
|
||||
vector-types = { workspace = true }
|
||||
node-macro = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
dyn-any = { workspace = true }
|
||||
glam = { workspace = true }
|
||||
specta = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
# Optional workspace dependencies
|
||||
serde = { workspace = true, optional = true }
|
||||
@@ -1,13 +1,12 @@
|
||||
use crate::blending::AlphaBlending;
|
||||
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use crate::gradient::GradientStops;
|
||||
use crate::math::quad::Quad;
|
||||
use crate::raster_types::{CPU, GPU, Raster};
|
||||
use crate::table::{Table, TableRow};
|
||||
use crate::transform::TransformMut;
|
||||
use crate::uuid::NodeId;
|
||||
use crate::vector::Vector;
|
||||
use crate::{CloneVarArgs, Color, Context, Ctx, ExtractAll, Graphic, OwnedContextImpl};
|
||||
use crate::graphic::Graphic;
|
||||
use core_types::Color;
|
||||
use core_types::blending::AlphaBlending;
|
||||
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use core_types::math::quad::Quad;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::table::{Table, TableRow};
|
||||
use core_types::transform::Transform;
|
||||
use core_types::uuid::NodeId;
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use std::hash::Hash;
|
||||
@@ -57,6 +56,22 @@ impl BoundingBox for Artboard {
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Artboard {
|
||||
fn render_complexity(&self) -> usize {
|
||||
self.content.render_complexity()
|
||||
}
|
||||
}
|
||||
|
||||
// Implementations for Artboard
|
||||
impl Transform for Artboard {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
DAffine2::from_translation(self.location.as_dvec2())
|
||||
}
|
||||
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
||||
self.location.as_dvec2() + self.dimensions.as_dvec2() * pivot
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Artboard>, D::Error> {
|
||||
use serde::Deserialize;
|
||||
@@ -110,57 +125,4 @@ pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Re
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs a new single artboard table with the chosen properties.
|
||||
#[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>,
|
||||
Context -> Table<Raster<CPU>>,
|
||||
Context -> Table<Raster<GPU>>,
|
||||
Context -> Table<Color>,
|
||||
Context -> Table<GradientStops>,
|
||||
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();
|
||||
|
||||
let footprint = ctx.try_footprint().copied();
|
||||
let mut new_ctx = OwnedContextImpl::from(ctx);
|
||||
if let Some(mut footprint) = footprint {
|
||||
footprint.translate(location.as_dvec2());
|
||||
new_ctx = new_ctx.with_footprint(footprint);
|
||||
}
|
||||
let content = content.eval(new_ctx.into_context()).await.into();
|
||||
|
||||
let dimensions = dimensions.as_ivec2().max(IVec2::ONE);
|
||||
|
||||
let location = location.min(location + dimensions);
|
||||
|
||||
let dimensions = dimensions.abs();
|
||||
|
||||
let background: Option<Color> = background.into();
|
||||
let background = background.unwrap_or(Color::WHITE);
|
||||
|
||||
Table::new_from_element(Artboard {
|
||||
content,
|
||||
label,
|
||||
location,
|
||||
dimensions,
|
||||
background,
|
||||
clip,
|
||||
})
|
||||
}
|
||||
// Node definitions moved to graphic-nodes crate
|
||||
421
node-graph/libraries/graphic-types/src/graphic.rs
Normal file
421
node-graph/libraries/graphic-types/src/graphic.rs
Normal file
@@ -0,0 +1,421 @@
|
||||
use core_types::Color;
|
||||
use core_types::blending::AlphaBlending;
|
||||
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use core_types::ops::TableConvert;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::table::{Table, TableRow};
|
||||
use core_types::uuid::NodeId;
|
||||
use dyn_any::DynAny;
|
||||
use glam::DAffine2;
|
||||
use raster_types::{CPU, GPU, Raster};
|
||||
use std::hash::Hash;
|
||||
use vector_types::GradientStops;
|
||||
// use vector_types::Vector;
|
||||
|
||||
pub type Vector = vector_types::Vector<Option<Table<Graphic>>>;
|
||||
|
||||
/// The possible forms of graphical content that can be rendered by the Render node into either an image or SVG syntax.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Graphic {
|
||||
Graphic(Table<Graphic>),
|
||||
Vector(Table<Vector>),
|
||||
RasterCPU(Table<Raster<CPU>>),
|
||||
RasterGPU(Table<Raster<GPU>>),
|
||||
Color(Table<Color>),
|
||||
Gradient(Table<GradientStops>),
|
||||
}
|
||||
|
||||
impl Default for Graphic {
|
||||
fn default() -> Self {
|
||||
Self::Graphic(Table::new())
|
||||
}
|
||||
}
|
||||
|
||||
// Graphic
|
||||
impl From<Table<Graphic>> for Graphic {
|
||||
fn from(graphic: Table<Graphic>) -> Self {
|
||||
Graphic::Graphic(graphic)
|
||||
}
|
||||
}
|
||||
|
||||
// Vector
|
||||
impl From<Vector> for Graphic {
|
||||
fn from(vector: Vector) -> Self {
|
||||
Graphic::Vector(Table::new_from_element(vector))
|
||||
}
|
||||
}
|
||||
impl From<Table<Vector>> for Graphic {
|
||||
fn from(vector: Table<Vector>) -> Self {
|
||||
Graphic::Vector(vector)
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Table<Vector> -> Table<Graphic> conversion handled by blanket impl in gcore
|
||||
|
||||
// Raster<CPU>
|
||||
impl From<Raster<CPU>> for Graphic {
|
||||
fn from(raster: Raster<CPU>) -> Self {
|
||||
Graphic::RasterCPU(Table::new_from_element(raster))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<CPU>>> for Graphic {
|
||||
fn from(raster: Table<Raster<CPU>>) -> Self {
|
||||
Graphic::RasterCPU(raster)
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
|
||||
// Raster<GPU>
|
||||
impl From<Raster<GPU>> for Graphic {
|
||||
fn from(raster: Raster<GPU>) -> Self {
|
||||
Graphic::RasterGPU(Table::new_from_element(raster))
|
||||
}
|
||||
}
|
||||
impl From<Table<Raster<GPU>>> for Graphic {
|
||||
fn from(raster: Table<Raster<GPU>>) -> Self {
|
||||
Graphic::RasterGPU(raster)
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
|
||||
// Color
|
||||
impl From<Color> for Graphic {
|
||||
fn from(color: Color) -> Self {
|
||||
Graphic::Color(Table::new_from_element(color))
|
||||
}
|
||||
}
|
||||
impl From<Table<Color>> for Graphic {
|
||||
fn from(color: Table<Color>) -> Self {
|
||||
Graphic::Color(color)
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
|
||||
// Option<Color>
|
||||
impl From<Option<Color>> for Graphic {
|
||||
fn from(color: Option<Color>) -> Self {
|
||||
if let Some(color) = color {
|
||||
Graphic::Color(Table::new_from_element(color))
|
||||
} else {
|
||||
Graphic::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
// Note: Table<Color> -> Option<Color> is in gcore (Color is defined there)
|
||||
|
||||
// GradientStops
|
||||
impl From<GradientStops> for Graphic {
|
||||
fn from(gradient: GradientStops) -> Self {
|
||||
Graphic::Gradient(Table::new_from_element(gradient))
|
||||
}
|
||||
}
|
||||
impl From<Table<GradientStops>> for Graphic {
|
||||
fn from(gradient: Table<GradientStops>) -> Self {
|
||||
Graphic::Gradient(gradient)
|
||||
}
|
||||
}
|
||||
|
||||
// Local trait to convert types to Table<Graphic> (avoids orphan rule issues)
|
||||
pub trait IntoGraphicTable {
|
||||
fn into_graphic_table(self) -> Table<Graphic>;
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Graphic> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Vector> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::Vector(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Raster<CPU>> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::RasterCPU(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Raster<GPU>> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::RasterGPU(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<Color> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::Color(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for Table<GradientStops> {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::Gradient(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGraphicTable for DAffine2 {
|
||||
fn into_graphic_table(self) -> Table<Graphic> {
|
||||
Table::new_from_element(Graphic::default())
|
||||
}
|
||||
}
|
||||
|
||||
// DAffine2
|
||||
impl From<DAffine2> for Graphic {
|
||||
fn from(_: DAffine2) -> Self {
|
||||
Graphic::default()
|
||||
}
|
||||
}
|
||||
// Note: Table conversions handled by blanket impl in gcore
|
||||
|
||||
impl Graphic {
|
||||
pub fn as_graphic(&self) -> Option<&Table<Graphic>> {
|
||||
match self {
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_graphic_mut(&mut self) -> Option<&mut Table<Graphic>> {
|
||||
match self {
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector(&self) -> Option<&Table<Vector>> {
|
||||
match self {
|
||||
Graphic::Vector(vector) => Some(vector),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector_mut(&mut self) -> Option<&mut Table<Vector>> {
|
||||
match self {
|
||||
Graphic::Vector(vector) => Some(vector),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster(&self) -> Option<&Table<Raster<CPU>>> {
|
||||
match self {
|
||||
Graphic::RasterCPU(raster) => Some(raster),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster_mut(&mut self) -> Option<&mut Table<Raster<CPU>>> {
|
||||
match self {
|
||||
Graphic::RasterCPU(raster) => Some(raster),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn had_clip_enabled(&self) -> bool {
|
||||
match self {
|
||||
Graphic::Vector(vector) => vector.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Graphic(graphic) => graphic.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::RasterCPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::RasterGPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Color(color) => color.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Gradient(gradient) => gradient.iter().all(|row| row.alpha_blending.clip),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_reduce_to_clip_path(&self) -> bool {
|
||||
match self {
|
||||
Graphic::Vector(vector) => vector.iter().all(|row| {
|
||||
let style = &row.element.style;
|
||||
let alpha_blending = &row.alpha_blending;
|
||||
(alpha_blending.opacity > 1. - f32::EPSILON) && style.fill().is_opaque() && style.stroke().is_none_or(|stroke| !stroke.has_renderable_stroke())
|
||||
}),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundingBox for Graphic {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||
match self {
|
||||
Graphic::Vector(vector) => vector.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterCPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterGPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
Graphic::Graphic(graphic) => graphic.bounding_box(transform, include_stroke),
|
||||
Graphic::Color(color) => color.bounding_box(transform, include_stroke),
|
||||
Graphic::Gradient(gradient) => gradient.bounding_box(transform, include_stroke),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TableConvert<Graphic> for Vector {
|
||||
fn convert_row(self) -> Graphic {
|
||||
Graphic::Vector(Table::new_from_element(self))
|
||||
}
|
||||
}
|
||||
impl TableConvert<Graphic> for Raster<CPU> {
|
||||
fn convert_row(self) -> Graphic {
|
||||
Graphic::RasterCPU(Table::new_from_element(self))
|
||||
}
|
||||
}
|
||||
impl TableConvert<Graphic> for Raster<GPU> {
|
||||
fn convert_row(self) -> Graphic {
|
||||
Graphic::RasterGPU(Table::new_from_element(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Graphic {
|
||||
fn render_complexity(&self) -> usize {
|
||||
match self {
|
||||
Self::Graphic(table) => table.render_complexity(),
|
||||
Self::Vector(table) => table.render_complexity(),
|
||||
Self::RasterCPU(table) => table.render_complexity(),
|
||||
Self::RasterGPU(table) => table.render_complexity(),
|
||||
Self::Color(table) => table.render_complexity(),
|
||||
Self::Gradient(table) => table.render_complexity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Node definitions moved to graphic-nodes crate
|
||||
|
||||
pub trait AtIndex {
|
||||
type Output;
|
||||
fn at_index(&self, index: usize) -> Option<Self::Output>;
|
||||
}
|
||||
impl<T: Clone> AtIndex for Vec<T> {
|
||||
type Output = T;
|
||||
|
||||
fn at_index(&self, index: usize) -> Option<Self::Output> {
|
||||
self.get(index).cloned()
|
||||
}
|
||||
}
|
||||
impl<T: Clone> AtIndex for Table<T> {
|
||||
type Output = Table<T>;
|
||||
|
||||
fn at_index(&self, index: usize) -> Option<Self::Output> {
|
||||
let mut result_table = Self::default();
|
||||
if let Some(row) = self.iter().nth(index) {
|
||||
result_table.push(row.into_cloned());
|
||||
Some(result_table)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_graphic<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Graphic>, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OldGraphicGroup {
|
||||
elements: Vec<(Graphic, Option<NodeId>)>,
|
||||
transform: DAffine2,
|
||||
alpha_blending: AlphaBlending,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GraphicGroup {
|
||||
elements: Vec<(Graphic, Option<NodeId>)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OlderTable<T> {
|
||||
id: Vec<u64>,
|
||||
#[serde(alias = "instances", alias = "instance")]
|
||||
element: Vec<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OldTable<T> {
|
||||
id: Vec<u64>,
|
||||
#[serde(alias = "instances", alias = "instance")]
|
||||
element: Vec<T>,
|
||||
transform: Vec<DAffine2>,
|
||||
alpha_blending: Vec<AlphaBlending>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum GraphicFormat {
|
||||
OldGraphicGroup(OldGraphicGroup),
|
||||
OlderTableOldGraphicGroup(OlderTable<OldGraphicGroup>),
|
||||
OldTableOldGraphicGroup(OldTable<OldGraphicGroup>),
|
||||
OldTableGraphicGroup(OldTable<GraphicGroup>),
|
||||
Table(serde_json::Value),
|
||||
}
|
||||
|
||||
Ok(match GraphicFormat::deserialize(deserializer)? {
|
||||
GraphicFormat::OldGraphicGroup(old) => {
|
||||
let mut graphic_table = Table::new();
|
||||
for (graphic, source_node_id) in old.elements {
|
||||
graphic_table.push(TableRow {
|
||||
element: graphic,
|
||||
transform: old.transform,
|
||||
alpha_blending: old.alpha_blending,
|
||||
source_node_id,
|
||||
});
|
||||
}
|
||||
graphic_table
|
||||
}
|
||||
GraphicFormat::OlderTableOldGraphicGroup(old) => old
|
||||
.element
|
||||
.into_iter()
|
||||
.flat_map(|element| {
|
||||
element.elements.into_iter().map(move |(graphic, source_node_id)| TableRow {
|
||||
element: graphic,
|
||||
transform: element.transform,
|
||||
alpha_blending: element.alpha_blending,
|
||||
source_node_id,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
GraphicFormat::OldTableOldGraphicGroup(old) => old
|
||||
.element
|
||||
.into_iter()
|
||||
.flat_map(|element| {
|
||||
element.elements.into_iter().map(move |(graphic, source_node_id)| TableRow {
|
||||
element: graphic,
|
||||
transform: element.transform,
|
||||
alpha_blending: element.alpha_blending,
|
||||
source_node_id,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
GraphicFormat::OldTableGraphicGroup(old) => old
|
||||
.element
|
||||
.into_iter()
|
||||
.flat_map(|element| {
|
||||
element.elements.into_iter().map(move |(graphic, source_node_id)| TableRow {
|
||||
element: graphic,
|
||||
transform: Default::default(),
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
GraphicFormat::Table(value) => {
|
||||
// Try to deserialize as either table format
|
||||
if let Ok(old_table) = serde_json::from_value::<Table<GraphicGroup>>(value.clone()) {
|
||||
let mut graphic_table = Table::new();
|
||||
for row in old_table.iter() {
|
||||
for (graphic, source_node_id) in &row.element.elements {
|
||||
graphic_table.push(TableRow {
|
||||
element: graphic.clone(),
|
||||
transform: *row.transform,
|
||||
alpha_blending: *row.alpha_blending,
|
||||
source_node_id: *source_node_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
graphic_table
|
||||
} else if let Ok(new_table) = serde_json::from_value::<Table<Graphic>>(value) {
|
||||
new_table
|
||||
} else {
|
||||
return Err(serde::de::Error::custom("Failed to deserialize Table<Graphic>"));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
100
node-graph/libraries/graphic-types/src/lib.rs
Normal file
100
node-graph/libraries/graphic-types/src/lib.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
pub mod artboard;
|
||||
pub mod graphic;
|
||||
|
||||
// Re-export all transitive dependencies so downstream crates only need to depend on graphic-types
|
||||
pub use core_types;
|
||||
pub use raster_types;
|
||||
pub use vector_types;
|
||||
|
||||
// Re-export commonly used types at the crate root
|
||||
pub use artboard::Artboard;
|
||||
pub use graphic::{Graphic, IntoGraphicTable, Vector};
|
||||
|
||||
pub mod migrations {
|
||||
use core_types::{
|
||||
AlphaBlending,
|
||||
table::{Table, TableRow},
|
||||
};
|
||||
use dyn_any::DynAny;
|
||||
use glam::DAffine2;
|
||||
use vector_types::vector::{PathStyle, PointDomain, RegionDomain, SegmentDomain, misc::HandleId};
|
||||
|
||||
use crate::{Graphic, Vector};
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_vector<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Vector>, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OldVectorData {
|
||||
pub transform: DAffine2,
|
||||
pub alpha_blending: AlphaBlending,
|
||||
|
||||
pub style: PathStyle,
|
||||
|
||||
pub colinear_manipulators: Vec<[HandleId; 2]>,
|
||||
|
||||
pub point_domain: PointDomain,
|
||||
pub segment_domain: SegmentDomain,
|
||||
pub region_domain: RegionDomain,
|
||||
|
||||
pub upstream_graphic_group: Option<Table<Graphic>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OldTable<T> {
|
||||
#[serde(alias = "instances", alias = "instance")]
|
||||
element: Vec<T>,
|
||||
transform: Vec<DAffine2>,
|
||||
alpha_blending: Vec<AlphaBlending>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OlderTable<T> {
|
||||
id: Vec<u64>,
|
||||
#[serde(alias = "instances", alias = "instance")]
|
||||
element: Vec<T>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum VectorFormat {
|
||||
Vector(Vector),
|
||||
OldVectorData(OldVectorData),
|
||||
OldVectorTable(OldTable<Vector>),
|
||||
OlderVectorTable(OlderTable<Vector>),
|
||||
VectorTable(Table<Vector>),
|
||||
}
|
||||
|
||||
Ok(match VectorFormat::deserialize(deserializer)? {
|
||||
VectorFormat::Vector(vector) => Table::new_from_element(vector),
|
||||
VectorFormat::OldVectorData(old) => {
|
||||
let mut vector_table = Table::new_from_element(Vector {
|
||||
style: old.style,
|
||||
colinear_manipulators: old.colinear_manipulators,
|
||||
point_domain: old.point_domain,
|
||||
segment_domain: old.segment_domain,
|
||||
region_domain: old.region_domain,
|
||||
upstream_data: old.upstream_graphic_group,
|
||||
});
|
||||
*vector_table.iter_mut().next().unwrap().transform = old.transform;
|
||||
*vector_table.iter_mut().next().unwrap().alpha_blending = old.alpha_blending;
|
||||
vector_table
|
||||
}
|
||||
VectorFormat::OlderVectorTable(older_table) => older_table.element.into_iter().map(|element| TableRow { element, ..Default::default() }).collect(),
|
||||
VectorFormat::OldVectorTable(old_table) => old_table
|
||||
.element
|
||||
.into_iter()
|
||||
.zip(old_table.transform.into_iter().zip(old_table.alpha_blending))
|
||||
.map(|(element, (transform, alpha_blending))| TableRow {
|
||||
element,
|
||||
transform,
|
||||
alpha_blending,
|
||||
source_node_id: None,
|
||||
})
|
||||
.collect(),
|
||||
VectorFormat::VectorTable(vector_table) => vector_table,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "graphene-core-shaders"
|
||||
name = "no-std-types"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "no_std API definitions for Graphene"
|
||||
description = "no_std types for Graphene (shader-compatible)"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -48,7 +48,7 @@ specta = { workspace = true, optional = true }
|
||||
log = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
graphene-core = { workspace = true }
|
||||
core-types = { workspace = true }
|
||||
|
||||
[lints.rust]
|
||||
# the spirv target is not in the list of common cfgs so must be added manually
|
||||
@@ -57,4 +57,4 @@ unexpected_cfgs = { level = "warn", check-cfg = [
|
||||
] }
|
||||
|
||||
[package.metadata.cargo-shear]
|
||||
ignored = ["graphene-core"]
|
||||
ignored = ["core-types"]
|
||||
@@ -360,7 +360,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.3, 0.14, 0.15, 0.92).unwrap();
|
||||
/// assert!(color.components() == (0.3, 0.14, 0.15, 0.92));
|
||||
///
|
||||
@@ -398,7 +398,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgb8_srgb(0x72, 0x67, 0x62);
|
||||
/// let color2 = Color::from_rgba8_srgb(0x72, 0x67, 0x62, 0xFF);
|
||||
/// assert_eq!(color, color2)
|
||||
@@ -413,7 +413,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgba8_srgb(0x72, 0x67, 0x62, 0x61);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
@@ -431,7 +431,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.);
|
||||
/// ```
|
||||
pub fn from_hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Color {
|
||||
@@ -473,7 +473,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// assert!(color.r() == 0.114);
|
||||
/// ```
|
||||
@@ -486,7 +486,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// assert!(color.g() == 0.103);
|
||||
/// ```
|
||||
@@ -499,7 +499,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// assert!(color.b() == 0.98);
|
||||
/// ```
|
||||
@@ -512,7 +512,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// assert!(color.a() == 0.97);
|
||||
/// ```
|
||||
@@ -788,7 +788,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// assert_eq!(color.components(), (0.114, 0.103, 0.98, 0.97));
|
||||
/// ```
|
||||
@@ -801,7 +801,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
||||
/// assert_eq!("3240a261", color.to_rgba_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
||||
/// ```
|
||||
@@ -819,7 +819,7 @@ impl Color {
|
||||
|
||||
/// Return a 6-character RGB hex string (without a # prefix). Use this if the [`Color`] is in linear space.
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
||||
/// assert_eq!("3240a2", color.to_rgb_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
||||
/// ```
|
||||
@@ -830,7 +830,7 @@ impl Color {
|
||||
|
||||
/// Return a 6-character RGB hex string (without a # prefix). Use this if the [`Color`] is in gamma space.
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
||||
/// assert_eq!("3240a2", color.to_rgb_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
||||
/// ```
|
||||
@@ -843,7 +843,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// // TODO: Add test
|
||||
/// ```
|
||||
@@ -857,7 +857,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// // TODO: Add test
|
||||
/// ```
|
||||
@@ -872,7 +872,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.).to_hsla();
|
||||
/// ```
|
||||
pub fn to_hsla(&self) -> [f32; 4] {
|
||||
@@ -908,7 +908,7 @@ impl Color {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgba_str("7C67FA61").unwrap();
|
||||
/// ```
|
||||
pub fn from_rgba_str(color_str: &str) -> Option<Color> {
|
||||
@@ -926,7 +926,7 @@ impl Color {
|
||||
/// Creates a color from a 6-character RGB hex string (without a # prefix).
|
||||
///
|
||||
/// ```
|
||||
/// use graphene_core::color::Color;
|
||||
/// use core_types::color::Color;
|
||||
/// let color = Color::from_rgb_str("7C67FA").unwrap();
|
||||
/// ```
|
||||
pub fn from_rgb_str(color_str: &str) -> Option<Color> {
|
||||
29
node-graph/libraries/raster-types/Cargo.toml
Normal file
29
node-graph/libraries/raster-types/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "raster-types"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "Raster data types for Graphene node system"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
wgpu = ["dep:wgpu"]
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
core-types = { workspace = true }
|
||||
node-macro = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
dyn-any = { workspace = true }
|
||||
glam = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
bytemuck = { workspace = true }
|
||||
specta = { workspace = true }
|
||||
image = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
# Optional workspace dependencies
|
||||
serde = { workspace = true, optional = true }
|
||||
wgpu = { workspace = true, optional = true }
|
||||
@@ -1,10 +1,12 @@
|
||||
use super::Color;
|
||||
use crate::AlphaBlending;
|
||||
use crate::color::float_to_srgb_u8;
|
||||
use crate::raster_types::Raster;
|
||||
use crate::table::{Table, TableRow};
|
||||
use crate::vector::Vector;
|
||||
use crate::raster_types::{CPU, Raster};
|
||||
use crate::{Bitmap, BitmapMut};
|
||||
use core_types::AlphaBlending;
|
||||
use core_types::Color;
|
||||
use core_types::color::float_to_srgb_u8;
|
||||
use core_types::table::{Table, TableRow};
|
||||
// use crate::vector::Vector; // TODO: Check if Vector is actually used, if so handle differently
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core_types::color::*;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::vec::Vec;
|
||||
@@ -12,8 +14,8 @@ use std::vec::Vec;
|
||||
mod base64_serde {
|
||||
//! Basic wrapper for [`serde`] to perform [`base64`] encoding
|
||||
|
||||
use super::super::Pixel;
|
||||
use base64::Engine;
|
||||
use core_types::color::*;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
pub fn as_base64<S: Serializer, P: Pixel>(key: &[P], serializer: S) -> Result<S::Ok, S::Error> {
|
||||
@@ -58,7 +60,7 @@ impl Hash for TransformImage {
|
||||
fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
|
||||
}
|
||||
|
||||
impl<P: Pixel + Debug> Debug for Image<P> {
|
||||
impl<P: Pixel + std::fmt::Debug> std::fmt::Debug for Image<P> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let length = self.data.len();
|
||||
f.debug_struct("Image")
|
||||
@@ -236,7 +238,6 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub enum GraphicElement {
|
||||
GraphicGroup(Table<GraphicElement>),
|
||||
VectorData(Table<Vector>),
|
||||
RasterFrame(RasterFrame),
|
||||
}
|
||||
|
||||
@@ -391,8 +392,6 @@ pub fn migrate_image_frame_row<'de, D: serde::Deserializer<'de>>(deserializer: D
|
||||
pub enum GraphicElement {
|
||||
/// Equivalent to the SVG <g> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
|
||||
GraphicGroup(Table<GraphicElement>),
|
||||
/// A vector shape, equivalent to the SVG <path> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
|
||||
VectorData(Table<Vector>),
|
||||
RasterFrame(RasterFrame),
|
||||
}
|
||||
|
||||
@@ -461,7 +460,7 @@ pub fn migrate_image_frame_row<'de, D: serde::Deserializer<'de>>(deserializer: D
|
||||
})
|
||||
}
|
||||
|
||||
impl<P: Debug + Copy + Pixel> Sample for Image<P> {
|
||||
impl<P: std::fmt::Debug + Copy + Pixel> Sample for Image<P> {
|
||||
type Pixel = P;
|
||||
|
||||
// TODO: Improve sampling logic
|
||||
@@ -1,13 +1,18 @@
|
||||
pub mod image;
|
||||
pub mod raster_types;
|
||||
|
||||
// Re-exports for convenience
|
||||
pub use image::Image;
|
||||
pub use raster_types::*;
|
||||
|
||||
// Re-export color types from no-std-types
|
||||
pub use core_types::color::*;
|
||||
|
||||
/// as to not yet rename all references
|
||||
pub mod color {
|
||||
pub use super::*;
|
||||
}
|
||||
|
||||
pub mod image;
|
||||
|
||||
pub use self::image::Image;
|
||||
pub use crate::color::*;
|
||||
use crate::raster_types::CPU;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait Bitmap {
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::Color;
|
||||
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use crate::math::quad::Quad;
|
||||
use crate::raster::Image;
|
||||
use crate::image::Image;
|
||||
use core::ops::Deref;
|
||||
use core_types::Color;
|
||||
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use core_types::math::quad::Quad;
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::fmt::Debug;
|
||||
@@ -211,3 +211,17 @@ where
|
||||
RenderBoundingBox::Rectangle((transform * unit_rectangle).bounding_box())
|
||||
}
|
||||
}
|
||||
|
||||
// RenderComplexity trait implementations
|
||||
impl core_types::render_complexity::RenderComplexity for Raster<CPU> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
(self.width * self.height / 500) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl core_types::render_complexity::RenderComplexity for Raster<GPU> {
|
||||
fn render_complexity(&self) -> usize {
|
||||
// GPU textures currently can't have a thumbnail
|
||||
usize::MAX
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
[package]
|
||||
name = "graphene-svg-renderer"
|
||||
name = "rendering"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "graphene svg renderer"
|
||||
description = "SVG rendering for Graphene"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
dyn-any = { workspace = true }
|
||||
graphene-core = { workspace = true }
|
||||
core-types = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
glam = { workspace = true }
|
||||
@@ -19,6 +19,9 @@ log = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
usvg = { workspace = true }
|
||||
kurbo = { workspace = true }
|
||||
vector-types = { workspace = true }
|
||||
graphic-types = { workspace = true }
|
||||
|
||||
# Optional workspace dependencies
|
||||
vello = { workspace = true, optional = true }
|
||||
|
||||
# Workspace dependencies
|
||||
vello = { workspace = true }
|
||||
@@ -1,6 +1,6 @@
|
||||
use glam::DVec2;
|
||||
use graphene_core::subpath::{ManipulatorGroup, Subpath};
|
||||
use graphene_core::vector::PointId;
|
||||
use vector_types::subpath::{ManipulatorGroup, Subpath};
|
||||
use vector_types::vector::PointId;
|
||||
|
||||
pub fn convert_usvg_path(path: &usvg::Path) -> Vec<Subpath<PointId>> {
|
||||
let mut subpaths = Vec::new();
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::renderer::{RenderParams, format_transform_matrix};
|
||||
use core_types::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
||||
use core_types::uuid::generate_uuid;
|
||||
use glam::DAffine2;
|
||||
use graphene_core::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
||||
use graphene_core::gradient::{Gradient, GradientType};
|
||||
use graphene_core::uuid::generate_uuid;
|
||||
use graphene_core::vector::style::{Fill, PaintOrder, PathStyle, RenderMode, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphic_types::vector_types::gradient::{Gradient, GradientType};
|
||||
use graphic_types::vector_types::vector::style::{Fill, PaintOrder, PathStyle, RenderMode, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use std::fmt::Write;
|
||||
|
||||
pub trait RenderExt {
|
||||
@@ -1,26 +1,26 @@
|
||||
use crate::render_ext::RenderExt;
|
||||
use crate::to_peniko::BlendModeExt;
|
||||
use core_types::blending::BlendMode;
|
||||
use core_types::bounds::BoundingBox;
|
||||
use core_types::bounds::RenderBoundingBox;
|
||||
use core_types::color::Color;
|
||||
use core_types::math::quad::Quad;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::table::{Table, TableRow};
|
||||
use core_types::transform::{Footprint, Transform};
|
||||
use core_types::uuid::{NodeId, generate_uuid};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_core::blending::BlendMode;
|
||||
use graphene_core::bounds::BoundingBox;
|
||||
use graphene_core::bounds::RenderBoundingBox;
|
||||
use graphene_core::color::Color;
|
||||
use graphene_core::gradient::GradientStops;
|
||||
use graphene_core::gradient::GradientType;
|
||||
use graphene_core::math::quad::Quad;
|
||||
use graphene_core::raster::BitmapMut;
|
||||
use graphene_core::raster::Image;
|
||||
use graphene_core::raster_types::{CPU, GPU, Raster};
|
||||
use graphene_core::render_complexity::RenderComplexity;
|
||||
use graphene_core::subpath::Subpath;
|
||||
use graphene_core::table::{Table, TableRow};
|
||||
use graphene_core::transform::{Footprint, Transform};
|
||||
use graphene_core::uuid::{NodeId, generate_uuid};
|
||||
use graphene_core::vector::Vector;
|
||||
use graphene_core::vector::click_target::{ClickTarget, FreePoint};
|
||||
use graphene_core::vector::style::{Fill, PaintOrder, RenderMode, Stroke, StrokeAlign};
|
||||
use graphene_core::{Artboard, Graphic};
|
||||
use graphic_types::Vector;
|
||||
use graphic_types::raster_types::BitmapMut;
|
||||
use graphic_types::raster_types::Image;
|
||||
use graphic_types::raster_types::{CPU, GPU, Raster};
|
||||
use graphic_types::vector_types::gradient::GradientStops;
|
||||
use graphic_types::vector_types::gradient::GradientType;
|
||||
use graphic_types::vector_types::subpath::Subpath;
|
||||
use graphic_types::vector_types::vector::click_target::{ClickTarget, FreePoint};
|
||||
use graphic_types::vector_types::vector::style::{Fill, PaintOrder, RenderMode, Stroke, StrokeAlign};
|
||||
use graphic_types::{Artboard, Graphic};
|
||||
use kurbo::Affine;
|
||||
use num_traits::Zero;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@@ -28,7 +28,6 @@ use std::fmt::Write;
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
#[cfg(feature = "vello")]
|
||||
use vello::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
@@ -152,7 +151,6 @@ impl Default for SvgRender {
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct RenderContext {
|
||||
#[cfg(feature = "vello")]
|
||||
pub resource_overrides: Vec<(peniko::ImageBrush, wgpu::Texture)>,
|
||||
}
|
||||
|
||||
@@ -264,7 +262,6 @@ impl RenderMetadata {
|
||||
pub trait Render: BoundingBox + RenderComplexity {
|
||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams);
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, _render_params: &RenderParams);
|
||||
|
||||
/// The upstream click targets for each layer are collected during the render so that they do not have to be calculated for each click detection.
|
||||
@@ -295,7 +292,6 @@ impl Render for Graphic {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||
match self {
|
||||
Graphic::Graphic(table) => table.render_to_vello(scene, transform, context, render_params),
|
||||
@@ -448,7 +444,6 @@ impl Render for Artboard {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||
use vello::peniko;
|
||||
|
||||
@@ -503,7 +498,6 @@ impl Render for Table<Artboard> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||
for row in self.iter() {
|
||||
row.element.render_to_vello(scene, transform, context, render_params);
|
||||
@@ -579,7 +573,6 @@ impl Render for Table<Graphic> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||
let mut iter = self.iter().peekable();
|
||||
let mut mask_element_and_transform = None;
|
||||
@@ -860,14 +853,15 @@ impl Render for Table<Vector> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, parent_transform: DAffine2, _context: &mut RenderContext, render_params: &RenderParams) {
|
||||
use graphene_core::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
||||
use graphene_core::vector::style::{GradientType, StrokeCap, StrokeJoin};
|
||||
use core_types::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
||||
use graphic_types::vector_types::vector::style::{GradientType, StrokeCap, StrokeJoin};
|
||||
use vello::kurbo::{Cap, Join};
|
||||
use vello::peniko;
|
||||
|
||||
for row in self.iter() {
|
||||
use graphic_types::vector_types::vector;
|
||||
|
||||
let multiplied_transform = parent_transform * *row.transform;
|
||||
let has_real_stroke = row.element.style.stroke().filter(|stroke| stroke.weight() > 0.);
|
||||
let set_stroke_transform = has_real_stroke.map(|stroke| stroke.transform).filter(|transform| transform.matrix2.determinant() != 0.);
|
||||
@@ -919,7 +913,7 @@ impl Render for Table<Vector> {
|
||||
row.element.style.stroke().is_some_and(|stroke| stroke.has_renderable_stroke() && stroke.align.is_not_centered()) && row.element.stroke_bezier_paths().all(|path| path.closed());
|
||||
|
||||
let use_layer = can_draw_aligned_stroke;
|
||||
let wants_stroke_below = row.element.style.stroke().is_some_and(|s| s.paint_order == graphene_core::vector::style::PaintOrder::StrokeBelow);
|
||||
let wants_stroke_below = row.element.style.stroke().is_some_and(|s| s.paint_order == vector::style::PaintOrder::StrokeBelow);
|
||||
|
||||
// Closures to avoid duplicated fill/stroke drawing logic
|
||||
let do_fill = |scene: &mut Scene| match row.element.style.fill() {
|
||||
@@ -1150,7 +1144,7 @@ impl Render for Table<Vector> {
|
||||
metadata.click_targets.entry(element_id).or_insert(click_targets);
|
||||
}
|
||||
|
||||
if let Some(upstream_nested_layers) = &vector.upstream_nested_layers {
|
||||
if let Some(upstream_nested_layers) = &vector.upstream_data {
|
||||
footprint.transform *= transform;
|
||||
upstream_nested_layers.collect_metadata(metadata, footprint, None);
|
||||
}
|
||||
@@ -1286,7 +1280,6 @@ impl Render for Table<Raster<CPU>> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _: &mut RenderContext, render_params: &RenderParams) {
|
||||
use vello::peniko;
|
||||
|
||||
@@ -1302,13 +1295,13 @@ impl Render for Table<Raster<CPU>> {
|
||||
let opacity = alpha_blending.opacity(render_params.for_mask);
|
||||
let mut layer = false;
|
||||
|
||||
if opacity < 1. || alpha_blending.blend_mode != BlendMode::default() {
|
||||
if let RenderBoundingBox::Rectangle(bounds) = self.bounding_box(transform, false) {
|
||||
let blending = peniko::BlendMode::new(blend_mode, peniko::Compose::SrcOver);
|
||||
let rect = kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||
scene.push_layer(blending, opacity, kurbo::Affine::IDENTITY, &rect);
|
||||
layer = true;
|
||||
}
|
||||
if (opacity < 1. || alpha_blending.blend_mode != BlendMode::default())
|
||||
&& let RenderBoundingBox::Rectangle(bounds) = self.bounding_box(transform, false)
|
||||
{
|
||||
let blending = peniko::BlendMode::new(blend_mode, peniko::Compose::SrcOver);
|
||||
let rect = kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||
scene.push_layer(blending, opacity, kurbo::Affine::IDENTITY, &rect);
|
||||
layer = true;
|
||||
}
|
||||
|
||||
let image_brush = peniko::ImageBrush::new(peniko::ImageData {
|
||||
@@ -1354,20 +1347,19 @@ impl Render for Table<Raster<GPU>> {
|
||||
log::warn!("tried to render texture as an svg");
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, _render_params: &RenderParams) {
|
||||
use vello::peniko;
|
||||
|
||||
for row in self.iter() {
|
||||
let blend_mode = *row.alpha_blending;
|
||||
let mut layer = false;
|
||||
if blend_mode != Default::default() {
|
||||
if let RenderBoundingBox::Rectangle(bounds) = self.bounding_box(transform, true) {
|
||||
let blending = peniko::BlendMode::new(blend_mode.blend_mode.to_peniko(), peniko::Compose::SrcOver);
|
||||
let rect = kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||
scene.push_layer(blending, blend_mode.opacity, kurbo::Affine::IDENTITY, &rect);
|
||||
layer = true;
|
||||
}
|
||||
if blend_mode != Default::default()
|
||||
&& let RenderBoundingBox::Rectangle(bounds) = self.bounding_box(transform, true)
|
||||
{
|
||||
let blending = peniko::BlendMode::new(blend_mode.blend_mode.to_peniko(), peniko::Compose::SrcOver);
|
||||
let rect = kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||
scene.push_layer(blending, blend_mode.opacity, kurbo::Affine::IDENTITY, &rect);
|
||||
layer = true;
|
||||
}
|
||||
|
||||
let width = row.element.data().width();
|
||||
@@ -1440,7 +1432,6 @@ impl Render for Table<Color> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, _parent_transform: DAffine2, _context: &mut RenderContext, render_params: &RenderParams) {
|
||||
use vello::peniko;
|
||||
|
||||
@@ -1534,7 +1525,6 @@ impl Render for Table<GradientStops> {
|
||||
}
|
||||
|
||||
// TODO: Fix infinite gradient rendering
|
||||
#[cfg(feature = "vello")]
|
||||
fn render_to_vello(&self, scene: &mut Scene, _parent_transform: DAffine2, _context: &mut RenderContext, render_params: &RenderParams) {
|
||||
use vello::peniko;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use graphene_core::BlendMode;
|
||||
use core_types::BlendMode;
|
||||
use vello::peniko;
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
pub trait BlendModeExt {
|
||||
fn to_peniko(&self) -> peniko::Mix;
|
||||
}
|
||||
|
||||
#[cfg(feature = "vello")]
|
||||
impl BlendModeExt for BlendMode {
|
||||
fn to_peniko(&self) -> peniko::Mix {
|
||||
match self {
|
||||
33
node-graph/libraries/vector-types/Cargo.toml
Normal file
33
node-graph/libraries/vector-types/Cargo.toml
Normal file
@@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "vector-types"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "Vector graphics types and algorithms for Graphene"
|
||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
core-types = { workspace = true }
|
||||
node-macro = { workspace = true }
|
||||
|
||||
# Workspace dependencies
|
||||
bitflags = { workspace = true }
|
||||
bytemuck = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
glam = { workspace = true }
|
||||
kurbo = { workspace = true }
|
||||
lyon_geom = { workspace = true }
|
||||
dyn-any = { workspace = true }
|
||||
specta = { workspace = true }
|
||||
log = { workspace = true }
|
||||
petgraph = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
polycool = { workspace = true }
|
||||
tinyvec = { workspace = true }
|
||||
|
||||
# Optional workspace dependencies
|
||||
serde = { workspace = true, optional = true }
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::Color;
|
||||
use core_types::{Color, render_complexity::RenderComplexity};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
||||
@@ -32,6 +32,12 @@ impl Default for GradientStops {
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for GradientStops {
|
||||
fn render_complexity(&self) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for GradientStops {
|
||||
type Item = (f64, Color);
|
||||
type IntoIter = std::vec::IntoIter<(f64, Color)>;
|
||||
@@ -232,3 +238,9 @@ impl Gradient {
|
||||
Some(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl core_types::bounds::BoundingBox for GradientStops {
|
||||
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> core_types::bounds::RenderBoundingBox {
|
||||
core_types::bounds::RenderBoundingBox::Infinite
|
||||
}
|
||||
}
|
||||
20
node-graph/libraries/vector-types/src/lib.rs
Normal file
20
node-graph/libraries/vector-types/src/lib.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod gradient;
|
||||
pub mod math;
|
||||
pub mod subpath;
|
||||
pub mod vector;
|
||||
|
||||
// Re-export commonly used types at the crate root
|
||||
pub use core_types as gcore;
|
||||
pub use gradient::{GradientStops, GradientType};
|
||||
pub use math::{QuadExt, RectExt};
|
||||
pub use subpath::Subpath;
|
||||
pub use vector::Vector;
|
||||
pub use vector::reference_point::ReferencePoint;
|
||||
|
||||
// Re-export dependencies that users of this crate will need
|
||||
pub use dyn_any;
|
||||
pub use glam;
|
||||
pub use kurbo;
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::math::quad::Quad;
|
||||
use crate::math::rect::Rect;
|
||||
use crate::subpath::Bezier;
|
||||
use crate::vector::misc::dvec2_to_point;
|
||||
use core_types::math::quad::Quad;
|
||||
use core_types::math::rect::Rect;
|
||||
use kurbo::{Line, PathSeg};
|
||||
|
||||
pub trait QuadExt {
|
||||
@@ -239,7 +239,7 @@ impl<PointId: Identifier> Subpath<PointId> {
|
||||
let mut start_angle = 0.;
|
||||
let mut sweep_angle = sweep_angle.abs();
|
||||
|
||||
if (sweep_angle / std::f64::consts::TAU).floor() as u32 % 2 == 0 {
|
||||
if ((sweep_angle / std::f64::consts::TAU).floor() as u32).is_multiple_of(2) {
|
||||
sweep_angle %= std::f64::consts::TAU;
|
||||
} else {
|
||||
start_angle = sweep_angle % std::f64::consts::TAU;
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::consts::MAX_ABSOLUTE_DIFFERENCE;
|
||||
use super::*;
|
||||
use crate::math::polynomial::pathseg_to_parametric_polynomial;
|
||||
use crate::vector::algorithms::bezpath_algorithms::pathseg_length_centroid_and_length;
|
||||
use crate::vector::algorithms::intersection::{filtered_all_segment_intersections, pathseg_self_intersections};
|
||||
use core_types::math::polynomial::pathseg_to_parametric_polynomial;
|
||||
use glam::DVec2;
|
||||
|
||||
impl<PointId: Identifier> Subpath<PointId> {
|
||||
@@ -1,9 +1,9 @@
|
||||
use super::intersection::bezpath_intersections;
|
||||
use super::poisson_disk::poisson_disk_sample;
|
||||
use super::util::pathseg_tangent;
|
||||
use crate::math::polynomial::pathseg_to_parametric_polynomial;
|
||||
use crate::vector::algorithms::offset_subpath::MAX_ABSOLUTE_DIFFERENCE;
|
||||
use crate::vector::misc::{PointSpacingType, dvec2_to_point, point_to_dvec2};
|
||||
use core_types::math::polynomial::pathseg_to_parametric_polynomial;
|
||||
use glam::{DMat2, DVec2};
|
||||
use kurbo::common::{solve_cubic, solve_quadratic};
|
||||
use kurbo::{BezPath, CubicBez, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveDeriv, PathEl, PathSeg, Point, QuadBez, Rect, Shape, Vec2};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user