mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 07:48:12 +08:00
fix issues in merge and update to vello pr
This commit is contained in:
@@ -80,97 +80,6 @@ jobs:
|
|||||||
npm run install-fonts
|
npm run install-fonts
|
||||||
zola --config config.toml build --minify
|
zola --config config.toml build --minify
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
- name: 💿 Restore cache of `website/other/dist` directory, if available and `website/other` didn't change
|
|
||||||
if: steps.changes.outputs.website-other != 'true'
|
|
||||||
id: cache-website-other-dist
|
|
||||||
uses: actions/cache/restore@v3
|
|
||||||
with:
|
|
||||||
path: website/other/dist
|
|
||||||
key: website-other-dist-${{ runner.os }}
|
|
||||||
|
|
||||||
- name: 🟢 Set up Node only if we are going to build in the next step
|
|
||||||
if: steps.cache-website-other-dist.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "latest"
|
|
||||||
|
|
||||||
- name: 📁 Build `website/other` directory only if changed or not cached
|
|
||||||
if: steps.cache-website-other-dist.outputs.cache-hit != 'true'
|
|
||||||
id: build-website-other
|
|
||||||
run: |
|
|
||||||
sh website/other/build.sh
|
|
||||||
|
|
||||||
- name: 💾 Save cache of `website/other/dist` directory if it was built above
|
|
||||||
if: steps.cache-website-other-dist.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache/save@v3
|
|
||||||
with:
|
|
||||||
path: website/other/dist
|
|
||||||
key: ${{ steps.cache-website-other-dist.outputs.cache-primary-key }}
|
|
||||||
|
|
||||||
- name: 🚚 Move `website/other/dist` contents to `website/public`
|
|
||||||
run: |
|
|
||||||
mkdir -p website/public
|
|
||||||
mv website/other/dist/* website/public
|
|
||||||
|
|
||||||
- name: 💿 Obtain cache of auto-generated code docs artifacts
|
|
||||||
id: cache-website-code-docs
|
|
||||||
uses: actions/cache/restore@v3
|
|
||||||
with:
|
|
||||||
path: artifacts
|
|
||||||
key: website-code-docs
|
|
||||||
|
|
||||||
- name: 📁 Fallback in case auto-generated code docs artifacts weren't cached
|
|
||||||
if: steps.cache-website-code-docs.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
echo "🦀 Initial system version of Rust:"
|
|
||||||
rustc --version
|
|
||||||
rustup update stable
|
|
||||||
echo "🦀 Latest updated version of Rust:"
|
|
||||||
rustc --version
|
|
||||||
cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree
|
|
||||||
mkdir artifacts
|
|
||||||
mv hierarchical_message_system_tree.txt artifacts/hierarchical_message_system_tree.txt
|
|
||||||
|
|
||||||
- name: 🚚 Move `artifacts` contents to `website/public`
|
|
||||||
run: |
|
|
||||||
mv artifacts/* website/public
|
|
||||||
|
|
||||||
||||||| 890da6a3
|
|
||||||
- name: 💿 Restore cache of `website/other/dist` directory, if available and `website/other` didn't change
|
|
||||||
if: steps.changes.outputs.website-other != 'true'
|
|
||||||
id: cache-website-other-dist
|
|
||||||
uses: actions/cache/restore@v3
|
|
||||||
with:
|
|
||||||
path: website/other/dist
|
|
||||||
key: website-other-dist-${{ runner.os }}
|
|
||||||
|
|
||||||
- name: 🟢 Set up Node only if we are going to build in the next step
|
|
||||||
if: steps.cache-website-other-dist.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "latest"
|
|
||||||
|
|
||||||
- name: 📁 Build `website/other` directory only if changed or not cached
|
|
||||||
if: steps.cache-website-other-dist.outputs.cache-hit != 'true'
|
|
||||||
id: build-website-other
|
|
||||||
run: |
|
|
||||||
sh website/other/build.sh
|
|
||||||
|
|
||||||
- name: 💾 Save cache of `website/other/dist` directory if it was built above
|
|
||||||
if: steps.cache-website-other-dist.outputs.cache-hit != 'true'
|
|
||||||
uses: actions/cache/save@v3
|
|
||||||
with:
|
|
||||||
path: website/other/dist
|
|
||||||
key: ${{ steps.cache-website-other-dist.outputs.cache-primary-key }}
|
|
||||||
|
|
||||||
- name: 🚚 Move `website/other/dist` contents to `website/public`
|
|
||||||
run: |
|
|
||||||
mkdir -p website/public
|
|
||||||
mv website/other/dist/* website/public
|
|
||||||
|
|
||||||
=======
|
|
||||||
>>>>>>> master
|
|
||||||
- name: 📤 Publish to Cloudflare Pages
|
- name: 📤 Publish to Cloudflare Pages
|
||||||
id: cloudflare
|
id: cloudflare
|
||||||
uses: cloudflare/pages-action@1
|
uses: cloudflare/pages-action@1
|
||||||
|
|||||||
Generated
+62
-70
@@ -92,7 +92,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
@@ -914,6 +914,16 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.7"
|
version = "0.8.7"
|
||||||
@@ -927,8 +937,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
|
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
"core-graphics-types",
|
"core-graphics-types 0.1.3",
|
||||||
"foreign-types 0.5.0",
|
"foreign-types 0.5.0",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -940,7 +950,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
|
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-graphics-types"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.3",
|
||||||
|
"core-foundation 0.10.1",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2128,7 +2149,7 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cef",
|
"cef",
|
||||||
"cef-dll-sys",
|
"cef-dll-sys",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
"derivative",
|
"derivative",
|
||||||
"dirs",
|
"dirs",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -3130,13 +3151,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metal"
|
name = "metal"
|
||||||
version = "0.31.0"
|
version = "0.32.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e"
|
checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
"block",
|
"block",
|
||||||
"core-graphics-types",
|
"core-graphics-types 0.2.0",
|
||||||
"foreign-types 0.5.0",
|
"foreign-types 0.5.0",
|
||||||
"log",
|
"log",
|
||||||
"objc",
|
"objc",
|
||||||
@@ -3188,26 +3209,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "25.0.1"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632"
|
checksum = "916cbc7cb27db60be930a4e2da243cf4bc39569195f22fd8ee419cd31d5b662c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"half",
|
"half",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"libm",
|
||||||
"log",
|
"log",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"petgraph 0.8.2",
|
"petgraph 0.8.2",
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"spirv",
|
"spirv",
|
||||||
"strum 0.26.3",
|
|
||||||
"thiserror 2.0.16",
|
"thiserror 2.0.16",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -3253,7 +3275,7 @@ dependencies = [
|
|||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
@@ -3265,15 +3287,6 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ndk-sys"
|
|
||||||
version = "0.5.0+25.2.9519653"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
|
|
||||||
dependencies = [
|
|
||||||
"jni-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk-sys"
|
name = "ndk-sys"
|
||||||
version = "0.6.0+11769913"
|
version = "0.6.0+11769913"
|
||||||
@@ -3313,7 +3326,7 @@ dependencies = [
|
|||||||
"proc-macro-error2",
|
"proc-macro-error2",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strum 0.27.2",
|
"strum",
|
||||||
"syn 2.0.106",
|
"syn 2.0.106",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3999,7 +4012,6 @@ dependencies = [
|
|||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4920,7 +4932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"security-framework-sys",
|
"security-framework-sys",
|
||||||
@@ -5255,35 +5267,13 @@ version = "0.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum"
|
|
||||||
version = "0.26.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
|
||||||
dependencies = [
|
|
||||||
"strum_macros 0.26.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum"
|
name = "strum"
|
||||||
version = "0.27.2"
|
version = "0.27.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strum_macros 0.27.2",
|
"strum_macros",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum_macros"
|
|
||||||
version = "0.26.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"rustversion",
|
|
||||||
"syn 2.0.106",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5386,7 +5376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
"system-configuration-sys",
|
"system-configuration-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -6092,14 +6082,14 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vello"
|
name = "vello"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/linebender/vello.git?rev=87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b#87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b"
|
source = "git+https://github.com/DJMcNab/vello.git?branch=luminance-mask-layer#2a6e445d9de397c1b552024cddfd8cb0d5881eaa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
"log",
|
"log",
|
||||||
"peniko",
|
"peniko",
|
||||||
"png 0.17.16",
|
"png 0.17.16",
|
||||||
"skrifa 0.31.3",
|
"skrifa 0.36.0",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"thiserror 2.0.16",
|
"thiserror 2.0.16",
|
||||||
"vello_encoding",
|
"vello_encoding",
|
||||||
@@ -6110,19 +6100,19 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vello_encoding"
|
name = "vello_encoding"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/linebender/vello.git?rev=87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b#87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b"
|
source = "git+https://github.com/DJMcNab/vello.git?branch=luminance-mask-layer#2a6e445d9de397c1b552024cddfd8cb0d5881eaa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"guillotiere",
|
"guillotiere",
|
||||||
"peniko",
|
"peniko",
|
||||||
"skrifa 0.31.3",
|
"skrifa 0.36.0",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vello_shaders"
|
name = "vello_shaders"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/linebender/vello.git?rev=87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b#87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b"
|
source = "git+https://github.com/DJMcNab/vello.git?branch=luminance-mask-layer#2a6e445d9de397c1b552024cddfd8cb0d5881eaa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"log",
|
"log",
|
||||||
@@ -6394,12 +6384,13 @@ checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu"
|
name = "wgpu"
|
||||||
version = "25.0.2"
|
version = "26.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec8fb398f119472be4d80bc3647339f56eb63b2a331f6a3d16e25d8144197dd9"
|
checksum = "70b6ff82bbf6e9206828e1a3178e851f8c20f1c9028e74dd3a8090741ccd5798"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"document-features",
|
"document-features",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -6422,9 +6413,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core"
|
name = "wgpu-core"
|
||||||
version = "25.0.2"
|
version = "26.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7b882196f8368511d613c6aeec80655160db6646aebddf8328879a88d54e500"
|
checksum = "d5f62f1053bd28c2268f42916f31588f81f64796e2ff91b81293515017ca8bd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
@@ -6454,27 +6445,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core-deps-apple"
|
name = "wgpu-core-deps-apple"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cfd488b3239b6b7b185c3b045c39ca6bf8af34467a4c5de4e0b1a564135d093d"
|
checksum = "18ae5fbde6a4cbebae38358aa73fcd6e0f15c6144b67ef5dc91ded0db125dbdf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core-deps-emscripten"
|
name = "wgpu-core-deps-emscripten"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f09ad7aceb3818e52539acc679f049d3475775586f3f4e311c30165cf2c00445"
|
checksum = "d7670e390f416006f746b4600fdd9136455e3627f5bd763abf9a65daa216dd2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core-deps-windows-linux-android"
|
name = "wgpu-core-deps-windows-linux-android"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cba5fb5f7f9c98baa7c889d444f63ace25574833df56f5b817985f641af58e46"
|
checksum = "720a5cb9d12b3d337c15ff0e24d3e97ed11490ff3f7506e7f3d98c68fa5d6f14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
]
|
]
|
||||||
@@ -6500,9 +6491,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-hal"
|
name = "wgpu-hal"
|
||||||
version = "25.0.2"
|
version = "26.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f968767fe4d3d33747bbd1473ccd55bf0f6451f55d733b5597e67b5deab4ad17"
|
checksum = "7df2c64ac282a91ad7662c90bc4a77d4a2135bc0b2a2da5a4d4e267afc034b9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
@@ -6513,7 +6504,7 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"core-graphics-types",
|
"core-graphics-types 0.2.0",
|
||||||
"glow",
|
"glow",
|
||||||
"glutin_wgl_sys",
|
"glutin_wgl_sys",
|
||||||
"gpu-alloc",
|
"gpu-alloc",
|
||||||
@@ -6527,11 +6518,12 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"metal",
|
"metal",
|
||||||
"naga",
|
"naga",
|
||||||
"ndk-sys 0.5.0+25.2.9519653",
|
"ndk-sys",
|
||||||
"objc",
|
"objc",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
|
"portable-atomic-util",
|
||||||
"profiling",
|
"profiling",
|
||||||
"range-alloc",
|
"range-alloc",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@@ -6547,9 +6539,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-types"
|
name = "wgpu-types"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2aa49460c2a8ee8edba3fca54325540d904dd85b2e086ada762767e17d06e8bc"
|
checksum = "eca7a8d8af57c18f57d393601a1fb159ace8b2328f1b6b5f80893f7d672c9ae2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.3",
|
"bitflags 2.9.3",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@@ -6961,7 +6953,7 @@ dependencies = [
|
|||||||
"calloop",
|
"calloop",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"cursor-icon",
|
"cursor-icon",
|
||||||
"dpi",
|
"dpi",
|
||||||
|
|||||||
+2
-2
@@ -101,7 +101,7 @@ quote = "1.0"
|
|||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
ron = "0.11"
|
ron = "0.11"
|
||||||
fastnoise-lite = "1.1"
|
fastnoise-lite = "1.1"
|
||||||
wgpu = { version = "25.0", features = [
|
wgpu = { version = "26.0.1", features = [
|
||||||
# We don't have wgpu on multiple threads (yet) https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#wgpu-types-now-send-sync-on-wasm
|
# We don't have wgpu on multiple threads (yet) https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#wgpu-types-now-send-sync-on-wasm
|
||||||
"fragile-send-sync-non-atomic-wasm",
|
"fragile-send-sync-non-atomic-wasm",
|
||||||
"spirv",
|
"spirv",
|
||||||
@@ -132,7 +132,7 @@ web-sys = { version = "=0.3.77", features = [
|
|||||||
winit = { version = "0.30", features = ["wayland", "rwh_06"] }
|
winit = { version = "0.30", features = ["wayland", "rwh_06"] }
|
||||||
url = "2.5"
|
url = "2.5"
|
||||||
tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt"] }
|
tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt"] }
|
||||||
vello = { git = "https://github.com/linebender/vello.git", rev = "87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b" } # TODO switch back to stable when a release is made
|
vello = { git = "https://github.com/DJMcNab/vello.git", branch = "luminance-mask-layer" } # TODO switch back to stable when a release is made
|
||||||
resvg = "0.45"
|
resvg = "0.45"
|
||||||
usvg = "0.45"
|
usvg = "0.45"
|
||||||
rand = { version = "0.9", default-features = false, features = ["std_rng"] }
|
rand = { version = "0.9", default-features = false, features = ["std_rng"] }
|
||||||
|
|||||||
@@ -1,325 +0,0 @@
|
|||||||
use super::VectorDataDomain;
|
|
||||||
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, LayoutTarget, WidgetLayout};
|
|
||||||
use crate::messages::prelude::*;
|
|
||||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
|
||||||
use graph_craft::document::NodeId;
|
|
||||||
use graphene_std::Color;
|
|
||||||
use graphene_std::Context;
|
|
||||||
use graphene_std::GraphicGroupTable;
|
|
||||||
use graphene_std::instances::Instances;
|
|
||||||
use graphene_std::memo::IORecord;
|
|
||||||
use graphene_std::raster::Image;
|
|
||||||
use graphene_std::vector::{VectorData, VectorDataTable};
|
|
||||||
use graphene_std::{Artboard, ArtboardGroupTable, GraphicElement};
|
|
||||||
use std::any::Any;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/// The spreadsheet UI allows for instance data to be previewed.
|
|
||||||
#[derive(Default, Debug, Clone, ExtractField)]
|
|
||||||
pub struct SpreadsheetMessageHandler {
|
|
||||||
/// Sets whether or not the spreadsheet is drawn.
|
|
||||||
pub spreadsheet_view_open: bool,
|
|
||||||
inspect_node: Option<NodeId>,
|
|
||||||
introspected_data: Option<Arc<dyn Any + Send + Sync>>,
|
|
||||||
instances_path: Vec<usize>,
|
|
||||||
viewing_vector_data_domain: VectorDataDomain,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[message_handler_data]
|
|
||||||
impl MessageHandler<SpreadsheetMessage, ()> for SpreadsheetMessageHandler {
|
|
||||||
fn process_message(&mut self, message: SpreadsheetMessage, responses: &mut VecDeque<Message>, _: ()) {
|
|
||||||
match message {
|
|
||||||
SpreadsheetMessage::ToggleOpen => {
|
|
||||||
self.spreadsheet_view_open = !self.spreadsheet_view_open;
|
|
||||||
// Run the graph to grab the data
|
|
||||||
if self.spreadsheet_view_open {
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
|
||||||
}
|
|
||||||
// Update checked UI state for open
|
|
||||||
responses.add(MenuBarMessage::SendLayout);
|
|
||||||
self.update_layout(responses);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpreadsheetMessage::UpdateLayout { mut inspect_result } => {
|
|
||||||
self.inspect_node = Some(inspect_result.inspect_node);
|
|
||||||
self.introspected_data = inspect_result.take_data();
|
|
||||||
self.update_layout(responses)
|
|
||||||
}
|
|
||||||
|
|
||||||
SpreadsheetMessage::PushToInstancePath { index } => {
|
|
||||||
self.instances_path.push(index);
|
|
||||||
self.update_layout(responses);
|
|
||||||
}
|
|
||||||
SpreadsheetMessage::TruncateInstancePath { len } => {
|
|
||||||
self.instances_path.truncate(len);
|
|
||||||
self.update_layout(responses);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpreadsheetMessage::ViewVectorDataDomain { domain } => {
|
|
||||||
self.viewing_vector_data_domain = domain;
|
|
||||||
self.update_layout(responses);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn actions(&self) -> ActionList {
|
|
||||||
actions!(SpreadsheetMessage;)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpreadsheetMessageHandler {
|
|
||||||
fn update_layout(&mut self, responses: &mut VecDeque<Message>) {
|
|
||||||
responses.add(FrontendMessage::UpdateSpreadsheetState {
|
|
||||||
node: self.inspect_node,
|
|
||||||
open: self.spreadsheet_view_open,
|
|
||||||
});
|
|
||||||
if !self.spreadsheet_view_open {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut layout_data = LayoutData {
|
|
||||||
current_depth: 0,
|
|
||||||
desired_path: &mut self.instances_path,
|
|
||||||
breadcrumbs: Vec::new(),
|
|
||||||
vector_data_domain: self.viewing_vector_data_domain,
|
|
||||||
};
|
|
||||||
let mut layout = self
|
|
||||||
.introspected_data
|
|
||||||
.as_ref()
|
|
||||||
.map(|instrospected_data| generate_layout(instrospected_data, &mut layout_data))
|
|
||||||
.unwrap_or_else(|| Some(label("No data")))
|
|
||||||
.unwrap_or_else(|| label("Failed to downcast data"));
|
|
||||||
|
|
||||||
if layout_data.breadcrumbs.len() > 1 {
|
|
||||||
let breadcrumb = BreadcrumbTrailButtons::new(layout_data.breadcrumbs)
|
|
||||||
.on_update(|&len| SpreadsheetMessage::TruncateInstancePath { len: len as usize }.into())
|
|
||||||
.widget_holder();
|
|
||||||
layout.insert(0, LayoutGroup::Row { widgets: vec![breadcrumb] });
|
|
||||||
}
|
|
||||||
|
|
||||||
responses.add(LayoutMessage::SendLayout {
|
|
||||||
layout: Layout::WidgetLayout(WidgetLayout { layout }),
|
|
||||||
layout_target: LayoutTarget::Spreadsheet,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LayoutData<'a> {
|
|
||||||
current_depth: usize,
|
|
||||||
desired_path: &'a mut Vec<usize>,
|
|
||||||
breadcrumbs: Vec<String>,
|
|
||||||
vector_data_domain: VectorDataDomain,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'static>, data: &mut LayoutData) -> Option<Vec<LayoutGroup>> {
|
|
||||||
// We simply try random types. TODO: better strategy.
|
|
||||||
#[allow(clippy::manual_map)]
|
|
||||||
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, ArtboardGroupTable>>() {
|
|
||||||
Some(io.output.layout_with_breadcrumb(data))
|
|
||||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<(), ArtboardGroupTable>>() {
|
|
||||||
Some(io.output.layout_with_breadcrumb(data))
|
|
||||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, VectorDataTable>>() {
|
|
||||||
Some(io.output.layout_with_breadcrumb(data))
|
|
||||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<(), VectorDataTable>>() {
|
|
||||||
Some(io.output.layout_with_breadcrumb(data))
|
|
||||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, GraphicGroupTable>>() {
|
|
||||||
Some(io.output.layout_with_breadcrumb(data))
|
|
||||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<(), GraphicGroupTable>>() {
|
|
||||||
Some(io.output.layout_with_breadcrumb(data))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn column_headings(value: &[&str]) -> Vec<WidgetHolder> {
|
|
||||||
value.iter().map(|text| TextLabel::new(*text).widget_holder()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn label(x: impl Into<String>) -> Vec<LayoutGroup> {
|
|
||||||
let error = vec![TextLabel::new(x).widget_holder()];
|
|
||||||
vec![LayoutGroup::Row { widgets: error }]
|
|
||||||
}
|
|
||||||
|
|
||||||
trait InstanceLayout {
|
|
||||||
fn type_name() -> &'static str;
|
|
||||||
fn identifier(&self) -> String;
|
|
||||||
fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
|
||||||
data.breadcrumbs.push(self.identifier());
|
|
||||||
self.compute_layout(data)
|
|
||||||
}
|
|
||||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InstanceLayout for GraphicElement {
|
|
||||||
fn type_name() -> &'static str {
|
|
||||||
"GraphicElement"
|
|
||||||
}
|
|
||||||
fn identifier(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Self::GraphicGroup(instances) => instances.identifier(),
|
|
||||||
Self::VectorData(instances) => instances.identifier(),
|
|
||||||
Self::RasterDataCPU(_) => "RasterDataCPU".to_string(),
|
|
||||||
Self::RasterDataGPU(_) => "RasterDataGPU".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Don't put a breadcrumb for GraphicElement
|
|
||||||
fn layout_with_breadcrumb(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
|
||||||
self.compute_layout(data)
|
|
||||||
}
|
|
||||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
|
||||||
match self {
|
|
||||||
Self::GraphicGroup(instances) => instances.layout_with_breadcrumb(data),
|
|
||||||
Self::VectorData(instances) => instances.layout_with_breadcrumb(data),
|
|
||||||
Self::RasterDataCPU(_) => label("Raster frame not supported"),
|
|
||||||
Self::RasterDataGPU(_) => label("Raster frame not supported"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InstanceLayout for VectorData {
|
|
||||||
fn type_name() -> &'static str {
|
|
||||||
"VectorData"
|
|
||||||
}
|
|
||||||
fn identifier(&self) -> String {
|
|
||||||
format!("Vector Data (points={}, segments={})", self.point_domain.ids().len(), self.segment_domain.ids().len())
|
|
||||||
}
|
|
||||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
|
||||||
let colinear = self.colinear_manipulators.iter().map(|[a, b]| format!("[{a} / {b}]")).collect::<Vec<_>>().join(", ");
|
|
||||||
let colinear = if colinear.is_empty() { "None" } else { &colinear };
|
|
||||||
let style = vec![
|
|
||||||
TextLabel::new(format!(
|
|
||||||
"{}\n\nColinear Handle IDs: {}\n\nUpstream Graphic Group Table: {}",
|
|
||||||
self.style,
|
|
||||||
colinear,
|
|
||||||
if self.upstream_graphic_group.is_some() { "Yes" } else { "No" }
|
|
||||||
))
|
|
||||||
.multiline(true)
|
|
||||||
.widget_holder(),
|
|
||||||
];
|
|
||||||
|
|
||||||
let domain_entries = [VectorDataDomain::Points, VectorDataDomain::Segments, VectorDataDomain::Regions]
|
|
||||||
.into_iter()
|
|
||||||
.map(|domain| {
|
|
||||||
RadioEntryData::new(format!("{domain:?}"))
|
|
||||||
.label(format!("{domain:?}"))
|
|
||||||
.on_update(move |_| SpreadsheetMessage::ViewVectorDataDomain { domain }.into())
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let domain = vec![RadioInput::new(domain_entries).selected_index(Some(data.vector_data_domain as u32)).widget_holder()];
|
|
||||||
|
|
||||||
let mut table_rows = Vec::new();
|
|
||||||
match data.vector_data_domain {
|
|
||||||
VectorDataDomain::Points => {
|
|
||||||
table_rows.push(column_headings(&["", "position"]));
|
|
||||||
table_rows.extend(
|
|
||||||
self.point_domain
|
|
||||||
.iter()
|
|
||||||
.map(|(id, position)| vec![TextLabel::new(format!("{}", id.inner())).widget_holder(), TextLabel::new(format!("{}", position)).widget_holder()]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
VectorDataDomain::Segments => {
|
|
||||||
table_rows.push(column_headings(&["", "start_index", "end_index", "handles"]));
|
|
||||||
table_rows.extend(self.segment_domain.iter().map(|(id, start, end, handles)| {
|
|
||||||
vec![
|
|
||||||
TextLabel::new(format!("{}", id.inner())).widget_holder(),
|
|
||||||
TextLabel::new(format!("{}", start)).widget_holder(),
|
|
||||||
TextLabel::new(format!("{}", end)).widget_holder(),
|
|
||||||
TextLabel::new(format!("{:?}", handles)).widget_holder(),
|
|
||||||
]
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
VectorDataDomain::Regions => {
|
|
||||||
table_rows.push(column_headings(&["", "segment_range", "fill"]));
|
|
||||||
table_rows.extend(self.region_domain.iter().map(|(id, segment_range, fill)| {
|
|
||||||
vec![
|
|
||||||
TextLabel::new(format!("{}", id.inner())).widget_holder(),
|
|
||||||
TextLabel::new(format!("{:?}", segment_range)).widget_holder(),
|
|
||||||
TextLabel::new(format!("{}", fill.inner())).widget_holder(),
|
|
||||||
]
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec![LayoutGroup::Row { widgets: style }, LayoutGroup::Row { widgets: domain }, LayoutGroup::Table { rows: table_rows }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InstanceLayout for Image<Color> {
|
|
||||||
fn type_name() -> &'static str {
|
|
||||||
"Image"
|
|
||||||
}
|
|
||||||
fn identifier(&self) -> String {
|
|
||||||
format!("Image (width={}, height={})", self.width, self.height)
|
|
||||||
}
|
|
||||||
fn compute_layout(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
|
||||||
let rows = vec![vec![TextLabel::new(format!("Image (width={}, height={})", self.width, self.height)).widget_holder()]];
|
|
||||||
vec![LayoutGroup::Table { rows }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InstanceLayout for Artboard {
|
|
||||||
fn type_name() -> &'static str {
|
|
||||||
"Artboard"
|
|
||||||
}
|
|
||||||
fn identifier(&self) -> String {
|
|
||||||
self.label.clone()
|
|
||||||
}
|
|
||||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
|
||||||
self.graphic_group.compute_layout(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InstanceLayout> InstanceLayout for Instances<T> {
|
|
||||||
fn type_name() -> &'static str {
|
|
||||||
"Instances"
|
|
||||||
}
|
|
||||||
fn identifier(&self) -> String {
|
|
||||||
format!("Instances<{}> (length={})", T::type_name(), self.len())
|
|
||||||
}
|
|
||||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
|
||||||
if let Some(index) = data.desired_path.get(data.current_depth).copied() {
|
|
||||||
if let Some(instance) = self.get(index) {
|
|
||||||
data.current_depth += 1;
|
|
||||||
let result = instance.instance.layout_with_breadcrumb(data);
|
|
||||||
data.current_depth -= 1;
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
warn!("Desired path truncated");
|
|
||||||
data.desired_path.truncate(data.current_depth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rows = self
|
|
||||||
.instance_ref_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(index, instance)| {
|
|
||||||
let (scale, angle, translation) = instance.transform.to_scale_angle_translation();
|
|
||||||
let rotation = if angle == -0. { 0. } else { angle.to_degrees() };
|
|
||||||
let round = |x: f64| (x * 1e3).round() / 1e3;
|
|
||||||
vec![
|
|
||||||
TextLabel::new(format!("{}", index)).widget_holder(),
|
|
||||||
TextButton::new(instance.instance.identifier())
|
|
||||||
.on_update(move |_| SpreadsheetMessage::PushToInstancePath { index }.into())
|
|
||||||
.widget_holder(),
|
|
||||||
// Add the mask information here. We'll simply display "Yes" or "No".
|
|
||||||
TextLabel::new(if instance.mask.is_some() { "Yes" } else { "No" }.to_string()).widget_holder(),
|
|
||||||
TextLabel::new(format!(
|
|
||||||
"Location: ({} px, {} px) — Rotation: {rotation:2}° — Scale: ({}x, {}x)",
|
|
||||||
round(translation.x),
|
|
||||||
round(translation.y),
|
|
||||||
round(scale.x),
|
|
||||||
round(scale.y)
|
|
||||||
))
|
|
||||||
.widget_holder(),
|
|
||||||
TextLabel::new(format!("{}", instance.alpha_blending)).widget_holder(),
|
|
||||||
TextLabel::new(instance.source_node_id.map_or_else(|| "-".to_string(), |id| format!("{}", id.0))).widget_holder(),
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Add "mask" to the column headings
|
|
||||||
rows.insert(0, column_headings(&["", "instance", "mask", "transform", "alpha_blending", "source_node_id"]));
|
|
||||||
|
|
||||||
let instances = vec![TextLabel::new("Instances:").widget_holder()];
|
|
||||||
vec![LayoutGroup::Row { widgets: instances }, LayoutGroup::Table { rows }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,626 +0,0 @@
|
|||||||
use crate::blending::AlphaBlending;
|
|
||||||
use crate::bounds::BoundingBox;
|
|
||||||
use crate::instances::{Instance, Instances};
|
|
||||||
use crate::math::quad::Quad;
|
|
||||||
use crate::raster::image::Image;
|
|
||||||
use crate::raster_types::{CPU, GPU, Raster, RasterDataTable};
|
|
||||||
use crate::transform::TransformMut;
|
|
||||||
use crate::uuid::NodeId;
|
|
||||||
use crate::vector::{VectorData, VectorDataTable};
|
|
||||||
use crate::{CloneVarArgs, Color, Context, Ctx, ExtractAll, OwnedContextImpl};
|
|
||||||
use dyn_any::DynAny;
|
|
||||||
use glam::{DAffine2, DVec2, IVec2};
|
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
// TODO: Eventually remove this migration document upgrade code
|
|
||||||
pub fn migrate_graphic_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<GraphicGroupTable, D::Error> {
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct OldGraphicGroup {
|
|
||||||
elements: Vec<(GraphicElement, Option<NodeId>)>,
|
|
||||||
transform: DAffine2,
|
|
||||||
alpha_blending: AlphaBlending,
|
|
||||||
}
|
|
||||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct GraphicGroup {
|
|
||||||
elements: Vec<(GraphicElement, Option<NodeId>)>,
|
|
||||||
}
|
|
||||||
pub type OldGraphicGroupTable = Instances<GraphicGroup>;
|
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
enum EitherFormat {
|
|
||||||
OldGraphicGroup(OldGraphicGroup),
|
|
||||||
InstanceTable(serde_json::Value),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(match EitherFormat::deserialize(deserializer)? {
|
|
||||||
EitherFormat::OldGraphicGroup(old) => {
|
|
||||||
let mut graphic_group_table = GraphicGroupTable::default();
|
|
||||||
for (graphic_element, source_node_id) in old.elements {
|
|
||||||
graphic_group_table.push(Instance {
|
|
||||||
instance: graphic_element,
|
|
||||||
mask: None,
|
|
||||||
transform: old.transform,
|
|
||||||
alpha_blending: old.alpha_blending,
|
|
||||||
source_node_id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
graphic_group_table
|
|
||||||
}
|
|
||||||
EitherFormat::InstanceTable(value) => {
|
|
||||||
// Try to deserialize as either table format
|
|
||||||
if let Ok(old_table) = serde_json::from_value::<OldGraphicGroupTable>(value.clone()) {
|
|
||||||
let mut graphic_group_table = GraphicGroupTable::default();
|
|
||||||
for instance in old_table.instance_ref_iter() {
|
|
||||||
for (graphic_element, source_node_id) in &instance.instance.elements {
|
|
||||||
graphic_group_table.push(Instance {
|
|
||||||
instance: graphic_element.clone(),
|
|
||||||
mask: None,
|
|
||||||
transform: *instance.transform,
|
|
||||||
alpha_blending: *instance.alpha_blending,
|
|
||||||
source_node_id: *source_node_id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
graphic_group_table
|
|
||||||
} else if let Ok(new_table) = serde_json::from_value::<GraphicGroupTable>(value) {
|
|
||||||
new_table
|
|
||||||
} else {
|
|
||||||
return Err(serde::de::Error::custom("Failed to deserialize GraphicGroupTable"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Rename to GraphicElementTable
|
|
||||||
pub type GraphicGroupTable = Instances<GraphicElement>;
|
|
||||||
|
|
||||||
impl From<VectorData> for GraphicGroupTable {
|
|
||||||
fn from(vector_data: VectorData) -> Self {
|
|
||||||
Self::new(GraphicElement::VectorData(VectorDataTable::new(vector_data)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<VectorDataTable> for GraphicGroupTable {
|
|
||||||
fn from(vector_data: VectorDataTable) -> Self {
|
|
||||||
Self::new(GraphicElement::VectorData(vector_data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Image<Color>> for GraphicGroupTable {
|
|
||||||
fn from(image: Image<Color>) -> Self {
|
|
||||||
Self::new(GraphicElement::RasterDataCPU(RasterDataTable::<CPU>::new(Raster::new_cpu(image))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<RasterDataTable<CPU>> for GraphicGroupTable {
|
|
||||||
fn from(raster_data_table: RasterDataTable<CPU>) -> Self {
|
|
||||||
Self::new(GraphicElement::RasterDataCPU(raster_data_table))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<RasterDataTable<GPU>> for GraphicGroupTable {
|
|
||||||
fn from(raster_data_table: RasterDataTable<GPU>) -> Self {
|
|
||||||
Self::new(GraphicElement::RasterDataGPU(raster_data_table))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<DAffine2> for GraphicGroupTable {
|
|
||||||
fn from(_: DAffine2) -> Self {
|
|
||||||
GraphicGroupTable::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The possible forms of graphical content held in a Vec by the `elements` field of [`GraphicElement`].
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub enum GraphicElement {
|
|
||||||
/// Equivalent to the SVG <g> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
|
|
||||||
GraphicGroup(GraphicGroupTable),
|
|
||||||
/// A vector shape, equivalent to the SVG <path> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
|
|
||||||
VectorData(VectorDataTable),
|
|
||||||
RasterDataCPU(RasterDataTable<CPU>),
|
|
||||||
RasterDataGPU(RasterDataTable<GPU>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GraphicElement {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::GraphicGroup(GraphicGroupTable::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DAffine2> for GraphicElement {
|
|
||||||
fn from(_: DAffine2) -> Self {
|
|
||||||
GraphicElement::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GraphicElement {
|
|
||||||
pub fn as_group(&self) -> Option<&GraphicGroupTable> {
|
|
||||||
match self {
|
|
||||||
GraphicElement::GraphicGroup(group) => Some(group),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_group_mut(&mut self) -> Option<&mut GraphicGroupTable> {
|
|
||||||
match self {
|
|
||||||
GraphicElement::GraphicGroup(group) => Some(group),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_vector_data(&self) -> Option<&VectorDataTable> {
|
|
||||||
match self {
|
|
||||||
GraphicElement::VectorData(data) => Some(data),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_vector_data_mut(&mut self) -> Option<&mut VectorDataTable> {
|
|
||||||
match self {
|
|
||||||
GraphicElement::VectorData(data) => Some(data),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_raster(&self) -> Option<&RasterDataTable<CPU>> {
|
|
||||||
match self {
|
|
||||||
GraphicElement::RasterDataCPU(raster) => Some(raster),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_raster_mut(&mut self) -> Option<&mut RasterDataTable<CPU>> {
|
|
||||||
match self {
|
|
||||||
GraphicElement::RasterDataCPU(raster) => Some(raster),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn had_clip_enabled(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
GraphicElement::VectorData(data) => data.instance_ref_iter().all(|instance| instance.alpha_blending.clip),
|
|
||||||
GraphicElement::GraphicGroup(data) => data.instance_ref_iter().all(|instance| instance.alpha_blending.clip),
|
|
||||||
GraphicElement::RasterDataCPU(data) => data.instance_ref_iter().all(|instance| instance.alpha_blending.clip),
|
|
||||||
GraphicElement::RasterDataGPU(data) => data.instance_ref_iter().all(|instance| instance.alpha_blending.clip),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_reduce_to_clip_path(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
GraphicElement::VectorData(vector_data_table) => vector_data_table.instance_ref_iter().all(|instance_data| {
|
|
||||||
let style = &instance_data.instance.style;
|
|
||||||
let alpha_blending = &instance_data.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 GraphicElement {
|
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
|
||||||
match self {
|
|
||||||
GraphicElement::VectorData(vector_data) => vector_data.bounding_box(transform, include_stroke),
|
|
||||||
GraphicElement::RasterDataCPU(raster) => raster.bounding_box(transform, include_stroke),
|
|
||||||
GraphicElement::RasterDataGPU(raster) => raster.bounding_box(transform, include_stroke),
|
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.bounding_box(transform, include_stroke),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BoundingBox for GraphicGroupTable {
|
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
|
||||||
self.instance_ref_iter()
|
|
||||||
.filter_map(|element| element.instance.bounding_box(transform * *element.transform, include_stroke))
|
|
||||||
.reduce(Quad::combine_bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for Raster<CPU> {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
Ok(Raster::new_cpu(Image::deserialize(deserializer)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl serde::Serialize for Raster<CPU> {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
self.data().serialize(serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'de> serde::Deserialize<'de> for Raster<GPU> {
|
|
||||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl serde::Serialize for Raster<GPU> {
|
|
||||||
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Some [`ArtboardData`] with some optional clipping bounds that can be exported.
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct Artboard {
|
|
||||||
pub graphic_group: GraphicGroupTable,
|
|
||||||
pub label: String,
|
|
||||||
pub location: IVec2,
|
|
||||||
pub dimensions: IVec2,
|
|
||||||
pub background: Color,
|
|
||||||
pub clip: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Artboard {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(IVec2::ZERO, IVec2::new(1920, 1080))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Artboard {
|
|
||||||
pub fn new(location: IVec2, dimensions: IVec2) -> Self {
|
|
||||||
Self {
|
|
||||||
graphic_group: GraphicGroupTable::default(),
|
|
||||||
label: "Artboard".to_string(),
|
|
||||||
location: location.min(location + dimensions),
|
|
||||||
dimensions: dimensions.abs(),
|
|
||||||
background: Color::WHITE,
|
|
||||||
clip: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BoundingBox for Artboard {
|
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
|
||||||
let artboard_bounds = (transform * Quad::from_box([self.location.as_dvec2(), self.location.as_dvec2() + self.dimensions.as_dvec2()])).bounding_box();
|
|
||||||
if self.clip {
|
|
||||||
Some(artboard_bounds)
|
|
||||||
} else {
|
|
||||||
[self.graphic_group.bounding_box(transform, include_stroke), Some(artboard_bounds)]
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.reduce(Quad::combine_bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Eventually remove this migration document upgrade code
|
|
||||||
pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<ArtboardGroupTable, D::Error> {
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct ArtboardGroup {
|
|
||||||
pub artboards: Vec<(Artboard, Option<NodeId>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
enum EitherFormat {
|
|
||||||
ArtboardGroup(ArtboardGroup),
|
|
||||||
ArtboardGroupTable(ArtboardGroupTable),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(match EitherFormat::deserialize(deserializer)? {
|
|
||||||
EitherFormat::ArtboardGroup(artboard_group) => {
|
|
||||||
let mut table = ArtboardGroupTable::default();
|
|
||||||
for (artboard, source_node_id) in artboard_group.artboards {
|
|
||||||
table.push(Instance {
|
|
||||||
instance: artboard,
|
|
||||||
mask: None,
|
|
||||||
transform: DAffine2::IDENTITY,
|
|
||||||
alpha_blending: AlphaBlending::default(),
|
|
||||||
source_node_id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
table
|
|
||||||
}
|
|
||||||
EitherFormat::ArtboardGroupTable(artboard_group_table) => artboard_group_table,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ArtboardGroupTable = Instances<Artboard>;
|
|
||||||
|
|
||||||
impl BoundingBox for ArtboardGroupTable {
|
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
|
||||||
self.instance_ref_iter()
|
|
||||||
.filter_map(|instance| instance.instance.bounding_box(transform, include_stroke))
|
|
||||||
.reduce(Quad::combine_bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
|
||||||
async fn layer<I: 'n + Send + Clone>(
|
|
||||||
_: impl Ctx,
|
|
||||||
#[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable<CPU>, RasterDataTable<GPU>)] mut stack: Instances<I>,
|
|
||||||
#[implementations(GraphicElement, VectorData, Raster<CPU>, Raster<GPU>)] element: I,
|
|
||||||
node_path: Vec<NodeId>,
|
|
||||||
) -> Instances<I> {
|
|
||||||
// Get the penultimate element of the node path, or None if the path is too short
|
|
||||||
let source_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
|
||||||
|
|
||||||
stack.push(Instance {
|
|
||||||
instance: element,
|
|
||||||
mask: None,
|
|
||||||
transform: DAffine2::IDENTITY,
|
|
||||||
alpha_blending: AlphaBlending::default(),
|
|
||||||
source_node_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
stack
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node_macro::node(category("Debug"))]
|
|
||||||
async fn to_element<Data: Into<GraphicElement> + 'n>(
|
|
||||||
_: impl Ctx,
|
|
||||||
#[implementations(
|
|
||||||
GraphicGroupTable,
|
|
||||||
VectorDataTable,
|
|
||||||
RasterDataTable<CPU>,
|
|
||||||
RasterDataTable<GPU>,
|
|
||||||
DAffine2,
|
|
||||||
)]
|
|
||||||
data: Data,
|
|
||||||
) -> GraphicElement {
|
|
||||||
data.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node_macro::node(category("General"))]
|
|
||||||
async fn to_group<Data: Into<GraphicGroupTable> + 'n>(
|
|
||||||
_: impl Ctx,
|
|
||||||
#[implementations(
|
|
||||||
GraphicGroupTable,
|
|
||||||
VectorDataTable,
|
|
||||||
RasterDataTable<CPU>,
|
|
||||||
RasterDataTable<GPU>,
|
|
||||||
)]
|
|
||||||
element: Data,
|
|
||||||
) -> GraphicGroupTable {
|
|
||||||
element.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node_macro::node(category("General"))]
|
|
||||||
async fn flatten_group(_: impl Ctx, group: GraphicGroupTable, fully_flatten: bool) -> GraphicGroupTable {
|
|
||||||
// TODO: Avoid mutable reference, instead return a new GraphicGroupTable?
|
|
||||||
fn flatten_group(output_group_table: &mut GraphicGroupTable, current_group_table: GraphicGroupTable, fully_flatten: bool, recursion_depth: usize) {
|
|
||||||
for current_instance in current_group_table.instance_ref_iter() {
|
|
||||||
let current_element = current_instance.instance.clone();
|
|
||||||
let reference = *current_instance.source_node_id;
|
|
||||||
|
|
||||||
let recurse = fully_flatten || recursion_depth == 0;
|
|
||||||
|
|
||||||
match current_element {
|
|
||||||
// If we're allowed to recurse, flatten any GraphicGroups we encounter
|
|
||||||
GraphicElement::GraphicGroup(mut current_element) if recurse => {
|
|
||||||
// Apply the parent group's transform to all child elements
|
|
||||||
for graphic_element in current_element.instance_mut_iter() {
|
|
||||||
*graphic_element.transform = *current_instance.transform * *graphic_element.transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
flatten_group(output_group_table, current_element, fully_flatten, recursion_depth + 1);
|
|
||||||
}
|
|
||||||
// Handle any leaf elements we encounter, which can be either non-GraphicGroup elements or GraphicGroups that we don't want to flatten
|
|
||||||
_ => {
|
|
||||||
output_group_table.push(Instance {
|
|
||||||
instance: current_element,
|
|
||||||
mask: None,
|
|
||||||
transform: *current_instance.transform,
|
|
||||||
alpha_blending: *current_instance.alpha_blending,
|
|
||||||
source_node_id: reference,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut output = GraphicGroupTable::default();
|
|
||||||
flatten_group(&mut output, group, fully_flatten, 0);
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node_macro::node(category("Vector"))]
|
|
||||||
async fn flatten_vector(_: impl Ctx, group: GraphicGroupTable) -> VectorDataTable {
|
|
||||||
// TODO: Avoid mutable reference, instead return a new GraphicGroupTable?
|
|
||||||
fn flatten_group(output_group_table: &mut VectorDataTable, current_group_table: GraphicGroupTable) {
|
|
||||||
for current_instance in current_group_table.instance_ref_iter() {
|
|
||||||
let current_element = current_instance.instance.clone();
|
|
||||||
let reference = *current_instance.source_node_id;
|
|
||||||
|
|
||||||
match current_element {
|
|
||||||
// If we're allowed to recurse, flatten any GraphicGroups we encounter
|
|
||||||
GraphicElement::GraphicGroup(mut current_element) => {
|
|
||||||
// Apply the parent group's transform to all child elements
|
|
||||||
for graphic_element in current_element.instance_mut_iter() {
|
|
||||||
*graphic_element.transform = *current_instance.transform * *graphic_element.transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
flatten_group(output_group_table, current_element);
|
|
||||||
}
|
|
||||||
// Handle any leaf elements we encounter, which can be either non-GraphicGroup elements or GraphicGroups that we don't want to flatten
|
|
||||||
GraphicElement::VectorData(vector_instance) => {
|
|
||||||
for current_element in vector_instance.instance_ref_iter() {
|
|
||||||
output_group_table.push(Instance {
|
|
||||||
instance: current_element.instance.clone(),
|
|
||||||
mask: None,
|
|
||||||
transform: *current_instance.transform * *current_element.transform,
|
|
||||||
alpha_blending: AlphaBlending {
|
|
||||||
blend_mode: current_element.alpha_blending.blend_mode,
|
|
||||||
opacity: current_instance.alpha_blending.opacity * current_element.alpha_blending.opacity,
|
|
||||||
fill: current_element.alpha_blending.fill,
|
|
||||||
clip: current_element.alpha_blending.clip,
|
|
||||||
},
|
|
||||||
source_node_id: reference,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut output = VectorDataTable::default();
|
|
||||||
flatten_group(&mut output, group);
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
|
||||||
async fn to_artboard<Data: Into<GraphicGroupTable> + 'n>(
|
|
||||||
ctx: impl ExtractAll + CloneVarArgs + Ctx,
|
|
||||||
#[implementations(
|
|
||||||
Context -> GraphicGroupTable,
|
|
||||||
Context -> VectorDataTable,
|
|
||||||
Context -> RasterDataTable<CPU>,
|
|
||||||
Context -> RasterDataTable<GPU>,
|
|
||||||
Context -> DAffine2,
|
|
||||||
)]
|
|
||||||
contents: impl Node<Context<'static>, Output = Data>,
|
|
||||||
label: String,
|
|
||||||
location: DVec2,
|
|
||||||
dimensions: DVec2,
|
|
||||||
background: Color,
|
|
||||||
clip: bool,
|
|
||||||
) -> Artboard {
|
|
||||||
let location = location.as_ivec2();
|
|
||||||
let dimensions = dimensions.as_ivec2().max(IVec2::ONE);
|
|
||||||
|
|
||||||
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 graphic_group = contents.eval(new_ctx.into_context()).await;
|
|
||||||
|
|
||||||
Artboard {
|
|
||||||
graphic_group: graphic_group.into(),
|
|
||||||
label,
|
|
||||||
location: location.min(location + dimensions),
|
|
||||||
dimensions: dimensions.abs(),
|
|
||||||
background,
|
|
||||||
clip,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
|
||||||
pub async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroupTable, artboard: Artboard, node_path: Vec<NodeId>) -> ArtboardGroupTable {
|
|
||||||
// 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 "Artboard" node (which encapsulates this internal "Append Artboard" node).
|
|
||||||
let encapsulating_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
|
||||||
|
|
||||||
artboards.push(Instance {
|
|
||||||
instance: artboard,
|
|
||||||
mask: None,
|
|
||||||
transform: DAffine2::IDENTITY,
|
|
||||||
alpha_blending: AlphaBlending::default(),
|
|
||||||
source_node_id: encapsulating_node_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
artboards
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove this one
|
|
||||||
impl From<Image<Color>> for GraphicElement {
|
|
||||||
fn from(raster_data: Image<Color>) -> Self {
|
|
||||||
GraphicElement::RasterDataCPU(RasterDataTable::<CPU>::new(Raster::new_cpu(raster_data)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<RasterDataTable<CPU>> for GraphicElement {
|
|
||||||
fn from(raster_data: RasterDataTable<CPU>) -> Self {
|
|
||||||
GraphicElement::RasterDataCPU(raster_data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<RasterDataTable<GPU>> for GraphicElement {
|
|
||||||
fn from(raster_data: RasterDataTable<GPU>) -> Self {
|
|
||||||
GraphicElement::RasterDataGPU(raster_data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Raster<CPU>> for GraphicElement {
|
|
||||||
fn from(raster_data: Raster<CPU>) -> Self {
|
|
||||||
GraphicElement::RasterDataCPU(RasterDataTable::new(raster_data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Raster<GPU>> for GraphicElement {
|
|
||||||
fn from(raster_data: Raster<GPU>) -> Self {
|
|
||||||
GraphicElement::RasterDataGPU(RasterDataTable::new(raster_data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: Remove this one
|
|
||||||
impl From<VectorData> for GraphicElement {
|
|
||||||
fn from(vector_data: VectorData) -> Self {
|
|
||||||
GraphicElement::VectorData(VectorDataTable::new(vector_data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<VectorDataTable> for GraphicElement {
|
|
||||||
fn from(vector_data: VectorDataTable) -> Self {
|
|
||||||
GraphicElement::VectorData(vector_data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<GraphicGroupTable> for GraphicElement {
|
|
||||||
fn from(graphic_group: GraphicGroupTable) -> Self {
|
|
||||||
GraphicElement::GraphicGroup(graphic_group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ToGraphicElement {
|
|
||||||
fn to_graphic_element(&self) -> GraphicElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the value at the specified index in the collection.
|
|
||||||
/// If that index has no value, the type's default value is returned.
|
|
||||||
#[node_macro::node(category("General"))]
|
|
||||||
fn index<T: AtIndex + Clone + Default>(
|
|
||||||
_: impl Ctx,
|
|
||||||
/// The collection of data, such as a list or table.
|
|
||||||
#[implementations(
|
|
||||||
Vec<Color>,
|
|
||||||
Vec<Option<Color>>,
|
|
||||||
Vec<f64>, Vec<u64>,
|
|
||||||
Vec<DVec2>,
|
|
||||||
VectorDataTable,
|
|
||||||
RasterDataTable<CPU>,
|
|
||||||
GraphicGroupTable,
|
|
||||||
)]
|
|
||||||
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 Instances<T> {
|
|
||||||
type Output = Instances<T>;
|
|
||||||
|
|
||||||
fn at_index(&self, index: usize) -> Option<Self::Output> {
|
|
||||||
let mut result_table = Self::default();
|
|
||||||
if let Some(row) = self.instance_ref_iter().nth(index) {
|
|
||||||
result_table.push(row.to_instance_cloned());
|
|
||||||
Some(result_table)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
use crate::Graphic;
|
||||||
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
||||||
use crate::transform::ApplyTransform;
|
use crate::transform::ApplyTransform;
|
||||||
use crate::uuid::NodeId;
|
use crate::uuid::NodeId;
|
||||||
use crate::Graphic;
|
|
||||||
use crate::{AlphaBlending, math::quad::Quad};
|
use crate::{AlphaBlending, math::quad::Quad};
|
||||||
use dyn_any::StaticType;
|
use dyn_any::StaticType;
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::adjustments::{CellularDistanceFunction, CellularReturnType, DomainWar
|
|||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use fastnoise_lite;
|
use fastnoise_lite;
|
||||||
use glam::{DAffine2, DVec2, Vec2};
|
use glam::{DAffine2, DVec2, Vec2};
|
||||||
|
use graphene_core::Graphic;
|
||||||
use graphene_core::blending::AlphaBlending;
|
use graphene_core::blending::AlphaBlending;
|
||||||
use graphene_core::color::Color;
|
use graphene_core::color::Color;
|
||||||
use graphene_core::color::{AlphaMut, Channel, LinearChannel, Luminance, RGBMut};
|
use graphene_core::color::{AlphaMut, Channel, LinearChannel, Luminance, RGBMut};
|
||||||
@@ -13,7 +14,6 @@ use graphene_core::raster_types::{CPU, Raster};
|
|||||||
use graphene_core::table::{Table, TableRow};
|
use graphene_core::table::{Table, TableRow};
|
||||||
use graphene_core::transform::Transform;
|
use graphene_core::transform::Transform;
|
||||||
use graphene_core::vector::Vector;
|
use graphene_core::vector::Vector;
|
||||||
use graphene_core::Graphic;
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand_chacha::ChaCha8Rng;
|
use rand_chacha::ChaCha8Rng;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|||||||
@@ -588,9 +588,8 @@ impl Render for Table<Graphic> {
|
|||||||
masked = true;
|
masked = true;
|
||||||
let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||||
|
|
||||||
scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect);
|
scene.push_luminance_mask_layer(1., kurbo::Affine::IDENTITY, &rect);
|
||||||
mask.render_to_vello(scene, transform, context, &render_params.for_clipper());
|
mask.render_to_vello(scene, transform, context, &render_params.for_clipper());
|
||||||
scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,7 +626,6 @@ impl Render for Table<Graphic> {
|
|||||||
|
|
||||||
if masked {
|
if masked {
|
||||||
scene.pop_layer();
|
scene.pop_layer();
|
||||||
scene.pop_layer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer {
|
if layer {
|
||||||
@@ -909,9 +907,8 @@ impl Render for Table<Vector> {
|
|||||||
masked = true;
|
masked = true;
|
||||||
let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||||
|
|
||||||
scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect);
|
scene.push_luminance_mask_layer(1., kurbo::Affine::IDENTITY, &rect);
|
||||||
mask.render_to_vello(scene, element_transform, _context, &render_params.for_clipper());
|
mask.render_to_vello(scene, element_transform, _context, &render_params.for_clipper());
|
||||||
scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1106,7 +1103,6 @@ impl Render for Table<Vector> {
|
|||||||
|
|
||||||
if masked {
|
if masked {
|
||||||
scene.pop_layer();
|
scene.pop_layer();
|
||||||
scene.pop_layer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we pushed a layer for opacity or a blend mode, we need to pop it
|
// If we pushed a layer for opacity or a blend mode, we need to pop it
|
||||||
@@ -1333,9 +1329,8 @@ impl Render for Table<Raster<CPU>> {
|
|||||||
masked = true;
|
masked = true;
|
||||||
let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||||
|
|
||||||
scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect);
|
scene.push_luminance_mask_layer(1., kurbo::Affine::IDENTITY, &rect);
|
||||||
mask.render_to_vello(scene, transform, _context, &render_params.for_clipper());
|
mask.render_to_vello(scene, transform, _context, &render_params.for_clipper());
|
||||||
scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1343,7 +1338,6 @@ impl Render for Table<Raster<CPU>> {
|
|||||||
|
|
||||||
if masked {
|
if masked {
|
||||||
scene.pop_layer();
|
scene.pop_layer();
|
||||||
scene.pop_layer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer {
|
if layer {
|
||||||
|
|||||||
Reference in New Issue
Block a user