mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 20:38:12 +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:
co-authored by
Keavon Chambers
parent
12453d2e61
commit
57b0b9c7ed
Generated
+308
-144
@@ -506,6 +506,18 @@ version = "2.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blending-nodes"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"core-types",
|
||||||
|
"glam",
|
||||||
|
"graphic-types",
|
||||||
|
"node-macro",
|
||||||
|
"serde",
|
||||||
|
"vector-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block"
|
name = "block"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@@ -552,6 +564,20 @@ dependencies = [
|
|||||||
"cfg_aliases",
|
"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]]
|
[[package]]
|
||||||
name = "built"
|
name = "built"
|
||||||
version = "0.7.7"
|
version = "0.7.7"
|
||||||
@@ -1025,6 +1051,37 @@ dependencies = [
|
|||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "core_maths"
|
name = "core_maths"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -2048,25 +2105,28 @@ dependencies = [
|
|||||||
name = "graph-craft"
|
name = "graph-craft"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"brush-nodes",
|
||||||
|
"core-types",
|
||||||
"criterion",
|
"criterion",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"glam",
|
"glam",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-application-io",
|
"graphene-application-io",
|
||||||
"graphene-brush",
|
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
"graphene-path-bool",
|
"graphic-types",
|
||||||
"graphene-raster-nodes",
|
|
||||||
"graphene-svg-renderer",
|
|
||||||
"iai-callgrind",
|
"iai-callgrind",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
|
"path-bool-nodes",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
"raster-nodes",
|
||||||
|
"rendering",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"specta",
|
"specta",
|
||||||
|
"text-nodes",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -2079,28 +2139,17 @@ dependencies = [
|
|||||||
name = "graphene-application-io"
|
name = "graphene-application-io"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"core-types",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"glam",
|
"glam",
|
||||||
"graphene-core",
|
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
|
"text-nodes",
|
||||||
|
"vector-types",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "graphene-brush"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"dyn-any",
|
|
||||||
"glam",
|
|
||||||
"graphene-core",
|
|
||||||
"graphene-raster-nodes",
|
|
||||||
"node-macro",
|
|
||||||
"serde",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "graphene-cli"
|
name = "graphene-cli"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -2110,7 +2159,6 @@ dependencies = [
|
|||||||
"fern",
|
"fern",
|
||||||
"futures",
|
"futures",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-core",
|
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"interpreted-executor",
|
"interpreted-executor",
|
||||||
"log",
|
"log",
|
||||||
@@ -2124,120 +2172,16 @@ dependencies = [
|
|||||||
name = "graphene-core"
|
name = "graphene-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"core-types",
|
||||||
"bitflags 2.9.3",
|
|
||||||
"bytemuck",
|
|
||||||
"ctor",
|
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"glam",
|
"glam",
|
||||||
"graphene-core-shaders",
|
"graphic-types",
|
||||||
"image",
|
|
||||||
"kurbo 0.12.0",
|
|
||||||
"log",
|
"log",
|
||||||
"lyon_geom",
|
|
||||||
"node-macro",
|
"node-macro",
|
||||||
"num-traits",
|
"raster-types",
|
||||||
"parley",
|
|
||||||
"petgraph 0.7.1",
|
|
||||||
"polycool",
|
|
||||||
"rand 0.9.2",
|
|
||||||
"rand_chacha 0.9.0",
|
|
||||||
"rustc-hash 2.1.1",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"skrifa 0.36.0",
|
|
||||||
"specta",
|
"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]]
|
[[package]]
|
||||||
@@ -2245,21 +2189,29 @@ name = "graphene-std"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
|
"blending-nodes",
|
||||||
|
"brush-nodes",
|
||||||
|
"core-types",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"glam",
|
"glam",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-application-io",
|
"graphene-application-io",
|
||||||
"graphene-brush",
|
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
"graphene-math-nodes",
|
"graphic-nodes",
|
||||||
"graphene-path-bool",
|
"graphic-types",
|
||||||
"graphene-raster-nodes",
|
|
||||||
"graphene-svg-renderer",
|
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
|
"math-nodes",
|
||||||
"node-macro",
|
"node-macro",
|
||||||
|
"path-bool-nodes",
|
||||||
|
"raster-nodes",
|
||||||
|
"rendering",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"text-nodes",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"transform-nodes",
|
||||||
|
"vector-nodes",
|
||||||
|
"vector-types",
|
||||||
"vello",
|
"vello",
|
||||||
"vello_encoding",
|
"vello_encoding",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -2269,19 +2221,32 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "graphene-svg-renderer"
|
name = "graphic-nodes"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"core-types",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"glam",
|
"glam",
|
||||||
"graphene-core",
|
"graphic-types",
|
||||||
"kurbo 0.12.0",
|
"node-macro",
|
||||||
"log",
|
"raster-types",
|
||||||
"num-traits",
|
|
||||||
"serde",
|
"serde",
|
||||||
"usvg 0.45.1",
|
"vector-types",
|
||||||
"vello",
|
]
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
@@ -2962,17 +2927,18 @@ dependencies = [
|
|||||||
name = "interpreted-executor"
|
name = "interpreted-executor"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"core-types",
|
||||||
"criterion",
|
"criterion",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"futures",
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
"graphene-path-bool",
|
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"iai-callgrind",
|
"iai-callgrind",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"path-bool-nodes",
|
||||||
"preprocessor",
|
"preprocessor",
|
||||||
"serde",
|
"serde",
|
||||||
"wgpu-executor",
|
"wgpu-executor",
|
||||||
@@ -3347,6 +3313,19 @@ dependencies = [
|
|||||||
"regex-automata",
|
"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]]
|
[[package]]
|
||||||
name = "math-parser"
|
name = "math-parser"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
@@ -3603,14 +3582,33 @@ dependencies = [
|
|||||||
"memoffset",
|
"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]]
|
[[package]]
|
||||||
name = "node-macro"
|
name = "node-macro"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
"graphene-core",
|
"core-types",
|
||||||
"graphene-core-shaders",
|
|
||||||
"indoc",
|
"indoc",
|
||||||
|
"no-std-types",
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro-error2",
|
"proc-macro-error2",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -4074,6 +4072,22 @@ dependencies = [
|
|||||||
"svg",
|
"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]]
|
[[package]]
|
||||||
name = "pathdiff"
|
name = "pathdiff"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@@ -4604,6 +4618,68 @@ version = "0.1.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
|
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]]
|
[[package]]
|
||||||
name = "rav1e"
|
name = "rav1e"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -4786,6 +4862,24 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
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]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.23"
|
version = "0.12.23"
|
||||||
@@ -5744,6 +5838,21 @@ dependencies = [
|
|||||||
"winapi-util",
|
"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]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
@@ -6124,6 +6233,18 @@ dependencies = [
|
|||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "transform-nodes"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"core-types",
|
||||||
|
"glam",
|
||||||
|
"graphic-types",
|
||||||
|
"node-macro",
|
||||||
|
"serde",
|
||||||
|
"vector-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
@@ -6408,6 +6529,48 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
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]]
|
[[package]]
|
||||||
name = "vello"
|
name = "vello"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@@ -6831,13 +6994,14 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"core-types",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"futures",
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"graphene-application-io",
|
"graphene-application-io",
|
||||||
"graphene-core",
|
|
||||||
"graphene-svg-renderer",
|
|
||||||
"node-macro",
|
"node-macro",
|
||||||
|
"raster-types",
|
||||||
|
"rendering",
|
||||||
"vello",
|
"vello",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
|
|||||||
+60
-33
@@ -12,19 +12,28 @@ members = [
|
|||||||
"libraries/dyn-any",
|
"libraries/dyn-any",
|
||||||
"libraries/path-bool",
|
"libraries/path-bool",
|
||||||
"libraries/math-parser",
|
"libraries/math-parser",
|
||||||
"node-graph/gapplication-io",
|
"node-graph/libraries/application-io",
|
||||||
"node-graph/gbrush",
|
"node-graph/libraries/core-types",
|
||||||
"node-graph/gcore",
|
"node-graph/libraries/no-std-types",
|
||||||
"node-graph/gcore-shaders",
|
"node-graph/libraries/raster-types",
|
||||||
"node-graph/gmath-nodes",
|
"node-graph/libraries/vector-types",
|
||||||
"node-graph/gpath-bool",
|
"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/graph-craft",
|
||||||
"node-graph/graphene-cli",
|
"node-graph/graphene-cli",
|
||||||
"node-graph/graster-nodes",
|
"node-graph/nodes/gstd",
|
||||||
"node-graph/graster-nodes/shaders",
|
|
||||||
"node-graph/graster-nodes/shaders/entrypoint",
|
|
||||||
"node-graph/gstd",
|
|
||||||
"node-graph/gsvg-renderer",
|
|
||||||
"node-graph/interpreted-executor",
|
"node-graph/interpreted-executor",
|
||||||
"node-graph/node-macro",
|
"node-graph/node-macro",
|
||||||
"node-graph/preprocessor",
|
"node-graph/preprocessor",
|
||||||
@@ -37,18 +46,27 @@ default-members = [
|
|||||||
"libraries/dyn-any",
|
"libraries/dyn-any",
|
||||||
"libraries/path-bool",
|
"libraries/path-bool",
|
||||||
"libraries/math-parser",
|
"libraries/math-parser",
|
||||||
"node-graph/gapplication-io",
|
"node-graph/libraries/application-io",
|
||||||
"node-graph/gbrush",
|
"node-graph/libraries/core-types",
|
||||||
"node-graph/gcore",
|
"node-graph/libraries/no-std-types",
|
||||||
"node-graph/gcore-shaders",
|
"node-graph/libraries/raster-types",
|
||||||
"node-graph/graster-nodes/shaders",
|
"node-graph/libraries/vector-types",
|
||||||
"node-graph/gmath-nodes",
|
"node-graph/libraries/graphic-types",
|
||||||
"node-graph/gpath-bool",
|
"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/graph-craft",
|
||||||
"node-graph/graphene-cli",
|
"node-graph/graphene-cli",
|
||||||
"node-graph/graster-nodes",
|
"node-graph/nodes/gstd",
|
||||||
"node-graph/gstd",
|
|
||||||
"node-graph/gsvg-renderer",
|
|
||||||
"node-graph/interpreted-executor",
|
"node-graph/interpreted-executor",
|
||||||
"node-graph/node-macro",
|
"node-graph/node-macro",
|
||||||
"node-graph/preprocessor",
|
"node-graph/preprocessor",
|
||||||
@@ -70,16 +88,25 @@ dyn-any = { path = "libraries/dyn-any", features = [
|
|||||||
preprocessor = { path = "node-graph/preprocessor" }
|
preprocessor = { path = "node-graph/preprocessor" }
|
||||||
math-parser = { path = "libraries/math-parser" }
|
math-parser = { path = "libraries/math-parser" }
|
||||||
path-bool = { path = "libraries/path-bool" }
|
path-bool = { path = "libraries/path-bool" }
|
||||||
graphene-application-io = { path = "node-graph/gapplication-io" }
|
graphene-application-io = { path = "node-graph/libraries/application-io" }
|
||||||
graphene-brush = { path = "node-graph/gbrush" }
|
core-types = { path = "node-graph/libraries/core-types" }
|
||||||
graphene-core = { path = "node-graph/gcore" }
|
no-std-types = { path = "node-graph/libraries/no-std-types" }
|
||||||
graphene-core-shaders = { path = "node-graph/gcore-shaders" }
|
raster-types = { path = "node-graph/libraries/raster-types" }
|
||||||
graphene-math-nodes = { path = "node-graph/gmath-nodes" }
|
vector-types = { path = "node-graph/libraries/vector-types" }
|
||||||
graphene-path-bool = { path = "node-graph/gpath-bool" }
|
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" }
|
graph-craft = { path = "node-graph/graph-craft" }
|
||||||
graphene-raster-nodes = { path = "node-graph/graster-nodes" }
|
raster-nodes = { path = "node-graph/nodes/raster" }
|
||||||
graphene-std = { path = "node-graph/gstd" }
|
graphene-std = { path = "node-graph/nodes/gstd" }
|
||||||
graphene-svg-renderer = { path = "node-graph/gsvg-renderer" }
|
|
||||||
interpreted-executor = { path = "node-graph/interpreted-executor" }
|
interpreted-executor = { path = "node-graph/interpreted-executor" }
|
||||||
node-macro = { path = "node-graph/node-macro" }
|
node-macro = { path = "node-graph/node-macro" }
|
||||||
wgpu-executor = { path = "node-graph/wgpu-executor" }
|
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
|
opt-level = 1
|
||||||
|
|
||||||
[profile.dev.package]
|
[profile.dev.package]
|
||||||
graphite-editor = { opt-level = 1 }
|
no-std-types = { opt-level = 1 }
|
||||||
graphene-core-shaders = { opt-level = 1 }
|
core-types= { opt-level = 1 }
|
||||||
graphene-std = { 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
|
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 }
|
graphite-proc-macros = { opt-level = 1 }
|
||||||
image = { opt-level = 2 }
|
image = { opt-level = 2 }
|
||||||
@@ -219,6 +245,7 @@ rustc-hash = { opt-level = 3 }
|
|||||||
serde_derive = { opt-level = 1 }
|
serde_derive = { opt-level = 1 }
|
||||||
specta-macros = { opt-level = 1 }
|
specta-macros = { opt-level = 1 }
|
||||||
syn = { opt-level = 1 }
|
syn = { opt-level = 1 }
|
||||||
|
node-macro = { opt-level = 2 }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "thin"
|
lto = "thin"
|
||||||
|
|||||||
Generated
+1
-1
File diff suppressed because one or more lines are too long
Generated
+1
-1
File diff suppressed because one or more lines are too long
Generated
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Generated
+1
-1
File diff suppressed because one or more lines are too long
Generated
+1
-1
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
|
# Local dependencies
|
||||||
graphite-editor = { path = "../../editor", features = [
|
graphite-editor = { path = "../../editor", features = [
|
||||||
"gpu",
|
"gpu",
|
||||||
"vello",
|
|
||||||
] }
|
] }
|
||||||
graphene-std = { workspace = true }
|
graphene-std = { workspace = true }
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
|
|||||||
+2
-9
@@ -11,18 +11,16 @@ repository = "https://github.com/GraphiteEditor/Graphite"
|
|||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["wasm"]
|
default = ["wasm", "gpu" ]
|
||||||
wasm = ["wasm-bindgen", "graphene-std/wasm"]
|
wasm = ["wasm-bindgen", "graphene-std/wasm"]
|
||||||
gpu = ["interpreted-executor/gpu", "wgpu-executor"]
|
gpu = ["interpreted-executor/gpu", "wgpu-executor"]
|
||||||
resvg = ["graphene-std/resvg"]
|
|
||||||
vello = ["graphene-std/vello", "resvg"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
graphite-proc-macros = { workspace = true }
|
graphite-proc-macros = { workspace = true }
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
interpreted-executor = { 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 }
|
preprocessor = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
@@ -59,8 +57,3 @@ env_logger = { workspace = true }
|
|||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
tokio = { 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![
|
table_rows.push(vec![
|
||||||
TextLabel::new("Upstream Nested Layers").narrow(true).widget_holder(),
|
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)"
|
"Yes (this preserves references to its upstream nested layers for editing by tools)"
|
||||||
} else {
|
} else {
|
||||||
"No (this doesn't preserve references to its upstream nested layers for editing by tools)"
|
"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"),
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: None,
|
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")]
|
#[cfg(feature = "gpu")]
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
identifier: "Create GPU Surface",
|
identifier: "Create GPU Surface",
|
||||||
@@ -915,7 +897,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -986,7 +968,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||||||
DocumentNode {
|
DocumentNode {
|
||||||
call_argument: generic!(T),
|
call_argument: generic!(T),
|
||||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -1073,7 +1055,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||||||
// category: "Raster: Adjustment",
|
// category: "Raster: Adjustment",
|
||||||
// node_template: NodeTemplate {
|
// node_template: NodeTemplate {
|
||||||
// document_node: DocumentNode {
|
// document_node: DocumentNode {
|
||||||
// implementation: DocumentNodeImplementation::proto("graphene_core::raster::CurvesNode"),
|
// implementation: DocumentNodeImplementation::proto("core_types::raster::CurvesNode"),
|
||||||
// inputs: vec![
|
// inputs: vec![
|
||||||
// NodeInput::value(TaggedValue::Raster(Default::default()), true),
|
// NodeInput::value(TaggedValue::Raster(Default::default()), true),
|
||||||
// NodeInput::value(TaggedValue::Curve(Default::default()), false),
|
// NodeInput::value(TaggedValue::Curve(Default::default()), false),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -150,10 +150,7 @@ impl NodeGraphExecutor {
|
|||||||
viewport,
|
viewport,
|
||||||
scale: viewport_scale,
|
scale: viewport_scale,
|
||||||
time,
|
time,
|
||||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
|
||||||
export_format: graphene_std::application_io::ExportFormat::Raster,
|
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,
|
render_mode: document.render_mode,
|
||||||
hide_artboards: false,
|
hide_artboards: false,
|
||||||
for_export: false,
|
for_export: false,
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ impl NodeRuntime {
|
|||||||
self.monitor_nodes = proto_network
|
self.monitor_nodes = proto_network
|
||||||
.nodes
|
.nodes
|
||||||
.iter()
|
.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())
|
.map(|(_, node)| node.original_location.path.clone().unwrap_or_default())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ crate-type = ["cdylib", "rlib"]
|
|||||||
# Local dependencies
|
# Local dependencies
|
||||||
editor = { path = "../../editor", package = "graphite-editor", features = [
|
editor = { path = "../../editor", package = "graphite-editor", features = [
|
||||||
"gpu",
|
"gpu",
|
||||||
"resvg",
|
|
||||||
"vello",
|
|
||||||
] }
|
] }
|
||||||
graphene-std = { workspace = true }
|
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"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["dealloc_nodes"]
|
default = ["dealloc_nodes", "wgpu"]
|
||||||
dealloc_nodes = ["graphene-core/dealloc_nodes"]
|
dealloc_nodes = ["core-types/dealloc_nodes"]
|
||||||
wgpu = ["wgpu-executor"]
|
wgpu = ["wgpu-executor"]
|
||||||
tokio = ["dep:tokio"]
|
tokio = ["dep:tokio"]
|
||||||
wayland = []
|
|
||||||
loading = ["serde_json"]
|
loading = ["serde_json"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
dyn-any = { workspace = true }
|
dyn-any = { workspace = true }
|
||||||
|
core-types = { workspace = true }
|
||||||
|
path-bool-nodes = { workspace = true }
|
||||||
|
brush-nodes = { workspace = true }
|
||||||
graphene-core = { workspace = true }
|
graphene-core = { workspace = true }
|
||||||
graphene-path-bool = { workspace = true }
|
|
||||||
graphene-brush = { workspace = true }
|
|
||||||
graphene-application-io = { workspace = true }
|
graphene-application-io = { workspace = true }
|
||||||
graphene-svg-renderer = { workspace = true }
|
rendering = { workspace = true }
|
||||||
graphene-raster-nodes = { workspace = true }
|
raster-nodes = { workspace = true }
|
||||||
|
graphic-types = { workspace = true }
|
||||||
|
text-nodes = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ pub mod value;
|
|||||||
|
|
||||||
use crate::document::value::TaggedValue;
|
use crate::document::value::TaggedValue;
|
||||||
use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode};
|
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 dyn_any::DynAny;
|
||||||
use glam::IVec2;
|
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 log::Metadata;
|
||||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -318,7 +318,7 @@ pub enum DocumentNodeImplementation {
|
|||||||
|
|
||||||
impl Default for DocumentNodeImplementation {
|
impl Default for DocumentNodeImplementation {
|
||||||
fn default() -> Self {
|
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
|
#[serde(alias = "outputs", deserialize_with = "deserialize_exports")] // TODO: Eventually remove this alias document upgrade code
|
||||||
pub exports: Vec<NodeInput>,
|
pub exports: Vec<NodeInput>,
|
||||||
/// The list of all nodes in this network.
|
/// 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>,
|
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.
|
/// 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)]
|
#[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)`.
|
/// A network may expose nodes as constants which can by used by other nodes using a `NodeInput::Scope(key)`.
|
||||||
#[serde(default)]
|
#[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)>,
|
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.
|
// 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>,
|
// pub import_types: Vec<Type>,
|
||||||
/// The list of all nodes in this network.
|
/// 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>,
|
pub nodes: FxHashMap<NodeId, DocumentNode>,
|
||||||
/// A network may expose nodes as constants which can by used by other nodes using a `NodeInput::Scope(key)`.
|
/// A network may expose nodes as constants which can by used by other nodes using a `NodeInput::Scope(key)`.
|
||||||
#[serde(default)]
|
#[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)>,
|
pub scope_injections: FxHashMap<String, (NodeId, Type)>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub generated: bool,
|
pub generated: bool,
|
||||||
@@ -773,7 +779,7 @@ impl NodeNetwork {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// If the node is hidden, replace it with an identity node
|
// 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 {
|
if !node.visible && node.implementation != identity_node {
|
||||||
node.implementation = identity_node;
|
node.implementation = identity_node;
|
||||||
|
|
||||||
@@ -787,7 +793,7 @@ impl NodeNetwork {
|
|||||||
let path = node.original_location.path.clone().unwrap_or_default();
|
let path = node.original_location.path.clone().unwrap_or_default();
|
||||||
|
|
||||||
// Replace value inputs with dedicated value nodes
|
// 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);
|
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,
|
merged_node_id,
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::Value { tagged_value, exposed }],
|
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,
|
original_location,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@@ -989,7 +995,7 @@ impl NodeNetwork {
|
|||||||
.nodes
|
.nodes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, node)| {
|
.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
|
&& node.inputs.len() == 1
|
||||||
&& matches!(node.inputs[0], NodeInput::Node { .. })
|
&& matches!(node.inputs[0], NodeInput::Node { .. })
|
||||||
})
|
})
|
||||||
@@ -1022,7 +1028,7 @@ impl NodeNetwork {
|
|||||||
assert_eq!(output_index, 0);
|
assert_eq!(output_index, 0);
|
||||||
// TODO: check if we can read lambda checking?
|
// TODO: check if we can read lambda checking?
|
||||||
let mut input_node = self.nodes.remove(&node_id).unwrap();
|
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) {
|
if let Some(input) = input_node.inputs.get_mut(0) {
|
||||||
*input = match &input {
|
*input = match &input {
|
||||||
NodeInput::Node { .. } => NodeInput::import(generic!(T), 0),
|
NodeInput::Node { .. } => NodeInput::import(generic!(T), 0),
|
||||||
@@ -1139,7 +1145,7 @@ mod test {
|
|||||||
NodeId(0),
|
NodeId(0),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::import(concrete!(u32), 0), NodeInput::import(concrete!(u32), 1)],
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1147,7 +1153,7 @@ mod test {
|
|||||||
NodeId(1),
|
NodeId(1),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1169,7 +1175,7 @@ mod test {
|
|||||||
NodeId(1),
|
NodeId(1),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::import(concrete!(u32), 0), NodeInput::import(concrete!(u32), 1)],
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1177,7 +1183,7 @@ mod test {
|
|||||||
NodeId(2),
|
NodeId(2),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1193,7 +1199,7 @@ mod test {
|
|||||||
fn extract_node() {
|
fn extract_node() {
|
||||||
let id_node = DocumentNode {
|
let id_node = DocumentNode {
|
||||||
inputs: vec![],
|
inputs: vec![],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into()),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_core::ops::identity::IDENTIFIER),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
// TODO: Extend test cases to test nested network
|
// TODO: Extend test cases to test nested network
|
||||||
@@ -1250,13 +1256,13 @@ mod test {
|
|||||||
let document_node = DocumentNode {
|
let document_node = DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||||
call_argument: concrete!(u32),
|
call_argument: concrete!(u32),
|
||||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::structural::ConsNode".into()),
|
implementation: DocumentNodeImplementation::ProtoNode("core_types::structural::ConsNode".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let proto_node = document_node.resolve_proto_node();
|
let proto_node = document_node.resolve_proto_node();
|
||||||
let reference = ProtoNode {
|
let reference = ProtoNode {
|
||||||
identifier: "graphene_core::structural::ConsNode".into(),
|
identifier: "core_types::structural::ConsNode".into(),
|
||||||
call_argument: concrete!(u32),
|
call_argument: concrete!(u32),
|
||||||
construction_args: ConstructionArgs::Nodes(vec![NodeId(0)]),
|
construction_args: ConstructionArgs::Nodes(vec![NodeId(0)]),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1273,7 +1279,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
NodeId(10),
|
NodeId(10),
|
||||||
ProtoNode {
|
ProtoNode {
|
||||||
identifier: "graphene_core::structural::ConsNode".into(),
|
identifier: "core_types::structural::ConsNode".into(),
|
||||||
call_argument: concrete!(u32),
|
call_argument: concrete!(u32),
|
||||||
construction_args: ConstructionArgs::Nodes(vec![NodeId(14)]),
|
construction_args: ConstructionArgs::Nodes(vec![NodeId(14)]),
|
||||||
original_location: OriginalLocation {
|
original_location: OriginalLocation {
|
||||||
@@ -1289,7 +1295,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
NodeId(11),
|
NodeId(11),
|
||||||
ProtoNode {
|
ProtoNode {
|
||||||
identifier: "graphene_core::ops::AddPairNode".into(),
|
identifier: "core_types::ops::AddPairNode".into(),
|
||||||
call_argument: concrete!(Context),
|
call_argument: concrete!(Context),
|
||||||
construction_args: ConstructionArgs::Nodes(vec![NodeId(10)]),
|
construction_args: ConstructionArgs::Nodes(vec![NodeId(10)]),
|
||||||
original_location: OriginalLocation {
|
original_location: OriginalLocation {
|
||||||
@@ -1304,8 +1310,8 @@ mod test {
|
|||||||
(
|
(
|
||||||
NodeId(14),
|
NodeId(14),
|
||||||
ProtoNode {
|
ProtoNode {
|
||||||
identifier: "graphene_core::value::ClonedNode".into(),
|
identifier: "core_types::value::ClonedNode".into(),
|
||||||
call_argument: concrete!(graphene_core::Context),
|
call_argument: concrete!(core_types::Context),
|
||||||
construction_args: ConstructionArgs::Value(TaggedValue::U32(2).into()),
|
construction_args: ConstructionArgs::Value(TaggedValue::U32(2).into()),
|
||||||
original_location: OriginalLocation {
|
original_location: OriginalLocation {
|
||||||
path: Some(vec![NodeId(1), NodeId(4)]),
|
path: Some(vec![NodeId(1), NodeId(4)]),
|
||||||
@@ -1338,7 +1344,7 @@ mod test {
|
|||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(14), 0)],
|
inputs: vec![NodeInput::node(NodeId(14), 0)],
|
||||||
call_argument: concrete!(u32),
|
call_argument: concrete!(u32),
|
||||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::structural::ConsNode".into()),
|
implementation: DocumentNodeImplementation::ProtoNode("core_types::structural::ConsNode".into()),
|
||||||
original_location: OriginalLocation {
|
original_location: OriginalLocation {
|
||||||
path: Some(vec![NodeId(1), NodeId(0)]),
|
path: Some(vec![NodeId(1), NodeId(0)]),
|
||||||
inputs_source: [(Source { node: vec![NodeId(1)], index: 1 }, 1)].into(),
|
inputs_source: [(Source { node: vec![NodeId(1)], index: 1 }, 1)].into(),
|
||||||
@@ -1352,7 +1358,7 @@ mod test {
|
|||||||
NodeId(14),
|
NodeId(14),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::value(TaggedValue::U32(2), false)],
|
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 {
|
original_location: OriginalLocation {
|
||||||
path: Some(vec![NodeId(1), NodeId(4)]),
|
path: Some(vec![NodeId(1), NodeId(4)]),
|
||||||
inputs_source: HashMap::new(),
|
inputs_source: HashMap::new(),
|
||||||
@@ -1366,7 +1372,7 @@ mod test {
|
|||||||
NodeId(11),
|
NodeId(11),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(10), 0)],
|
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 {
|
original_location: OriginalLocation {
|
||||||
path: Some(vec![NodeId(1), NodeId(1)]),
|
path: Some(vec![NodeId(1), NodeId(1)]),
|
||||||
inputs_source: HashMap::new(),
|
inputs_source: HashMap::new(),
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
use super::DocumentNode;
|
use super::DocumentNode;
|
||||||
use crate::proto::{Any as DAny, FutureAny};
|
use crate::proto::{Any as DAny, FutureAny};
|
||||||
use crate::wasm_application_io::WasmEditorApi;
|
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;
|
use dyn_any::DynAny;
|
||||||
pub use dyn_any::StaticType;
|
pub use dyn_any::StaticType;
|
||||||
use glam::{Affine2, Vec2};
|
use glam::{Affine2, Vec2};
|
||||||
pub use glam::{DAffine2, DVec2, IVec2, UVec2};
|
pub use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||||
use graphene_application_io::{ImageTexture, SurfaceFrame};
|
use graphene_application_io::{ImageTexture, SurfaceFrame};
|
||||||
use graphene_brush::brush_cache::BrushCache;
|
use graphic_types::Artboard;
|
||||||
use graphene_brush::brush_stroke::BrushStroke;
|
use graphic_types::Graphic;
|
||||||
use graphene_core::raster::Image;
|
use graphic_types::Vector;
|
||||||
use graphene_core::raster_types::{CPU, Raster};
|
use graphic_types::raster_types::Image;
|
||||||
use graphene_core::table::Table;
|
use graphic_types::raster_types::{CPU, Raster};
|
||||||
use graphene_core::transform::ReferencePoint;
|
use graphic_types::vector_types::vector;
|
||||||
use graphene_core::uuid::NodeId;
|
use graphic_types::vector_types::vector::ReferencePoint;
|
||||||
use graphene_core::vector::Vector;
|
use graphic_types::vector_types::vector::style::Fill;
|
||||||
use graphene_core::vector::style::Fill;
|
use graphic_types::vector_types::vector::style::GradientStops;
|
||||||
use graphene_core::vector::style::GradientStops;
|
use rendering::RenderMetadata;
|
||||||
use graphene_core::{Artboard, Color, ContextFeatures, Graphic, MemoHash, Node, Type};
|
|
||||||
use graphene_svg_renderer::RenderMetadata;
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@@ -76,7 +79,7 @@ macro_rules! tagged_value {
|
|||||||
Self::EditorApi(x) => Arc::new(x),
|
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 {
|
pub fn ty(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
Self::None => concrete!(()),
|
Self::None => concrete!(()),
|
||||||
@@ -186,19 +189,19 @@ tagged_value! {
|
|||||||
// TABLE TYPES
|
// 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
|
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")]
|
#[serde(alias = "VectorData")]
|
||||||
Vector(Table<Vector>),
|
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")]
|
#[serde(alias = "ImageFrame", alias = "RasterData", alias = "Image")]
|
||||||
Raster(Table<Raster<CPU>>),
|
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")]
|
#[serde(alias = "GraphicGroup", alias = "Group")]
|
||||||
Graphic(Table<Graphic>),
|
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")]
|
#[serde(alias = "ArtboardGroup")]
|
||||||
Artboard(Table<Artboard>),
|
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")]
|
#[serde(alias = "ColorTable", alias = "OptionalColor")]
|
||||||
Color(Table<Color>),
|
Color(Table<Color>),
|
||||||
GradientTable(Table<GradientStops>),
|
GradientTable(Table<GradientStops>),
|
||||||
@@ -210,52 +213,52 @@ tagged_value! {
|
|||||||
#[serde(alias = "IVec2", alias = "UVec2")]
|
#[serde(alias = "IVec2", alias = "UVec2")]
|
||||||
DVec2(DVec2),
|
DVec2(DVec2),
|
||||||
DAffine2(DAffine2),
|
DAffine2(DAffine2),
|
||||||
Stroke(graphene_core::vector::style::Stroke),
|
Stroke(graphic_types::vector_types::vector::style::Stroke),
|
||||||
Gradient(graphene_core::vector::style::Gradient),
|
Gradient(graphic_types::vector_types::vector::style::Gradient),
|
||||||
#[serde(alias = "GradientPositions")] // TODO: Eventually remove this alias document upgrade code
|
#[serde(alias = "GradientPositions")] // TODO: Eventually remove this alias document upgrade code
|
||||||
GradientStops(GradientStops),
|
GradientStops(GradientStops),
|
||||||
Font(graphene_core::text::Font),
|
Font(text_nodes::Font),
|
||||||
BrushStrokes(Vec<BrushStroke>),
|
BrushStrokes(Vec<BrushStroke>),
|
||||||
BrushCache(BrushCache),
|
BrushCache(BrushCache),
|
||||||
DocumentNode(DocumentNode),
|
DocumentNode(DocumentNode),
|
||||||
ContextFeatures(ContextFeatures),
|
ContextFeatures(ContextFeatures),
|
||||||
Curve(graphene_raster_nodes::curve::Curve),
|
Curve(raster_nodes::curve::Curve),
|
||||||
Footprint(graphene_core::transform::Footprint),
|
Footprint(core_types::transform::Footprint),
|
||||||
VectorModification(Box<graphene_core::vector::VectorModification>),
|
VectorModification(Box<vector::VectorModification>),
|
||||||
// ==========
|
// ==========
|
||||||
// ENUM TYPES
|
// ENUM TYPES
|
||||||
// ==========
|
// ==========
|
||||||
Fill(graphene_core::vector::style::Fill),
|
Fill(vector::style::Fill),
|
||||||
BlendMode(graphene_core::blending::BlendMode),
|
BlendMode(core_types::blending::BlendMode),
|
||||||
LuminanceCalculation(graphene_raster_nodes::adjustments::LuminanceCalculation),
|
LuminanceCalculation(raster_nodes::adjustments::LuminanceCalculation),
|
||||||
XY(graphene_core::extract_xy::XY),
|
XY(graphene_core::extract_xy::XY),
|
||||||
RedGreenBlue(graphene_raster_nodes::adjustments::RedGreenBlue),
|
RedGreenBlue(raster_nodes::adjustments::RedGreenBlue),
|
||||||
RedGreenBlueAlpha(graphene_raster_nodes::adjustments::RedGreenBlueAlpha),
|
RedGreenBlueAlpha(raster_nodes::adjustments::RedGreenBlueAlpha),
|
||||||
RealTimeMode(graphene_core::animation::RealTimeMode),
|
RealTimeMode(graphene_core::animation::RealTimeMode),
|
||||||
NoiseType(graphene_raster_nodes::adjustments::NoiseType),
|
NoiseType(raster_nodes::adjustments::NoiseType),
|
||||||
FractalType(graphene_raster_nodes::adjustments::FractalType),
|
FractalType(raster_nodes::adjustments::FractalType),
|
||||||
CellularDistanceFunction(graphene_raster_nodes::adjustments::CellularDistanceFunction),
|
CellularDistanceFunction(raster_nodes::adjustments::CellularDistanceFunction),
|
||||||
CellularReturnType(graphene_raster_nodes::adjustments::CellularReturnType),
|
CellularReturnType(raster_nodes::adjustments::CellularReturnType),
|
||||||
DomainWarpType(graphene_raster_nodes::adjustments::DomainWarpType),
|
DomainWarpType(raster_nodes::adjustments::DomainWarpType),
|
||||||
RelativeAbsolute(graphene_raster_nodes::adjustments::RelativeAbsolute),
|
RelativeAbsolute(raster_nodes::adjustments::RelativeAbsolute),
|
||||||
SelectiveColorChoice(graphene_raster_nodes::adjustments::SelectiveColorChoice),
|
SelectiveColorChoice(raster_nodes::adjustments::SelectiveColorChoice),
|
||||||
GridType(graphene_core::vector::misc::GridType),
|
GridType(vector::misc::GridType),
|
||||||
ArcType(graphene_core::vector::misc::ArcType),
|
ArcType(vector::misc::ArcType),
|
||||||
MergeByDistanceAlgorithm(graphene_core::vector::misc::MergeByDistanceAlgorithm),
|
MergeByDistanceAlgorithm(vector::misc::MergeByDistanceAlgorithm),
|
||||||
PointSpacingType(graphene_core::vector::misc::PointSpacingType),
|
PointSpacingType(vector::misc::PointSpacingType),
|
||||||
SpiralType(graphene_core::vector::misc::SpiralType),
|
SpiralType(vector::misc::SpiralType),
|
||||||
#[serde(alias = "LineCap")]
|
#[serde(alias = "LineCap")]
|
||||||
StrokeCap(graphene_core::vector::style::StrokeCap),
|
StrokeCap(vector::style::StrokeCap),
|
||||||
#[serde(alias = "LineJoin")]
|
#[serde(alias = "LineJoin")]
|
||||||
StrokeJoin(graphene_core::vector::style::StrokeJoin),
|
StrokeJoin(vector::style::StrokeJoin),
|
||||||
StrokeAlign(graphene_core::vector::style::StrokeAlign),
|
StrokeAlign(vector::style::StrokeAlign),
|
||||||
PaintOrder(graphene_core::vector::style::PaintOrder),
|
PaintOrder(vector::style::PaintOrder),
|
||||||
FillType(graphene_core::vector::style::FillType),
|
FillType(vector::style::FillType),
|
||||||
GradientType(graphene_core::vector::style::GradientType),
|
GradientType(vector::style::GradientType),
|
||||||
ReferencePoint(graphene_core::transform::ReferencePoint),
|
ReferencePoint(vector::ReferencePoint),
|
||||||
CentroidType(graphene_core::vector::misc::CentroidType),
|
CentroidType(vector::misc::CentroidType),
|
||||||
BooleanOperation(graphene_path_bool::BooleanOperation),
|
BooleanOperation(path_bool_nodes::BooleanOperation),
|
||||||
TextAlign(graphene_core::text::TextAlign),
|
TextAlign(text_nodes::TextAlign),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaggedValue {
|
impl TaggedValue {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[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 document;
|
||||||
pub mod graphene_compiler;
|
pub mod graphene_compiler;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::document::value::TaggedValue;
|
use crate::document::value::TaggedValue;
|
||||||
use crate::document::{InlineRust, value};
|
use crate::document::{InlineRust, value};
|
||||||
use crate::document::{NodeId, OriginalLocation};
|
use crate::document::{NodeId, OriginalLocation};
|
||||||
pub use graphene_core::registry::*;
|
pub use core_types::registry::*;
|
||||||
use graphene_core::*;
|
use core_types::*;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@@ -139,7 +139,7 @@ pub struct ProtoNode {
|
|||||||
impl Default for ProtoNode {
|
impl Default for ProtoNode {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
identifier: ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode"),
|
identifier: graphene_core::ops::identity::IDENTIFIER,
|
||||||
construction_args: ConstructionArgs::Value(value::TaggedValue::U32(0).into()),
|
construction_args: ConstructionArgs::Value(value::TaggedValue::U32(0).into()),
|
||||||
call_argument: concrete!(()),
|
call_argument: concrete!(()),
|
||||||
original_location: OriginalLocation::default(),
|
original_location: OriginalLocation::default(),
|
||||||
@@ -175,7 +175,7 @@ impl ProtoNode {
|
|||||||
_ => 2,
|
_ => 2,
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
identifier: ProtoNodeIdentifier::new("graphene_core::value::ClonedNode"),
|
identifier: ProtoNodeIdentifier::new("core_types::value::ClonedNode"),
|
||||||
construction_args: value,
|
construction_args: value,
|
||||||
call_argument: concrete!(Context),
|
call_argument: concrete!(Context),
|
||||||
original_location: OriginalLocation {
|
original_location: OriginalLocation {
|
||||||
@@ -340,7 +340,7 @@ impl ProtoNetwork {
|
|||||||
ProtoNode {
|
ProtoNode {
|
||||||
construction_args: ConstructionArgs::Value(MemoHash::new(TaggedValue::ContextFeatures(context_deps))),
|
construction_args: ConstructionArgs::Value(MemoHash::new(TaggedValue::ContextFeatures(context_deps))),
|
||||||
call_argument: concrete!(Context),
|
call_argument: concrete!(Context),
|
||||||
identifier: ProtoNodeIdentifier::new("graphene_core::value::ClonedNode"),
|
identifier: ProtoNodeIdentifier::new("core_types::value::ClonedNode"),
|
||||||
original_location: OriginalLocation {
|
original_location: OriginalLocation {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
@@ -9,12 +9,10 @@ license = "MIT OR Apache-2.0"
|
|||||||
[features]
|
[features]
|
||||||
default = ["wgpu"]
|
default = ["wgpu"]
|
||||||
wgpu = ["wgpu-executor", "gpu", "graphene-std/wgpu"]
|
wgpu = ["wgpu-executor", "gpu", "graphene-std/wgpu"]
|
||||||
wayland = ["graphene-std/wayland"]
|
|
||||||
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "wgpu-executor"]
|
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "wgpu-executor"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
graphene-core = { workspace = true }
|
|
||||||
graphene-std = { workspace = true }
|
graphene-std = { workspace = true }
|
||||||
interpreted-executor = { workspace = true }
|
interpreted-executor = { workspace = true }
|
||||||
graph-craft = { workspace = true, features = ["loading"] }
|
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::proto::ProtoNetwork;
|
||||||
use graph_craft::util::load_network;
|
use graph_craft::util::load_network;
|
||||||
use graph_craft::wasm_application_io::EditorPreferences;
|
use graph_craft::wasm_application_io::EditorPreferences;
|
||||||
use graphene_core::text::FontCache;
|
|
||||||
use graphene_std::application_io::{ApplicationIo, NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
use graphene_std::application_io::{ApplicationIo, NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||||
|
use graphene_std::text_nodes::FontCache;
|
||||||
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
||||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||||
use interpreted_executor::util::wrap_network_in_scope;
|
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
|
// 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.
|
// 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)
|
DocumentNodeImplementation::ProtoNode(proto_node_identifier)
|
||||||
if (proto_node_identifier.name.starts_with("graphene_core::ConstructLayerNode") || proto_node_identifier.name.starts_with("graphene_core::AddArtboardNode"))
|
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.len() < 3 =>
|
|
||||||
{
|
{
|
||||||
node.inputs.push(NodeInput::Reflection(DocumentNodeMetadata::DocumentNodePath));
|
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
|
# Local dependencies
|
||||||
graphene-std = { workspace = true }
|
graphene-std = { workspace = true }
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
wgpu-executor = { workspace = true }
|
|
||||||
graphene-core = { 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 }
|
dyn-any = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ pub mod util;
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use core_types::*;
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use graphene_core::*;
|
use graphene_core::ops::identity;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn double_number() {
|
fn double_number() {
|
||||||
@@ -21,7 +22,7 @@ mod tests {
|
|||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![],
|
inputs: vec![],
|
||||||
call_argument: concrete!(u32),
|
call_argument: concrete!(u32),
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(identity::IDENTIFIER),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -30,7 +31,7 @@ mod tests {
|
|||||||
NodeId(1),
|
NodeId(1),
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(0), 0)],
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,15 +3,7 @@ use glam::{DAffine2, DVec2, IVec2};
|
|||||||
use graph_craft::document::DocumentNode;
|
use graph_craft::document::DocumentNode;
|
||||||
use graph_craft::document::value::RenderOutput;
|
use graph_craft::document::value::RenderOutput;
|
||||||
use graph_craft::proto::{NodeConstructor, TypeErasedBox};
|
use graph_craft::proto::{NodeConstructor, TypeErasedBox};
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_std::Artboard;
|
||||||
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::Context;
|
use graphene_std::Context;
|
||||||
use graphene_std::Graphic;
|
use graphene_std::Graphic;
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
@@ -20,7 +12,13 @@ use graphene_std::any::DynAnyNode;
|
|||||||
use graphene_std::application_io::{ImageTexture, SurfaceFrame};
|
use graphene_std::application_io::{ImageTexture, SurfaceFrame};
|
||||||
use graphene_std::brush::brush_cache::BrushCache;
|
use graphene_std::brush::brush_cache::BrushCache;
|
||||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||||
|
use graphene_std::concrete;
|
||||||
use graphene_std::gradient::GradientStops;
|
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::render_node::RenderIntermediate;
|
||||||
use graphene_std::table::Table;
|
use graphene_std::table::Table;
|
||||||
use graphene_std::transform::Footprint;
|
use graphene_std::transform::Footprint;
|
||||||
@@ -29,6 +27,9 @@ use graphene_std::vector::Vector;
|
|||||||
use graphene_std::wasm_application_io::WasmEditorApi;
|
use graphene_std::wasm_application_io::WasmEditorApi;
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
use graphene_std::wasm_application_io::WasmSurfaceHandle;
|
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 node_registry_macros::{async_node, convert_node, into_node};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::collections::HashMap;
|
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>>),
|
into_node!(from: Table<Raster<CPU>>, to: Table<Raster<CPU>>),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
into_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>),
|
into_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>),
|
||||||
into_node!(from: Table<Vector>, to: Table<Graphic>),
|
convert_node!(from: Table<Vector>, to: Table<Graphic>),
|
||||||
into_node!(from: Table<Raster<CPU>>, to: Table<Graphic>),
|
convert_node!(from: Table<Raster<CPU>>, to: Table<Graphic>),
|
||||||
#[cfg(feature = "gpu")]
|
#[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>>),
|
// into_node!(from: Table<Raster<CPU>>, to: Table<Raster<SRGBA8>>),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
into_node!(from: &WasmEditorApi, to: &WgpuExecutor),
|
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 => BlendMode]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
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_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_std::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_std::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_std::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_std::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_std::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_std::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_std::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::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 => 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 => Vec<graphene_std::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 => 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::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 => graphene_std::vector::misc::PointSpacingType]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Option<f64>]),
|
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 => [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 => 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 => 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 => 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 => BrushCache]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => DocumentNode]),
|
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_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_std::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::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_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::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_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::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::FractalType]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::raster::adjustments::CellularDistanceFunction]),
|
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::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::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_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_std::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_std::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_std::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_std::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_std::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_std::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_std::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_std::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::text::TextAlign]),
|
||||||
// Context nullification
|
// Context nullification
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => &WasmEditorApi, Context => graphene_std::ContextFeatures]),
|
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 => 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::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 => 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_std::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_std::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::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 => 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 => BrushCache]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => DocumentNode]),
|
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::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_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 => graphene_std::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 => Box<graphene_std::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_std::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::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_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::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_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::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::FractalType]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::raster::CellularDistanceFunction]),
|
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::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::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_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_std::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_std::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_std::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_std::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_std::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_std::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_std::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_std::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_std::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_std::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_std::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_std::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 => path_bool_nodes::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::text::TextAlign]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RenderIntermediate]),
|
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
|
// 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();
|
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() {
|
for (constructor, types) in entry.iter() {
|
||||||
map.entry(id.clone()).or_default().insert(types.clone(), *constructor);
|
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), ">"]),
|
ProtoNodeIdentifier::new(concat!["graphene_core::ops::IntoNode<", stringify!($to), ">"]),
|
||||||
|mut args| {
|
|mut args| {
|
||||||
Box::pin(async move {
|
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::downcast_node::<Context, $from>(args.pop().unwrap()),
|
||||||
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>)),
|
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::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>)),
|
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>)),
|
||||||
);
|
);
|
||||||
@@ -412,7 +399,7 @@ mod node_registry_macros {
|
|||||||
|mut args| {
|
|mut args| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut args = args.drain(..);
|
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, $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::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>))
|
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 = $from> + Send>>>::new(),
|
||||||
graphene_std::any::PanicNode::<Context, core::pin::Pin<Box<dyn core::future::Future<Output = $convert> + 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>))
|
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 {
|
DocumentNode {
|
||||||
call_argument: concrete!(Context),
|
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),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render_intermediate::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
context_features: graphene_std::ContextDependencies {
|
||||||
extract: ContextFeatures::VARARGS,
|
extract: ContextFeatures::VARARGS,
|
||||||
|
|||||||
+3
-1
@@ -13,7 +13,9 @@ wgpu = ["dep:wgpu"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
dyn-any = { workspace = true }
|
dyn-any = { workspace = true }
|
||||||
graphene-core = { workspace = true }
|
core-types = { workspace = true }
|
||||||
|
vector-types = { workspace = true }
|
||||||
|
text-nodes = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
glam = { workspace = true }
|
glam = { workspace = true }
|
||||||
+3
-3
@@ -1,8 +1,6 @@
|
|||||||
|
use core_types::transform::Footprint;
|
||||||
use dyn_any::{DynAny, StaticType, StaticTypeSized};
|
use dyn_any::{DynAny, StaticType, StaticTypeSized};
|
||||||
use glam::{DAffine2, UVec2};
|
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::fmt::Debug;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
@@ -10,6 +8,8 @@ use std::pin::Pin;
|
|||||||
use std::ptr::addr_of;
|
use std::ptr::addr_of;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct SurfaceId(pub u64);
|
pub struct SurfaceId(pub u64);
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "graphene-core"
|
name = "core-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "API definitions for Graphene"
|
description = "Core types and traits for Graphene node system"
|
||||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
@@ -10,12 +10,11 @@ license = "MIT OR Apache-2.0"
|
|||||||
default = ["serde"]
|
default = ["serde"]
|
||||||
nightly = []
|
nightly = []
|
||||||
type_id_logging = []
|
type_id_logging = []
|
||||||
wgpu = ["dep:wgpu"]
|
|
||||||
dealloc_nodes = []
|
dealloc_nodes = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
graphene-core-shaders = { workspace = true, features = ["std"] }
|
no-std-types = { workspace = true, features = ["std"] }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
bitflags = { workspace = true }
|
bitflags = { workspace = true }
|
||||||
@@ -43,7 +42,6 @@ polycool = { workspace = true }
|
|||||||
|
|
||||||
# Optional workspace dependencies
|
# Optional workspace dependencies
|
||||||
serde = { workspace = true, optional = true }
|
serde = { workspace = true, optional = true }
|
||||||
wgpu = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{Color, gradient::GradientStops};
|
use crate::Color;
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
||||||
@@ -33,8 +33,3 @@ impl BoundingBox for Color {
|
|||||||
RenderBoundingBox::Infinite
|
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
|
// RENDERING
|
||||||
pub const LAYER_OUTLINE_STROKE_COLOR: Color = Color::BLACK;
|
pub const LAYER_OUTLINE_STROKE_COLOR: Color = Color::BLACK;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::transform::Footprint;
|
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::any::Any;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
@@ -1,51 +1,34 @@
|
|||||||
#[macro_use]
|
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
pub mod animation;
|
|
||||||
pub mod artboard;
|
|
||||||
pub mod blending_nodes;
|
|
||||||
pub mod bounds;
|
pub mod bounds;
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod context_modification;
|
|
||||||
pub mod debug;
|
|
||||||
pub mod extract_xy;
|
|
||||||
pub mod generic;
|
pub mod generic;
|
||||||
pub mod gradient;
|
|
||||||
pub mod graphic;
|
|
||||||
pub mod logic;
|
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod memo;
|
pub mod memo;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod ops;
|
pub mod ops;
|
||||||
pub mod raster;
|
|
||||||
pub mod raster_types;
|
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
pub mod render_complexity;
|
pub mod render_complexity;
|
||||||
pub mod subpath;
|
|
||||||
pub mod table;
|
pub mod table;
|
||||||
pub mod text;
|
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
pub mod transform_nodes;
|
|
||||||
pub mod uuid;
|
pub mod uuid;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub mod vector;
|
|
||||||
|
|
||||||
pub use crate as graphene_core;
|
pub use crate as core_types;
|
||||||
pub use artboard::Artboard;
|
|
||||||
pub use blending::*;
|
pub use blending::*;
|
||||||
pub use color::Color;
|
pub use color::Color;
|
||||||
pub use context::*;
|
pub use context::*;
|
||||||
pub use ctor;
|
pub use ctor;
|
||||||
pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync};
|
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 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 num_traits;
|
||||||
|
pub use specta;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
pub mod bbox;
|
pub mod bbox;
|
||||||
pub mod math_ext;
|
|
||||||
pub mod polynomial;
|
pub mod polynomial;
|
||||||
pub mod quad;
|
pub mod quad;
|
||||||
pub mod rect;
|
pub mod rect;
|
||||||
@@ -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
|
// 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 crate::table::Table;
|
||||||
use graphene_core_shaders::color::Color;
|
use no_std_types::color::Color;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
use graphene_core_shaders::Ctx;
|
use crate::{
|
||||||
|
Node,
|
||||||
use crate::{ExtractFootprint, Node, transform::Footprint};
|
table::{Table, TableRow},
|
||||||
|
transform::Footprint,
|
||||||
|
};
|
||||||
|
use std::future::Future;
|
||||||
use std::marker::PhantomData;
|
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
|
// Type
|
||||||
// TODO: Document this
|
// TODO: Document this
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[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> {}
|
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.
|
/// 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.
|
/// Because number casting is lossy, we cannot use the normal [`Into`] trait like we do for other types.
|
||||||
pub trait Convert<T, C>: Sized {
|
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.
|
/// Implements the [`Convert`] trait for conversion between the cartesian product of Rust's primitive numeric types.
|
||||||
macro_rules! impl_convert {
|
macro_rules! impl_convert {
|
||||||
($from:ty, $to:ty) => {
|
($from:ty, $to:ty) => {
|
||||||
@@ -105,18 +116,3 @@ impl_convert!(i128);
|
|||||||
impl_convert!(u128);
|
impl_convert!(u128);
|
||||||
impl_convert!(isize);
|
impl_convert!(isize);
|
||||||
impl_convert!(usize);
|
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::pin::Pin;
|
||||||
use std::sync::{LazyLock, Mutex};
|
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
|
// Translation struct between macro and definition
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -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 alpha_blending: &'a mut AlphaBlending,
|
||||||
pub source_node_id: &'a mut Option<NodeId>,
|
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;
|
use crate::math::bbox::AxisAlignedBbox;
|
||||||
pub use crate::vector::ReferencePoint;
|
|
||||||
use core::f64;
|
use core::f64;
|
||||||
use glam::{DAffine2, DMat2, DVec2, UVec2};
|
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
|
// Implementations for DAffine2
|
||||||
impl Transform for DAffine2 {
|
impl Transform for DAffine2 {
|
||||||
fn transform(&self) -> 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 = String::deserialize(deserializer)?;
|
||||||
let name = match name.as_str() {
|
let name = match name.as_str() {
|
||||||
"f32" => "f64".to_string(),
|
"f32" => "f64".to_string(),
|
||||||
"graphene_core::transform::Footprint" => "std::option::Option<std::sync::Arc<graphene_core::context::OwnedContextImpl>>".to_string(),
|
"grahpene_core::transform::Footprint" => "std::option::Option<std::sync::Arc<grahpene_core::context::OwnedContextImpl>>".to_string(),
|
||||||
"graphene_core::graphic_element::GraphicGroup" => "graphene_core::table::Table<graphene_core::graphic::Graphic>".to_string(),
|
"grahpene_core::graphic_element::GraphicGroup" => "grahpene_core::table::Table<grahpene_core::graphic_types::Graphic>".to_string(),
|
||||||
"graphene_core::raster::image::ImageFrame<Color>"
|
"grahpene_core::raster::image::ImageFrame<Color>"
|
||||||
| "graphene_core::raster::image::ImageFrame<graphene_core::raster::color::Color>"
|
| "grahpene_core::raster::image::ImageFrame<grahpene_core::raster::color::Color>"
|
||||||
| "graphene_core::instances::Instances<graphene_core::raster::image::ImageFrame<Color>>"
|
| "grahpene_core::instances::Instances<grahpene_core::raster::image::ImageFrame<Color>>"
|
||||||
| "graphene_core::instances::Instances<graphene_core::raster::image::ImageFrame<graphene_core::raster::color::Color>>"
|
| "grahpene_core::instances::Instances<grahpene_core::raster::image::ImageFrame<grahpene_core::raster::color::Color>>"
|
||||||
| "graphene_core::instances::Instances<graphene_core::raster::image::Image<graphene_core::raster::color::Color>>" => {
|
| "grahpene_core::instances::Instances<grahpene_core::raster::image::Image<grahpene_core::raster::color::Color>>" => {
|
||||||
"graphene_core::table::Table<graphene_core::raster::image::Image<graphene_core::raster::color::Color>>".to_string()
|
"grahpene_core::table::Table<grahpene_core::raster::image::Image<grahpene_core::raster::color::Color>>".to_string()
|
||||||
}
|
}
|
||||||
"graphene_core::vector::vector_data::VectorData"
|
"grahpene_core::vector::vector_data::VectorData"
|
||||||
| "graphene_core::instances::Instances<graphene_core::vector::vector_data::VectorData>"
|
| "grahpene_core::instances::Instances<grahpene_core::vector::vector_data::VectorData>"
|
||||||
| "graphene_core::table::Table<graphene_core::vector::vector_data::VectorData>"
|
| "grahpene_core::table::Table<grahpene_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(),
|
| "grahpene_core::table::Table<grahpene_core::vector::vector_data::Vector>" => "grahpene_core::table::Table<grahpene_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(),
|
"grahpene_core::instances::Instances<grahpene_core::graphic_element::Artboard>" => "grahpene_core::table::Table<grahpene_core::artboard::Artboard>".to_string(),
|
||||||
"graphene_core::vector::vector_data::modification::VectorModification" => "graphene_core::vector::vector_modification::VectorModification".to_string(),
|
"grahpene_core::vector::vector_data::modification::VectorModification" => "grahpene_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::table::Table<grahpene_core::graphic_element::Graphic>" => "grahpene_core::table::Table<grahpene_core::graphic_types::Graphic>".to_string(),
|
||||||
_ => name,
|
_ => name,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -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 }
|
||||||
+26
-64
@@ -1,13 +1,12 @@
|
|||||||
use crate::blending::AlphaBlending;
|
use crate::graphic::Graphic;
|
||||||
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
use core_types::Color;
|
||||||
use crate::gradient::GradientStops;
|
use core_types::blending::AlphaBlending;
|
||||||
use crate::math::quad::Quad;
|
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||||
use crate::raster_types::{CPU, GPU, Raster};
|
use core_types::math::quad::Quad;
|
||||||
use crate::table::{Table, TableRow};
|
use core_types::render_complexity::RenderComplexity;
|
||||||
use crate::transform::TransformMut;
|
use core_types::table::{Table, TableRow};
|
||||||
use crate::uuid::NodeId;
|
use core_types::transform::Transform;
|
||||||
use crate::vector::Vector;
|
use core_types::uuid::NodeId;
|
||||||
use crate::{CloneVarArgs, Color, Context, Ctx, ExtractAll, Graphic, OwnedContextImpl};
|
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use glam::{DAffine2, DVec2, IVec2};
|
use glam::{DAffine2, DVec2, IVec2};
|
||||||
use std::hash::Hash;
|
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
|
// TODO: Eventually remove this migration document upgrade code
|
||||||
pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Artboard>, D::Error> {
|
pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Artboard>, D::Error> {
|
||||||
use serde::Deserialize;
|
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 definitions moved to graphic-nodes crate
|
||||||
#[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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -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>"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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]
|
[package]
|
||||||
name = "graphene-core-shaders"
|
name = "no-std-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "no_std API definitions for Graphene"
|
description = "no_std types for Graphene (shader-compatible)"
|
||||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ specta = { workspace = true, optional = true }
|
|||||||
log = { workspace = true, optional = true }
|
log = { workspace = true, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
graphene-core = { workspace = true }
|
core-types = { workspace = true }
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
# the spirv target is not in the list of common cfgs so must be added manually
|
# 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]
|
[package.metadata.cargo-shear]
|
||||||
ignored = ["graphene-core"]
|
ignored = ["core-types"]
|
||||||
+17
-17
@@ -360,7 +360,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// 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));
|
/// assert!(color.components() == (0.3, 0.14, 0.15, 0.92));
|
||||||
///
|
///
|
||||||
@@ -398,7 +398,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use graphene_core::color::Color;
|
/// use core_types::color::Color;
|
||||||
/// let color = Color::from_rgb8_srgb(0x72, 0x67, 0x62);
|
/// let color = Color::from_rgb8_srgb(0x72, 0x67, 0x62);
|
||||||
/// let color2 = Color::from_rgba8_srgb(0x72, 0x67, 0x62, 0xFF);
|
/// let color2 = Color::from_rgba8_srgb(0x72, 0x67, 0x62, 0xFF);
|
||||||
/// assert_eq!(color, color2)
|
/// assert_eq!(color, color2)
|
||||||
@@ -413,7 +413,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use graphene_core::color::Color;
|
/// use core_types::color::Color;
|
||||||
/// let color = Color::from_rgba8_srgb(0x72, 0x67, 0x62, 0x61);
|
/// let color = Color::from_rgba8_srgb(0x72, 0x67, 0x62, 0x61);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -431,7 +431,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use graphene_core::color::Color;
|
/// use core_types::color::Color;
|
||||||
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.);
|
/// 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 {
|
pub fn from_hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Color {
|
||||||
@@ -473,7 +473,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||||
/// assert!(color.r() == 0.114);
|
/// assert!(color.r() == 0.114);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -486,7 +486,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||||
/// assert!(color.g() == 0.103);
|
/// assert!(color.g() == 0.103);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -499,7 +499,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||||
/// assert!(color.b() == 0.98);
|
/// assert!(color.b() == 0.98);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -512,7 +512,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||||
/// assert!(color.a() == 0.97);
|
/// assert!(color.a() == 0.97);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -788,7 +788,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// 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));
|
/// assert_eq!(color.components(), (0.114, 0.103, 0.98, 0.97));
|
||||||
/// ```
|
/// ```
|
||||||
@@ -801,7 +801,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use graphene_core::color::Color;
|
/// use core_types::color::Color;
|
||||||
/// let color = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61); // Premultiplied alpha
|
/// 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
|
/// 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.
|
/// 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
|
/// 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
|
/// 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.
|
/// 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
|
/// 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
|
/// assert_eq!("3240a2", color.to_rgb_hex_srgb()); // Equivalent hex incorporating premultiplied alpha
|
||||||
/// ```
|
/// ```
|
||||||
@@ -843,7 +843,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||||
/// // TODO: Add test
|
/// // TODO: Add test
|
||||||
/// ```
|
/// ```
|
||||||
@@ -857,7 +857,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||||
/// // TODO: Add test
|
/// // TODO: Add test
|
||||||
/// ```
|
/// ```
|
||||||
@@ -872,7 +872,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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();
|
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.).to_hsla();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn to_hsla(&self) -> [f32; 4] {
|
pub fn to_hsla(&self) -> [f32; 4] {
|
||||||
@@ -908,7 +908,7 @@ impl Color {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use graphene_core::color::Color;
|
/// use core_types::color::Color;
|
||||||
/// let color = Color::from_rgba_str("7C67FA61").unwrap();
|
/// let color = Color::from_rgba_str("7C67FA61").unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_rgba_str(color_str: &str) -> Option<Color> {
|
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).
|
/// 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();
|
/// let color = Color::from_rgb_str("7C67FA").unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_rgb_str(color_str: &str) -> Option<Color> {
|
pub fn from_rgb_str(color_str: &str) -> Option<Color> {
|
||||||
@@ -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 }
|
||||||
+11
-12
@@ -1,10 +1,12 @@
|
|||||||
use super::Color;
|
use crate::raster_types::{CPU, Raster};
|
||||||
use crate::AlphaBlending;
|
use crate::{Bitmap, BitmapMut};
|
||||||
use crate::color::float_to_srgb_u8;
|
use core_types::AlphaBlending;
|
||||||
use crate::raster_types::Raster;
|
use core_types::Color;
|
||||||
use crate::table::{Table, TableRow};
|
use core_types::color::float_to_srgb_u8;
|
||||||
use crate::vector::Vector;
|
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::hash::{Hash, Hasher};
|
||||||
|
use core_types::color::*;
|
||||||
use dyn_any::{DynAny, StaticType};
|
use dyn_any::{DynAny, StaticType};
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
@@ -12,8 +14,8 @@ use std::vec::Vec;
|
|||||||
mod base64_serde {
|
mod base64_serde {
|
||||||
//! Basic wrapper for [`serde`] to perform [`base64`] encoding
|
//! Basic wrapper for [`serde`] to perform [`base64`] encoding
|
||||||
|
|
||||||
use super::super::Pixel;
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
|
use core_types::color::*;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
pub fn as_base64<S: Serializer, P: Pixel>(key: &[P], serializer: S) -> Result<S::Ok, S::Error> {
|
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) {}
|
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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let length = self.data.len();
|
let length = self.data.len();
|
||||||
f.debug_struct("Image")
|
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)]
|
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum GraphicElement {
|
pub enum GraphicElement {
|
||||||
GraphicGroup(Table<GraphicElement>),
|
GraphicGroup(Table<GraphicElement>),
|
||||||
VectorData(Table<Vector>),
|
|
||||||
RasterFrame(RasterFrame),
|
RasterFrame(RasterFrame),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,8 +392,6 @@ pub fn migrate_image_frame_row<'de, D: serde::Deserializer<'de>>(deserializer: D
|
|||||||
pub enum GraphicElement {
|
pub enum GraphicElement {
|
||||||
/// Equivalent to the SVG <g> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
|
/// Equivalent to the SVG <g> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
|
||||||
GraphicGroup(Table<GraphicElement>),
|
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),
|
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;
|
type Pixel = P;
|
||||||
|
|
||||||
// TODO: Improve sampling logic
|
// 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
|
/// as to not yet rename all references
|
||||||
pub mod color {
|
pub mod color {
|
||||||
pub use super::*;
|
pub use super::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod image;
|
|
||||||
|
|
||||||
pub use self::image::Image;
|
|
||||||
pub use crate::color::*;
|
|
||||||
use crate::raster_types::CPU;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub trait Bitmap {
|
pub trait Bitmap {
|
||||||
+18
-4
@@ -1,8 +1,8 @@
|
|||||||
use crate::Color;
|
use crate::image::Image;
|
||||||
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
|
||||||
use crate::math::quad::Quad;
|
|
||||||
use crate::raster::Image;
|
|
||||||
use core::ops::Deref;
|
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 dyn_any::DynAny;
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@@ -211,3 +211,17 @@ where
|
|||||||
RenderBoundingBox::Rectangle((transform * unit_rectangle).bounding_box())
|
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]
|
[package]
|
||||||
name = "graphene-svg-renderer"
|
name = "rendering"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "graphene svg renderer"
|
description = "SVG rendering for Graphene"
|
||||||
authors = ["Graphite Authors <contact@graphite.rs>"]
|
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
dyn-any = { workspace = true }
|
dyn-any = { workspace = true }
|
||||||
graphene-core = { workspace = true }
|
core-types = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
glam = { workspace = true }
|
glam = { workspace = true }
|
||||||
@@ -19,6 +19,9 @@ log = { workspace = true }
|
|||||||
num-traits = { workspace = true }
|
num-traits = { workspace = true }
|
||||||
usvg = { workspace = true }
|
usvg = { workspace = true }
|
||||||
kurbo = { 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 }
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
use graphene_core::subpath::{ManipulatorGroup, Subpath};
|
use vector_types::subpath::{ManipulatorGroup, Subpath};
|
||||||
use graphene_core::vector::PointId;
|
use vector_types::vector::PointId;
|
||||||
|
|
||||||
pub fn convert_usvg_path(path: &usvg::Path) -> Vec<Subpath<PointId>> {
|
pub fn convert_usvg_path(path: &usvg::Path) -> Vec<Subpath<PointId>> {
|
||||||
let mut subpaths = Vec::new();
|
let mut subpaths = Vec::new();
|
||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
use crate::renderer::{RenderParams, format_transform_matrix};
|
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 glam::DAffine2;
|
||||||
use graphene_core::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
use graphic_types::vector_types::gradient::{Gradient, GradientType};
|
||||||
use graphene_core::gradient::{Gradient, GradientType};
|
use graphic_types::vector_types::vector::style::{Fill, PaintOrder, PathStyle, RenderMode, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
use graphene_core::uuid::generate_uuid;
|
|
||||||
use graphene_core::vector::style::{Fill, PaintOrder, PathStyle, RenderMode, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub trait RenderExt {
|
pub trait RenderExt {
|
||||||
+39
-49
@@ -1,26 +1,26 @@
|
|||||||
use crate::render_ext::RenderExt;
|
use crate::render_ext::RenderExt;
|
||||||
use crate::to_peniko::BlendModeExt;
|
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 dyn_any::DynAny;
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graphene_core::blending::BlendMode;
|
use graphic_types::Vector;
|
||||||
use graphene_core::bounds::BoundingBox;
|
use graphic_types::raster_types::BitmapMut;
|
||||||
use graphene_core::bounds::RenderBoundingBox;
|
use graphic_types::raster_types::Image;
|
||||||
use graphene_core::color::Color;
|
use graphic_types::raster_types::{CPU, GPU, Raster};
|
||||||
use graphene_core::gradient::GradientStops;
|
use graphic_types::vector_types::gradient::GradientStops;
|
||||||
use graphene_core::gradient::GradientType;
|
use graphic_types::vector_types::gradient::GradientType;
|
||||||
use graphene_core::math::quad::Quad;
|
use graphic_types::vector_types::subpath::Subpath;
|
||||||
use graphene_core::raster::BitmapMut;
|
use graphic_types::vector_types::vector::click_target::{ClickTarget, FreePoint};
|
||||||
use graphene_core::raster::Image;
|
use graphic_types::vector_types::vector::style::{Fill, PaintOrder, RenderMode, Stroke, StrokeAlign};
|
||||||
use graphene_core::raster_types::{CPU, GPU, Raster};
|
use graphic_types::{Artboard, Graphic};
|
||||||
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 kurbo::Affine;
|
use kurbo::Affine;
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@@ -28,7 +28,6 @@ use std::fmt::Write;
|
|||||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
#[cfg(feature = "vello")]
|
|
||||||
use vello::*;
|
use vello::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
@@ -152,7 +151,6 @@ impl Default for SvgRender {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct RenderContext {
|
pub struct RenderContext {
|
||||||
#[cfg(feature = "vello")]
|
|
||||||
pub resource_overrides: Vec<(peniko::ImageBrush, wgpu::Texture)>,
|
pub resource_overrides: Vec<(peniko::ImageBrush, wgpu::Texture)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +262,6 @@ impl RenderMetadata {
|
|||||||
pub trait Render: BoundingBox + RenderComplexity {
|
pub trait Render: BoundingBox + RenderComplexity {
|
||||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams);
|
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);
|
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.
|
/// 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) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
match self {
|
match self {
|
||||||
Graphic::Graphic(table) => table.render_to_vello(scene, transform, context, render_params),
|
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) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
use vello::peniko;
|
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) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
for row in self.iter() {
|
for row in self.iter() {
|
||||||
row.element.render_to_vello(scene, transform, context, render_params);
|
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) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
let mut iter = self.iter().peekable();
|
let mut iter = self.iter().peekable();
|
||||||
let mut mask_element_and_transform = None;
|
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) {
|
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 core_types::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
|
||||||
use graphene_core::vector::style::{GradientType, StrokeCap, StrokeJoin};
|
use graphic_types::vector_types::vector::style::{GradientType, StrokeCap, StrokeJoin};
|
||||||
use vello::kurbo::{Cap, Join};
|
use vello::kurbo::{Cap, Join};
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
for row in self.iter() {
|
for row in self.iter() {
|
||||||
|
use graphic_types::vector_types::vector;
|
||||||
|
|
||||||
let multiplied_transform = parent_transform * *row.transform;
|
let multiplied_transform = parent_transform * *row.transform;
|
||||||
let has_real_stroke = row.element.style.stroke().filter(|stroke| stroke.weight() > 0.);
|
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.);
|
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());
|
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 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
|
// Closures to avoid duplicated fill/stroke drawing logic
|
||||||
let do_fill = |scene: &mut Scene| match row.element.style.fill() {
|
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);
|
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;
|
footprint.transform *= transform;
|
||||||
upstream_nested_layers.collect_metadata(metadata, footprint, None);
|
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) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _: &mut RenderContext, render_params: &RenderParams) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
@@ -1302,13 +1295,13 @@ impl Render for Table<Raster<CPU>> {
|
|||||||
let opacity = alpha_blending.opacity(render_params.for_mask);
|
let opacity = alpha_blending.opacity(render_params.for_mask);
|
||||||
let mut layer = false;
|
let mut layer = false;
|
||||||
|
|
||||||
if opacity < 1. || alpha_blending.blend_mode != BlendMode::default() {
|
if (opacity < 1. || alpha_blending.blend_mode != BlendMode::default())
|
||||||
if let RenderBoundingBox::Rectangle(bounds) = self.bounding_box(transform, false) {
|
&& 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);
|
let blending = peniko::BlendMode::new(blend_mode, peniko::Compose::SrcOver);
|
||||||
scene.push_layer(blending, opacity, kurbo::Affine::IDENTITY, &rect);
|
let rect = kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||||
layer = true;
|
scene.push_layer(blending, opacity, kurbo::Affine::IDENTITY, &rect);
|
||||||
}
|
layer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let image_brush = peniko::ImageBrush::new(peniko::ImageData {
|
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");
|
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) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, _render_params: &RenderParams) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
for row in self.iter() {
|
for row in self.iter() {
|
||||||
let blend_mode = *row.alpha_blending;
|
let blend_mode = *row.alpha_blending;
|
||||||
let mut layer = false;
|
let mut layer = false;
|
||||||
if blend_mode != Default::default() {
|
if blend_mode != Default::default()
|
||||||
if let RenderBoundingBox::Rectangle(bounds) = self.bounding_box(transform, true) {
|
&& 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);
|
let blending = peniko::BlendMode::new(blend_mode.blend_mode.to_peniko(), peniko::Compose::SrcOver);
|
||||||
scene.push_layer(blending, blend_mode.opacity, kurbo::Affine::IDENTITY, &rect);
|
let rect = kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||||
layer = true;
|
scene.push_layer(blending, blend_mode.opacity, kurbo::Affine::IDENTITY, &rect);
|
||||||
}
|
layer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let width = row.element.data().width();
|
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) {
|
fn render_to_vello(&self, scene: &mut Scene, _parent_transform: DAffine2, _context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
@@ -1534,7 +1525,6 @@ impl Render for Table<GradientStops> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix infinite gradient rendering
|
// 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) {
|
fn render_to_vello(&self, scene: &mut Scene, _parent_transform: DAffine2, _context: &mut RenderContext, render_params: &RenderParams) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
+1
-3
@@ -1,12 +1,10 @@
|
|||||||
use graphene_core::BlendMode;
|
use core_types::BlendMode;
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
|
||||||
pub trait BlendModeExt {
|
pub trait BlendModeExt {
|
||||||
fn to_peniko(&self) -> peniko::Mix;
|
fn to_peniko(&self) -> peniko::Mix;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
|
||||||
impl BlendModeExt for BlendMode {
|
impl BlendModeExt for BlendMode {
|
||||||
fn to_peniko(&self) -> peniko::Mix {
|
fn to_peniko(&self) -> peniko::Mix {
|
||||||
match self {
|
match self {
|
||||||
@@ -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 }
|
||||||
+13
-1
@@ -1,4 +1,4 @@
|
|||||||
use crate::Color;
|
use core_types::{Color, render_complexity::RenderComplexity};
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use glam::{DAffine2, DVec2};
|
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 {
|
impl IntoIterator for GradientStops {
|
||||||
type Item = (f64, Color);
|
type Item = (f64, Color);
|
||||||
type IntoIter = std::vec::IntoIter<(f64, Color)>;
|
type IntoIter = std::vec::IntoIter<(f64, Color)>;
|
||||||
@@ -232,3 +238,9 @@ impl Gradient {
|
|||||||
Some(index)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
use crate::math::quad::Quad;
|
|
||||||
use crate::math::rect::Rect;
|
|
||||||
use crate::subpath::Bezier;
|
use crate::subpath::Bezier;
|
||||||
use crate::vector::misc::dvec2_to_point;
|
use crate::vector::misc::dvec2_to_point;
|
||||||
|
use core_types::math::quad::Quad;
|
||||||
|
use core_types::math::rect::Rect;
|
||||||
use kurbo::{Line, PathSeg};
|
use kurbo::{Line, PathSeg};
|
||||||
|
|
||||||
pub trait QuadExt {
|
pub trait QuadExt {
|
||||||
+1
-1
@@ -239,7 +239,7 @@ impl<PointId: Identifier> Subpath<PointId> {
|
|||||||
let mut start_angle = 0.;
|
let mut start_angle = 0.;
|
||||||
let mut sweep_angle = sweep_angle.abs();
|
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;
|
sweep_angle %= std::f64::consts::TAU;
|
||||||
} else {
|
} else {
|
||||||
start_angle = sweep_angle % std::f64::consts::TAU;
|
start_angle = sweep_angle % std::f64::consts::TAU;
|
||||||
+1
-1
@@ -1,8 +1,8 @@
|
|||||||
use super::consts::MAX_ABSOLUTE_DIFFERENCE;
|
use super::consts::MAX_ABSOLUTE_DIFFERENCE;
|
||||||
use super::*;
|
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::bezpath_algorithms::pathseg_length_centroid_and_length;
|
||||||
use crate::vector::algorithms::intersection::{filtered_all_segment_intersections, pathseg_self_intersections};
|
use crate::vector::algorithms::intersection::{filtered_all_segment_intersections, pathseg_self_intersections};
|
||||||
|
use core_types::math::polynomial::pathseg_to_parametric_polynomial;
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
|
|
||||||
impl<PointId: Identifier> Subpath<PointId> {
|
impl<PointId: Identifier> Subpath<PointId> {
|
||||||
+1
-1
@@ -1,9 +1,9 @@
|
|||||||
use super::intersection::bezpath_intersections;
|
use super::intersection::bezpath_intersections;
|
||||||
use super::poisson_disk::poisson_disk_sample;
|
use super::poisson_disk::poisson_disk_sample;
|
||||||
use super::util::pathseg_tangent;
|
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::algorithms::offset_subpath::MAX_ABSOLUTE_DIFFERENCE;
|
||||||
use crate::vector::misc::{PointSpacingType, dvec2_to_point, point_to_dvec2};
|
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 glam::{DMat2, DVec2};
|
||||||
use kurbo::common::{solve_cubic, solve_quadratic};
|
use kurbo::common::{solve_cubic, solve_quadratic};
|
||||||
use kurbo::{BezPath, CubicBez, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveDeriv, PathEl, PathSeg, Point, QuadBez, Rect, Shape, Vec2};
|
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