mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 19:48:12 +08:00
Downscale Images to document resolution (#1077)
* Add DownscaleNode * Add lambda (call argument) input type + fix caching * Add comment explaining Lambda input * Automatically insert cache node after downscale node * Implement sparse hashing of images
This commit is contained in:
Generated
+1
-185
@@ -331,12 +331,6 @@ version = "0.6.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bit_field"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@@ -722,30 +716,6 @@ dependencies = [
|
|||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"memoffset 0.8.0",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@@ -1041,12 +1011,6 @@ version = "1.0.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embed_plist"
|
name = "embed_plist"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
@@ -1096,22 +1060,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "exr"
|
|
||||||
version = "1.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e8af5ef47e2ed89d23d0ecbc1b681b30390069de70260937877514377fc24feb"
|
|
||||||
dependencies = [
|
|
||||||
"bit_field",
|
|
||||||
"flume",
|
|
||||||
"half",
|
|
||||||
"lebe",
|
|
||||||
"miniz_oxide",
|
|
||||||
"smallvec",
|
|
||||||
"threadpool",
|
|
||||||
"zune-inflate",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@@ -1137,7 +1085,7 @@ version = "0.3.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
|
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memoffset 0.6.5",
|
"memoffset",
|
||||||
"rustc_version 0.3.3",
|
"rustc_version 0.3.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1169,19 +1117,6 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flume"
|
|
||||||
version = "0.10.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
"nanorand",
|
|
||||||
"pin-project",
|
|
||||||
"spin 0.9.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -1453,20 +1388,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gif"
|
|
||||||
version = "0.11.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
|
|
||||||
dependencies = [
|
|
||||||
"color_quant",
|
|
||||||
"weezl",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2136,14 +2059,9 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"exr",
|
|
||||||
"gif",
|
|
||||||
"jpeg-decoder",
|
|
||||||
"num-rational",
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
"png",
|
||||||
"scoped_threadpool",
|
|
||||||
"tiff",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2262,15 +2180,6 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jpeg-decoder"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
|
|
||||||
dependencies = [
|
|
||||||
"rayon",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.61"
|
version = "0.3.61"
|
||||||
@@ -2329,12 +2238,6 @@ version = "1.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lebe"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "levenberg-marquardt"
|
name = "levenberg-marquardt"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
@@ -2529,15 +2432,6 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metal"
|
name = "metal"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
@@ -2644,15 +2538,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nanorand"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.2.8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
@@ -3443,28 +3328,6 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@@ -3746,12 +3609,6 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scoped_threadpool"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -4024,12 +3881,6 @@ dependencies = [
|
|||||||
"wide",
|
"wide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simd-adler32"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "14a5df39617d7c8558154693a1bb8157a4aab8179209540cc0b10e5dc24e0b18"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
@@ -4693,26 +4544,6 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "threadpool"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
|
||||||
dependencies = [
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tiff"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471"
|
|
||||||
dependencies = [
|
|
||||||
"flate2",
|
|
||||||
"jpeg-decoder",
|
|
||||||
"weezl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
@@ -5455,12 +5286,6 @@ dependencies = [
|
|||||||
"windows-metadata",
|
"windows-metadata",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "weezl"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu"
|
name = "wgpu"
|
||||||
version = "0.14.2"
|
version = "0.14.2"
|
||||||
@@ -5932,12 +5757,3 @@ name = "xxhash-rust"
|
|||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70"
|
checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zune-inflate"
|
|
||||||
version = "0.2.50"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "589245df6230839c305984dcc0a8385cc72af1fd223f360ffd5d65efa4216d40"
|
|
||||||
dependencies = [
|
|
||||||
"simd-adler32",
|
|
||||||
]
|
|
||||||
|
|||||||
+14
-7
@@ -24,19 +24,26 @@ members = [
|
|||||||
|
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
exclude = [
|
exclude = ["node-graph/gpu-compiler"]
|
||||||
"node-graph/gpu-compiler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
specta = { git = "https://github.com/oscartbeaumont/rspc", rev = "9725ddbfe40183debc055b88c37910eb6f818eae", features = ["glam"] }
|
specta = { git = "https://github.com/oscartbeaumont/rspc", rev = "9725ddbfe40183debc055b88c37910eb6f818eae", features = [
|
||||||
|
"glam",
|
||||||
|
] }
|
||||||
xxhash-rust = { version = "0.8.4", features = ["xxh3"] }
|
xxhash-rust = { version = "0.8.4", features = ["xxh3"] }
|
||||||
|
|
||||||
[profile.release.package.graphite-wasm]
|
|
||||||
opt-level = 3
|
[profile.dev.package.graphite-editor]
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
[profile.dev.package.graphene-core]
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
|
[profile.dev.package.graphene-std]
|
||||||
|
opt-level = 1
|
||||||
|
|
||||||
[profile.dev.package.graphite-wasm]
|
[profile.dev.package.graphite-wasm]
|
||||||
opt-level = 3
|
opt-level = 1
|
||||||
|
|
||||||
[profile.dev.package.autoquant]
|
[profile.dev.package.autoquant]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|||||||
+9
-3
@@ -12,7 +12,10 @@ license = "Apache-2.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "graphene-core/gpu"]
|
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "graphene-core/gpu"]
|
||||||
quantization = ["graphene-std/quantization", "interpreted-executor/quantization"]
|
quantization = [
|
||||||
|
"graphene-std/quantization",
|
||||||
|
"interpreted-executor/quantization",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
@@ -22,7 +25,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
serde_json = { version = "1.0" }
|
serde_json = { version = "1.0" }
|
||||||
graphite-proc-macros = { path = "../proc-macros" }
|
graphite-proc-macros = { path = "../proc-macros" }
|
||||||
bezier-rs = { path = "../libraries/bezier-rs" }
|
bezier-rs = { path = "../libraries/bezier-rs" }
|
||||||
glam = { version="0.22", features = ["serde"] }
|
glam = { version = "0.22", features = ["serde"] }
|
||||||
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
||||||
"serde",
|
"serde",
|
||||||
] }
|
] }
|
||||||
@@ -32,7 +35,10 @@ once_cell = "1.13.0" # Remove when `core::cell::OnceCell` is stabilized (<https:
|
|||||||
specta.workspace = true
|
specta.workspace = true
|
||||||
|
|
||||||
# Node graph
|
# Node graph
|
||||||
image = { version = "0.24", default-features = false, features = ["bmp"] }
|
image = { version = "0.24", default-features = false, features = [
|
||||||
|
"bmp",
|
||||||
|
"png",
|
||||||
|
] }
|
||||||
graph-craft = { path = "../node-graph/graph-craft" }
|
graph-craft = { path = "../node-graph/graph-craft" }
|
||||||
interpreted-executor = { path = "../node-graph/interpreted-executor" }
|
interpreted-executor = { path = "../node-graph/interpreted-executor" }
|
||||||
borrow_stack = { path = "../node-graph/borrow_stack" }
|
borrow_stack = { path = "../node-graph/borrow_stack" }
|
||||||
|
|||||||
@@ -612,6 +612,9 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||||||
let center_in_viewport = DAffine2::from_translation(viewport_location - ipp.viewport_bounds.top_left);
|
let center_in_viewport = DAffine2::from_translation(viewport_location - ipp.viewport_bounds.top_left);
|
||||||
let center_in_viewport_layerspace = to_parent_folder.inverse() * center_in_viewport;
|
let center_in_viewport_layerspace = to_parent_folder.inverse() * center_in_viewport;
|
||||||
|
|
||||||
|
// Scale the image to fit into a 512x512 box
|
||||||
|
let image_size = image_size / DVec2::splat((image_size.max_element() / 512.).max(1.));
|
||||||
|
|
||||||
// Make layer the size of the image
|
// Make layer the size of the image
|
||||||
let fit_image_size = DAffine2::from_scale_angle_translation(image_size, 0., image_size / -2.);
|
let fit_image_size = DAffine2::from_scale_angle_translation(image_size, 0., image_size / -2.);
|
||||||
|
|
||||||
|
|||||||
+30
-2
@@ -107,7 +107,35 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "Image",
|
name: "Image",
|
||||||
category: "Ignore",
|
category: "Ignore",
|
||||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||||
|
inputs: vec![0],
|
||||||
|
outputs: vec![NodeOutput::new(2, 0)],
|
||||||
|
nodes: [
|
||||||
|
DocumentNode {
|
||||||
|
name: "Downscale".to_string(),
|
||||||
|
inputs: vec![NodeInput::Network(concrete!(ImageFrame))],
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::raster::DownscaleNode")),
|
||||||
|
metadata: Default::default(),
|
||||||
|
},
|
||||||
|
DocumentNode {
|
||||||
|
name: "Cache".to_string(),
|
||||||
|
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)],
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||||
|
metadata: Default::default(),
|
||||||
|
},
|
||||||
|
DocumentNode {
|
||||||
|
name: "Clone".to_string(),
|
||||||
|
inputs: vec![NodeInput::node(1, 0)],
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
|
||||||
|
metadata: Default::default(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(id, node)| (id as NodeId, node))
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), false)],
|
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), false)],
|
||||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||||
properties: |_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
|
properties: |_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
|
||||||
@@ -422,7 +450,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||||||
0,
|
0,
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "CacheNode".to_string(),
|
name: "CacheNode".to_string(),
|
||||||
inputs: vec![NodeInput::Network(concrete!(Image))],
|
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::Network(concrete!(ImageFrame))],
|
||||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||||
metadata: Default::default(),
|
metadata: Default::default(),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ impl NodeGraphExecutor {
|
|||||||
inner_network.outputs[0] = NodeOutput::new(*node_id, *output_index);
|
inner_network.outputs[0] = NodeOutput::new(*node_id, *output_index);
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
|
NodeInput::ShortCircut(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ impl NodeGraphExecutor {
|
|||||||
use image::{ImageBuffer, Rgba};
|
use image::{ImageBuffer, Rgba};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
let (result_bytes, width, height) = image.as_flat_u8();
|
let (result_bytes, width, height) = image.into_flat_u8();
|
||||||
|
|
||||||
let mut output: ImageBuffer<Rgba<u8>, _> = image::ImageBuffer::from_raw(width, height, result_bytes).ok_or_else(|| "Invalid image size".to_string())?;
|
let mut output: ImageBuffer<Rgba<u8>, _> = image::ImageBuffer::from_raw(width, height, result_bytes).ok_or_else(|| "Invalid image size".to_string())?;
|
||||||
if let Some(size) = resize {
|
if let Some(size) = resize {
|
||||||
|
|||||||
@@ -329,10 +329,9 @@ mod image {
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use dyn_any::{DynAny, StaticType};
|
use dyn_any::{DynAny, StaticType};
|
||||||
use glam::DAffine2;
|
use glam::{DAffine2, DVec2};
|
||||||
use glam::DVec2;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, specta::Type, Hash)]
|
#[derive(Clone, Debug, PartialEq, DynAny, Default, specta::Type)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
@@ -340,6 +339,17 @@ mod image {
|
|||||||
pub data: Vec<Color>,
|
pub data: Vec<Color>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Hash for Image {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
const HASH_SAMPLES: usize = 1000;
|
||||||
|
self.width.hash(state);
|
||||||
|
self.height.hash(state);
|
||||||
|
for i in 0..HASH_SAMPLES.min(self.data.len()) {
|
||||||
|
self.data[i * self.data.len() / HASH_SAMPLES].hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
pub const fn empty() -> Self {
|
pub const fn empty() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -362,7 +372,7 @@ mod image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Flattens each channel cast to a u8
|
/// Flattens each channel cast to a u8
|
||||||
pub fn as_flat_u8(self) -> (Vec<u8>, u32, u32) {
|
pub fn into_flat_u8(self) -> (Vec<u8>, u32, u32) {
|
||||||
let Image { width, height, data } = self;
|
let Image { width, height, data } = self;
|
||||||
|
|
||||||
let result_bytes = data.into_iter().flat_map(|color| color.to_rgba8()).collect();
|
let result_bytes = data.into_iter().flat_map(|color| color.to_rgba8()).collect();
|
||||||
@@ -431,11 +441,12 @@ mod image {
|
|||||||
&mut self.image.data[y * (self.image.width as usize) + x]
|
&mut self.image.data[y * (self.image.width as usize) + x]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sample(&self, x: f64, y: f64) -> Color {
|
/// Clamps the provided point to (0, 0) (ImageSize) and returns the closest pixel
|
||||||
let x = x.clamp(0.0, self.image.width as f64 - 1.0) as usize;
|
pub fn sample(&self, position: DVec2) -> Color {
|
||||||
let y = y.clamp(0.0, self.image.height as f64 - 1.0) as usize;
|
let x = position.x.clamp(0., self.image.width as f64 - 1.) as usize;
|
||||||
|
let y = position.y.clamp(0., self.image.height as f64 - 1.) as usize;
|
||||||
|
|
||||||
self.image.data[y * (self.image.width as usize) + x]
|
self.image.data[x + y * self.image.width as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ impl DocumentNode {
|
|||||||
(ProtoNodeInput::Node(node_id, lambda), ConstructionArgs::Nodes(vec![]))
|
(ProtoNodeInput::Node(node_id, lambda), ConstructionArgs::Nodes(vec![]))
|
||||||
}
|
}
|
||||||
NodeInput::Network(ty) => (ProtoNodeInput::Network(ty), ConstructionArgs::Nodes(vec![])),
|
NodeInput::Network(ty) => (ProtoNodeInput::Network(ty), ConstructionArgs::Nodes(vec![])),
|
||||||
|
NodeInput::ShortCircut(ty) => (ProtoNodeInput::ShortCircut(ty), ConstructionArgs::Nodes(vec![])),
|
||||||
};
|
};
|
||||||
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network(_))), "recieved non resolved parameter");
|
assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network(_))), "recieved non resolved parameter");
|
||||||
assert!(
|
assert!(
|
||||||
@@ -121,12 +122,52 @@ impl DocumentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the possible inputs to a node.
|
||||||
|
/// # ShortCircuting
|
||||||
|
/// In Graphite nodes are functions and by default, these are composed into a single function
|
||||||
|
/// by inserting Compose nodes.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||||
|
/// │ │◄──────────────┤ │◄───────────────┤ │
|
||||||
|
/// │ A │ │ B │ │ C │
|
||||||
|
/// │ ├──────────────►│ ├───────────────►│ │
|
||||||
|
/// └─────────────────┘ └──────────────────┘ └──────────────────┘
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// This is equivalent to calling c(b(a(input))) when evaluating c with input ( `c.eval(input)`)
|
||||||
|
/// But sometimes we might want to have a little more control over the order of execution.
|
||||||
|
/// This is why we allow nodes to opt out of the input forwarding by consuming the input directly.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// ┌─────────────────────┐ ┌─────────────┐
|
||||||
|
/// │ │◄───────────────┤ │
|
||||||
|
/// │ Cache Node │ │ C │
|
||||||
|
/// │ ├───────────────►│ │
|
||||||
|
/// ┌──────────────────┐ ├─────────────────────┤ └─────────────┘
|
||||||
|
/// │ │◄──────────────┤ │
|
||||||
|
/// │ A │ │ * Cached Node │
|
||||||
|
/// │ ├──────────────►│ │
|
||||||
|
/// └──────────────────┘ └─────────────────────┘
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// In this case the Cache node actually consumes it's input and then manually forwards it to it's parameter
|
||||||
|
/// Node. This is necessary because the Cache Node needs to short-circut the actual node evaluation
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum NodeInput {
|
pub enum NodeInput {
|
||||||
Node { node_id: NodeId, output_index: usize, lambda: bool },
|
Node { node_id: NodeId, output_index: usize, lambda: bool },
|
||||||
Value { tagged_value: crate::document::value::TaggedValue, exposed: bool },
|
Value { tagged_value: crate::document::value::TaggedValue, exposed: bool },
|
||||||
Network(Type),
|
Network(Type),
|
||||||
|
// A short circuting input represents an input that is not resolved through function composition but
|
||||||
|
// actually consuming the provided input instead of passing it to its predecessor
|
||||||
|
ShortCircut(Type),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeInput {
|
impl NodeInput {
|
||||||
@@ -153,6 +194,7 @@ impl NodeInput {
|
|||||||
NodeInput::Node { .. } => true,
|
NodeInput::Node { .. } => true,
|
||||||
NodeInput::Value { exposed, .. } => *exposed,
|
NodeInput::Value { exposed, .. } => *exposed,
|
||||||
NodeInput::Network(_) => false,
|
NodeInput::Network(_) => false,
|
||||||
|
NodeInput::ShortCircut(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn ty(&self) -> Type {
|
pub fn ty(&self) -> Type {
|
||||||
@@ -160,6 +202,7 @@ impl NodeInput {
|
|||||||
NodeInput::Node { .. } => unreachable!("ty() called on NodeInput::Node"),
|
NodeInput::Node { .. } => unreachable!("ty() called on NodeInput::Node"),
|
||||||
NodeInput::Value { tagged_value, .. } => tagged_value.ty(),
|
NodeInput::Value { tagged_value, .. } => tagged_value.ty(),
|
||||||
NodeInput::Network(ty) => ty.clone(),
|
NodeInput::Network(ty) => ty.clone(),
|
||||||
|
NodeInput::ShortCircut(ty) => ty.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,6 +440,7 @@ impl NodeNetwork {
|
|||||||
self.inputs[index] = *network_input;
|
self.inputs[index] = *network_input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NodeInput::ShortCircut(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.implementation = DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into());
|
node.implementation = DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into());
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ impl core::fmt::Display for ProtoNetwork {
|
|||||||
match &node.input {
|
match &node.input {
|
||||||
ProtoNodeInput::None => f.write_str("None")?,
|
ProtoNodeInput::None => f.write_str("None")?,
|
||||||
ProtoNodeInput::Network(ty) => f.write_fmt(format_args!("Network (type = {:?})", ty))?,
|
ProtoNodeInput::Network(ty) => f.write_fmt(format_args!("Network (type = {:?})", ty))?,
|
||||||
|
ProtoNodeInput::ShortCircut(ty) => f.write_fmt(format_args!("Lambda (type = {:?})", ty))?,
|
||||||
ProtoNodeInput::Node(_, _) => f.write_str("Node")?,
|
ProtoNodeInput::Node(_, _) => f.write_str("Node")?,
|
||||||
}
|
}
|
||||||
f.write_str("\n")?;
|
f.write_str("\n")?;
|
||||||
@@ -116,11 +117,19 @@ pub struct ProtoNode {
|
|||||||
pub identifier: NodeIdentifier,
|
pub identifier: NodeIdentifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A ProtoNodeInput represents the input of a node in a ProtoNetwork.
|
||||||
|
/// For documentation on the meaning of the variants, see the documentation of the `NodeInput` enum
|
||||||
|
/// in the `document` module
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum ProtoNodeInput {
|
pub enum ProtoNodeInput {
|
||||||
None,
|
None,
|
||||||
Network(Type),
|
Network(Type),
|
||||||
// the bool indicates whether to treat the node as lambda node
|
/// A ShortCircut input represents an input that is not resolved through function composition but
|
||||||
|
/// actually consuming the provided input instead of passing it to its predecessor
|
||||||
|
ShortCircut(Type),
|
||||||
|
/// the bool indicates whether to treat the node as lambda node.
|
||||||
|
/// When treating it as a lambda, only the node that is connected itself is fed as input.
|
||||||
|
/// Otherwise, the the entire network of which the node is the output is fed as input.
|
||||||
Node(NodeId, bool),
|
Node(NodeId, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +151,10 @@ impl ProtoNode {
|
|||||||
self.construction_args.hash(&mut hasher);
|
self.construction_args.hash(&mut hasher);
|
||||||
match self.input {
|
match self.input {
|
||||||
ProtoNodeInput::None => "none".hash(&mut hasher),
|
ProtoNodeInput::None => "none".hash(&mut hasher),
|
||||||
|
ProtoNodeInput::ShortCircut(ref ty) => {
|
||||||
|
"lambda".hash(&mut hasher);
|
||||||
|
ty.hash(&mut hasher);
|
||||||
|
}
|
||||||
ProtoNodeInput::Network(ref ty) => {
|
ProtoNodeInput::Network(ref ty) => {
|
||||||
"network".hash(&mut hasher);
|
"network".hash(&mut hasher);
|
||||||
ty.hash(&mut hasher);
|
ty.hash(&mut hasher);
|
||||||
@@ -422,6 +435,7 @@ impl TypingContext {
|
|||||||
// Get the node input type from the proto node declaration
|
// Get the node input type from the proto node declaration
|
||||||
let input = match node.input {
|
let input = match node.input {
|
||||||
ProtoNodeInput::None => concrete!(()),
|
ProtoNodeInput::None => concrete!(()),
|
||||||
|
ProtoNodeInput::ShortCircut(ref ty) => ty.clone(),
|
||||||
ProtoNodeInput::Network(ref ty) => ty.clone(),
|
ProtoNodeInput::Network(ref ty) => ty.clone(),
|
||||||
ProtoNodeInput::Node(id, _) => {
|
ProtoNodeInput::Node(id, _) => {
|
||||||
let input = self
|
let input = self
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ once_cell = {version= "1.10", optional = true}
|
|||||||
syn = {version = "1.0", default-features = false, features = ["parsing", "printing"]}
|
syn = {version = "1.0", default-features = false, features = ["parsing", "printing"]}
|
||||||
proc-macro2 = {version = "1.0", default-features = false, features = ["proc-macro"]}
|
proc-macro2 = {version = "1.0", default-features = false, features = ["proc-macro"]}
|
||||||
quote = {version = "1.0", default-features = false }
|
quote = {version = "1.0", default-features = false }
|
||||||
image = "*"
|
image = { version = "*", default-features = false }
|
||||||
dyn-clone = "1.0"
|
dyn-clone = "1.0"
|
||||||
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
@@ -6,14 +6,18 @@ use graphene_core::Node;
|
|||||||
|
|
||||||
/// Caches the output of a given Node and acts as a proxy
|
/// Caches the output of a given Node and acts as a proxy
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CacheNode<T> {
|
pub struct CacheNode<T, CachedNode> {
|
||||||
// We have to use an append only data structure to make sure the references
|
// We have to use an append only data structure to make sure the references
|
||||||
// to the cache entries are always valid
|
// to the cache entries are always valid
|
||||||
cache: boxcar::Vec<(u64, T)>,
|
cache: boxcar::Vec<(u64, T)>,
|
||||||
|
node: CachedNode,
|
||||||
}
|
}
|
||||||
impl<'i, T: 'i + Hash> Node<'i, T> for CacheNode<T> {
|
impl<'i, T: 'i, I: 'i + Hash, CachedNode: 'i> Node<'i, I> for CacheNode<T, CachedNode>
|
||||||
|
where
|
||||||
|
CachedNode: for<'any_input> Node<'any_input, I, Output = T>,
|
||||||
|
{
|
||||||
type Output = &'i T;
|
type Output = &'i T;
|
||||||
fn eval<'s: 'i>(&'s self, input: T) -> Self::Output {
|
fn eval<'s: 'i>(&'s self, input: I) -> Self::Output {
|
||||||
let mut hasher = Xxh3::new();
|
let mut hasher = Xxh3::new();
|
||||||
input.hash(&mut hasher);
|
input.hash(&mut hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
@@ -22,15 +26,16 @@ impl<'i, T: 'i + Hash> Node<'i, T> for CacheNode<T> {
|
|||||||
return cached_value;
|
return cached_value;
|
||||||
} else {
|
} else {
|
||||||
trace!("Cache miss");
|
trace!("Cache miss");
|
||||||
let index = self.cache.push((hash, input));
|
let output = self.node.eval(input);
|
||||||
|
let index = self.cache.push((hash, output));
|
||||||
return &self.cache[index].1;
|
return &self.cache[index].1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> CacheNode<T> {
|
impl<T, CachedNode> CacheNode<T, CachedNode> {
|
||||||
pub fn new() -> CacheNode<T> {
|
pub fn new(node: CachedNode) -> CacheNode<T, CachedNode> {
|
||||||
CacheNode { cache: boxcar::Vec::new() }
|
CacheNode { cache: boxcar::Vec::new(), node }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,33 @@ pub fn export_image_node<'i, 's: 'i>() -> impl Node<'i, 's, (Image, &'i str), Ou
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
pub struct DownscaleNode;
|
||||||
|
|
||||||
|
#[node_macro::node_fn(DownscaleNode)]
|
||||||
|
fn downscale(image_frame: ImageFrame) -> ImageFrame {
|
||||||
|
let target_width = image_frame.transform.transform_vector2((1., 0.).into()).length() as usize;
|
||||||
|
let target_height = image_frame.transform.transform_vector2((0., 1.).into()).length() as usize;
|
||||||
|
|
||||||
|
let mut image = Image {
|
||||||
|
width: target_width as u32,
|
||||||
|
height: target_height as u32,
|
||||||
|
data: Vec::with_capacity(target_width * target_height),
|
||||||
|
};
|
||||||
|
|
||||||
|
let scale_factor = DVec2::new(image_frame.image.width as f64, image_frame.image.height as f64) / DVec2::new(target_width as f64, target_height as f64);
|
||||||
|
for y in 0..target_height {
|
||||||
|
for x in 0..target_width {
|
||||||
|
let pixel = image_frame.sample(DVec2::new(x as f64, y as f64) * scale_factor);
|
||||||
|
image.data.push(pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageFrame {
|
||||||
|
image,
|
||||||
|
transform: image_frame.transform,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct MapImageNode<MapFn> {
|
pub struct MapImageNode<MapFn> {
|
||||||
map_fn: MapFn,
|
map_fn: MapFn,
|
||||||
@@ -168,8 +195,8 @@ fn compute_transformed_bounding_box(transform: DAffine2) -> Bbox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct BlendImageNode<background, MapFn> {
|
pub struct BlendImageNode<Background, MapFn> {
|
||||||
background: background,
|
background: Background,
|
||||||
map_fn: MapFn,
|
map_fn: MapFn,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +229,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dst_pixel = background.get_mut(x as usize, y as usize);
|
let dst_pixel = background.get_mut(x as usize, y as usize);
|
||||||
let src_pixel = foreground.sample(fg_point.x, fg_point.y);
|
let src_pixel = foreground.sample(fg_point);
|
||||||
|
|
||||||
*dst_pixel = map_fn.eval((src_pixel, *dst_pixel));
|
*dst_pixel = map_fn.eval((src_pixel, *dst_pixel));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||||||
register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [&f64]),
|
register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [&f64]),
|
||||||
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]),
|
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]),
|
||||||
register_node!(graphene_core::ops::SomeNode, input: ImageFrame, params: []),
|
register_node!(graphene_core::ops::SomeNode, input: ImageFrame, params: []),
|
||||||
|
register_node!(graphene_std::raster::DownscaleNode, input: ImageFrame, params: []),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
register_node!(graphene_std::executor::MapGpuSingleImageNode<_>, input: Image, params: [String]),
|
register_node!(graphene_std::executor::MapGpuSingleImageNode<_>, input: Image, params: [String]),
|
||||||
vec![(
|
vec![(
|
||||||
@@ -289,21 +290,43 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||||||
//register_node!(graphene_std::memo::CacheNode<_>, input: Image, params: []),
|
//register_node!(graphene_std::memo::CacheNode<_>, input: Image, params: []),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|_| {
|
|args| {
|
||||||
let node: CacheNode<Image> = graphene_std::memo::CacheNode::new();
|
let input: DowncastBothNode<(), Image> = DowncastBothNode::new(args[0]);
|
||||||
|
let node: CacheNode<Image, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
let any = DynAnyRefNode::new(node);
|
let any = DynAnyRefNode::new(node);
|
||||||
any.into_type_erased()
|
any.into_type_erased()
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(Image), concrete!(&Image), vec![]),
|
NodeIOTypes::new(concrete!(()), concrete!(&Image), vec![(concrete!(()), concrete!(Image))]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|_| {
|
|args| {
|
||||||
let node: CacheNode<QuantizationChannels> = graphene_std::memo::CacheNode::new();
|
let input: DowncastBothNode<(), ImageFrame> = DowncastBothNode::new(args[0]);
|
||||||
|
let node: CacheNode<ImageFrame, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
let any = DynAnyRefNode::new(node);
|
let any = DynAnyRefNode::new(node);
|
||||||
any.into_type_erased()
|
any.into_type_erased()
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(QuantizationChannels), concrete!(&QuantizationChannels), vec![]),
|
NodeIOTypes::new(concrete!(()), concrete!(&ImageFrame), vec![(concrete!(()), concrete!(ImageFrame))]),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|
|args| {
|
||||||
|
let input: DowncastBothNode<ImageFrame, ImageFrame> = DowncastBothNode::new(args[0]);
|
||||||
|
let node: CacheNode<ImageFrame, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
|
let any = DynAnyRefNode::new(node);
|
||||||
|
any.into_type_erased()
|
||||||
|
},
|
||||||
|
NodeIOTypes::new(concrete!(ImageFrame), concrete!(&ImageFrame), vec![(concrete!(ImageFrame), concrete!(ImageFrame))]),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|
|args| {
|
||||||
|
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
|
||||||
|
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
|
let any = DynAnyRefNode::new(node);
|
||||||
|
any.into_type_erased()
|
||||||
|
},
|
||||||
|
NodeIOTypes::new(concrete!(()), concrete!(&QuantizationChannels), vec![(concrete!(()), concrete!(QuantizationChannels))]),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image, params: [&str]),
|
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image, params: [&str]),
|
||||||
|
|||||||
Reference in New Issue
Block a user