commit 2bb1acbecef480efe3d27746cae7f26f461fa08b Author: Jens Becker Date: Wed May 13 18:52:00 2026 +0200 init diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..09431b2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +indent_style = tab +indent_size = 4 +tab_width = 4 +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb48c87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Godot 4+ specific ignores +.godot/ +/android/ + +.idea/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a2806f1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 hmdfrds + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Node War.csproj b/Node War.csproj new file mode 100644 index 0000000..6f63ed1 --- /dev/null +++ b/Node War.csproj @@ -0,0 +1,8 @@ + + + net8.0 + net9.0 + true + NodeWar + + \ No newline at end of file diff --git a/Node War.sln b/Node War.sln new file mode 100644 index 0000000..89c27b6 --- /dev/null +++ b/Node War.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Node War", "Node War.csproj", "{4C582811-BADF-4C82-8A05-94A9B4C5926F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + ExportDebug|Any CPU = ExportDebug|Any CPU + ExportRelease|Any CPU = ExportRelease|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4C582811-BADF-4C82-8A05-94A9B4C5926F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C582811-BADF-4C82-8A05-94A9B4C5926F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C582811-BADF-4C82-8A05-94A9B4C5926F}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {4C582811-BADF-4C82-8A05-94A9B4C5926F}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {4C582811-BADF-4C82-8A05-94A9B4C5926F}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {4C582811-BADF-4C82-8A05-94A9B4C5926F}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md new file mode 100644 index 0000000..a41443f --- /dev/null +++ b/README.md @@ -0,0 +1,175 @@ +

+ GodotVim Logo +

+ +

GodotVim

+ +

+ Vim emulation for Godot's built-in script editor. +

+ +

+ + Godot Asset Library + + + Release + + License +

+ +

+ GodotVim Demo +

+ +--- + +## Installation + +### Godot Asset Library (Recommended) +1. Open your Godot project → **AssetLib** tab +2. Search **"[GodotVim](https://godotengine.org/asset-library/asset/4666)"** → **Download** +3. In the install dialog, click **Install** +4. **Project → Project Settings** → **Plugins** → Enable **GodotVim** +5. **Restart the Editor** (required for full initialization) + +### Manual (from Releases page) +1. Download `godot-vim-vX.Y.Z.zip` from the [Releases page](https://github.com/hmdfrds/godot-vim/releases/latest) +2. Extract the archive — you'll get a `godot-vim-vX.Y.Z/` folder containing `addons/`, `LICENSE`, and `README.md` +3. Copy the **`addons/godot_vim/`** folder (from inside the extracted folder) into your Godot project's root, so the final path is `/addons/godot_vim/` +4. **Project → Project Settings** → **Plugins** → Enable **GodotVim** +5. **Restart the Editor** (required for full initialization) + +### Upgrading from v0.x + +This is a complete rewrite — settings, config format, and internals are all new. + +1. **Remove the old `addons/godot_vim/` folder** from your Godot project before installing +2. **Clear old EditorSettings** (optional): old GodotVim keys in `editor_settings-4.tres` are harmless — the new version ignores them — but you can delete lines starting with `plugins/GodotVim` in that file for a clean slate. The file is located at: + - **Windows:** `%APPDATA%\Godot\editor_settings-4.tres` + - **Linux:** `~/.config/godot/editor_settings-4.tres` + - **macOS:** `~/Library/Application Support/Godot/editor_settings-4.tres` +3. **Recreate key mappings**: v0.x stored mappings in EditorSettings; v1.0 uses a `.godot-vimrc` config file instead (see [Configuration](#configuration)) + +## Quick Start + +Open any script. + +| Keys | What happens | +|------|-------------| +| `i` | Enter Insert mode (type normally) | +| `Escape` | Return to Normal mode | +| `dd` | Delete the current line | +| `ci"` | Change text inside quotes | +| `/pattern` | Search forward | +| `:w` | Save the file | +| `:run` | Run the project (F5) | +| `Ctrl+h/j/k/l` | Navigate between Godot panels | + +## Features + +### Full Composable Vim Grammar + +`d2w`, `ci"`, `gUiw`, `>ap` — operators compose with motions and text objects exactly like real Vim. Counts multiply, registers route output. Dot repeat (`.`) replays any edit faithfully, including complex multi-key sequences. + +``` +[count] [register] operator [count] motion/textobject +``` + +Motions, operators, text objects — including advanced text objects like `ib` (any bracket), `iq` (any quote), `ii` (indent), `im` (symbol), and `ie` (entire buffer). Visual block mode supports `I`/`A` for multi-line insert/append. Undo tree with time-based navigation. [Full list →](docs/REFERENCE.md#motions) + +### Built for Godot + +Not just Vim in an editor — Vim that speaks Godot: + +- **`:run`** / **`:runcurrent`** — launch scenes without leaving the keyboard +- **`:GodotBreakpoint`** — toggle breakpoints, step through with `:next` / `:stepin` +- **`Ctrl+h/j/k/l`** — spatial panel navigation (script editor, scene tree, inspector, filesystem) +- **`j/k/h/l` in docks** — browse the scene tree, filesystem, and output with Vim keys; `/` to search +- **File explorer** — `a` create file/dir, `d` delete, `r` rename, `y` yank path, `R` refresh (nvim-tree style) +- **`gd`** — go-to-definition; **`K`** — hover docs +- **Code completion** — `Ctrl-N`/`Ctrl-P`/`Ctrl-Space` trigger and navigate completions +- **Cross-buffer jump list** — `Ctrl-O`/`Ctrl-I` switch tabs when the jump is in another buffer +- **`:zen`** — distraction-free mode + +[All Godot commands →](docs/REFERENCE.md#custom-commands) + +

+ Panel Navigation +
Navigate between docks with Ctrl+h/j/k/l — browse files, scenes, and inspector without the mouse +

+ +

+ Go-to-definition and Hover Docs +
K for hover docs, gd for go-to-definition +

+ +### Search and Replace + +Incremental search highlighting as you type. `:s/old/new/g` highlights every match region in yellow as you type the pattern — see exactly what will be affected before you press Enter. + +

+ Incremental Search and Replace +
Live match highlighting as you type the substitution pattern +

+ +### Custom Cursor + +A GLSL difference-blend shader renders the cursor above Godot's native caret. Block, beam, and underline shapes with smooth animation, per-mode colors, and adjustable blink speed. [Cursor settings →](docs/REFERENCE.md#cursor) + +### Configuration + +Create a `.godot-vimrc` at your project root or user directory: + +```vim +let mapleader = " " +set timeoutlen=500 + +nnoremap w :save +inoremap jk +vnoremap < >gv +``` + + +Hot-reloads on save. 20 built-in presets togglable via the `:mappings` dialog. [Config syntax →](docs/REFERENCE.md#godot-vimrc-syntax) · [All presets →](docs/REFERENCE.md#preset-mappings) + +

+ Mappings Dialog +
Toggle built-in presets and manage custom mappings with :mappings +

+ +### Macros, Registers, and Marks + +Record with `qa`, replay with `@a`. Named registers `"a`-`"z`, system clipboard via `"+`. Local and global marks, jump list with `Ctrl-O`/`Ctrl-I`. [Full details →](docs/REFERENCE.md#registers-and-macros) + +## Troubleshooting + +| Problem | Solution | +|---------|----------| +| Plugin not appearing | Ensure `addons/godot_vim/` contains `plugin.cfg`, `.gdextension`, and the compiled library. Enable in Project Settings > Plugins. | +| `addons/` folder missing after Asset Library install | "Ignore asset root" was unchecked. Re-install from AssetLib with the box **checked**, or manually copy `addons/godot_vim/` from the release zip. | +| Key not working | Check `passthrough_keys` setting — the key may be bypassing Vim. Check `:mappings` for conflicts. | +| `.godot-vimrc` not loading | Verify the file is at `res://.godot-vimrc` or `user://.godot-vimrc`. Run `:source` to force reload. | +| Clipboard not working | Enable `editor/clipboard_enabled` in EditorSettings. Both `y`/`p` and `"+y`/`"+p` sync with the system clipboard when enabled. | +| Cursor not rendering | The custom cursor uses a GLSL shader. Set `cursor/enabled = false` to fall back to native caret. | +| macOS: held keys don't repeat | macOS's "Press and Hold" accent picker can interfere with key repeat. Run `defaults write com.godotengine.godot ApplePressAndHoldEnabled -bool false` in Terminal and restart Godot. GodotVim includes a built-in fallback, but disabling Press and Hold gives the most reliable experience. | + +**For bug reports:** Set **Log Level** to `Debug` in Editor Settings > GodotVim, reproduce the issue, then copy the Output panel into GitHub issue. The debug log shows every keystroke and what command was executed. + +## Architecture + +``` ++----------------+ +----------+ +----------+ +| Godot CodeEdit | <-> | Bridge | <-> | vim-core | +| | | (gdext) | | (Rust) | ++----------------+ +----------+ +----------+ +``` + +**vim-core** is a standalone Vim engine — pure Rust, zero Godot dependencies. It processes keystrokes and returns `Effect` values that the host applies. The same engine could power any editor. + +[All settings](docs/REFERENCE.md#settings) · [All commands](docs/REFERENCE.md#custom-commands) · [Full reference](docs/REFERENCE.md) + +## License + +[MIT](LICENSE) diff --git a/addons/curved_lines_2d/AdaptableVectorShape3D.svg b/addons/curved_lines_2d/AdaptableVectorShape3D.svg new file mode 100644 index 0000000..f978afe --- /dev/null +++ b/addons/curved_lines_2d/AdaptableVectorShape3D.svg @@ -0,0 +1,30 @@ + + diff --git a/addons/curved_lines_2d/AdaptableVectorShape3D.svg.import b/addons/curved_lines_2d/AdaptableVectorShape3D.svg.import new file mode 100644 index 0000000..afede77 --- /dev/null +++ b/addons/curved_lines_2d/AdaptableVectorShape3D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://go4564jqj3hx" +path="res://.godot/imported/AdaptableVectorShape3D.svg-fb61f1579497b3af713b816581b03c84.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/AdaptableVectorShape3D.svg" +dest_files=["res://.godot/imported/AdaptableVectorShape3D.svg-fb61f1579497b3af713b816581b03c84.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/DefaultMode.svg b/addons/curved_lines_2d/DefaultMode.svg new file mode 100644 index 0000000..02f4fb1 --- /dev/null +++ b/addons/curved_lines_2d/DefaultMode.svg @@ -0,0 +1,105 @@ + + diff --git a/addons/curved_lines_2d/DefaultMode.svg.import b/addons/curved_lines_2d/DefaultMode.svg.import new file mode 100644 index 0000000..cb82fe7 --- /dev/null +++ b/addons/curved_lines_2d/DefaultMode.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://daemvs3ws7fpk" +path="res://.godot/imported/DefaultMode.svg-322d0054747e94d97892a6dc6a51ecd2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/DefaultMode.svg" +dest_files=["res://.godot/imported/DefaultMode.svg-322d0054747e94d97892a6dc6a51ecd2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/DrawablePath2D.svg b/addons/curved_lines_2d/DrawablePath2D.svg new file mode 100644 index 0000000..aa12497 --- /dev/null +++ b/addons/curved_lines_2d/DrawablePath2D.svg @@ -0,0 +1,30 @@ + + diff --git a/addons/curved_lines_2d/DrawablePath2D.svg.import b/addons/curved_lines_2d/DrawablePath2D.svg.import new file mode 100644 index 0000000..e433d37 --- /dev/null +++ b/addons/curved_lines_2d/DrawablePath2D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c4iwjwirkh4qi" +path="res://.godot/imported/DrawablePath2D.svg-099d0bb923e6ea3c9ba933305574eccb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/DrawablePath2D.svg" +dest_files=["res://.godot/imported/DrawablePath2D.svg-099d0bb923e6ea3c9ba933305574eccb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/FlipHorizontal.svg b/addons/curved_lines_2d/FlipHorizontal.svg new file mode 100644 index 0000000..c7f8bbd --- /dev/null +++ b/addons/curved_lines_2d/FlipHorizontal.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/FlipHorizontal.svg.import b/addons/curved_lines_2d/FlipHorizontal.svg.import new file mode 100644 index 0000000..e026f42 --- /dev/null +++ b/addons/curved_lines_2d/FlipHorizontal.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dvrgy7r2fvcxk" +path="res://.godot/imported/FlipHorizontal.svg-05762722fb050f0a8f9ca51a98b28cff.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/FlipHorizontal.svg" +dest_files=["res://.godot/imported/FlipHorizontal.svg-05762722fb050f0a8f9ca51a98b28cff.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/FlipVertical.svg b/addons/curved_lines_2d/FlipVertical.svg new file mode 100644 index 0000000..5861c1e --- /dev/null +++ b/addons/curved_lines_2d/FlipVertical.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/FlipVertical.svg.import b/addons/curved_lines_2d/FlipVertical.svg.import new file mode 100644 index 0000000..5011c6f --- /dev/null +++ b/addons/curved_lines_2d/FlipVertical.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ly2rtvkn6ush" +path="res://.godot/imported/FlipVertical.svg-65a107e2bc86ccde12ecd018a466acd7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/FlipVertical.svg" +dest_files=["res://.godot/imported/FlipVertical.svg-65a107e2bc86ccde12ecd018a466acd7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/Gradients.svg b/addons/curved_lines_2d/Gradients.svg new file mode 100644 index 0000000..af62f08 --- /dev/null +++ b/addons/curved_lines_2d/Gradients.svg @@ -0,0 +1,157 @@ + + diff --git a/addons/curved_lines_2d/Gradients.svg.import b/addons/curved_lines_2d/Gradients.svg.import new file mode 100644 index 0000000..4bb12b8 --- /dev/null +++ b/addons/curved_lines_2d/Gradients.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://caqsvv6rdxkm4" +path="res://.godot/imported/Gradients.svg-442389ec367d37fa1fc4089ae6f2e926.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/Gradients.svg" +dest_files=["res://.godot/imported/Gradients.svg-442389ec367d37fa1fc4089ae6f2e926.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/Key.svg b/addons/curved_lines_2d/Key.svg new file mode 100644 index 0000000..72d4dd3 --- /dev/null +++ b/addons/curved_lines_2d/Key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/curved_lines_2d/Key.svg.import b/addons/curved_lines_2d/Key.svg.import new file mode 100644 index 0000000..119464d --- /dev/null +++ b/addons/curved_lines_2d/Key.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://31qakec1dm6y" +path="res://.godot/imported/Key.svg-a834afef46c7b244ee3f6f041d1a070a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/Key.svg" +dest_files=["res://.godot/imported/Key.svg-a834afef46c7b244ee3f6f041d1a070a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/LICENSE b/addons/curved_lines_2d/LICENSE new file mode 100644 index 0000000..7133ea3 --- /dev/null +++ b/addons/curved_lines_2d/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 René van der Ark, Mark Hedberg and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/addons/curved_lines_2d/LineCaps.svg b/addons/curved_lines_2d/LineCaps.svg new file mode 100644 index 0000000..2ff0357 --- /dev/null +++ b/addons/curved_lines_2d/LineCaps.svg @@ -0,0 +1,265 @@ + + diff --git a/addons/curved_lines_2d/LineCaps.svg.import b/addons/curved_lines_2d/LineCaps.svg.import new file mode 100644 index 0000000..9cf3a3e --- /dev/null +++ b/addons/curved_lines_2d/LineCaps.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdkf2g8b5e55r" +path="res://.godot/imported/LineCaps.svg-d0c5b895aee70887354b4f313bec8f0c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/LineCaps.svg" +dest_files=["res://.godot/imported/LineCaps.svg-d0c5b895aee70887354b4f313bec8f0c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/LockViewport.svg b/addons/curved_lines_2d/LockViewport.svg new file mode 100644 index 0000000..b60f9c5 --- /dev/null +++ b/addons/curved_lines_2d/LockViewport.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/curved_lines_2d/LockViewport.svg.import b/addons/curved_lines_2d/LockViewport.svg.import new file mode 100644 index 0000000..0476f0c --- /dev/null +++ b/addons/curved_lines_2d/LockViewport.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8ludy6aqsejg" +path="res://.godot/imported/LockViewport.svg-3eb11eac4fb123bef92b15fdbe2fa6de.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/LockViewport.svg" +dest_files=["res://.godot/imported/LockViewport.svg-3eb11eac4fb123bef92b15fdbe2fa6de.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/LumAlpha8.tex b/addons/curved_lines_2d/LumAlpha8.tex new file mode 100644 index 0000000..cb9ec4a Binary files /dev/null and b/addons/curved_lines_2d/LumAlpha8.tex differ diff --git a/addons/curved_lines_2d/MergeChain.svg b/addons/curved_lines_2d/MergeChain.svg new file mode 100644 index 0000000..9be496d --- /dev/null +++ b/addons/curved_lines_2d/MergeChain.svg @@ -0,0 +1,107 @@ + + diff --git a/addons/curved_lines_2d/MergeChain.svg.import b/addons/curved_lines_2d/MergeChain.svg.import new file mode 100644 index 0000000..c63827c --- /dev/null +++ b/addons/curved_lines_2d/MergeChain.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6mmxldln6pdn" +path="res://.godot/imported/MergeChain.svg-b55975687f678fac86711208c660d64a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/MergeChain.svg" +dest_files=["res://.godot/imported/MergeChain.svg-b55975687f678fac86711208c660d64a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/PaintOrder.svg b/addons/curved_lines_2d/PaintOrder.svg new file mode 100644 index 0000000..27750a1 --- /dev/null +++ b/addons/curved_lines_2d/PaintOrder.svg @@ -0,0 +1,139 @@ + + diff --git a/addons/curved_lines_2d/PaintOrder.svg.import b/addons/curved_lines_2d/PaintOrder.svg.import new file mode 100644 index 0000000..0bd23e1 --- /dev/null +++ b/addons/curved_lines_2d/PaintOrder.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://7hhlkt6n4b32" +path="res://.godot/imported/PaintOrder.svg-b53e3dfee775f6d968e90108f6946848.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/PaintOrder.svg" +dest_files=["res://.godot/imported/PaintOrder.svg-b53e3dfee775f6d968e90108f6946848.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/README.md b/addons/curved_lines_2d/README.md new file mode 100644 index 0000000..a9d7432 --- /dev/null +++ b/addons/curved_lines_2d/README.md @@ -0,0 +1,919 @@ +# Scalable Vector Shapes 2D plugin for Godot 4 + +Ask questions on [discord](https://discord.gg/mNTdwgwBy) + +Scalable Vector Shapes 2D lets you do 3 things: +1. Draw seamless vector shapes using a Path Editor inspired by the awesome [Inkscape](https://inkscape.org/) with a new node type: [`ScalableVectorShape2D`](./scalable_vector_shape_2d.gd)[^1] +2. Animate the shape of the curve using keyframes on a [property-track](https://docs.godotengine.org/en/stable/tutorials/animation/introduction.html#doc-introduction-animation) in an [`AnimationPlayer`](https://docs.godotengine.org/en/stable/classes/class_animationplayer.html#class-animationplayer) +3. Import [.svg](https://www.w3.org/TR/SVG/) files as seamless vector shapes in stead of as raster images[^2] + +[^2]: __Important sidenote__: _This plugin only supports a small - yet relevant - subset of the huge [SVG Specification](https://www.w3.org/TR/SVG/struct.html)_ + +## Watch the A-Z explainer on Youtube + +In this 10 minute video I explain how to use all the features of Scalable Vector Shapes 2D in short succession: + +[![link to the explainer](./video_thumbnails/a_z_deep_dive.png)](https://youtu.be/z8Y1e-TehoE) + +[^1]: Looking for EZ Curved Lines 2D? The renamed plugin deprecates the old [`DrawablePath2D`](./drawable_path_2d.gd) custom node in favor of `ScalableVectorShape2D`. A Conversion button is provided: [converter button](./screenshots/00-converter.png). The reason is that [`ScalableVectorShape2D`](./scalable_vector_shape_2d.gd) inherits directly from `Node2D` giving much more control to the plugin over how you can draw. + + +# Table of Contents + +- [Scalable Vector Shapes 2D plugin for Godot 4](#scalable-vector-shapes-2d-plugin-for-godot-4) + - [Watch the A-Z explainer on Youtube](#watch-the-a-z-explainer-on-youtube) +- [Table of Contents](#table-of-contents) +- [Drawing Shapes in the Godot 2D Viewport](#drawing-shapes-in-the-godot-2d-viewport) + - [Basic Drawing Explainer on youtube](#basic-drawing-explainer-on-youtube) + - [Quick Start](#quick-start) +- [The Create Shapes Dock](#the-create-shapes-dock) + - [Creating Paths based on Bézier curves](#creating-paths-based-on-bézier-curves) + - [Creating 'primitive' shapes: Rectangle and Ellipse](#creating-primitive-shapes-rectangle-and-ellipse) + - [Draw Settings](#draw-settings) + - [Futher reading](#futher-reading) +- [The Import SVG File Dock](#the-import-svg-file-dock) + - [Watch an explainer on Youtube](#watch-an-explainer-on-youtube) + - [Using the Import SVG File Dock](#using-the-import-svg-file-dock) + - [`Line2D` Stroke versus `Polygon2D` Stroke](#line2d-stroke-versus-polygon2d-stroke) + - [The import log](#the-import-log) +- [The Project Settings Dock](#the-project-settings-dock) + - [Editor Settings (how the 2D Viewport should behave):](#editor-settings-how-the-2d-viewport-should-behave) + - [Curve Settings](#curve-settings) + - [Extra's: Line2D antialiasing for Compatibility Mode](#extras-line2d-antialiasing-for-compatibility-mode) +- [The Advanced Tab](#the-advanced-tab) + - [Basic export options](#basic-export-options) + - [Bake Animations](#bake-animations) +- [Moving, Rotating and Resizing the Points of a Shape](#moving-rotating-and-resizing-the-points-of-a-shape) + - [Moving (Translating) all the points](#moving-translating-all-the-points) + - [Translating Ellipses and Rectangles](#translating-ellipses-and-rectangles) + - [Translating Paths](#translating-paths) + - [Rotating all the Points](#rotating-all-the-points) + - [Rotating Ellipses and Rectangles](#rotating-ellipses-and-rectangles) + - [Rotating Paths](#rotating-paths) + - [Resizing all the Points](#resizing-all-the-points) + - [Resizing Ellipses and Rectangles](#resizing-ellipses-and-rectangles) + - [Resizing Paths](#resizing-paths) + - [Flipping your shapes](#flipping-your-shapes) + - [Flipping primitive shapes](#flipping-primitive-shapes) + - [Flipping paths](#flipping-paths) +- [Manipulating shapes](#manipulating-shapes) + - [Adding a point to a shape](#adding-a-point-to-a-shape) + - [Subdividing a shape](#subdividing-a-shape) + - [Bending a curve](#bending-a-curve) + - [Creating, mirroring and dragging control point handles](#creating-mirroring-and-dragging-control-point-handles) + - [Closing the loop and breaking the loop](#closing-the-loop-and-breaking-the-loop) + - [Deleting points and control points](#deleting-points-and-control-points) + - [Setting the global position of a point / curve handle manually](#setting-the-global-position-of-a-point--curve-handle-manually) + - [Create a cutout/clip/merge shape (a hole, a clipped frame, ...)](#create-a-cutoutclipmerge-shape-a-hole-a-clipped-frame-) + - [Cutting out an empty shape](#cutting-out-an-empty-shape) + - [Converting a line segment into an arc-segment](#converting-a-line-segment-into-an-arc-segment) + - [Editing arc properties](#editing-arc-properties) + - [Setting the pivot of your shape](#setting-the-pivot-of-your-shape) + - [Sticking two or more shapes together by vertex merge](#sticking-two-or-more-shapes-together-by-vertex-merge) +- [Manipulating 2D Shapes in the 3D export](#manipulating-2d-shapes-in-the-3d-export) + - [Animating 3D curves](#animating-3d-curves) +- [Manipulating gradients](#manipulating-gradients) + - [Changing the start- and endpoint of the gradient](#changing-the-start--and-endpoint-of-the-gradient) + - [Changing the color stop positions](#changing-the-color-stop-positions) + - [Add new color stops](#add-new-color-stops) +- [Ways to prevent 'over-selecting' `ScalableVectorShape2D` nodes](#ways-to-prevent-over-selecting-scalablevectorshape2d-nodes) +- [Using the Inspector Form for `ScalableVectorShape2D`](#using-the-inspector-form-for-scalablevectorshape2d) + - [Inspector Form](#inspector-form) + - [Convert to Path button](#convert-to-path-button) + - [The Fill inspector form](#the-fill-inspector-form) + - [The Stroke inspector form](#the-stroke-inspector-form) + - [Creating new Strokes](#creating-new-strokes) + - [The Collision inspector form](#the-collision-inspector-form) + - [The Navigation inspector form](#the-navigation-inspector-form) + - [The Curve settings inspector form](#the-curve-settings-inspector-form) + - [The Glue Map property](#the-glue-map-property) + - [The Masking Inspector form](#the-masking-inspector-form) + - [The Shape type inspector form](#the-shape-type-inspector-form) + - [The Editor settings inspector form](#the-editor-settings-inspector-form) + - [The Export Options inspector form](#the-export-options-inspector-form) + - [Export as PNG button](#export-as-png-button) + - [Export as 'baked' scene button](#export-as-baked-scene-button) + - [Caveats when 'Baking'](#caveats-when-baking) +- [More about assigned `Line2D`, `Polygon2D` and `CollisionObject2D`](#more-about-assigned-line2d-polygon2d-and-collisionobject2d) + - [Watch the chapter about working with collisions, paint order and the node hierarchy on youtube](#watch-the-chapter-about-working-with-collisions-paint-order-and-the-node-hierarchy-on-youtube) +- [Animating / Changing shapes at runtime](#animating--changing-shapes-at-runtime) + - [Youtube explainer on animating](#youtube-explainer-on-animating) + - [A note up front (this being said)](#a-note-up-front-this-being-said) + - [Animating the shape and gradients at Runtime](#animating-the-shape-and-gradients-at-runtime) + - [Add keyframes in an animation player](#add-keyframes-in-an-animation-player) + - [Don't duplicate `ScalableVectorShape2D`, use the `path_changed` signal in stead](#dont-duplicate-scalablevectorshape2d-use-the-path_changed-signal-in-stead) + - [Performance impact](#performance-impact) +- [Autoscaling SVG Textures for GUI Controls](#autoscaling-svg-textures-for-gui-controls) + - [Adding Autoscaling SVG Textures via the Inspector](#adding-autoscaling-svg-textures-via-the-inspector) + - [Example of Autoscaling GUI](#example-of-autoscaling-gui) + - [Removing an Automatically Scaled Texture](#removing-an-automatically-scaled-texture) + - [Advanced use of `SVGTextureHelper`](#advanced-use-of-svgtexturehelper) +- [FAQ's](#faqs) + - [The curve of my `ScalableVectorShape2D` won't animate at runtime, what do I do?](#the-curve-of-my-scalablevectorshape2d-wont-animate-at-runtime-what-do-i-do) + - [I want to change shapes while debugging my game. Is this even possible?](#i-want-to-change-shapes-while-debugging-my-game-is-this-even-possible) + - [When I animate the curve of an imported scene, it animates all the other curves as well](#when-i-animate-the-curve-of-an-imported-scene-it-animates-all-the-other-curves-as-well) + - [When I duplicate a `ScalableVectorShape2D` and change its shape, the original `ScalableVectorShape2D` shape also changes](#when-i-duplicate-a-scalablevectorshape2d-and-change-its-shape-the-original-scalablevectorshape2d-shape-also-changes) + - [Can I draw shapes programmatically?](#can-i-draw-shapes-programmatically) + - [Should I draw shapes programmatically?](#should-i-draw-shapes-programmatically) + - [When should I draw shapes programmatically?](#when-should-i-draw-shapes-programmatically) + - [Can I change shapes in the 2D editor while running the game?](#can-i-change-shapes-in-the-2d-editor-while-running-the-game) +- [Attributions](#attributions) + - [Lots of thanks go out to those who helped me out getting started:](#lots-of-thanks-go-out-to-those-who-helped-me-out-getting-started) + - [And a big thank you goes to to @MewPurPur](#and-a-big-thank-you-goes-to-to-mewpurpur) + - [Many thanks to @HannesParth/Permotion](#many-thanks-to-hannesparthpermotion) + - [And of course everyone who helped test and review the code thus far](#and-of-course-everyone-who-helped-test-and-review-the-code-thus-far) +- [Reaching out / Contributing](#reaching-out--contributing) + +# Drawing Shapes in the Godot 2D Viewport + +## Basic Drawing Explainer on youtube + +[![Explainer basic drawing on youtube](./screenshots/basic-drawing-youtube-thumnail.png)](https://youtu.be/gaug5zv57IE) + +## Quick Start +After activating this plugin a new bottom panel item appears, called "Scalable Vector Shapes 2D". + +There are 2 recommended ways to start drawing: +1. [Creating a Circle/Ellipse, Rectangle or empty Path using the bottom panel item](#the-create-shapes-dock) +2. [Using the `.svg` importer](#using-the-import-svg-file-dock) + + +# The Create Shapes Dock + +The `Create Shapes` tab gives you some basic choices: + +![the bottom panel](./screenshots/06-scalable-vector-shapes-panel.png) + +## Creating Paths based on Bézier curves + +Pressing the `Create Empty Path` or one of the `Create Path` buttons will add a new shape to an open `2D Scene` in 'Path' mode, meaning all points in the 'Bézier' curve are editable. + +![create ellipse as path](./screenshots/create-ellipse-as-path.png) + + +## Creating 'primitive' shapes: Rectangle and Ellipse + +It's probably easier to start out with a basic primitive shape (like you would in Inkscape <3) using the `Create Rectangle` or `Create Ellipse` button. This will expose less features, but will make it a lot easier to manipulate shapes: + +![create rect as rect](./screenshots/create-rect-as-rect.png) + +Ellipses will only have one handle to change the `size` property with (representing the x and y diameter). This will set the `rx` and `ry` property indirectly. + +Rectangles will have a handle for `size` and 2 handles for rounded corners `rx` and `ry` property. + +## Draw Settings + +- Enable/Disable Fill (when creating new shapes via this bottom panel) +- Fill color (when creating new shapes in this bottom panel) +- Enable/Disable Stroke (when creating new shapes this this bottom panel) +- Stroke color (when creating new shapes in this bottom panel) +- Choose a `CollisionObject2D` type (when creating new shapes in this bottom panel, default is no collision object assignment) +- Paint order: a toggle which represent what comes in front of what (when creating new shapes in the bottom panel) +- Stroke Settings: +- Stroke Width (when creating new shapes via this bottom panel) +- Use `Line2D`: when flagged off, a `Polygon2D` will be used to draw strokes with in stead (see also: [`Line2D Stroke` versus `Polygon2D Stroke`](#line2d-stroke-versus-polygon2d-stroke) ) +- Begin- and End Cap modes +- Line Joint Mode + + +## Futher reading +Read more about [manipulating shapes](#manipulating-shapes) + +# The Import SVG File Dock + +![svg importer dock](./screenshots/svg_importer_dock.png) + +## Watch an explainer on Youtube + +[![watch explainer on youtube](./video_thumbnails/importing-svg-files-splash.png)](https://youtu.be/5PIVoQcm8QE) + + +## Using the Import SVG File Dock + +On the left side of this panel is a form with a couple of options: + +- Import as ScalableVectorShape2D: check this Off if you want to import the svg file with only built-in godot nodes, without being able to edit/animate the curves in the editor. +- Lock imported shapes in editor: this simply flags on the lock so that the `Polygon2D`, `Line2D`, etc are not selected on click, but the owning ScalableVectorShape2D is +- Flag on antialiased on Polygon2D and Line2D: flags on the `antialiased` property of either +- Use Line2D for Strokes: when flagged Off a `Polygon2D` is used for strokes in stead of a Line2D +- Pick a `CollisionObject2D` type to also generate collision polygons when importing the svg file + +## `Line2D` Stroke versus `Polygon2D` Stroke + +A tooltip highlights the costs and benefits when picking either of these to draw strokes with: +- A `Polygon2D` stroke can be more neatly clipped than a `Line2D` +- `CollisionPolygon2D`'s match `Polygon2D` Stroke better +- A `Polygon2D` stroke can be textured with gradients like fills are textured +- `Line2D` has sharper caps and line joints at high zoom +- `Line2D` can be textured directionally in stead of like a Fill texture +- `Line2D` can set different Begin and End Cap Modes where `Polygon2D` can only pick one + +## The import log + +On the right side is an import log, which will show warnings of known problems, usually unsupported stuff. + +The link it shows is to the issues list on the github repository hosting this plugin. Here you can report any encountered bugs while importing SVG files using this plugin. + +# The Project Settings Dock + +![Project settings dock](./screenshots/project-settings.png) + +## Editor Settings (how the 2D Viewport should behave): + +- Enable/Disable ScalableVectorShape2D Editing (when checked off, you can edit nodes the normal, built-in, godot-way. You _are_ going to need this) +- Show/Hide Edit hints +- Show Point Details (which are the exact _indices_ of each point on the `Curve2D` of this shape, what is it's global position) +- Snap to Pixel (snaps points and curve handles to whole pixels on the global transform) +- Snap distance (the snap step / resolution) + +## Curve Settings + +These settings are applied to the `Curve Settings` of new shapes when added via the bottom panel docks (either SVG importer or via Create Shapes). + +For more information on these settings, please refer to the section on [The Curve settings inspector form](#the-curve-settings-inspector-form) + +## Extra's: Line2D antialiasing for Compatibility Mode + +As of release `2.18.0` a new flag was added which causes any `Line2D` that you add as stroke to be antialiased via a repeating texture. + +This approach follows exactly the [Antialiased Line2D plugin](https://github.com/godot-extended-libraries/godot-antialiased-line2d) by @Calinou. + +To be more specific, I reused these bits: +- The tool script code for the `Line2D` creation is here: [addons/antialiased_line2d/antialiased_line2d.gd](https://github.com/godot-extended-libraries/godot-antialiased-line2d/blob/v1.2.0/addons/antialiased_line2d/antialiased_line2d.gd) +- And the [LumAlpha8.tex](./LumAlpha8.tex) texture resource it uses was generated by this script: [addons/antialiased_line2d/texture.gd](https://github.com/godot-extended-libraries/godot-antialiased-line2d/blob/v1.2.0/addons/antialiased_line2d/texture.gd) + +Of course, once you assign this to the `Line2D.texture`, you cannot use another texture on that `Line2D` anymore. + +# The Advanced Tab + +Since release `2.13.0` a tab named 'Advanced' is added to the bottom dock. + +![Advanced tab](./screenshots/advanced-tab.png) + +## Basic export options +- PNG file (see [Export as PNG Button](#export-as-png-button) ) +- A 'Baked' scene (see [Export as 'baked' scene button](#export-as-baked-scene-button)) +- 3D scene: creates a new 3D scene, in which all the Fills and Strokes in the scene are turned into instances of `CSGPolygon3D`[^6] + +[^6]: Coming soon: a 3D Node with an editable outline using a `ScalableVectorShape2D` node + +## Bake Animations +Since `2.14.0` you can export your animated scene as sprite frames in one PNG spritesheet or separate PNG files. + +# Moving, Rotating and Resizing the Points of a Shape + +Release `2.16.0` adds the posibility to do uniform transforms on the points of a shape, as opposed to the entire node. + +When a `ScalableVectorShape2D` is selected in `Select Mode (Q)`, the following command buttons are made available: + +- `Move all the Points without moving the Node (Z)` +- `Rotate all the Points without rotating the Node (X)` +- `Resize all the Points without scaling the Node (C)` +- `Edit the points normally (Q)` + +![uniform transform buttons](./screenshots/uniform_transforms.png) + + +## Moving (Translating) all the points + +When moving all the points of a shape, the `Node2D.position` property does not change. + +This operation responds to the snap-to-pixel mode of the `Project Settings` tab. + +### Translating Ellipses and Rectangles + +In the case of the 2 supported primitive shapes, the `offset` property is changed, to represent the translation. + +The `offset` property can be used to set keyframes in an `AnimationPlayer` and is so easier to use than the `Batch Update` button for an entire curve. + +### Translating Paths + +When the `Shape Type Settings > Shape Type` is `Path`, all the points are simply moved, relative to the node position (translating their individual local position). + +## Rotating all the Points + +When rotating all the points of a shape, the `Node2D.rotation` property does not change. + +Just like rotating `Node2D`, holding `Ctrl` allows you to rotate in steps of 5°. + +### Rotating Ellipses and Rectangles + +In the case of the 2 supported primitive shapes, the `spin` property is changed, to represent the rotation of all the points. + +The `spin` property can be used to set keyframes in an `AnimationPlayer` and is so easier to use than the `Batch Update` button for an entire cruve. + +### Rotating Paths + +When the `Shape Type Settings > Shape Type` is `Path`, all the points can be rotated in 2 ways: +1. Around the `Node2D`'s pivot +2. Around their natural center (by holding the `Shift` button - this is not perfect, but comes close enough) + +![Uniform Rotate a Path Hole](./screenshots/uniform_rotate_a_path_hole.png) + +## Resizing all the Points + +When resizing all the points of a shape, the `Node2D.scale` property does not change, this is especially useful when using strokes, because their width will remain the same this way. + +This operation responds to the snap-to-pixel mode of the `Project Settings` tab. + +### Resizing Ellipses and Rectangles + +In the case of the 2 supported primitive shapes, the `size` property is changed, to represent the 'distance' of all the points away from their origin. + +The `size` property can be used to set keyframes in an `AnimationPlayer` and is so easier to use than the `Batch Update` button for an entire cruve. + +### Resizing Paths + +When the `Shape Type Settings > Shape Type` is `Path`, all the points can be resized in 2 ways: +1. Away from / towards the `Node2D`'s pivot +2. Away from / towards their natural center (by holding Shift) + + + +## Flipping your shapes + +Release `2.17.0` adds vertical and horizontal flip buttons. This allows you to flip your shape without changing the `Node2D.scale` property of your `ScalableVectorShape2D`. + +### Flipping primitive shapes + +Flipping primitive shapes (shape type is ellipse, or rectangle) simply reverses the rotation of points around their pivot by negating the value of the `spin` property. + +### Flipping paths + +Flipping paths multiplies the position of each point by negative-x for horizontal flipping, or negative-y for vertical flipping. The in- and out- control points are also flipped, effectively flipping the bézier curves. + +Arcs are flipped by toggling negating the `sweep` flag of each listed arc. + +# Manipulating shapes + +The hints in the 2D viewport should have you covered, but this section lists all the operations available to you. You can also watch the chapter on sculpting paths on youtube: + +[![sculpting paths on youtube](./screenshots/sculpting-paths-on-youtube.png)](https://www.youtube.com/watch?v=z8Y1e-TehoE&t=710s) + + +## Adding a point to a shape + +Using `Ctrl`[^5] + `Left Click` you can add a point anywhere in the 2D viewport, while your shape is selected. + +[^5]: Use `Cmd` in stead of `Ctrl` on a mac + +By double clicking on a line segment you can add a point _inbetween_ 2 existing points: + +![add point to a line](./screenshots/18-add-point-to-line.png) + +By holding alt and left-clicking while hovering over a line segment you add a point at the halfway-mark of a curve: + +![add a point at the halfway mark of an edge](./screenshots/alt-click-subdivide.png) + + +## Subdividing a shape + +Double click on a shape without hovering over an edge to subdivide all edges on the shape: + +![subdivide shape](./screenshots/subdivide.gif) + + + +## Bending a curve + +Holding the mouse over line segment you can start dragging it to turn it into a curve. + +![bend line](./screenshots/05-bend.png) + +## Creating, mirroring and dragging control point handles + +When you have new node you can drag out curve manipulation control points while holding the `Shift` button. The 2 control points will be mirrored for a symmetrical / round effect. + +Dragging control point handles while holding `Shift` will keep them mirrored / round: + +![mirrored handle manipulation](./screenshots/07-mirrored-handles.png) + +Dragging them without holding shift will allow for unmirrored / shap corners: + +![shar corner](./screenshots/08-sharp.png) + +## Closing the loop and breaking the loop + +Double clicking on the start node, or end node of an unclosed shape will close the loop. + +Double clicking on the start-/endpoint again will break the loop back up: + +![closed loop](./screenshots/09-loop.png) + +You can recognise the start-/endpoint(s) by the infinity symbol: ∞ + +## Deleting points and control points + +You can delete points and control points by using right click. + +## Setting the global position of a point / curve handle manually + +Using `Alt+Click` you can now open a form to set the global position of a point manually: + +![global position popup dialog](./screenshots/global_position_popup.png) + +## Create a cutout/clip/merge shape (a hole, a clipped frame, ...) + +While holding `Ctrl+Shift`[^5] on a selected shape you can start adding cutouts to your selected shape: +- Use `mousewheel` to change shapes (rectangle, ellipse, or empty path) +- Use `right click` to change operation (cut out, clip, or merge) +- Use `left click` __on__ your selected shape to create _and_ select the new `ScalableVectorShape2D` which acta as a cutout, a frame clipping, or merged shape: + +![add a hole](./screenshots/add_a_hole.png) + +### Cutting out an empty shape + +When cutting out an empty shapem, the created cutout will have only _one_ point, so to see the effect you'd need to add more points to using regular `Ctrl+Click`[^5]: + +![a hole was added](./screenshots/hole_added.png) + +## Converting a line segment into an arc-segment + +Use `Right click` on a line segment to convert it into an arc[^3] (a an ellipse-shaped bend with an x- and y-radius). + +![add an arc](./screenshots/add-arc.png) + +Use `Right click` on an arc again to convert it back into a normal line segment. + +![remove an arc](./screenshots/remove-arc.png) + +## Editing arc properties + +Using `Left click` on an arc segment opens a popup form to edit the properties of the arc: +- radius (`rx` / `ry`) +- rotation (rotates the arc around its elliptical center; is only noticable when radius is non-uniform) +- large arc (when the arc's radius is greater than distance between its start- and endpoint it can be drawn the short and the long way 'round) +- sweep (determines the direction the arc points are drawn: clockwise / counter-clockwise; this effectively flips the arc) + +![open arc settings](./screenshots/arc-settings.png) + + +[^3]: Arcs are implemented the same way as specified by the [w3c for scalable vecor graphics](https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands). + +## Setting the pivot of your shape + +You can use the `Change pivot` mode to change the origin of your shape, just like you would a `Sprite2D`. In this case, the 'pivot' will actually be the `position` property of you `ScalableVectorShape2D` node. + +This rat will want to rotate it's head elsewhere: + +![set origin](./screenshots/16-set-origin.png) + +Like this: + +![set origin 2](./screenshots/16a-set_origin.png) + +## Sticking two or more shapes together by vertex merge + +Press 'M' while editing, or by pressing the chainlink button to 'Merge Vertices'. + +![merge mode button](./screenshots/merge_mode_button.png) + +This allows you to link one point of 2 or more shapes together, so they will now always have the same global position. + +![merge 2 points](./screenshots/merge_2_points.png) + +This action create a new instance of the `SVSVertexMerge2D` node. Delete this node to break the link between points. + +![merge 2 points](./screenshots/svs_vertex_merge_2d_node.png) + + +# Manipulating 2D Shapes in the 3D export + +Using the new `Export to 3D Scene` in the [Advanced Editing Tab](#the-advanced-tab) produces the new `AdaptableVectorShape3D` node, which holds instances of `CSGPolygon3D` with: + +![AdaptableVectorShape3D inspector](./screenshots/adaptable-vector-shape-3d.png) + +Pressing the button `Add 2D Shape Editor` will instantiate a new `ScalableVectorShape2D` that can be used to edit with. For now I will suffice with a screenshot. I'm hope to record a long explainer about this soon. + +This screenshot was made using the [DualEditor](https://github.com/Meta-Ben/DualEditor) plugin by @Meta-Ben, which is _very_ useful for this purpose: + +![editing 3d shapes](./screenshots/dualview-preview.png) + +## Animating 3D curves + +You can also use the `Batch insert` button for curve key frames to animate the 3D shape's curve. Of course the [performace impact](#performance-impact) for this is not negligable. + +# Manipulating gradients + +Once a gradient is assigned to the 'Fill' of your shape via the inspector, its properties can be changed using the same controls as will the other handles. + +## Changing the start- and endpoint of the gradient + +Drag the outer orbit of the start- and endpoint of a the gradient line using the left mouse button to move them: + +![drag gradient start- and end-position](./screenshots/drag_gradient_start.png) + + +## Changing the color stop positions + +Drag the color stops along the gradient line to change their position. + +Right click to remove a color stop. + +![changing color stops](./screenshots/drag_remove_color_stops.png) + +## Add new color stops + +Double clicking on the gradient line will add a new color stop (the assigned color will be sampled from the existing color at that point) + +![adding a color stop](./screenshots/add_color_stop.png) + + + + + +# Ways to prevent 'over-selecting' `ScalableVectorShape2D` nodes + +This plugin can sometimes get in the way of the default 2D viewport behavior. Sometimes it is hard _not_ to select a `ScalableVectorShape2D`. + +There are 4 ways to get around this: +1. Locking the `ScalableVectorShape2D` using the lock toggle ![lock toggle](./LockViewport.svg) button above the 2D viewport +2. Hiding the `ScalableVectorShape2D` via the scene tree +3. Saving the branch containing the `ScalableVectorShape2D` as a new scene via the scene tree and importing it will also prevent selection +4. Toggling off Enable/Disable ScalableVectorShape2D Editing altogether in the bottom panel + + +# Using the Inspector Form for `ScalableVectorShape2D` + +The following custom forms were added, with extensive tooltips to help explain the actual functions they provide: + +- [Fill](#the-fill-inspector-form) (actually the assigned `Polygon2D`) +- [Stroke](#the-stroke-inspector-form) (actually the assigned `Line2D` or `Polygon2D`) +- [Collision](#the-collision-inspector-form) (manages an assigned `CollisionObject2D`) +- [Navigation](#the-navigation-inspector-form) (manages an assigned `NavigationRegion2D`) +- [Curve Settings](#the-curve-settings-inspector-form) +- [Masking](#the-masking-inspector-form) +- [Shape Type Settings](#the-shape-type-inspector-form) +- [Editor Settings](#the-editor-settings-inspector-form) +- [Export Options](#the-export-options-inspector-form) + +![screenshot of the inspector](./screenshots/inspector-in-2.6.png) + + +## Inspector Form + +### Convert to Path button + +When a primitive shape (basic rectangle or ellipse) is selected, a `Convert to Path`-button is available at the top of the inspector. + +## The Fill inspector form + +When the selected shape has no fill, an `Add Fill` button is provided. Clicking that will create and assign a new `Polygon2D` to the selected `ScalableVectorShape2D`: + +![screenshot of fill form without fill](./screenshots/fill-form-no-fill.png) + +Once assigned, the following options are available: +- Fill color, changes the `color` property of the assigned `Polygon2D` +- Gradient, will assign or remove a `GradientTexture2D` to the `Polygon2D` +- Stop colors (if a gradient is set), one color button per color +- A `Edit Polygon2D` button, which will make the editor select the assigned `Polygon2D` + +Below that, a standard godot `Assign ...`-field is also available to set the `polygon`-property directly with and to enable unassignment. + +## The Stroke inspector form + +![screenshot of stroke formm](./screenshots/stroke_inspector.png) + +With this form the following `ScalableVectorShape2D` properties can be edited: +- `stroke_color` +- `stroke_width` +- `begin_cap_mode` (in case of a `Polygon2D`-based stroke, this will also set the end cap) +- `end_cap_mode` +- `line_joint_mode` + +When a `Line2D` is assigned to draw the stroke with, these properties will be kept synchronized with the `ScalableVectorShape2D` properties. + +In case of a `Polygon2D` based stroke, the `stroke_color` will be kept synchronized with the `Polygon2D` color. + +### Creating new Strokes +When the selected shape has no stroke, an extra set of buttons is provided: +- `Add Line2D Stroke` +- `Add Polygon2D Stroke` + +Clicking either will create and assign a new `Line2D` or `Polygon2D` to the selected `ScalableVectorShape2D`: + +Below that, a standard godot `Assign ...`-field is also available to set these properties: +- `line`: a `Line2D` assignment +- `poly_stroke`: a `Polygon2D` assignment + +## The Collision inspector form + +This works the same as the Fill- and Stroke forms, but in this case a descendant of a `CollisionObject2D` is assigned to the `collision_object`-property[^4]: + +[^4]: Note that the `collision_polygon` property of `ScalableVectorShape2D` remains supported for backward compatibility, even though the inspector form will now show a deprecation warning and suggest replacing it by assigning a `CollisionObject2D` to the `collision_object` property. + +![the collision inspector form](./screenshots/collision-inspector-form.png) + +Every time the shape is changed, one or more `Polygon2D` nodes will be added/updated as direct children of this `collision_object`. The descendants of `CollisionObject2D` are: + +- `StaticBody2D` +- `Area2D` +- `AnimatableBody2D` +- `RigidBody2D` +- `CharacterBody2D` +- `PhysicalBone2D` + +## The Navigation inspector form + +This form can hold a reference to an assigned `NavigationRegion2D`. When the shape changes, a new navigation polygon is calculated. + +## The Curve settings inspector form + +![A screenshot of the Curve settings inspector form as per release 2.9](./screenshots/curve_settings_inspector_form.png) + +The curve settings inspector form provides the following options +- A `Batch insert` keyframes button for all the `Curve2D`'s control points (the whole shape). This will be active when a valid track is being edited in a `AnimationPlayer` via the bottom panel +- The standard godot built-in editor for `Curve2D` resources, assigned to the `curve` property of the selected `ScalableVectorShape2D` +- The `update_curve_at_runtime` checkbox, which enables animating the entire shape +- The `max_stages` property which influences smoothness (and performance!) of curve drawing; a higher value means smoother lines +- The `tolerance_degrees` property, which also influences smoothness (and performance) of curve drawing: a lower value adds a smoother curve, especially for very subtle bends +- The `arc_list` property: a container for the metadata-objects describing elliptical arc segments of the curve (implemented via `ScalableArc2D` and `ScalableArcList` resource-classes). +- The `glue_map` property: with this dictionary you can control the position of any `Node2D` in the scene with the a point position in the `curve`. + +### The Glue Map property + +With the property `glue_map : Dictionary[int, Node2D]` you can control the position of any `Node2D` in the scene with the a point position in the `curve`. + +![The new glue map](./screenshots/glue_map.png) + + + +## The Masking Inspector form + +These properties are used for clipping this shape and cutting out of this shape. + +- The `clip_paths` property: an array of assigned `ScalableVectorShape2D`-nodes, which describe the shapes to cut out of this shape +- When the `use_interect_when_clipping` property is checked on and this `ScalableVectorShape2D` is used in another's clip_paths array, the `Geometry2D.intersect_polygons(...)` operation is used in stead of the `Geometry2D.clip_polygons(...) operation` +- When the `use_union_in_stead_of_clipping` property is check on and this `ScalableVectorShape2D` is used in another's clip_paths array, the `Geometry2D.merge_polygons(...)` operation is used in stead of the `Geometry2D.clip_polygons(...) operation`[^8] + +[^8]: see also: the [cloud example](./examples/cloud.tscn) + +## The Shape type inspector form + +This form allows manipulation of the properties of primitive shape types (rectangle, ellipsis): +- Shape type, here you can selected the type of the shape: Path, Rect and Ellipse. (Be warned: changing a shape from a path to a primitive shape is a destructive action and cannot be undone) +- Offset: this represents the position of the pivot relative to the shape's natural center. +- Size: the box size of the entire shape (stroke thickness excluded) +- Rx: the x-radius of the shape +- Ry: the y-radius of the shape + +It is best to change these properties via the handles in the 2D editor. They are, however, quite useful for animating key frames. + + +## The Editor settings inspector form + +This form exposes 2 settings: + +- Shape Hint Color: the color of the line with which this shape is drawn, when selected +- Lock Assigned Shapes: when this is checked, added strokes, fills and collision polygons will be locked in the editor, once created. + +## The Export Options inspector form + +### Export as PNG button + +With the `Export as PNG`-button you can save any `ScalableVectorShape2D` and its children as a new `.png`-file. Note that nodes which are assigned as Fill or Stroke that are higher up in the hierarchy will be excluded from the exported file. + +You _can_ however change the type of any `Node2D` to `ScalableVectorShape2D` temporarily in order to export group of shapes as a PNG file. + +### Export as 'baked' scene button + +With the `Export as baked scene` button you can generate a new scene (like `Save branch as scene`), with all the `ScalableVectorShape2D`-nodes converted to basic `Node2D`-nodes. + +Use this when you are done drawing entirely and do not want to update curves at runtime, or when you want to keep the shapes but drop the dependency of this plugin from your project. + +#### Caveats when 'Baking' +An exported AnimationPlayer will not support animated curves, track references will, however, remain. + + +# More about assigned `Line2D`, `Polygon2D` and `CollisionObject2D` + +Using the `Add ...` buttons in the inspector simply adds a new node as a child to `ScalableVectorShape2D` but it does __not need to be__ a child. The important bit is that the new node is _assigned_ to it via its properties: `polygon`, `line` and `collision_object`. + +## Watch the chapter about working with collisions, paint order and the node hierarchy on youtube + +This video gives more context on how `Line2D`, `Polygon2D` and `CollisionPolygon2D` are _assigned_ to the `ScalableVectorShape2D`: + +[![working with collisions, paint order and the node hierarchy on youtube](./screenshots/more-on-node-hierarchy.png)](https://www.youtube.com/watch?v=z8Y1e-TehoE&t=1453s) + + +# Animating / Changing shapes at runtime + +## Youtube explainer on animating + +Watch this explainer on youtube on animating: + +[![link to Youtube explainer about animating](./screenshots/animating-youtube-thumbnail.png)](https://youtu.be/IwS2Rf65i18?feature=shared) + +## A note up front (this being said) + +The shapes you create will work fine with basic key-frame operations. + +You can even detach the Line2D, Polygon2D and CollisionObject2D from `ScalableVectorShape2D` entirely, once you're done drawing and aligning, and change the `ScalableVectorShape2D` to a simple `Node2D` if necessary. + +## Animating the shape and gradients at Runtime + +Sometimes, however, you want your shape to change at runtime (or even your collision shape!) + +You can use the `Update Curve at Runtime` checkbox in the inspector to enable dynamic changing of your curved shapes at runtime. + +![update curve at runtime](./screenshots/update-curve-at-runtime-in-2.4.0.png) + +## Add keyframes in an animation player + +You can then add an `AnimationPlayer` node to your scene, create a new animation and (batch) insert key frames for the following: + +- The entire shape of your `ScalableVectorShape2D`, which are: + - `curve:point_*/position` + - `curve:point_*/in` + - `curve:point_*/out` + - `arc_list:arc_*/radius` + - `arc_list:arc_*/rotation_deg` + - `arc_list:arc_*/large_arc_flag` + - `arc_list:arc_*/sweep_flag` +- All the gradient properties of your fill (`Polygon2D` assigned to `ScalableVectorShape2D`), which are: + - `texture:gradient:colors` (the entire `PackedColorArray`) + - `texture:gradient:offsets` (the entire `PackedFloat32Array`) + - `texture:fill_from` + - `texture:fill_to` +- Fill color, i.e.: the `color` of the assigned `Polygon2D` + +__* Note: the keyframes of stroke properties are set directly on `ScalableVectorShape2D` as of release 2.12__ + +![the new key frame buttons in the inspector](./screenshots/animating-in-2.4.0.png) + +## Don't duplicate `ScalableVectorShape2D`, use the `path_changed` signal in stead + +When the `update_curve_at_runtime` property is checked, every time the curve changes in your game the `path_changed` signal is emitted. + +Duplicating a `ScalableVectorShape2D` will __not__ make a new `Curve2D`, but use a reference. This means line-segments will be calculated multiple times on one and the same curve! Very wasteful. + +If however you want to, for instance, animate 100 blades of grass, just use __one__ `ScalableVectorShape2D` and have the 100 `Line2D` node listen to the `path_changed` signal and overwrite their `points` property with the `PackedVector2Array` argument of your listener `func`: + +![path_changed signal](./screenshots/10-path_changed-signal.png) + +This very short section of the youtube video illustrates how to do this: https://youtu.be/IwS2Rf65i18?feature=shared&t=55 + + +## Performance impact + +Animating curve points at runtime does, however, impact performance of your game, because calculating segments is an expensive operation. + +Under `Tesselation settings` you can lower `Max Stages` or bump up `Tolerance Degrees` to reduce curve smoothness and increase performance (and vice-versa) + +# Autoscaling SVG Textures for GUI Controls + +Release `2.15` makes it easy to add crisp, autoscaling images for your GUI Control nodes using two new classes: + +- `SVGTextureHelper`: a `Node` that manages an SVG image resource when it's a direct child of a `TextureRect`, `Button`, or `TextureButton` +- `SVGTextureResource`: a `Resource` that holds a reference to the svg file and a base64 encoded string of the file's contents, as well as a baseline scale factor (so you can even keep the image crips and sharp at higher zoom levels) + +## Adding Autoscaling SVG Textures via the Inspector + +These 3 control nodes now have an extra button `Set Scalable SVG Texture` in the inspector to set their texture with: + +- `TextureRect` +- `Button` +- `TextureButton` + +![setting autoscaling svg textures](./screenshots/scaling_textures.png) + +Once an SVG file has been chosen as a texture, a `SVGTextureHelper` node is automatically added to manage the automatically scaled image via a `SVGTextureResource`. + +A button with the name of the texture property and an icon-preview will then be presented with which you can pick another SVG file source. + +### Example of Autoscaling GUI + +There is an example scene in the plugin directory: `addons/curved_lines_2d/examples/gui.tscn`. + +## Removing an Automatically Scaled Texture + +To remove this type of texture again, the `SVGTextureHelper` node needs to be deleted via the scene tree: + +![SVGTextureHelper in the scene tree](./screenshots/svg_texture_helper_in_scene_tree.png) + +## Advanced use of `SVGTextureHelper` + +Any `Control` node's `Texture2D` properties can be managed by a manually added `SVGTextureHelper`. For this you will need to set the `target_property`-field of the `SVGTextureHelper` manually. + +# FAQ's + +## The curve of my `ScalableVectorShape2D` won't animate at runtime, what do I do? +Check the box: + +![update curve at runtime](./screenshots/update-curve-at-runtime-in-2.4.0.png) + +## I want to change shapes while debugging my game. Is this even possible? + +Yes, when you check the box `Update Curve at Runtime` box. + +## When I animate the curve of an imported scene, it animates all the other curves as well + +This is a common issue: there is _one_ `Curve2D` instance being referenced by all scenes. You fix this by checking On "Local To Scene" for the `Curve2D`: + +![local to scene](./screenshots/local_to_scene.png) + + +## When I duplicate a `ScalableVectorShape2D` and change its shape, the original `ScalableVectorShape2D` shape also changes + +This is a common issue: there is _one_ `Curve2D` instance being referenced by both nodes. + +You can work around this by using 'Make unique' by right-clicking `Curve settings > Curve > Curve2D` in the Inspector of your duplicated shape: + +![make unique in inspector](./screenshots/make-unique.png) + +When using [arcs](#editing-arc-properties) in a shape the `Arc List` property must also be 'made unique' + +Overriding the default duplication behavior of godot can lead to more unforeseen problems. So [a good solution must be well thought through](https://github.com/Teaching-myself-Godot/ez-curved-lines-2d/issues/200#issuecomment-3318594193). + +Search reddit on the trials and tribulations of 'Make Unique': + +- https://www.reddit.com/r/godot/search/?q=make+unique + + + +## Can I draw shapes programmatically? + +Yes you can. There are a couple of small things to be aware of: +1. You need to set `my_shape.up_date_curve_at_runtime = true` +2. To draw anything, your shape needs a Stroke, Fill, or Collision Object: + 1. Setting a stroke: `my_shape.line = Line2D.new()` + 2. Setting a fill: `my_shape.polygon = Polygon2D.new()` + 3. Setting a collision object: `my_shape.collision_object = StaticBody2D.new()` +3. The Stroke, Fill, Collision Object need to be inside the scene tree, i.e.: `my_shape.add_child(my_shape.line)` + +I added a [small example](./examples/add_shapes_programmatically/click_ellipse.gd) based on [this question](https://github.com/Teaching-myself-Godot/ez-curved-lines-2d/issues/111) + +## Should I draw shapes programmatically? + +This depends on the complexity of what you want to achieve. + +In many cases just drawing something in the editor and saving it as a scene to import elsewhere (or `instantiate()` via preloading) is a better option, adhering to the _Keep it Simple_ principle. + +But that's just my personal opinion. + +## When should I draw shapes programmatically? + +There are very many situations left where you might want to do exactly this, but that is up to your own creativity. + +One powerful feature I can think of is 'mining': use `ScalableVectorShape2D`-nodes to make cuts in collision shapes and navigation areas. + +Playing [Rat's Return](./examples/rat/rats_return.tscn) will give a first impression how this might work: + +![Rat's return](./screenshots/rats-return.png) + + +`ScalableVectorShape2D` already ships quite some convenience methods like: +- `clipped_polygon_has_point(global_pos : Vector2) -> bool` and +- `add_clip_path(other_shape : ScalableVectorShape2D)` + +But I have not come around to documenting yet. + +## Can I change shapes in the 2D editor while running the game? + +When the `Update Curve At Runtime` checkbox is checked, the shape will also sync up with a scene running in debug mode. + +Once you're done drawing and do not need the shape to change anymore at runtime you can turn this checkbox off again. + +# Attributions + +## Lots of thanks go out to those who helped me out getting started: +- This plugin was first inspired by [Mark Hedberg's blog on rendering curves in Godot](https://www.hedberggames.com/blog/rendering-curves-in-godot). +- The suggestion to support both `Polygon2D` and collisions was done by [GeminiSquishGames](https://github.com/GeminiSquishGames), who's pointers inspired me to go further, like implementing uniform transform tools. +- The SVG Importer code was adapted from the script hosted on github in the [pixelriot/SVG2Godot](https://github.com/pixelriot/SVG2Godot) repository +- The code for making cutout shapes was adapted from the great [knife tool plugin](https://github.com/mrkdji/knife-tool/) by @mrkdji +- The inspiration for using [Geometry2D.offset_polyline](https://docs.godotengine.org/en/stable/classes/class_geometry2d.html#class-geometry2d-method-offset-polyline) for strokes came from @theshaggydev, who recorded [this video](https://www.youtube.com/watch?v=5TW7H7aXhxQ) about it. +- Lot's of gratitude to [@kcfresh53](https://github.com/kcfresh) for architecting the auto-scaling control image textures via the `SVGTextureHelper` node and the `SVGTextureResource` + + + +## And a big thank you goes to to [@MewPurPur](https://github.com/MewPurPur) + +The author of GodSVG for writing a great [SVG Arc command implementation](https://github.com/MewPurPur/GodSVG/blob/v1.0-alpha10/src/data_classes/ElementPath.gd#L117) I could reuse here: +- Download from the [GodSVG website](https://www.godsvg.com/) +- Or try out the [web version](https://www.godsvg.com/editor/) +- Also on [itch.io](https://mewpurpur.itch.io/godsvg) + + +## Many thanks to @HannesParth/Permotion + +As an early adopter Hannes was quick to point out good quality of life improvements like snap to pixel, setting global position exactly and exporting as PNG. + +Make sure to try out ["Spring Ball" on Itch](https://permotion.itch.io/spring-ball), a 48h game jam solo project that used ScalableVectorShape2D for all level objects, including a wrapper script to change the block that makes up the majority of the level between cube and triangle shapes: + +[![spring ball](./screenshots/spring-ball.png)](https://permotion.itch.io/spring-ball) + + +## And of course everyone who helped test and review the code thus far + +- @hedberg-games +- @thiagola92 +- @HannesParth + + +# Reaching out / Contributing +If you have feedback on this project, feel free to post an [issue](https://github.com/Teaching-myself-Godot/ez-curved-lines-2d/issues) on github, or to: +- Follow my channel on youtube: [@scalablev2d](https://www.youtube.com/@scalablev2d) + +If you'd like to improve on the code yourself, ideally use a fork and make a pull request. + +This stuff makes me zero money, so you can always branch off in your own direction if you're in a hurry. diff --git a/addons/curved_lines_2d/UniformRotate.svg b/addons/curved_lines_2d/UniformRotate.svg new file mode 100644 index 0000000..6616f41 --- /dev/null +++ b/addons/curved_lines_2d/UniformRotate.svg @@ -0,0 +1,125 @@ + + diff --git a/addons/curved_lines_2d/UniformRotate.svg.import b/addons/curved_lines_2d/UniformRotate.svg.import new file mode 100644 index 0000000..d0f5451 --- /dev/null +++ b/addons/curved_lines_2d/UniformRotate.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1uok4qb3xets" +path="res://.godot/imported/UniformRotate.svg-10dc5b9eaf58dd371cbfddfaf791ebda.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/UniformRotate.svg" +dest_files=["res://.godot/imported/UniformRotate.svg-10dc5b9eaf58dd371cbfddfaf791ebda.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/UniformScale.svg b/addons/curved_lines_2d/UniformScale.svg new file mode 100644 index 0000000..9713ce7 --- /dev/null +++ b/addons/curved_lines_2d/UniformScale.svg @@ -0,0 +1,139 @@ + + diff --git a/addons/curved_lines_2d/UniformScale.svg.import b/addons/curved_lines_2d/UniformScale.svg.import new file mode 100644 index 0000000..846d9aa --- /dev/null +++ b/addons/curved_lines_2d/UniformScale.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://do5uut1a4xvqf" +path="res://.godot/imported/UniformScale.svg-24a4eaf51d0b7050b6af3cdf16383613.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/UniformScale.svg" +dest_files=["res://.godot/imported/UniformScale.svg-24a4eaf51d0b7050b6af3cdf16383613.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/UniformTranslate.svg b/addons/curved_lines_2d/UniformTranslate.svg new file mode 100644 index 0000000..e59331b --- /dev/null +++ b/addons/curved_lines_2d/UniformTranslate.svg @@ -0,0 +1,101 @@ + + diff --git a/addons/curved_lines_2d/UniformTranslate.svg.import b/addons/curved_lines_2d/UniformTranslate.svg.import new file mode 100644 index 0000000..132699c --- /dev/null +++ b/addons/curved_lines_2d/UniformTranslate.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://chojkn0i6ngam" +path="res://.godot/imported/UniformTranslate.svg-8157aa4196071516483ecc9cee08cb21.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/UniformTranslate.svg" +dest_files=["res://.godot/imported/UniformTranslate.svg-8157aa4196071516483ecc9cee08cb21.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/adaptable_vector_shape_3d.gd b/addons/curved_lines_2d/adaptable_vector_shape_3d.gd new file mode 100644 index 0000000..ce8c4f3 --- /dev/null +++ b/addons/curved_lines_2d/adaptable_vector_shape_3d.gd @@ -0,0 +1,114 @@ +@tool +extends Node3D + +class_name AdaptableVectorShape3D + +const STORED_CURVE_META_NAME := "_stored_curve_data_" +const STORED_ARC_LIST_META_NAME := "_stored_arc_list_data_" +const STORED_SHAPE_TYPE_META_NAME := "_stored_shape_type_" +const STORED_SIZE_META_NAME := "_stored_shape_size_" +const STORED_RX_META_NAME := "_stored_shape_rx_" +const STORED_RY_META_NAME := "_stored_shape_ry_" +const STORED_OFFSET_META_NAME := "_stored_shape_offset_" +const STORED_STROKE_WIDTH_META_NAME := "_stored_stroke_width_" +const STORED_JOINT_MODE_META_NAME := "_stored_joint_mode_" +const STORED_LINE_CAP_META_NAME := "_stored_line_cap_" + +@export var guide_svs : ScalableVectorShape2D: + set(svs): + if is_instance_valid(guide_svs) and guide_svs != svs: + if guide_svs.polygons_updated.is_connected(_on_guide_svs_polygons_updated): + guide_svs.polygons_updated.disconnect(_on_guide_svs_polygons_updated) + guide_svs = svs + if is_instance_valid(guide_svs): + _on_guide_svs_assigned() + + +@export var fill_polygons : Array[CSGPolygon3D] = [] +@export var stroke_polygons : Array[CSGPolygon3D] = [] + +var _update_locked := false + +func _on_guide_svs_assigned(): + guide_svs.update_curve_at_runtime = true + guide_svs.polygons_updated.connect(_on_guide_svs_polygons_updated) + guide_svs.curve_changed() + + +func _on_guide_svs_polygons_updated(polygons : Array[PackedVector2Array], + poly_strokes : Array[PackedVector2Array], _svs : ScalableVectorShape2D): + + if _update_locked: + return + _update_locked = true + for p in fill_polygons + stroke_polygons: + p.hide() + + for i in polygons.size(): + if i < fill_polygons.size(): + fill_polygons[i].show() + fill_polygons[i].polygon = polygons[i] + else: + var extra_fp := fill_polygons[i - 1].duplicate() + extra_fp.polygon = polygons[i] + fill_polygons.append(extra_fp) + add_child(extra_fp, true) + extra_fp.owner = owner + + for i in poly_strokes.size(): + if i < stroke_polygons.size(): + stroke_polygons[i].show() + stroke_polygons[i].polygon = poly_strokes[i] + else: + var extra_sp := stroke_polygons[i - 1].duplicate() + extra_sp.polygon = poly_strokes[i] + stroke_polygons.append(extra_sp) + add_child(extra_sp, true) + extra_sp.owner = owner + _update_locked = false + +static func is_stroke_in_front_of_fill(svs : ScalableVectorShape2D) -> bool: + var stroke_node : Node2D = (svs.line if is_instance_valid(svs.line) else svs.poly_stroke) + if not is_instance_valid(stroke_node): + return false + if not is_instance_valid(svs.polygon): + return true + var fill_found := false + for ch in svs.get_children(): + if ch == svs.polygon: + fill_found = true + if ch == stroke_node and fill_found: + return true + + return false + + +static func extract_csg_polygons_from_scalable_vector_shapes(svs : ScalableVectorShape2D, + is_strokes := false, is_line_2d_strokes := false, z_index := 0.0) -> Array[CSGPolygon3D]: + var result : Array[CSGPolygon3D] = [] + var polygons = ( + svs.cached_poly_strokes + if is_strokes else + ([svs.cached_outline] if svs.clip_paths.is_empty() else svs.cached_clipped_polygons) + ) + for poly : PackedVector2Array in polygons: + var csg_polygon := CSGPolygon3D.new() + csg_polygon.depth = 0.01 + csg_polygon.position.z = 0.01 * z_index + csg_polygon.polygon = poly + csg_polygon.material = StandardMaterial3D.new() + csg_polygon.material.shading_mode = BaseMaterial3D.SHADING_MODE_PER_PIXEL + csg_polygon.material.transparency = BaseMaterial3D.TRANSPARENCY_DISABLED + if is_strokes: + csg_polygon.material.albedo_color = svs.stroke_color + if is_line_2d_strokes: + csg_polygon.name = svs.line.name + else: + csg_polygon.name = svs.poly_stroke.name + csg_polygon.material.albedo_texture = svs.poly_stroke.texture + else: + csg_polygon.name = svs.polygon.name + csg_polygon.material.albedo_color = svs.polygon.color + csg_polygon.material.albedo_texture = svs.polygon.texture + result.append(csg_polygon) + return result diff --git a/addons/curved_lines_2d/adaptable_vector_shape_3d.gd.uid b/addons/curved_lines_2d/adaptable_vector_shape_3d.gd.uid new file mode 100644 index 0000000..43ebb97 --- /dev/null +++ b/addons/curved_lines_2d/adaptable_vector_shape_3d.gd.uid @@ -0,0 +1 @@ +uid://cx1no66jo1sdd diff --git a/addons/curved_lines_2d/advanced_tab.gd b/addons/curved_lines_2d/advanced_tab.gd new file mode 100644 index 0000000..469b531 --- /dev/null +++ b/addons/curved_lines_2d/advanced_tab.gd @@ -0,0 +1,118 @@ +@tool +extends Control + +var _init_hint_label_text := "" +var _selected_animation_player : AnimationPlayer +var fps_number_input : EditorSpinSlider + +func _enter_tree() -> void: + _init_hint_label_text = $%HintLabel.text + fps_number_input = _make_number_input("FPS", 60.0, 5.0, 120.0, "fps", 1.0) + %FpsInputContainer.add_child(fps_number_input) + + +func _on_export_as_png_button_pressed() -> void: + var selected_node := EditorInterface.get_selection().get_selected_nodes().pop_back() + Line2DGeneratorInspectorPlugin._on_export_png_button_pressed(selected_node) + + +func _on_export_as_baked_scene_button_pressed() -> void: + var selected_node := EditorInterface.get_selection().get_selected_nodes().pop_back() + Line2DGeneratorInspectorPlugin._show_exported_scene_dialog( + selected_node, Line2DGeneratorInspectorPlugin._export_baked_scene + ) + + +func _on_export_as_3d_scene_button_pressed() -> void: + var selected_node := EditorInterface.get_selection().get_selected_nodes().pop_back() + Line2DGeneratorInspectorPlugin._show_exported_scene_dialog( + selected_node, Line2DGeneratorInspectorPlugin._export_3d_scene + ) + + +func set_animation_player(animation_player : AnimationPlayer) -> void: + if not animation_player is AnimationPlayer: + %HintLabel.text = _init_hint_label_text + %HintLabel.show() + %SelectAnimationOptionButton.hide() + %CreateSpriteSheetButton.hide() + %FpsInputContainer.hide() + %ExportAsSpritesheetCheckButton.hide() + %StatusLabel.hide() + return + + _selected_animation_player = animation_player + %HintLabel.hide() + %StatusLabel.text = "" + %SelectAnimationOptionButton.clear() + %SelectAnimationOptionButton.add_item(" - select animation -") + %SelectAnimationOptionButton.select(0) + %SelectAnimationOptionButton.set_item_disabled(0, true) + for anim_name in animation_player.get_animation_list(): + if anim_name == "RESET": + continue + %SelectAnimationOptionButton.add_item(anim_name) + %SelectAnimationOptionButton.show() + %CreateSpriteSheetButton.show() + %FpsInputContainer.show() + %ExportAsSpritesheetCheckButton.show() + + +func _on_create_sprite_sheet_button_pressed() -> void: + if not _selected_animation_player is AnimationPlayer: + return + var dialog := EditorFileDialog.new() + var anim_name : String = %SelectAnimationOptionButton.get_item_text(%SelectAnimationOptionButton.get_selected_id()) + dialog.add_filter("*.png", "PNG") + dialog.current_file = ("%s_%s" % [ + EditorInterface.get_edited_scene_root().name, + anim_name + ]).to_snake_case() + + dialog.file_mode = EditorFileDialog.FILE_MODE_SAVE_FILE + dialog.file_selected.connect(func(path): _on_animation_file_name_chosen(path, anim_name, dialog)) + EditorInterface.get_base_control().add_child(dialog) + dialog.popup_centered(Vector2i(800, 400)) + + +func _on_animation_file_name_chosen(file_path : String, anim_name : String, dialog : EditorFileDialog): + dialog.queue_free() + var fps := fps_number_input.value + %StatusLabel.show() + %CreateSpriteSheetButton.disabled = true + %CreateSpriteSheetButton.text = "Creating..." + + var sprite_frames := await SVSSceneExporter.export_sprite_frames( + EditorInterface.get_edited_scene_root(), _selected_animation_player, anim_name, fps, + EditorInterface.get_base_control(), func(status_msg : String): %StatusLabel.text = status_msg + ) + + if %ExportAsSpritesheetCheckButton.button_pressed: + var im : Image = Image.create_empty( + sprite_frames[0].get_size().x * sprite_frames.size(), + sprite_frames[0].get_size().y, false, sprite_frames[0].get_format()) + for idx in sprite_frames.size(): + im.blit_rect(sprite_frames[idx], + Rect2i(Vector2i.ZERO, sprite_frames[idx].get_size()), + Vector2i(sprite_frames[0].get_size().x * idx, 0) + ) + im.save_png(file_path) + else: + for idx in sprite_frames.size(): + sprite_frames[idx].save_png(file_path.replacen(".png", "_%d.png" % idx)) + + %StatusLabel.text = "Exported %d frames" % sprite_frames.size() + %CreateSpriteSheetButton.disabled = false + %CreateSpriteSheetButton.text = "Create" + EditorInterface.get_resource_filesystem().scan() + + +func _make_number_input(lbl : String, value : float, min_value : float, max_value : float, suffix : String, step := 1.0) -> EditorSpinSlider: + var x_slider := EditorSpinSlider.new() + x_slider.value = value + x_slider.min_value = min_value + x_slider.max_value = max_value + x_slider.suffix = suffix + x_slider.label = lbl + x_slider.step = step + return x_slider diff --git a/addons/curved_lines_2d/advanced_tab.gd.uid b/addons/curved_lines_2d/advanced_tab.gd.uid new file mode 100644 index 0000000..36848b6 --- /dev/null +++ b/addons/curved_lines_2d/advanced_tab.gd.uid @@ -0,0 +1 @@ +uid://duyq57sg3jn7q diff --git a/addons/curved_lines_2d/advanced_tab.tscn b/addons/curved_lines_2d/advanced_tab.tscn new file mode 100644 index 0000000..9819883 --- /dev/null +++ b/addons/curved_lines_2d/advanced_tab.tscn @@ -0,0 +1,98 @@ +[gd_scene load_steps=3 format=3 uid="uid://3r7rlhrwfmfe"] + +[ext_resource type="Script" uid="uid://duyq57sg3jn7q" path="res://addons/curved_lines_2d/advanced_tab.gd" id="1_h55kp"] + +[sub_resource type="LabelSettings" id="LabelSettings_h55kp"] +line_spacing = 0.0 +font_size = 14 +font_color = Color(0.73, 0.73, 0.73, 1) + +[node name="AdvancedTab" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 8 +script = ExtResource("1_h55kp") +metadata/_tab_index = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer"] +custom_minimum_size = Vector2(170, 0) +layout_mode = 2 +tooltip_text = "Exports the entire scene as a PNG spritesheet, or separate PNG files using the selected animation." +mouse_filter = 0 +text = "Export Options*" + +[node name="ExportAsPNGButton" type="Button" parent="HBoxContainer"] +layout_mode = 2 +text = "PNG Image" + +[node name="ExportAsBakedSceneButton" type="Button" parent="HBoxContainer"] +layout_mode = 2 +text = "'Baked' Scene +" + +[node name="ExportAs3DSceneButton" type="Button" parent="HBoxContainer"] +layout_mode = 2 +text = "3D Scene" + +[node name="HSeparator" type="HSeparator" parent="."] +layout_mode = 2 + +[node name="HBoxContainer2" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer2"] +custom_minimum_size = Vector2(170, 0) +layout_mode = 2 +tooltip_text = "Exports the entire scene as a PNG spritesheet, or separate PNG files using the selected animation." +mouse_filter = 0 +text = "Bake Sprite Frames*" + +[node name="HintLabel" type="Label" parent="HBoxContainer2"] +unique_name_in_owner = true +layout_mode = 2 +text = "- Select a 2D scene with at least an AnimationPlayer and one ScalableVectorShape2D -" +label_settings = SubResource("LabelSettings_h55kp") + +[node name="SelectAnimationOptionButton" type="OptionButton" parent="HBoxContainer2"] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 + +[node name="FpsInputContainer" type="PanelContainer" parent="HBoxContainer2"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="ExportAsSpritesheetCheckButton" type="CheckButton" parent="HBoxContainer2"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +text = "Export as Spritesheet" + +[node name="StatusLabel" type="Label" parent="HBoxContainer2"] +unique_name_in_owner = true +visible = false +layout_mode = 2 + +[node name="CreateSpriteSheetButton" type="Button" parent="HBoxContainer2"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 8 +text = "Create" + +[node name="HSeparator2" type="HSeparator" parent="."] +layout_mode = 2 + +[connection signal="pressed" from="HBoxContainer/ExportAsPNGButton" to="." method="_on_export_as_png_button_pressed"] +[connection signal="pressed" from="HBoxContainer/ExportAsBakedSceneButton" to="." method="_on_export_as_baked_scene_button_pressed"] +[connection signal="pressed" from="HBoxContainer/ExportAs3DSceneButton" to="." method="_on_export_as_3d_scene_button_pressed"] +[connection signal="pressed" from="HBoxContainer2/CreateSpriteSheetButton" to="." method="_on_create_sprite_sheet_button_pressed"] diff --git a/addons/curved_lines_2d/arc_settings_popup_panel.gd b/addons/curved_lines_2d/arc_settings_popup_panel.gd new file mode 100644 index 0000000..c5a23a5 --- /dev/null +++ b/addons/curved_lines_2d/arc_settings_popup_panel.gd @@ -0,0 +1,95 @@ +@tool +extends PopupPanel + +var rx_input : EditorSpinSlider +var ry_input : EditorSpinSlider +var rotation_input : EditorSpinSlider +var _arc_under_edit : ScalableArc + +var _dragging := false +var _drag_start := Vector2.ZERO + +func _enter_tree() -> void: + visible = false + rx_input = _mk_input() + ry_input = _mk_input() + rotation_input = _mk_input(1.0) + %RxInputContainer.add_child(rx_input) + %RyInputContainer.add_child(ry_input) + %RotationInputContainer.add_child(rotation_input) + if not rx_input.value_changed.is_connected(_on_radius_changed): + rx_input.value_changed.connect(_on_radius_changed) + if not ry_input.value_changed.is_connected(_on_radius_changed): + ry_input.value_changed.connect(_on_radius_changed) + if not rotation_input.value_changed.is_connected(_on_rotation_changed): + rotation_input.value_changed.connect(_on_rotation_changed) + +func _on_button_pressed() -> void: + hide() + + +func _on_rotation_changed(new_rot : float) -> void: + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Update arc rotation") + undo_redo.add_do_property(_arc_under_edit, 'rotation_deg', new_rot) + undo_redo.add_undo_property(_arc_under_edit, 'rotation_deg', _arc_under_edit.rotation_deg) + undo_redo.commit_action() + + +func _on_radius_changed(_v : float) -> void: + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Update arc radius") + undo_redo.add_do_property(_arc_under_edit, 'radius', Vector2(rx_input.value, ry_input.value)) + undo_redo.add_undo_property(_arc_under_edit, 'radius', _arc_under_edit.radius) + undo_redo.commit_action() + + +func _on_sweep_check_box_toggled(toggled_on: bool) -> void: + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Update arc sweep flag") + undo_redo.add_do_property(_arc_under_edit, 'sweep_flag', toggled_on) + undo_redo.add_undo_property(_arc_under_edit, 'sweep_flag', _arc_under_edit.sweep_flag) + undo_redo.commit_action() + + +func _on_large_arc_check_box_toggled(toggled_on: bool) -> void: + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Update arc large arc flag") + undo_redo.add_do_property(_arc_under_edit, 'large_arc_flag', toggled_on) + undo_redo.add_undo_property(_arc_under_edit, 'large_arc_flag', _arc_under_edit.large_arc_flag) + undo_redo.commit_action() + + +func popup_with_value(arc : ScalableArc): + _arc_under_edit = arc + rx_input.set_value_no_signal(arc.radius.x) + ry_input.set_value_no_signal(arc.radius.y) + rotation_input.set_value_no_signal(arc.rotation_deg) + %LargeArcCheckBox.set_pressed_no_signal(arc.large_arc_flag) + %SweepCheckBox.set_pressed_no_signal(arc.sweep_flag) + popup_centered() + + +func _mk_input(step := 0.001) -> EditorSpinSlider: + var num_input := EditorSpinSlider.new() + num_input.suffix = "px" + num_input.hide_slider = true + num_input.value = 0.0 + num_input.editing_integer = false + num_input.allow_lesser = true + num_input.allow_greater = true + num_input.step = 0.001 + return num_input + + +func _on_label_gui_input(event: InputEvent) -> void: + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + if not _dragging: + _dragging = true + _drag_start = EditorInterface.get_base_control().get_local_mouse_position() + else: + _dragging = false + if event is InputEventMouseMotion and _dragging: + position += Vector2i(EditorInterface.get_base_control().get_local_mouse_position() - _drag_start) + _drag_start = EditorInterface.get_base_control().get_local_mouse_position() diff --git a/addons/curved_lines_2d/arc_settings_popup_panel.gd.uid b/addons/curved_lines_2d/arc_settings_popup_panel.gd.uid new file mode 100644 index 0000000..ed3a5ee --- /dev/null +++ b/addons/curved_lines_2d/arc_settings_popup_panel.gd.uid @@ -0,0 +1 @@ +uid://mk3r6d801wbn diff --git a/addons/curved_lines_2d/arc_settings_popup_panel.tscn b/addons/curved_lines_2d/arc_settings_popup_panel.tscn new file mode 100644 index 0000000..9518853 --- /dev/null +++ b/addons/curved_lines_2d/arc_settings_popup_panel.tscn @@ -0,0 +1,185 @@ +[gd_scene load_steps=8 format=3 uid="uid://c2vk4emclmyfd"] + +[ext_resource type="Script" uid="uid://mk3r6d801wbn" path="res://addons/curved_lines_2d/arc_settings_popup_panel.gd" id="1_3bjn8"] + +[sub_resource type="LabelSettings" id="LabelSettings_3bjn8"] +font_color = Color(0.552956, 0.552956, 0.552956, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3bjn8"] +bg_color = Color(0, 0, 0, 1) +corner_radius_top_left = 2 +corner_radius_bottom_left = 2 + +[sub_resource type="LabelSettings" id="LabelSettings_kcp7s"] +line_spacing = 0.0 +font_color = Color(0.54, 0.33696, 0.2808, 1) + +[sub_resource type="LabelSettings" id="LabelSettings_2efm4"] +font_color = Color(0.345098, 0.47451, 0.396078, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kcp7s"] +bg_color = Color(0.0588235, 0.0588235, 0.0588235, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1vtg0"] +bg_color = Color(0.0588235, 0.0588235, 0.0588235, 1) + +[node name="ArcSettingsPopupPanel" type="PopupPanel"] +size = Vector2i(250, 251) +script = ExtResource("1_3bjn8") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 4.0 +offset_right = -4.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +theme_override_constants/separation = 5 + +[node name="Label" type="Label" parent="VBoxContainer"] +layout_mode = 2 +mouse_filter = 0 +text = "Arc settings" +horizontal_alignment = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(90, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "Radius" +label_settings = SubResource("LabelSettings_3bjn8") + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 1.25 + +[node name="PanelContainer" type="PanelContainer" parent="VBoxContainer/HBoxContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_3bjn8") + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/HBoxContainer/VBoxContainer/PanelContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/VBoxContainer/PanelContainer/HBoxContainer"] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "x" +label_settings = SubResource("LabelSettings_kcp7s") +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="RxInputContainer" type="PanelContainer" parent="VBoxContainer/HBoxContainer/VBoxContainer/PanelContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="PanelContainer2" type="PanelContainer" parent="VBoxContainer/HBoxContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_3bjn8") + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/HBoxContainer/VBoxContainer/PanelContainer2"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/VBoxContainer/PanelContainer2/HBoxContainer"] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "y" +label_settings = SubResource("LabelSettings_2efm4") +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="RyInputContainer" type="PanelContainer" parent="VBoxContainer/HBoxContainer/VBoxContainer/PanelContainer2/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer2"] +custom_minimum_size = Vector2(90, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "Rotation" +label_settings = SubResource("LabelSettings_3bjn8") + +[node name="RotationInputContainer" type="PanelContainer" parent="VBoxContainer/HBoxContainer2"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_kcp7s") + +[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer3"] +custom_minimum_size = Vector2(90, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "Large Arc" +label_settings = SubResource("LabelSettings_3bjn8") + +[node name="Container" type="PanelContainer" parent="VBoxContainer/HBoxContainer3"] +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_1vtg0") + +[node name="LargeArcCheckBox" type="CheckBox" parent="VBoxContainer/HBoxContainer3/Container"] +unique_name_in_owner = true +layout_mode = 2 +text = "On" + +[node name="HBoxContainer4" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer4"] +custom_minimum_size = Vector2(90, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "Sweep" +label_settings = SubResource("LabelSettings_3bjn8") + +[node name="Container" type="PanelContainer" parent="VBoxContainer/HBoxContainer4"] +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_1vtg0") + +[node name="SweepCheckBox" type="CheckBox" parent="VBoxContainer/HBoxContainer4/Container"] +unique_name_in_owner = true +layout_mode = 2 +text = "On" + +[node name="Button" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Ok" + +[connection signal="gui_input" from="VBoxContainer/Label" to="." method="_on_label_gui_input"] +[connection signal="toggled" from="VBoxContainer/HBoxContainer3/Container/LargeArcCheckBox" to="." method="_on_large_arc_check_box_toggled"] +[connection signal="toggled" from="VBoxContainer/HBoxContainer4/Container/SweepCheckBox" to="." method="_on_sweep_check_box_toggled"] +[connection signal="pressed" from="VBoxContainer/Button" to="." method="_on_button_pressed"] diff --git a/addons/curved_lines_2d/assign_collision_inspector_form.gd b/addons/curved_lines_2d/assign_collision_inspector_form.gd new file mode 100644 index 0000000..9f895cc --- /dev/null +++ b/addons/curved_lines_2d/assign_collision_inspector_form.gd @@ -0,0 +1,50 @@ +@tool +extends Control + +var scalable_vector_shape_2d : ScalableVectorShape2D + +func _enter_tree() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if 'assigned_node_changed' in scalable_vector_shape_2d: + scalable_vector_shape_2d.assigned_node_changed.connect(_on_svs_assignment_changed) + _on_svs_assignment_changed() + + +func _on_svs_assignment_changed() -> void: + if is_instance_valid(scalable_vector_shape_2d.collision_polygon): + %GotoCollisionButton.show() + %GotoCollisionButton.disabled = false + %CreateCollisionButton.hide() + %CreateCollisionButton.disabled = true + else: + %GotoCollisionButton.hide() + %GotoCollisionButton.disabled = true + %CreateCollisionButton.show() + %CreateCollisionButton.disabled = false + + +func _on_goto_collision_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.collision_polygon): + return + EditorInterface.call_deferred('edit_node', scalable_vector_shape_2d.collision_polygon) + + +func _on_create_collision_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + var undo_redo := EditorInterface.get_editor_undo_redo() + var new_poly := CollisionPolygon2D.new() + undo_redo.create_action("Add CollisionPolygon2D to %s " % str(scalable_vector_shape_2d)) + undo_redo.add_do_method(scalable_vector_shape_2d, 'add_child', new_poly, true) + if scalable_vector_shape_2d == EditorInterface.get_edited_scene_root(): + undo_redo.add_do_method(new_poly, 'set_owner', scalable_vector_shape_2d) + else: + undo_redo.add_do_method(new_poly, 'set_owner', scalable_vector_shape_2d.owner) + undo_redo.add_do_reference(new_poly) + undo_redo.add_do_property(scalable_vector_shape_2d, 'collision_polygon', new_poly) + undo_redo.add_undo_method(scalable_vector_shape_2d, 'remove_child', new_poly) + undo_redo.add_undo_property(scalable_vector_shape_2d, 'collision_polygon', null) + undo_redo.commit_action() diff --git a/addons/curved_lines_2d/assign_collision_inspector_form.gd.uid b/addons/curved_lines_2d/assign_collision_inspector_form.gd.uid new file mode 100644 index 0000000..e7c2d2d --- /dev/null +++ b/addons/curved_lines_2d/assign_collision_inspector_form.gd.uid @@ -0,0 +1 @@ +uid://1a3nrkdo50tg diff --git a/addons/curved_lines_2d/assign_collision_inspector_form.tscn b/addons/curved_lines_2d/assign_collision_inspector_form.tscn new file mode 100644 index 0000000..c1cd619 --- /dev/null +++ b/addons/curved_lines_2d/assign_collision_inspector_form.tscn @@ -0,0 +1,41 @@ +[gd_scene load_steps=2 format=3 uid="uid://bqudr864ptf7r"] + +[ext_resource type="Script" uid="uid://1a3nrkdo50tg" path="res://addons/curved_lines_2d/assign_collision_inspector_form.gd" id="1_wi77q"] + +[node name="AssignCollisionInspectorForm" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_wi77q") + +[node name="ButtonContainer2" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="ButtonContainer2"] +clip_contents = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "⚠️ Assigning a CollisionPolygon2D directly will at some point be deprecated in favour of assigning a CollisionObject2D: a clipped ScalableVectorShape2D can result in multiple CollisionPolygon2D" +mouse_filter = 0 +text = "⚠️ CollisionPolygon2D*" + +[node name="GotoCollisionButton" type="Button" parent="ButtonContainer2"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 2 +tooltip_text = "Click on this button to select the CollisionPolygon2D node that is assigned to this shape in the Scene Tree. + +Use this for advanced features which are already built-in into godot." +text = "Go To Node" + +[node name="CreateCollisionButton" type="Button" parent="ButtonContainer2"] +unique_name_in_owner = true +layout_mode = 2 +text = "Create CollisionPolygon2D" + +[connection signal="pressed" from="ButtonContainer2/GotoCollisionButton" to="." method="_on_goto_collision_button_pressed"] +[connection signal="pressed" from="ButtonContainer2/CreateCollisionButton" to="." method="_on_create_collision_button_pressed"] diff --git a/addons/curved_lines_2d/assign_collision_object_inspector_form.gd b/addons/curved_lines_2d/assign_collision_object_inspector_form.gd new file mode 100644 index 0000000..c68008a --- /dev/null +++ b/addons/curved_lines_2d/assign_collision_object_inspector_form.gd @@ -0,0 +1,67 @@ +@tool +extends Control + +var scalable_vector_shape_2d : ScalableVectorShape2D + +func _enter_tree() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if 'assigned_node_changed' in scalable_vector_shape_2d: + scalable_vector_shape_2d.assigned_node_changed.connect(_on_svs_assignment_changed) + _on_svs_assignment_changed() + + +func _on_svs_assignment_changed() -> void: + if is_instance_valid(scalable_vector_shape_2d.collision_object): + %GoToCollisionObjectButton.show() + %CollisionObjectTypeOptionButton.hide() + else: + %GoToCollisionObjectButton.hide() + %CollisionObjectTypeOptionButton.show() + %CollisionObjectTypeOptionButton.select(0) + + +func _on_collision_object_type_option_button_type_selected(obj_type: ScalableVectorShape2D.CollisionObjectType) -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + + match obj_type: + ScalableVectorShape2D.CollisionObjectType.STATIC_BODY_2D: + _assign_collision_object(StaticBody2D.new()) + ScalableVectorShape2D.CollisionObjectType.AREA_2D: + _assign_collision_object(Area2D.new()) + ScalableVectorShape2D.CollisionObjectType.ANIMATABLE_BODY_2D: + _assign_collision_object(AnimatableBody2D.new()) + ScalableVectorShape2D.CollisionObjectType.RIGID_BODY_2D: + _assign_collision_object(RigidBody2D.new()) + ScalableVectorShape2D.CollisionObjectType.CHARACTER_BODY_2D: + _assign_collision_object(CharacterBody2D.new()) + ScalableVectorShape2D.CollisionObjectType.PHYSICAL_BONE_2D: + _assign_collision_object(PhysicalBone2D.new()) + _, ScalableVectorShape2D.CollisionObjectType.NONE: + scalable_vector_shape_2d.collision_object = null + + +func _assign_collision_object(new_obj : CollisionObject2D) -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Add %s to %s " % [str(new_obj.name), str(scalable_vector_shape_2d)]) + undo_redo.add_do_method(scalable_vector_shape_2d, 'add_child', new_obj, true) + if scalable_vector_shape_2d == EditorInterface.get_edited_scene_root(): + undo_redo.add_do_method(new_obj, 'set_owner', scalable_vector_shape_2d) + else: + undo_redo.add_do_method(new_obj, 'set_owner', scalable_vector_shape_2d.owner) + undo_redo.add_do_reference(new_obj) + undo_redo.add_do_property(scalable_vector_shape_2d, 'collision_object', new_obj) + undo_redo.add_undo_method(scalable_vector_shape_2d, 'remove_child', new_obj) + undo_redo.add_undo_property(scalable_vector_shape_2d, 'collision_object', null) + undo_redo.commit_action() + + +func _on_go_to_collision_object_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.collision_object): + return + EditorInterface.call_deferred('edit_node', scalable_vector_shape_2d.collision_object) diff --git a/addons/curved_lines_2d/assign_collision_object_inspector_form.gd.uid b/addons/curved_lines_2d/assign_collision_object_inspector_form.gd.uid new file mode 100644 index 0000000..e6d8202 --- /dev/null +++ b/addons/curved_lines_2d/assign_collision_object_inspector_form.gd.uid @@ -0,0 +1 @@ +uid://ci3o0cnwiet6 diff --git a/addons/curved_lines_2d/assign_collision_object_inspector_form.tscn b/addons/curved_lines_2d/assign_collision_object_inspector_form.tscn new file mode 100644 index 0000000..18e20e6 --- /dev/null +++ b/addons/curved_lines_2d/assign_collision_object_inspector_form.tscn @@ -0,0 +1,41 @@ +[gd_scene load_steps=3 format=3 uid="uid://dar1y7o5qcxic"] + +[ext_resource type="Script" uid="uid://ci3o0cnwiet6" path="res://addons/curved_lines_2d/assign_collision_object_inspector_form.gd" id="1_csmls"] +[ext_resource type="PackedScene" uid="uid://cjbkvx1pj7gq2" path="res://addons/curved_lines_2d/collision_object_type_option_button.tscn" id="2_ks3po"] + +[node name="AssignCollisionObjectInspectorForm" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 4 +script = ExtResource("1_csmls") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Assign a new CollisionObject2D to this shape. +This will hold any generated CollisionPolygon2D nodes. + +Selecting 'none' will unassign any existing node, but will not delete the node." +mouse_filter = 0 +text = "Collision Object* " + +[node name="CollisionObjectTypeOptionButton" parent="HBoxContainer" instance=ExtResource("2_ks3po")] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="GoToCollisionObjectButton" type="Button" parent="HBoxContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +text = "Go To Node" + +[connection signal="type_selected" from="HBoxContainer/CollisionObjectTypeOptionButton" to="." method="_on_collision_object_type_option_button_type_selected"] +[connection signal="pressed" from="HBoxContainer/GoToCollisionObjectButton" to="." method="_on_go_to_collision_object_button_pressed"] diff --git a/addons/curved_lines_2d/assign_fill_inspector_form.gd b/addons/curved_lines_2d/assign_fill_inspector_form.gd new file mode 100644 index 0000000..dcd3a6f --- /dev/null +++ b/addons/curved_lines_2d/assign_fill_inspector_form.gd @@ -0,0 +1,245 @@ +@tool +extends KeyframeButtonCapableInspectorFormBase + +var scalable_vector_shape_2d : ScalableVectorShape2D + + +func _enter_tree() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if 'assigned_node_changed' in scalable_vector_shape_2d: + scalable_vector_shape_2d.assigned_node_changed.connect(_on_svs_assignment_changed) + _on_svs_assignment_changed() + _initialize_keyframe_capabilities() + + +func _on_key_frame_capabilities_changed(): + %AddFillKeyFrameButton.visible = _is_key_frame_capable() + %BatchInsertGradientKeyFrameButton.visible = _is_key_frame_capable() + + +func _on_svs_assignment_changed() -> void: + if is_instance_valid(scalable_vector_shape_2d.polygon): + %CreateFillButton.get_parent().hide() + %GotoPolygon2DButton.get_parent().show() + %GradientFieldContainer.show() + %GradientStopColorButtonContainer.show() + %CreateFillButton.disabled = true + %GotoPolygon2DButton.disabled = false + %ColorPickerButton.color = scalable_vector_shape_2d.polygon.color + %RadialGradientToggleButton.disabled = false + %LinearGradientToggleButton.disabled = false + %RemoveGradientToggleButton.disabled = false + if scalable_vector_shape_2d.polygon.texture is GradientTexture2D: + if scalable_vector_shape_2d.polygon.texture.fill == GradientTexture2D.FILL_RADIAL: + %RadialGradientToggleButton.button_pressed = true + else: + %LinearGradientToggleButton.button_pressed = true + _set_gradient_stop_color_buttons() + elif scalable_vector_shape_2d.polygon.texture: + %OtherTextureToggleButton.button_pressed = true + %GradientStopColorButtonContainer.hide() + else: + %RemoveGradientToggleButton.button_pressed = true + %GradientStopColorButtonContainer.hide() + else: + %CreateFillButton.get_parent().show() + %GotoPolygon2DButton.get_parent().hide() + %GradientFieldContainer.hide() + %GradientStopColorButtonContainer.hide() + %CreateFillButton.disabled = false + %GotoPolygon2DButton.disabled = true + %ColorPickerButton.color = CurvedLines2D._get_default_fill_color() + %RadialGradientToggleButton.disabled = true + %LinearGradientToggleButton.disabled = true + %RemoveGradientToggleButton.disabled = true + %RemoveGradientToggleButton.button_pressed = true + + +func _on_color_picker_button_color_changed(color: Color) -> void: + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + scalable_vector_shape_2d.polygon.color = color + + +func _on_goto_polygon_2d_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + EditorInterface.call_deferred('edit_node', scalable_vector_shape_2d.polygon) + + +func _on_create_fill_button_pressed(): + if not is_instance_valid(scalable_vector_shape_2d): + return + if is_instance_valid(scalable_vector_shape_2d.polygon): + return + + var polygon_2d := Polygon2D.new() + var root := EditorInterface.get_edited_scene_root() + var undo_redo = EditorInterface.get_editor_undo_redo() + polygon_2d.color = %ColorPickerButton.color + undo_redo.create_action("Add Polygon2D to %s " % str(scalable_vector_shape_2d)) + undo_redo.add_do_method(scalable_vector_shape_2d, 'add_child', polygon_2d, true) + undo_redo.add_do_method(polygon_2d, 'set_owner', root) + undo_redo.add_do_reference(polygon_2d) + undo_redo.add_do_property(scalable_vector_shape_2d, 'polygon', polygon_2d) + undo_redo.add_undo_method(scalable_vector_shape_2d, 'remove_child', polygon_2d) + undo_redo.add_undo_property(scalable_vector_shape_2d, 'polygon', null) + undo_redo.commit_action() + + +func _set_texture(texture : Texture2D, texture_offset := Vector2.ZERO) -> void: + var undo_redo = EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Set texture for %s" % str(scalable_vector_shape_2d)) + undo_redo.add_do_property(scalable_vector_shape_2d.polygon, 'texture', texture) + undo_redo.add_do_property(scalable_vector_shape_2d.polygon, 'texture_offset', texture_offset) + undo_redo.add_do_method(self, '_on_svs_assignment_changed') + undo_redo.add_undo_property(scalable_vector_shape_2d.polygon, 'texture', scalable_vector_shape_2d.polygon.texture) + undo_redo.add_undo_property(scalable_vector_shape_2d.polygon, 'texture_offset', scalable_vector_shape_2d.polygon.texture_offset) + undo_redo.add_undo_method(self, '_on_svs_assignment_changed') + undo_redo.commit_action() + + +func _update_stop_color(idx : int, color : Color) -> void: + scalable_vector_shape_2d.polygon.texture.gradient.colors[idx] = color + + +func _handle_stop_color_undo_redo_action(idx : int, btn : ColorPickerButton, toggled_on : bool) -> void: + var undo_redo = EditorInterface.get_editor_undo_redo() + if toggled_on: + undo_redo.create_action("Set stop color for %s" % str(scalable_vector_shape_2d)) + undo_redo.add_undo_property(scalable_vector_shape_2d.polygon.texture.gradient, 'colors', + scalable_vector_shape_2d.polygon.texture.gradient.colors) + undo_redo.add_undo_property(btn, 'color', + scalable_vector_shape_2d.polygon.texture.gradient.colors[idx]) + else: + var new_colors = scalable_vector_shape_2d.polygon.texture.gradient.colors.duplicate() + new_colors[idx] = btn.color + undo_redo.add_do_property(scalable_vector_shape_2d.polygon.texture.gradient, 'colors', new_colors) + undo_redo.add_do_property(btn, 'color', btn.color) + undo_redo.commit_action() + + +func _on_remove_gradient_toggle_button_button_down() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + + _set_texture(null) + + +func _set_gradient_stop_color_buttons() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + if not scalable_vector_shape_2d.polygon.texture is GradientTexture2D: + return + + for b in %StopColorButtonsContainer.get_children(): + b.queue_free() + + for idx in range(scalable_vector_shape_2d.polygon.texture.gradient.colors.size()): + var color : Color = scalable_vector_shape_2d.polygon.texture.gradient.colors[idx] + var new_button := ColorPickerButton.new() + new_button.color = color + new_button.color_changed.connect(func(c): _update_stop_color(idx, c)) + new_button.toggled.connect(func(toggled_on): _handle_stop_color_undo_redo_action(idx, new_button, toggled_on)) + new_button.custom_minimum_size = Vector2(40, 40) + %StopColorButtonsContainer.add_child(new_button) + + +func _on_linear_gradient_toggle_button_button_down() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + if (scalable_vector_shape_2d.polygon.texture is GradientTexture2D and + scalable_vector_shape_2d.polygon.texture.fill == GradientTexture2D.FILL_LINEAR): + return + + var box := scalable_vector_shape_2d.get_bounding_rect() + var texture := _initialize_gradient(box) + texture.fill = GradientTexture2D.FILL_LINEAR + texture.fill_from = Vector2(0.0, 0.5) + texture.fill_to = Vector2(1.0, 0.5) + _set_texture(texture, -box.position) + + +func _on_radial_gradient_toggle_button_button_down() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + if (scalable_vector_shape_2d.polygon.texture is GradientTexture2D and + scalable_vector_shape_2d.polygon.texture.fill == GradientTexture2D.FILL_RADIAL): + return + + var box := scalable_vector_shape_2d.get_bounding_rect() + var texture := _initialize_gradient(box) + texture.fill = GradientTexture2D.FILL_RADIAL + texture.fill_from = -box.position / box.size + texture.fill_to = (scalable_vector_shape_2d.get_farthest_point() - box.position) / box.size + _set_texture(texture, -box.position) + + +static func _initialize_gradient(box : Rect2) -> GradientTexture2D: + var texture := GradientTexture2D.new() + texture.width = ceil(box.size.x) + texture.height = ceil(box.size.y) + texture.gradient = Gradient.new() + texture.gradient.colors = [Color.WHITE, Color.BLACK] + texture.gradient.offsets = [0.0, 1.0] + return texture + + +func _on_add_fill_key_frame_button_pressed() -> void: + if is_instance_valid(scalable_vector_shape_2d.polygon): + add_key_frame( + scalable_vector_shape_2d.polygon, "color", %ColorPickerButton.color + ) + + +func _on_batch_insert_gradient_key_frame_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + if not scalable_vector_shape_2d.polygon.texture is GradientTexture2D: + return + + var p2d := scalable_vector_shape_2d.polygon + var animation_name := animation_under_edit_button.get_item_text(animation_under_edit_button.get_selected_id()) + var animation_player := _find_animation_player(animation_name) + var track_position := _guarded_get_track_position() + var animation := _guarded_get_animation(animation_player) + var path_to_node := _guarded_get_path_to_node(animation_player, p2d) + if not animation: + return + if path_to_node.is_empty(): + return + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Batch all gradient keyframes for %s on animation %s" % [str(p2d), str(animation)]) + _add_key_frame(undo_redo, animation, NodePath("%s:texture:gradient:colors" % path_to_node), + track_position, p2d.texture.gradient.colors) + _add_key_frame(undo_redo, animation, NodePath("%s:texture:gradient:offsets" % path_to_node), + track_position, p2d.texture.gradient.offsets) + _add_key_frame(undo_redo, animation, NodePath("%s:texture:fill_from" % path_to_node), + track_position, p2d.texture.fill_from) + _add_key_frame(undo_redo, animation, NodePath("%s:texture:fill_to" % path_to_node), + track_position, p2d.texture.fill_to) + + undo_redo.commit_action() + + +func _on_color_picker_button_toggled(toggled_on: bool) -> void: + if not is_instance_valid(scalable_vector_shape_2d.polygon): + return + var undo_redo = EditorInterface.get_editor_undo_redo() + if toggled_on: + undo_redo.create_action("Adjust Polygon2D color for %s" % str(scalable_vector_shape_2d)) + undo_redo.add_undo_property(scalable_vector_shape_2d.polygon, 'color', scalable_vector_shape_2d.polygon.color) + else: + undo_redo.add_do_property(scalable_vector_shape_2d.polygon, 'color', %ColorPickerButton.color) + undo_redo.commit_action(false) diff --git a/addons/curved_lines_2d/assign_fill_inspector_form.gd.uid b/addons/curved_lines_2d/assign_fill_inspector_form.gd.uid new file mode 100644 index 0000000..42c2b5c --- /dev/null +++ b/addons/curved_lines_2d/assign_fill_inspector_form.gd.uid @@ -0,0 +1 @@ +uid://b1ii4843yuwkw diff --git a/addons/curved_lines_2d/assign_fill_inspector_form.tscn b/addons/curved_lines_2d/assign_fill_inspector_form.tscn new file mode 100644 index 0000000..ae800f9 --- /dev/null +++ b/addons/curved_lines_2d/assign_fill_inspector_form.tscn @@ -0,0 +1,253 @@ +[gd_scene load_steps=11 format=3 uid="uid://53oqf8j7uyuu"] + +[ext_resource type="Script" uid="uid://b1ii4843yuwkw" path="res://addons/curved_lines_2d/assign_fill_inspector_form.gd" id="1_ogtsd"] +[ext_resource type="StyleBox" uid="uid://v0ueesjbdyrk" path="res://addons/curved_lines_2d/snazzy_toggle_button.stylebox" id="3_alhox"] +[ext_resource type="Texture2D" uid="uid://31qakec1dm6y" path="res://addons/curved_lines_2d/Key.svg" id="3_d26vq"] +[ext_resource type="Texture2D" uid="uid://caqsvv6rdxkm4" path="res://addons/curved_lines_2d/Gradients.svg" id="4_d26vq"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ogtsd"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0823529, 0.0941176, 0.117647, 1) + +[sub_resource type="ButtonGroup" id="ButtonGroup_6uned"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_7smxo"] +atlas = ExtResource("4_d26vq") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_j40rh"] +atlas = ExtResource("4_d26vq") +region = Rect2(32, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_7rdpo"] +atlas = ExtResource("4_d26vq") +region = Rect2(65, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_alhox"] +atlas = ExtResource("4_d26vq") +region = Rect2(96, 0, 32, 32) + +[node name="AssignFillInspectorForm" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_ogtsd") + +[node name="FillColorFieldContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label" type="Label" parent="FillColorFieldContainer"] +clip_contents = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will set the color of the assigned Polygon2D." +mouse_filter = 0 +text = "Fill Color*" + +[node name="HBoxContainer" type="HBoxContainer" parent="FillColorFieldContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="ColorPickerButton" type="ColorPickerButton" parent="FillColorFieldContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will set the color of the assigned Polygon2D." +theme_override_styles/normal = SubResource("StyleBoxFlat_ogtsd") +text = "Fill" +color = Color(1, 1, 1, 1) + +[node name="AddFillKeyFrameButton" type="Button" parent="FillColorFieldContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Add key frame for Polygon2D's color property" +icon = ExtResource("3_d26vq") + +[node name="GradientFieldContainer" type="HBoxContainer" parent="."] +unique_name_in_owner = true +layout_mode = 2 + +[node name="Label" type="Label" parent="GradientFieldContainer"] +clip_contents = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "- This will change set the texture of the Polygon2D to a GradientTexture2D. +- If the Polygon2D already has an active texture, it will be replaced." +mouse_filter = 0 +text = "Gradient*" + +[node name="HBoxContainer" type="HBoxContainer" parent="GradientFieldContainer"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="RemoveGradientToggleButton" type="Button" parent="GradientFieldContainer/HBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Remove texture of the Polygon2D" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("3_alhox") +toggle_mode = true +button_pressed = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_6uned") +icon = SubResource("AtlasTexture_7smxo") + +[node name="LinearGradientToggleButton" type="Button" parent="GradientFieldContainer/HBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Set the texture of the Polygon2D to a Linear Gradient" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("3_alhox") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_6uned") +icon = SubResource("AtlasTexture_j40rh") + +[node name="RadialGradientToggleButton" type="Button" parent="GradientFieldContainer/HBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Set the texture of the Polygon2D to a Radial Gradient" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("3_alhox") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_6uned") +icon = SubResource("AtlasTexture_7rdpo") + +[node name="OtherTextureToggleButton" type="Button" parent="GradientFieldContainer/HBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This disabled toggle is active if another type of texture is applied to the Polygon2D" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("3_alhox") +disabled = true +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_6uned") +icon = SubResource("AtlasTexture_alhox") + +[node name="GradientStopColorButtonContainer" type="HBoxContainer" parent="."] +unique_name_in_owner = true +layout_mode = 2 + +[node name="Label" type="Label" parent="GradientStopColorButtonContainer"] +clip_contents = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +tooltip_text = "- Change the stop colors of the gradient +- To add or remove color-stops, use the guide and handles in the 2D Viewport +- Or click the `Edit Polgyon2D` button below and use the built-in texture editor" +mouse_filter = 0 +text = "Stop Colors*" + +[node name="HBoxContainer" type="HBoxContainer" parent="GradientStopColorButtonContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="StopColorButtonsContainer" type="HFlowContainer" parent="GradientStopColorButtonContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 40) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="BatchInsertGradientKeyFrameButton" type="Button" parent="GradientStopColorButtonContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 4 +tooltip_text = "Pressing this button will add key frames for all aspects* of the GradientTexture2D on the Polygon2D: +- The start- and end position +- The stop colors +- The stop positions of the colors + +* For more refined control, use the inspector foe the assigned Polygon2D node" +icon = ExtResource("3_d26vq") + +[node name="ButtonContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="ButtonContainer"] +clip_contents = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will create a new Polygon2D node and assign it to the polygon property of this ScalableVectorScape2D." +mouse_filter = 0 +text = "Add Fill*" + +[node name="CreateFillButton" type="Button" parent="ButtonContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 2 +tooltip_text = "This will create a new Polygon2D node and assign it to the polygon property of this ScalableVectorScape2D." +text = "Add Fill" + +[node name="HSeparator" type="HSeparator" parent="."] +layout_mode = 2 + +[node name="ButtonContainer2" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="ButtonContainer2"] +clip_contents = true +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Click on this button to select the Polygon2D node that is assigned to this shape in the Scene Tree. + +Use this for advanced features which are already built-in into godot, like gradients and repeating textures." +mouse_filter = 0 +text = "Edit Polygon2D *" + +[node name="GotoPolygon2DButton" type="Button" parent="ButtonContainer2"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 2 +tooltip_text = "Click on this button to select the Polygon2D node that is assigned to this shape in the Scene Tree. + +Use this for advanced features which are already built-in into godot, like gradients and repeating textures." +text = "Edit Polygon2D" + +[connection signal="color_changed" from="FillColorFieldContainer/HBoxContainer/ColorPickerButton" to="." method="_on_color_picker_button_color_changed"] +[connection signal="toggled" from="FillColorFieldContainer/HBoxContainer/ColorPickerButton" to="." method="_on_color_picker_button_toggled"] +[connection signal="pressed" from="FillColorFieldContainer/HBoxContainer/AddFillKeyFrameButton" to="." method="_on_add_fill_key_frame_button_pressed"] +[connection signal="button_down" from="GradientFieldContainer/HBoxContainer/RemoveGradientToggleButton" to="." method="_on_remove_gradient_toggle_button_button_down"] +[connection signal="button_down" from="GradientFieldContainer/HBoxContainer/LinearGradientToggleButton" to="." method="_on_linear_gradient_toggle_button_button_down"] +[connection signal="button_down" from="GradientFieldContainer/HBoxContainer/RadialGradientToggleButton" to="." method="_on_radial_gradient_toggle_button_button_down"] +[connection signal="pressed" from="GradientStopColorButtonContainer/HBoxContainer/BatchInsertGradientKeyFrameButton" to="." method="_on_batch_insert_gradient_key_frame_button_pressed"] +[connection signal="pressed" from="ButtonContainer/CreateFillButton" to="." method="_on_create_fill_button_pressed"] +[connection signal="pressed" from="ButtonContainer2/GotoPolygon2DButton" to="." method="_on_goto_polygon_2d_button_pressed"] diff --git a/addons/curved_lines_2d/assign_navigation_region_inspector_form.gd b/addons/curved_lines_2d/assign_navigation_region_inspector_form.gd new file mode 100644 index 0000000..6710617 --- /dev/null +++ b/addons/curved_lines_2d/assign_navigation_region_inspector_form.gd @@ -0,0 +1,47 @@ +@tool +extends Control + +var scalable_vector_shape_2d : ScalableVectorShape2D + +func _enter_tree() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if 'assigned_node_changed' in scalable_vector_shape_2d: + scalable_vector_shape_2d.assigned_node_changed.connect(_on_svs_assignment_changed) + _on_svs_assignment_changed() + + +func _on_svs_assignment_changed() -> void: + if is_instance_valid(scalable_vector_shape_2d.navigation_region): + %GoToNavigationRegionButton.show() + %AddNavigationRegionButton.hide() + else: + %GoToNavigationRegionButton.hide() + %AddNavigationRegionButton.show() + + +func _on_add_navigation_region_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + + var new_obj := NavigationRegion2D.new() + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Add NavigationRegion2D to %s " % str(scalable_vector_shape_2d)) + undo_redo.add_do_method(scalable_vector_shape_2d, 'add_child', new_obj, true) + if scalable_vector_shape_2d == EditorInterface.get_edited_scene_root(): + undo_redo.add_do_method(new_obj, 'set_owner', scalable_vector_shape_2d) + else: + undo_redo.add_do_method(new_obj, 'set_owner', scalable_vector_shape_2d.owner) + undo_redo.add_do_reference(new_obj) + undo_redo.add_do_property(scalable_vector_shape_2d, 'navigation_region', new_obj) + undo_redo.add_undo_method(scalable_vector_shape_2d, 'remove_child', new_obj) + undo_redo.add_undo_property(scalable_vector_shape_2d, 'navigation_region', null) + undo_redo.commit_action() + + +func _on_go_to_navigation_region_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.navigation_region): + return + EditorInterface.call_deferred('edit_node', scalable_vector_shape_2d.navigation_region) diff --git a/addons/curved_lines_2d/assign_navigation_region_inspector_form.gd.uid b/addons/curved_lines_2d/assign_navigation_region_inspector_form.gd.uid new file mode 100644 index 0000000..920bf99 --- /dev/null +++ b/addons/curved_lines_2d/assign_navigation_region_inspector_form.gd.uid @@ -0,0 +1 @@ +uid://dsfcnewvnijjx diff --git a/addons/curved_lines_2d/assign_navigation_region_inspector_form.tscn b/addons/curved_lines_2d/assign_navigation_region_inspector_form.tscn new file mode 100644 index 0000000..f1cfe5e --- /dev/null +++ b/addons/curved_lines_2d/assign_navigation_region_inspector_form.tscn @@ -0,0 +1,38 @@ +[gd_scene load_steps=2 format=3 uid="uid://eo53xo3ylo1a"] + +[ext_resource type="Script" uid="uid://dsfcnewvnijjx" path="res://addons/curved_lines_2d/assign_navigation_region_inspector_form.gd" id="1_opyos"] + +[node name="AssignNavigationRegionInspectorForm" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_opyos") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Creates and assigns a NavigationRegion2D to this shape." +mouse_filter = 0 +text = "Navigation Region *" + +[node name="AddNavigationRegionButton" type="Button" parent="HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "Add" + +[node name="GoToNavigationRegionButton" type="Button" parent="HBoxContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +text = "Go To Node" + +[connection signal="pressed" from="HBoxContainer/AddNavigationRegionButton" to="." method="_on_add_navigation_region_button_pressed"] +[connection signal="pressed" from="HBoxContainer/GoToNavigationRegionButton" to="." method="_on_go_to_navigation_region_button_pressed"] diff --git a/addons/curved_lines_2d/assign_stroke_inspector_form.gd b/addons/curved_lines_2d/assign_stroke_inspector_form.gd new file mode 100644 index 0000000..fbfdbf9 --- /dev/null +++ b/addons/curved_lines_2d/assign_stroke_inspector_form.gd @@ -0,0 +1,106 @@ +@tool +extends Control + +var scalable_vector_shape_2d : ScalableVectorShape2D + + +func _enter_tree() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if 'assigned_node_changed' in scalable_vector_shape_2d: + scalable_vector_shape_2d.assigned_node_changed.connect(_on_svs_assignment_changed) + _on_svs_assignment_changed() + + +func _on_svs_assignment_changed() -> void: + if is_instance_valid(scalable_vector_shape_2d.line): + %CreateStrokeButton.get_parent().hide() + %GotoLine2DButton.get_parent().show() + %CreateStrokeButton.disabled = true + %GotoLine2DButton.disabled = false + else: + %CreateStrokeButton.get_parent().show() + %GotoLine2DButton.get_parent().hide() + %CreateStrokeButton.disabled = false + %GotoLine2DButton.disabled = true + + if is_instance_valid(scalable_vector_shape_2d.poly_stroke): + %CreatePolyStrokeButton.get_parent().hide() + %GotoPolygon2DButton.get_parent().show() + %CreatePolyStrokeButton.disabled = true + %GotoPolygon2DButton.disabled = false + else: + %CreatePolyStrokeButton.get_parent().show() + %GotoPolygon2DButton.get_parent().hide() + %CreatePolyStrokeButton.disabled = false + %GotoPolygon2DButton.disabled = true + + +func _on_goto_line_2d_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.line): + return + EditorInterface.call_deferred('edit_node', scalable_vector_shape_2d.line) + + +func _on_goto_polygon_2d_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if not is_instance_valid(scalable_vector_shape_2d.poly_stroke): + return + EditorInterface.call_deferred('edit_node', scalable_vector_shape_2d.poly_stroke) + + +func _on_create_stroke_button_pressed(): + if not is_instance_valid(scalable_vector_shape_2d): + return + if is_instance_valid(scalable_vector_shape_2d.line): + return + + var line_2d := Line2D.new() + var root := EditorInterface.get_edited_scene_root() + var undo_redo = EditorInterface.get_editor_undo_redo() + line_2d.name = "Stroke" + line_2d.default_color = scalable_vector_shape_2d.stroke_color + line_2d.width = scalable_vector_shape_2d.stroke_width + line_2d.begin_cap_mode = scalable_vector_shape_2d.begin_cap_mode + line_2d.end_cap_mode = scalable_vector_shape_2d.end_cap_mode + line_2d.joint_mode = scalable_vector_shape_2d.line_joint_mode + line_2d.sharp_limit = 90.0 + if CurvedLines2D._use_antialiased_line_2d(): + line_2d.texture = load("res://addons/curved_lines_2d/LumAlpha8.tex") + line_2d.texture_mode = Line2D.LINE_TEXTURE_TILE + line_2d.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC + + undo_redo.create_action("Add Line2D to %s " % str(scalable_vector_shape_2d)) + undo_redo.add_do_method(scalable_vector_shape_2d, 'add_child', line_2d, true) + undo_redo.add_do_method(line_2d, 'set_owner', root) + undo_redo.add_do_reference(line_2d) + undo_redo.add_do_property(scalable_vector_shape_2d, 'line', line_2d) + undo_redo.add_undo_method(scalable_vector_shape_2d, 'remove_child', line_2d) + undo_redo.add_undo_property(scalable_vector_shape_2d, 'line', null) + undo_redo.commit_action() + + + +func _on_create_poly_stroke_button_pressed() -> void: + if not is_instance_valid(scalable_vector_shape_2d): + return + if is_instance_valid(scalable_vector_shape_2d.poly_stroke): + return + + var poly_stroke := Polygon2D.new() + var root := EditorInterface.get_edited_scene_root() + var undo_redo = EditorInterface.get_editor_undo_redo() + poly_stroke.name = "PolyStroke" + poly_stroke.color = scalable_vector_shape_2d.stroke_color + + undo_redo.create_action("Add Polygon2D for Stroke to %s " % str(scalable_vector_shape_2d)) + undo_redo.add_do_method(scalable_vector_shape_2d, 'add_child', poly_stroke, true) + undo_redo.add_do_method(poly_stroke, 'set_owner', root) + undo_redo.add_do_reference(poly_stroke) + undo_redo.add_do_property(scalable_vector_shape_2d, 'poly_stroke', poly_stroke) + undo_redo.add_undo_method(scalable_vector_shape_2d, 'remove_child', poly_stroke) + undo_redo.add_undo_property(scalable_vector_shape_2d, 'poly_stroke', null) + undo_redo.commit_action() diff --git a/addons/curved_lines_2d/assign_stroke_inspector_form.gd.uid b/addons/curved_lines_2d/assign_stroke_inspector_form.gd.uid new file mode 100644 index 0000000..2f5df2e --- /dev/null +++ b/addons/curved_lines_2d/assign_stroke_inspector_form.gd.uid @@ -0,0 +1 @@ +uid://bv0hffvudv51d diff --git a/addons/curved_lines_2d/assign_stroke_inspector_form.tscn b/addons/curved_lines_2d/assign_stroke_inspector_form.tscn new file mode 100644 index 0000000..e35b6fd --- /dev/null +++ b/addons/curved_lines_2d/assign_stroke_inspector_form.tscn @@ -0,0 +1,107 @@ +[gd_scene load_steps=2 format=3 uid="uid://bm31gemem22uc"] + +[ext_resource type="Script" uid="uid://bv0hffvudv51d" path="res://addons/curved_lines_2d/assign_stroke_inspector_form.gd" id="1_j8wjx"] + +[node name="AssignStrokeInspectorForm" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_j8wjx") + +[node name="ButtonContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="ButtonContainer"] +clip_contents = true +custom_minimum_size = Vector2(140, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will create a new Line2D node and assign it to the line property of this ScalableVectorScape2D." +mouse_filter = 0 +text = "Add Line2D Stroke *" + +[node name="CreateStrokeButton" type="Button" parent="ButtonContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 2 +tooltip_text = "This will create a new Line2D node and assign it to the line property of this ScalableVectorScape2D." +text = "Add Line2D Stroke" + +[node name="HBoxContainer" type="HBoxContainer" parent="ButtonContainer"] +layout_mode = 2 + +[node name="ButtonContainer3" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="ButtonContainer3"] +clip_contents = true +custom_minimum_size = Vector2(140, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will create a new Polygon2D node and assign it to the poly_stroke property of this ScalableVectorScape2D." +mouse_filter = 0 +text = "Add Polygon2D Stroke *" + +[node name="CreatePolyStrokeButton" type="Button" parent="ButtonContainer3"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 2 +tooltip_text = "This will create a new Polygon2D node and assign it to the poly_stroke property of this ScalableVectorScape2D." +text = "Add Polygon2D Stroke" + +[node name="HBoxContainer" type="HBoxContainer" parent="ButtonContainer3"] +layout_mode = 2 + +[node name="HSeparator" type="HSeparator" parent="."] +layout_mode = 2 + +[node name="ButtonContainer2" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="ButtonContainer2"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Click on this button to select the Line2D node that is assigned to this shape in the Scene Tree. + +Use this for advanced features which are already built-in into godot, like gradients, width curvature, and repeating textures." +mouse_filter = 0 +text = "Edit Line2D *" + +[node name="GotoLine2DButton" type="Button" parent="ButtonContainer2"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 2 +tooltip_text = "Click on this button to select the Line2D node that is assigned to this shape in the Scene Tree. + +Use this for advanced features which are already built-in into godot, like gradients, width curvature, and repeating textures." +text = "Edit Line2D" + +[node name="ButtonContainer4" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label2" type="Label" parent="ButtonContainer4"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Click on this button to select the Polygon2D node that is assigned to this shape in the Scene Tree. + +Use this for advanced features which are already built-in into godot, like image textures." +mouse_filter = 0 +text = "Edit Polygon2D *" + +[node name="GotoPolygon2DButton" type="Button" parent="ButtonContainer4"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 2 +tooltip_text = "Click on this button to select the Polygon2D node that is assigned to this shape in the Scene Tree. + +Use this for advanced features which are already built-in into godot, like image textures." +text = "Edit Polygon2D" + +[connection signal="pressed" from="ButtonContainer/CreateStrokeButton" to="." method="_on_create_stroke_button_pressed"] +[connection signal="pressed" from="ButtonContainer3/CreatePolyStrokeButton" to="." method="_on_create_poly_stroke_button_pressed"] +[connection signal="pressed" from="ButtonContainer2/GotoLine2DButton" to="." method="_on_goto_line_2d_button_pressed"] +[connection signal="pressed" from="ButtonContainer4/GotoPolygon2DButton" to="." method="_on_goto_polygon_2d_button_pressed"] diff --git a/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.gd b/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.gd new file mode 100644 index 0000000..c07c7a5 --- /dev/null +++ b/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.gd @@ -0,0 +1,48 @@ +@tool +extends KeyframeButtonCapableInspectorFormBase + +var scalable_vector_shape_2d : ScalableVectorShape2D + +func _enter_tree() -> void: + _initialize_keyframe_capabilities() + + +func _on_key_frame_capabilities_changed() -> void: + if _is_key_frame_capable(): + %BatchInsertButton.disabled = false + else: + %BatchInsertButton.disabled = true + + +func _on_batch_insert_button_pressed() -> void: + var animation_name := animation_under_edit_button.get_item_text(animation_under_edit_button.get_selected_id()) + var animation_player := _find_animation_player(animation_name) + var animation := _guarded_get_animation(animation_player) + var path_to_node := _guarded_get_path_to_node(animation_player, scalable_vector_shape_2d) + var track_position := _guarded_get_track_position() + if not animation: + return + if path_to_node.is_empty(): + return + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Batch insert curve keyframes for %s on animation %s" % [str(scalable_vector_shape_2d), str(animation)]) + for p_idx in range(scalable_vector_shape_2d.curve.point_count): + _add_key_frame(undo_redo, animation, NodePath("%s:curve:point_%d/position" % [path_to_node, p_idx]), + track_position, scalable_vector_shape_2d.curve.get_point_position(p_idx)) + if p_idx > 0: + _add_key_frame(undo_redo, animation, NodePath("%s:curve:point_%d/in" % [path_to_node, p_idx]), + track_position, scalable_vector_shape_2d.curve.get_point_in(p_idx)) + if p_idx < scalable_vector_shape_2d.curve.point_count - 1: + _add_key_frame(undo_redo, animation, NodePath("%s:curve:point_%d/out" % [path_to_node, p_idx]), + track_position, scalable_vector_shape_2d.curve.get_point_out(p_idx)) + for a_idx in scalable_vector_shape_2d.arc_list.arcs.size(): + _add_key_frame(undo_redo, animation, NodePath("%s:arc_list:arc_%d/radius" % [path_to_node, a_idx]), + track_position, scalable_vector_shape_2d.arc_list.arcs[a_idx].radius) + _add_key_frame(undo_redo, animation, NodePath("%s:arc_list:arc_%d/rotation_deg" % [path_to_node, a_idx]), + track_position, scalable_vector_shape_2d.arc_list.arcs[a_idx].rotation_deg) + _add_key_frame(undo_redo, animation, NodePath("%s:arc_list:arc_%d/large_arc_flag" % [path_to_node, a_idx]), + track_position, scalable_vector_shape_2d.arc_list.arcs[a_idx].large_arc_flag) + _add_key_frame(undo_redo, animation, NodePath("%s:arc_list:arc_%d/sweep_flag" % [path_to_node, a_idx]), + track_position, scalable_vector_shape_2d.arc_list.arcs[a_idx].sweep_flag) + + undo_redo.commit_action() diff --git a/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.gd.uid b/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.gd.uid new file mode 100644 index 0000000..ada9695 --- /dev/null +++ b/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.gd.uid @@ -0,0 +1 @@ +uid://cm4sio0ryplts diff --git a/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.tscn b/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.tscn new file mode 100644 index 0000000..76a50d7 --- /dev/null +++ b/addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=3 format=3 uid="uid://cb72od43gg2ew"] + +[ext_resource type="Script" uid="uid://cm4sio0ryplts" path="res://addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.gd" id="1_65iy1"] +[ext_resource type="Texture2D" uid="uid://31qakec1dm6y" path="res://addons/curved_lines_2d/Key.svg" id="2_2yrvp"] + +[node name="BatchInsertCurvePointKeyFramesInspectorForm" type="VBoxContainer"] +anchors_preset = 14 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +offset_top = -15.5 +offset_bottom = 42.5 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_65iy1") + +[node name="HSeparator2" type="HSeparator" parent="."] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "- Clicking this button will insert key frames for all the curve points and control points at the current animation postion for all their property tracks +- When a track for a certain point, or control point is not found based on its relative it will newly be created +- Be aware that removing points or control points that are referenced in an animation track will cause warnings" +mouse_filter = 0 +text = "Insert key frames*" + +[node name="BatchInsertButton" type="Button" parent="HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "- Clicking this button will insert key frames for all the curve points and control points at the current animation postion for all their property tracks +- When a track for a certain point, or control point is not found based on its relative it will newly be created +- Be aware that removing points or control points that are referenced in an animation track will cause warnings" +disabled = true +text = "Batch insert" +icon = ExtResource("2_2yrvp") + +[node name="HSeparator" type="HSeparator" parent="."] +layout_mode = 2 + +[connection signal="pressed" from="HBoxContainer/BatchInsertButton" to="." method="_on_batch_insert_button_pressed"] diff --git a/addons/curved_lines_2d/closest_point_on_curve_meta.gd b/addons/curved_lines_2d/closest_point_on_curve_meta.gd new file mode 100644 index 0000000..e3e220a --- /dev/null +++ b/addons/curved_lines_2d/closest_point_on_curve_meta.gd @@ -0,0 +1,20 @@ +@tool +extends Object +class_name ClosestPointOnCurveMeta +var before_segment : int +var point_position : Vector2 +var local_point_position : Vector2 + +func _init(bs : int = 0, pp := Vector2.ZERO , lpp := Vector2.ZERO): + before_segment = bs + point_position = pp + local_point_position = lpp + + +func _to_string() -> String: + return ( + "ClosestPointOnCurveMeta(before_segment: " + str(before_segment) + + ", point_position: " + str(point_position) + + ", local_point_position: " + str(local_point_position) + + ")" + ) diff --git a/addons/curved_lines_2d/closest_point_on_curve_meta.gd.uid b/addons/curved_lines_2d/closest_point_on_curve_meta.gd.uid new file mode 100644 index 0000000..5ee5554 --- /dev/null +++ b/addons/curved_lines_2d/closest_point_on_curve_meta.gd.uid @@ -0,0 +1 @@ +uid://b5xapyc6rm4ew diff --git a/addons/curved_lines_2d/collision_object_type_option_button.gd b/addons/curved_lines_2d/collision_object_type_option_button.gd new file mode 100644 index 0000000..38762c5 --- /dev/null +++ b/addons/curved_lines_2d/collision_object_type_option_button.gd @@ -0,0 +1,8 @@ +@tool +extends OptionButton + +signal type_selected(obj_type : ScalableVectorShape2D.CollisionObjectType) + + +func _on_item_selected(index: int) -> void: + type_selected.emit(index) diff --git a/addons/curved_lines_2d/collision_object_type_option_button.gd.uid b/addons/curved_lines_2d/collision_object_type_option_button.gd.uid new file mode 100644 index 0000000..df6ae28 --- /dev/null +++ b/addons/curved_lines_2d/collision_object_type_option_button.gd.uid @@ -0,0 +1 @@ +uid://ppu1camg8q83 diff --git a/addons/curved_lines_2d/collision_object_type_option_button.tscn b/addons/curved_lines_2d/collision_object_type_option_button.tscn new file mode 100644 index 0000000..2f7a9e2 --- /dev/null +++ b/addons/curved_lines_2d/collision_object_type_option_button.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=2 format=3 uid="uid://cjbkvx1pj7gq2"] + +[ext_resource type="Script" uid="uid://ppu1camg8q83" path="res://addons/curved_lines_2d/collision_object_type_option_button.gd" id="1_cky2p"] + +[node name="CollisionObjectTypeOptionButton" type="OptionButton"] +selected = 0 +item_count = 7 +popup/item_0/text = "- No Collision -" +popup/item_0/id = 0 +popup/item_1/text = "StaticBody2D" +popup/item_1/id = 1 +popup/item_2/text = "Area2D" +popup/item_2/id = 2 +popup/item_3/text = "AnimatableBody2D" +popup/item_3/id = 3 +popup/item_4/text = "RigidBody2D" +popup/item_4/id = 4 +popup/item_5/text = "CharacterBody2D" +popup/item_5/id = 5 +popup/item_6/text = "PhysicalBone2D" +popup/item_6/id = 6 +script = ExtResource("1_cky2p") + +[connection signal="item_selected" from="." to="." method="_on_item_selected"] diff --git a/addons/curved_lines_2d/curved_lines_2d.gd b/addons/curved_lines_2d/curved_lines_2d.gd new file mode 100644 index 0000000..58bd775 --- /dev/null +++ b/addons/curved_lines_2d/curved_lines_2d.gd @@ -0,0 +1,2066 @@ +@tool +extends EditorPlugin + +class_name CurvedLines2D + +const SETTING_NAME_EDITING_ENABLED := "addons/curved_lines_2d/editing_enabled" +const SETTING_NAME_HINTS_ENABLED := "addons/curved_lines_2d/hints_enabled" +const SETTING_NAME_SHOW_POINT_NUMBERS := "addons/curved_lines_2d/show_point_numbers" +const SETTING_NAME_STROKE_WIDTH := "addons/curved_lines_2d/stroke_width" +const SETTING_NAME_STROKE_COLOR := "addons/curved_lines_2d/stroke_color" +const SETTING_NAME_USE_LINE_2D_FOR_STROKE = "addons/curved_lines_2d/use_line_2d_for_stroke" +const SETTING_NAME_FILL_COLOR := "addons/curved_lines_2d/fill_color" +const SETTING_NAME_ADD_STROKE_ENABLED := "addons/curved_lines_2d/add_stroke_enabled" +const SETTING_NAME_ADD_FILL_ENABLED := "addons/curved_lines_2d/add_fill_enabled" +const SETTING_NAME_ADD_COLLISION_TYPE = "addons/curved_lines_2d/add_collision_type" + +const SETTING_NAME_PAINT_ORDER := "addons/curved_lines_2d/paint_order" +const SETTING_NAME_DEFAULT_LINE_BEGIN_CAP := "addons/curved_lines_2d/line_begin_cap" +const SETTING_NAME_DEFAULT_LINE_END_CAP := "addons/curved_lines_2d/line_end_cap" +const SETTING_NAME_DEFAULT_LINE_JOINT_MODE := "addons/curved_lines_2d/line_joint_mode" +const SETTING_NAME_SNAP_TO_PIXEL := "addons/curved_lines_2d/snap_to_pixel" +const SETTING_NAME_SNAP_RESOLUTION := "addons/curved_lines_2d/snap_resolution" + +const SETTING_NAME_CURVE_UPDATE_CURVE_AT_RUNTIME := "addons/curved_lines_2d/update_curve_at_runtime" +const SETTING_NAME_CURVE_RESOURCE_LOCAL_TO_SCENE := "addons/curved_lines_2d/make_resources_local_to_scene" +const SETTING_NAME_CURVE_TOLERANCE_DEGREES := "addons/curved_lines_2d/default_tolerance_degrees" +const SETTING_NAME_CURVE_MAX_STAGES := "addons/curved_lines_2d/default_max_stages" + +const SETTING_NAME_ANTIALIASED_LINE_2D := "addons/curved_lines_2d/antialiased_line_2d" + +const META_NAME_HOVER_POINT_IDX := "_hover_point_idx_" +const META_NAME_HOVER_CP_IN_IDX := "_hover_cp_in_idx_" +const META_NAME_HOVER_CP_OUT_IDX := "_hover_cp_out_idx_" +const META_NAME_HOVER_CLOSEST_POINT := "_hover_closest_point_on_curve_" +const META_NAME_HOVER_GRADIENT_FROM := "_hover_gradient_from_" +const META_NAME_HOVER_GRADIENT_TO := "_hover_gradient_to_" +const META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX := "_hover_gradient_color_stop_idx_" +const META_NAME_HOVER_CLOSEST_POINT_ON_GRADIENT_LINE := "_hover_closest_point_on_gradient_" + +const META_NAME_SELECT_HINT := "_select_hint_" + +const VIEWPORT_ORANGE := Color(0.737, 0.463, 0.337) + +enum PaintOrder { + FILL_STROKE_MARKERS, + STROKE_FILL_MARKERS, + FILL_MARKERS_STROKE, + MARKERS_FILL_STROKE, + STROKE_MARKERS_FILL, + MARKERS_STROKE_FILL +} +enum UndoRedoEntry { UNDOS, DOS, NAME, DO_PROPS, UNDO_PROPS } + +const PAINT_ORDER_MAP := { + PaintOrder.FILL_STROKE_MARKERS: ['_add_fill_to_created_shape', '_add_stroke_to_created_shape', '_add_collision_to_created_shape'], + PaintOrder.STROKE_FILL_MARKERS: ['_add_stroke_to_created_shape', '_add_fill_to_created_shape', '_add_collision_to_created_shape'], + PaintOrder.FILL_MARKERS_STROKE: ['_add_fill_to_created_shape', '_add_collision_to_created_shape', '_add_stroke_to_created_shape'], + PaintOrder.MARKERS_FILL_STROKE: ['_add_collision_to_created_shape', '_add_fill_to_created_shape', '_add_stroke_to_created_shape'], + PaintOrder.STROKE_MARKERS_FILL: ['_add_stroke_to_created_shape', '_add_collision_to_created_shape', '_add_fill_to_created_shape'], + PaintOrder.MARKERS_STROKE_FILL: ['_add_collision_to_created_shape', '_add_stroke_to_created_shape', '_add_fill_to_created_shape'] +} +const SHAPE_NAME_MAP := { + ScalableVectorShape2D.ShapeType.RECT: "a rectangle", + ScalableVectorShape2D.ShapeType.ELLIPSE: "a circle", + ScalableVectorShape2D.ShapeType.PATH: "an empty shape" +} +const OPERATION_NAME_MAP := { + Geometry2D.OPERATION_DIFFERENCE: { "verb": "cut out", "noun": "cutout" }, + Geometry2D.OPERATION_INTERSECTION: { "verb": "clip off", "noun": "clip" }, + Geometry2D.OPERATION_UNION: { "verb": "merge with", "noun": "merged shape" } +} + +enum UniformTransformMode { NONE, TRANSLATE, ROTATE, SCALE } + +var plugin : Line2DGeneratorInspectorPlugin +var scalable_vector_shapes_2d_dock +var select_mode_button : Button +var undo_redo : EditorUndoRedoManager +var in_undo_redo_transaction := false +var shape_preview : Curve2D = null +var selection_candidate : Node = null +var current_cutout_shape := ScalableVectorShape2D.ShapeType.RECT +var current_clip_operation := Geometry2D.OPERATION_DIFFERENCE + +var undo_redo_transaction : Dictionary = { + UndoRedoEntry.NAME: "", + UndoRedoEntry.DOS: [], + UndoRedoEntry.UNDOS: [], + UndoRedoEntry.DO_PROPS: [], + UndoRedoEntry.UNDO_PROPS: [] +} + +var set_global_position_popup_panel : PopupPanel +var arc_settings_popup_panel : PopupPanel + +var _vp_horizontal_scrollbar_locked_value := 0.0 +var _locking_vp_horizontal_scrollbar := false + +var uniform_transform_edit_buttons : Control +var _uniform_transform_mode := UniformTransformMode.NONE +var _drag_start := Vector2.ZERO +var _prev_uniform_rotate_angle := 0.0 +var _stored_natural_center := Vector2.ZERO +var _lmb_is_down_inside_viewport := false + +var merge_node_toggle_button : Button +var _merge_box_rect := Rect2(Vector2.ZERO, Vector2.ZERO) + +func _enter_tree(): + scalable_vector_shapes_2d_dock = preload("res://addons/curved_lines_2d/scalable_vector_shapes_2d_dock.tscn").instantiate() + plugin = preload("res://addons/curved_lines_2d/line_2d_generator_inspector_plugin.gd").new() + add_inspector_plugin(plugin) + add_custom_type( + "DrawablePath2D", + "Path2D", + preload("res://addons/curved_lines_2d/drawable_path_2d.gd"), + preload("res://addons/curved_lines_2d/DrawablePath2D.svg") + ) + add_custom_type( + "ScalableVectorShape2D", + "Node2D", + preload("res://addons/curved_lines_2d/scalable_vector_shape_2d.gd"), + preload("res://addons/curved_lines_2d/DrawablePath2D.svg") + ) + add_custom_type( + "AdaptableVectorShape3D", + "Node3D", + preload("res://addons/curved_lines_2d/adaptable_vector_shape_3d.gd"), + preload("res://addons/curved_lines_2d/AdaptableVectorShape3D.svg") + ) + undo_redo = get_undo_redo() + add_control_to_bottom_panel(scalable_vector_shapes_2d_dock as Control, "Scalable Vector Shapes 2D") + EditorInterface.get_selection().selection_changed.connect(_on_selection_changed) + undo_redo.version_changed.connect(update_overlays) + make_bottom_panel_item_visible(scalable_vector_shapes_2d_dock) + + set_global_position_popup_panel = preload("res://addons/curved_lines_2d/set_global_position_popup_panel.tscn").instantiate() + arc_settings_popup_panel = preload("res://addons/curved_lines_2d/arc_settings_popup_panel.tscn").instantiate() + EditorInterface.get_base_control().add_child(set_global_position_popup_panel) + EditorInterface.get_base_control().add_child(arc_settings_popup_panel) + if not set_global_position_popup_panel.value_changed.is_connected(_on_global_position_for_handle_changed): + set_global_position_popup_panel.value_changed.connect(_on_global_position_for_handle_changed) + if not set_global_position_popup_panel.visibility_changed.is_connected(_commit_undo_redo_transaction): + set_global_position_popup_panel.visibility_changed.connect(_commit_undo_redo_transaction) + + if not scalable_vector_shapes_2d_dock.shape_created.is_connected(_on_shape_created): + scalable_vector_shapes_2d_dock.shape_created.connect(_on_shape_created) + if not scalable_vector_shapes_2d_dock.set_shape_preview.is_connected(_on_shape_preview): + scalable_vector_shapes_2d_dock.set_shape_preview.connect(_on_shape_preview) + if not scalable_vector_shapes_2d_dock.edit_tab.rect_created.is_connected(_on_rect_created): + scalable_vector_shapes_2d_dock.edit_tab.rect_created.connect(_on_rect_created) + if not scalable_vector_shapes_2d_dock.edit_tab.ellipse_created.is_connected(_on_ellipse_created): + scalable_vector_shapes_2d_dock.edit_tab.ellipse_created.connect(_on_ellipse_created) + scene_changed.connect(_on_scene_changed) + + uniform_transform_edit_buttons = load("res://addons/curved_lines_2d/uniform_transform_edit_buttons.tscn").instantiate() + var canvas_editor_buttons_container = EditorInterface.get_editor_viewport_2d().find_parent("*CanvasItemEditor*").find_child("*HFlowContainer*", true, false) + canvas_editor_buttons_container.add_child(uniform_transform_edit_buttons) + merge_node_toggle_button = Button.new() + merge_node_toggle_button.tooltip_text = "Merge vertices (M)" + merge_node_toggle_button.icon = load("res://addons/curved_lines_2d/MergeChain.svg") + merge_node_toggle_button.toggle_mode = true + merge_node_toggle_button.flat = true + merge_node_toggle_button.toggled.connect(_on_merge_node_toggle_button_toggled) + canvas_editor_buttons_container.add_child(merge_node_toggle_button) + + if not _get_select_mode_button().toggled.is_connected(_on_select_mode_toggled): + _get_select_mode_button().toggled.connect(_on_select_mode_toggled) + _on_select_mode_toggled(_get_select_mode_button().button_pressed) + uniform_transform_edit_buttons.mode_changed.connect(_on_uniform_transform_mode_changed) + uniform_transform_edit_buttons.flip_horizontal.connect(_flip_svs_horizontal) + uniform_transform_edit_buttons.flip_vertical.connect(_flip_svs_vertical) + + +func select_node_reversibly(target_node : Node) -> void: + if is_instance_valid(target_node): + EditorInterface.edit_node(target_node) + + +func _on_merge_node_toggle_button_toggled(toggled_on : bool) -> void: + _merge_box_rect.size = Vector2.ZERO + if not toggled_on: + return + var scene_root := EditorInterface.get_edited_scene_root() + if is_instance_valid(scene_root): + EditorInterface.edit_node(scene_root) + update_overlays() + + +func _on_select_mode_toggled(toggled_on : bool) -> void: + var current_selection := EditorInterface.get_selection().get_selected_nodes().pop_back() + if toggled_on and _is_svs_valid(current_selection): + uniform_transform_edit_buttons.enable() + merge_node_toggle_button.show() + elif toggled_on: + uniform_transform_edit_buttons.hide() + merge_node_toggle_button.show() + else: + uniform_transform_edit_buttons.hide() + merge_node_toggle_button.hide() + merge_node_toggle_button.button_pressed = false + + +func _on_uniform_transform_mode_changed(new_mode : UniformTransformMode) -> void: + _uniform_transform_mode = new_mode + update_overlays() + + +func _is_ctrl_or_cmd_pressed() -> bool: + return Input.is_key_pressed(KEY_CTRL) or Input.is_key_pressed(KEY_META) + + +func _on_shape_preview(curve : Curve2D): + shape_preview = curve + update_overlays() + + +func _on_rect_created(width : float, height : float, rx : float, ry : float, scene_root : Node) -> void: + var new_rect := ScalableVectorShape2D.new() + new_rect.shape_type = ScalableVectorShape2D.ShapeType.RECT + new_rect.size = Vector2(width, height) + new_rect.rx = rx + new_rect.ry = ry + _create_shape(new_rect, scene_root, "Rectangle") + + +func _on_ellipse_created(rx : float, ry : float, scene_root : Node) -> void: + var new_ellipse := ScalableVectorShape2D.new() + new_ellipse.shape_type = ScalableVectorShape2D.ShapeType.ELLIPSE + new_ellipse.size = Vector2(rx * 2, ry * 2) + _create_shape(new_ellipse, scene_root, "Ellipse") + + +func _on_shape_created(curve : Curve2D, scene_root : Node, node_name : String) -> void: + var new_shape := ScalableVectorShape2D.new() + new_shape.curve = curve + _create_shape(new_shape, scene_root, node_name) + + +func _create_shape(new_shape : ScalableVectorShape2D, scene_root : Node, node_name : String, is_cutout_for : ScalableVectorShape2D = null) -> void: + var current_selection := EditorInterface.get_selection().get_selected_nodes().pop_back() + var parent = current_selection if current_selection is Node else scene_root + new_shape.update_curve_at_runtime = _is_setting_update_curve_at_runtime() + new_shape.curve.resource_local_to_scene = _is_making_curve_resources_local_to_scene() + new_shape.arc_list.resource_local_to_scene = _is_making_curve_resources_local_to_scene() + new_shape.tolerance_degrees = _get_default_tolerance_degrees() + new_shape.max_stages = _get_default_max_stages() + new_shape.name = node_name + if not is_instance_valid(is_cutout_for): + new_shape.position = Vector2.ZERO + undo_redo.create_action("Add a %s to the scene " % node_name) + undo_redo.add_do_method(parent, 'add_child', new_shape, true) + undo_redo.add_do_method(new_shape, 'set_owner', scene_root) + undo_redo.add_do_reference(new_shape) + undo_redo.add_undo_method(parent, 'remove_child', new_shape) + if is_instance_valid(is_cutout_for): + var new_clip_paths := is_cutout_for.clip_paths.duplicate() + match current_clip_operation: + Geometry2D.OPERATION_UNION: + new_shape.use_union_in_stead_of_clipping = true + Geometry2D.OPERATION_INTERSECTION: + new_shape.use_interect_when_clipping = true + Geometry2D.OPERATION_DIFFERENCE: + new_shape.use_interect_when_clipping = false + new_shape.use_union_in_stead_of_clipping = false + new_clip_paths.append(new_shape) + undo_redo.add_do_property(is_cutout_for, 'clip_paths', new_clip_paths) + undo_redo.add_undo_property(is_cutout_for, 'clip_paths', is_cutout_for.clip_paths) + else: + for draw_fn in PAINT_ORDER_MAP[_get_default_paint_order()]: + call(draw_fn, new_shape, scene_root) + undo_redo.add_do_method(self, 'select_node_reversibly', new_shape) + undo_redo.add_undo_method(self, 'select_node_reversibly', parent) + undo_redo.commit_action() + new_shape.stroke_color = _get_default_stroke_color() + new_shape.stroke_width = _get_default_stroke_width() + new_shape.begin_cap_mode = _get_default_begin_cap() + new_shape.end_cap_mode = _get_default_end_cap() + new_shape.line_joint_mode = _get_default_joint_mode() + if not is_instance_valid(is_cutout_for): + _set_viewport_pos_to_selection() + + +func _create_svs_vertex_merge_2d() -> void: + var vertex_map := _find_merge_vertices() + if vertex_map.size() < 2: + return + var new_vertex_merge := SVSVertexMerge2D.new() + new_vertex_merge.name = "SVSVertexMerge2D" + var scene_root := EditorInterface.get_edited_scene_root() + var current_selection := EditorInterface.get_selection().get_selected_nodes().pop_back() + var parent = current_selection if current_selection is Node else scene_root + undo_redo.create_action("Add SVSVertexMerge2D") + undo_redo.add_do_method(parent, 'add_child', new_vertex_merge, true) + undo_redo.add_do_method(new_vertex_merge, 'set_owner', scene_root) + undo_redo.add_do_property(new_vertex_merge, "vertex_map", vertex_map) + undo_redo.add_undo_property(new_vertex_merge, "vertex_map", {}) + undo_redo.add_undo_method(new_vertex_merge, 'set_owner', null) + undo_redo.add_undo_method(parent, 'remove_child', new_vertex_merge) + for svs in vertex_map.keys(): + undo_redo.add_undo_property(svs, "curve", svs.curve.duplicate()) + undo_redo.commit_action() + + +func _add_fill_to_created_shape(new_shape : ScalableVectorShape2D, scene_root : Node) -> void: + if _is_add_fill_enabled(): + var polygon := Polygon2D.new() + polygon.name = "Fill" + polygon.color = _get_default_fill_color() + undo_redo.add_do_property(new_shape, 'polygon', polygon) + undo_redo.add_do_method(new_shape, 'add_child', polygon, true) + undo_redo.add_do_method(polygon, 'set_owner', scene_root) + undo_redo.add_do_reference(polygon) + undo_redo.add_undo_method(new_shape, 'remove_child', polygon) + + +func _add_stroke_to_created_shape(new_shape : ScalableVectorShape2D, scene_root : Node) -> void: + if _is_add_stroke_enabled(): + if _using_line_2d_for_stroke(): + var line := Line2D.new() + line.name = "Stroke" + line.sharp_limit = 90.0 + if CurvedLines2D._use_antialiased_line_2d(): + line.texture = load("res://addons/curved_lines_2d/LumAlpha8.tex") + line.texture_mode = Line2D.LINE_TEXTURE_TILE + line.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC + + undo_redo.add_do_property(new_shape, 'line', line) + undo_redo.add_do_method(new_shape, 'add_child', line, true) + undo_redo.add_do_method(line, 'set_owner', scene_root) + undo_redo.add_do_reference(line) + undo_redo.add_undo_method(new_shape, 'remove_child', line) + else: + var poly_stroke := Polygon2D.new() + poly_stroke.name = "Stroke" + undo_redo.add_do_property(new_shape, 'poly_stroke', poly_stroke) + undo_redo.add_do_method(new_shape, 'add_child', poly_stroke, true) + undo_redo.add_do_method(poly_stroke, 'set_owner', scene_root) + undo_redo.add_do_reference(poly_stroke) + undo_redo.add_undo_method(new_shape, 'remove_child', poly_stroke) + + +func _add_collision_to_created_shape(new_shape : ScalableVectorShape2D, scene_root : Node) -> void: + if _add_collision_object_type() != ScalableVectorShape2D.CollisionObjectType.NONE: + var collision : CollisionObject2D = null + match _add_collision_object_type(): + ScalableVectorShape2D.CollisionObjectType.STATIC_BODY_2D: + collision = StaticBody2D.new() + ScalableVectorShape2D.CollisionObjectType.AREA_2D: + collision = Area2D.new() + ScalableVectorShape2D.CollisionObjectType.ANIMATABLE_BODY_2D: + collision = AnimatableBody2D.new() + ScalableVectorShape2D.CollisionObjectType.RIGID_BODY_2D: + collision = RigidBody2D.new() + ScalableVectorShape2D.CollisionObjectType.CHARACTER_BODY_2D: + collision = CharacterBody2D.new() + ScalableVectorShape2D.CollisionObjectType.PHYSICAL_BONE_2D: + collision = PhysicalBone2D.new() + undo_redo.add_do_method(new_shape, 'add_child', collision, true) + undo_redo.add_do_reference(collision) + undo_redo.add_do_method(collision, 'set_owner', scene_root) + undo_redo.add_do_property(new_shape, 'collision_object', collision) + undo_redo.add_undo_method(new_shape, 'remove_child', collision) + +func _scene_can_export_animations() -> bool: + return (EditorInterface.get_edited_scene_root() is CanvasItem and + not EditorInterface.get_edited_scene_root().find_children("*", "AnimationPlayer").filter( + func(an): return an.owner == EditorInterface.get_edited_scene_root() + ).is_empty() and + not EditorInterface.get_edited_scene_root() + .find_children("*", "ScalableVectorShape2D").is_empty() + ) + +func _on_selection_changed(): + var scene_root := EditorInterface.get_edited_scene_root() + var current_selection := EditorInterface.get_selection().get_selected_nodes().pop_back() + if _is_editing_enabled() and is_instance_valid(scene_root): + # inelegant fix to always keep an instance of Node selected, so + # _forward_canvas_gui_input will still be called upon losing focus + if (not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) + and EditorInterface.get_selection().get_selected_nodes().is_empty()): + EditorInterface.edit_node(scene_root) + if current_selection is AnimationPlayer and _scene_can_export_animations(): + scalable_vector_shapes_2d_dock.set_selected_animation_player(current_selection) + _on_select_mode_toggled(_get_select_mode_button().button_pressed) + update_overlays() + + +func _on_scene_changed(scn : Node): + if _scene_can_export_animations(): + var anim_pl = scn.find_children("*", "AnimationPlayer").filter( + func(an): return an.owner == EditorInterface.get_edited_scene_root() + ).pop_back() + scalable_vector_shapes_2d_dock.set_selected_animation_player(anim_pl) + else: + scalable_vector_shapes_2d_dock.set_selected_animation_player(null) + + +func _handles(object: Object) -> bool: + return object is Node + + +func _find_scalable_vector_shape_2d_nodes() -> Array[Node]: + var scene_root := EditorInterface.get_edited_scene_root() + if is_instance_valid(scene_root): + var result := scene_root.find_children("*", "ScalableVectorShape2D") + if scene_root is ScalableVectorShape2D: + result.push_front(scene_root) + return result + return [] + + +func _find_scalable_vector_shape_2d_nodes_at(pos : Vector2) -> Array[Node]: + if is_instance_valid(EditorInterface.get_edited_scene_root()): + return (_find_scalable_vector_shape_2d_nodes() + .filter(func(x : ScalableVectorShape2D): return not x.has_meta("_edit_lock_")) + .filter(func(x : ScalableVectorShape2D): return x.is_visible_in_tree()) + .filter(func(x : ScalableVectorShape2D): return x.owner == EditorInterface.get_edited_scene_root()) + .filter(func(x : ScalableVectorShape2D): return x.has_point(pos)) + ) + return [] + + +func _is_change_pivot_button_active() -> bool: + var results = ( + EditorInterface.get_editor_viewport_2d().find_parent("*CanvasItemEditor*") + .find_children("*Button*", "", true, false) + ) + if results.size() >= 6: + return results[5].button_pressed + return false + + +func _get_select_mode_button() -> Button: + if is_instance_valid(select_mode_button): + return select_mode_button + else: + select_mode_button = ( + EditorInterface.get_editor_viewport_2d().find_parent("*CanvasItemEditor*") + .find_child("*Button*", true, false) + ) + return select_mode_button + + +func _get_viewport_center() -> Vector2: + var tr := EditorInterface.get_editor_viewport_2d().global_canvas_transform + var og := tr.get_origin() + var sz := Vector2(EditorInterface.get_editor_viewport_2d().size) + return (sz / 2) / tr.get_scale() - og / tr.get_scale() + + +func _set_viewport_pos_to_selection() -> void: + EditorInterface.get_editor_viewport_2d().get_parent().grab_focus() + var key_ev := InputEventKey.new() + key_ev.keycode = KEY_F + key_ev.pressed = true + Input.parse_input_event(key_ev) + + +func _vp_transform(p : Vector2) -> Vector2: + var s := EditorInterface.get_editor_viewport_2d().get_final_transform().get_scale() + var o := EditorInterface.get_editor_viewport_2d().get_final_transform().get_origin() + return (p * s) + o + + +func _is_svs_valid(svs : Object) -> bool: + return is_instance_valid(svs) and svs is ScalableVectorShape2D and svs.curve + + +func _get_hovered_handle_metadata(svs : ScalableVectorShape2D) -> Dictionary: + + if svs.has_meta(META_NAME_HOVER_POINT_IDX): + return { + 'global_pos': svs.to_global(svs.curve.get_point_position( + svs.get_meta(META_NAME_HOVER_POINT_IDX) + )), + 'meta_name': META_NAME_HOVER_POINT_IDX, + 'point_idx': svs.get_meta(META_NAME_HOVER_POINT_IDX) + } + elif svs.has_meta(META_NAME_HOVER_CP_IN_IDX): + return { + 'global_pos': svs.to_global(svs.curve.get_point_position( + svs.get_meta(META_NAME_HOVER_CP_IN_IDX) + ) + svs.curve.get_point_in( + svs.get_meta(META_NAME_HOVER_CP_IN_IDX) + )), + 'meta_name': META_NAME_HOVER_CP_IN_IDX, + 'point_idx': svs.get_meta(META_NAME_HOVER_CP_IN_IDX) + } + elif svs.has_meta(META_NAME_HOVER_CP_OUT_IDX): + return { + 'global_pos': svs.to_global(svs.curve.get_point_position( + svs.get_meta(META_NAME_HOVER_CP_OUT_IDX) + ) + svs.curve.get_point_out( + svs.get_meta(META_NAME_HOVER_CP_OUT_IDX) + )), + 'meta_name': META_NAME_HOVER_CP_OUT_IDX, + 'point_idx': svs.get_meta(META_NAME_HOVER_CP_OUT_IDX) + } + return {} + + +func _curve_control_has_hover(svs : ScalableVectorShape2D) -> bool: + return ( + svs.has_meta(META_NAME_HOVER_POINT_IDX) or + svs.has_meta(META_NAME_HOVER_CP_IN_IDX) or + svs.has_meta(META_NAME_HOVER_CP_OUT_IDX) + ) + + +func _handle_has_hover(svs : ScalableVectorShape2D) -> bool: + return ( + svs.has_meta(META_NAME_HOVER_POINT_IDX) or + svs.has_meta(META_NAME_HOVER_CP_IN_IDX) or + svs.has_meta(META_NAME_HOVER_CP_OUT_IDX) or + svs.has_meta(META_NAME_HOVER_GRADIENT_FROM) or + svs.has_meta(META_NAME_HOVER_GRADIENT_TO) or + svs.has_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX) + ) + + +func _draw_control_point_handle(viewport_control : Control, svs : ScalableVectorShape2D, + handle : Dictionary, prefix : String, is_hovered : bool, self_is_hovered : bool) -> String: + if handle[prefix].length(): + var color := VIEWPORT_ORANGE if is_hovered else Color.WHITE + var width := 2 if is_hovered else 1 + viewport_control.draw_line(_vp_transform(handle['point_position']), + _vp_transform(handle[prefix + '_position']), Color.WEB_GRAY, 1, true) + viewport_control.draw_circle(_vp_transform(handle[prefix + '_position']), 5, Color.DIM_GRAY) + viewport_control.draw_circle(_vp_transform(handle[prefix + '_position']), 5, color, false, width) + if self_is_hovered: + var hint_txt := "Control point " + prefix + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + hint_txt += "\n - Drag to move\n - Right click to delete" + hint_txt += "\n - Hold Shift + Drag to move mirrored" + if Input.is_key_pressed(KEY_ALT): + hint_txt += "\n - Click to set exact global position (Alt held)" + else: + hint_txt += "\n - Alt + Click to set exact global position" + return hint_txt + return "" + + +func _draw_rect_control_point_handle(viewport_control : Control, svs : ScalableVectorShape2D, + handle : Dictionary, prefix : String, is_hovered : bool) -> String: + var prop_name := "rx" if prefix == "in" else "ry" + var color := VIEWPORT_ORANGE if is_hovered else Color.WHITE + var width := 2 if is_hovered else 1 + viewport_control.draw_line( + _vp_transform(handle['top_left_pos']), + _vp_transform(handle[prefix + '_position']), Color.WEB_GRAY, 1, true) + viewport_control.draw_circle(_vp_transform(handle[prefix + '_position']), 5, Color.DIM_GRAY) + viewport_control.draw_circle(_vp_transform(handle[prefix + '_position']), 5, color, false, width) + if is_hovered: + var hint_txt := "Control point rounded corners " + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + var dir := "right / left" if prefix == 'in' else "up / down" + hint_txt += "\n - Drag %s to move \n - Right click to remove rounded corners" % dir + hint_txt += "\n - Hold Shift + Drag to drag only this handle" + return hint_txt + return "" + + +func _draw_hint(viewport_control : Control, txt : String, force_draw := false) -> void: + if set_global_position_popup_panel.visible: + return + if not _get_select_mode_button().button_pressed: + return + if not _are_hints_enabled() and not force_draw: + return + var txt_pos := (_vp_transform(EditorInterface.get_editor_viewport_2d().get_mouse_position()) + + Vector2(15, 8)) + var lines := txt.split("\n") + for i in range(lines.size()): + var text := lines[i] + var pos := txt_pos + Vector2.DOWN * (i * (ThemeDB.fallback_font_size + ThemeDB.fallback_font_size * .2)) + viewport_control.draw_string_outline(ThemeDB.fallback_font, pos, text, + HORIZONTAL_ALIGNMENT_LEFT, -1, ThemeDB.fallback_font_size, 3, Color.BLACK) + viewport_control.draw_string(ThemeDB.fallback_font, pos, text, + HORIZONTAL_ALIGNMENT_LEFT, -1, ThemeDB.fallback_font_size, Color.WHITE_SMOKE) + + +func _draw_point_number(viewport_control: Control, p : Vector2, text : String) -> void: + if not _am_showing_point_numbers(): + return + var pos := _vp_transform(p) + var width := 8 * (text.length() + 1) + viewport_control.draw_string_outline(ThemeDB.fallback_font, pos + + Vector2(-width, 6), text, + HORIZONTAL_ALIGNMENT_LEFT, width, ThemeDB.fallback_font_size, 3, Color.BLACK) + viewport_control.draw_string(ThemeDB.fallback_font, pos + Vector2(-width, 6), text, + HORIZONTAL_ALIGNMENT_LEFT, width, ThemeDB.fallback_font_size, Color.WHITE_SMOKE) + + +func _draw_handles(viewport_control : Control, svs : ScalableVectorShape2D) -> void: + if not _get_select_mode_button().button_pressed: + return + var hint_txt := "" + var point_txt := "" + var point_pos_txt := "" + var point_hint_pos := Vector2.ZERO + var handles = svs.get_curve_handles() + for i in range(handles.size()): + var handle = handles[i] + + var is_hovered : bool = svs.get_meta(META_NAME_HOVER_POINT_IDX, -1) == i + var cp_in_is_hovered : bool = svs.get_meta(META_NAME_HOVER_CP_IN_IDX, -1) == i + var cp_out_is_hovered : bool = svs.get_meta(META_NAME_HOVER_CP_OUT_IDX, -1) == i + var color := VIEWPORT_ORANGE if is_hovered else Color.WHITE + var width := 2 if is_hovered else 1 + if is_hovered: + point_pos_txt = "Global point position: (%.3f, %.3f)" % [handle["point_position"].x, handle["point_position"].y] + elif cp_in_is_hovered: + point_pos_txt = "Global curve handle position: (%.3f, %.3f)" % [handle["in_position"].x,handle["in_position"].y] + elif cp_out_is_hovered: + point_pos_txt = "Global curve handle position: (%.3f, %.3f)" % [handle["out_position"].x, handle["out_position"].y] + + if svs.shape_type == ScalableVectorShape2D.ShapeType.RECT: + hint_txt += _draw_rect_control_point_handle(viewport_control, svs, handle, 'in', + cp_in_is_hovered) + if handle['out'].length(): + hint_txt += _draw_rect_control_point_handle(viewport_control, svs, handle, 'out', + cp_out_is_hovered) + elif svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + if not svs.is_arc_start(i - 1): + hint_txt += _draw_control_point_handle(viewport_control, svs, handle, 'in', + is_hovered or cp_in_is_hovered, cp_in_is_hovered) + if not svs.is_arc_start(i): + hint_txt +=_draw_control_point_handle(viewport_control, svs, handle, 'out', + is_hovered or cp_out_is_hovered, cp_out_is_hovered) + + if handle['mirrored']: + # mirrored handles + var rect := Rect2(_vp_transform(handle['point_position']) - Vector2(5, 5), Vector2(10, 10)) + viewport_control.draw_rect(rect, Color.DIM_GRAY, .5) + viewport_control.draw_rect(rect, color, false, width) + else: + # unmirrored handles / zero length handles + var p1 := _vp_transform(handle['point_position']) + var pts := PackedVector2Array([ + Vector2(p1.x - 8, p1.y), Vector2(p1.x, p1.y - 8), + Vector2(p1.x + 8, p1.y), Vector2(p1.x, p1.y + 8) + ]) + viewport_control.draw_polygon(pts, [Color.DIM_GRAY]) + pts.append(Vector2(p1.x - 8, p1.y)) + viewport_control.draw_polyline(pts, color, width) + + if is_hovered: + if svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + point_txt = str(i) + handle['is_closed'] + point_hint_pos = handle['point_position'] + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + if Input.is_key_pressed(KEY_SHIFT) and svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + hint_txt += " - Release mouse to set curve handles" + else: + if svs.shape_type == ScalableVectorShape2D.ShapeType.RECT: + hint_txt += " - Drag to resize rectange" + elif svs.shape_type == ScalableVectorShape2D.ShapeType.ELLIPSE: + hint_txt += " - Drag to resize ellipse" + else: + hint_txt += " - Drag to move" + if handle['is_closed'].length() > 0: + hint_txt += "\n - Double click to break loop" + elif svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + hint_txt += "\n - Right click to delete" + if not svs.is_curve_closed() and ( + (i == 0 and handles.size() > 2) or + (i == handles.size() - 1 and i > 1) + ): + hint_txt += "\n - Double click to close loop" + if svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + hint_txt += "\n - Hold Shift + Drag to create curve handles" + if Input.is_key_pressed(KEY_ALT): + hint_txt += "\n - Click to set exact global position (Alt held)" + else: + hint_txt += "\n - Alt + Click to set exact global position" + + + var gradient_handles := svs.get_gradient_handles() + if not gradient_handles.is_empty(): + var p1 := _vp_transform(gradient_handles['fill_from_pos']) + var p2 := _vp_transform(gradient_handles['fill_to_pos']) + var hint_color := svs.shape_hint_color if svs.shape_hint_color else Color.LIME_GREEN + + if svs.has_meta(META_NAME_HOVER_GRADIENT_FROM): + hint_txt = "- Drag to move gradient start position" + viewport_control.draw_circle(p1, 16, hint_color) + viewport_control.draw_circle(p1, 12, Color.WHITE, false, 0.5, true) + if svs.has_meta(META_NAME_HOVER_GRADIENT_TO): + hint_txt = "- Drag to move gradient end position" + viewport_control.draw_circle(p2, 16, hint_color) + viewport_control.draw_circle(p2, 12, Color.WHITE, false, 0.5, true) + + for p : Vector2 in gradient_handles['stop_positions']: + viewport_control.draw_circle(_vp_transform(p) + Vector2(1,1), 5, Color(0.0,0.0,0.0, 0.4), true, -1, true) + + viewport_control.draw_line(p1, p2, hint_color, .5, true) + + for idx in range(gradient_handles['stop_positions'].size()): + var p := _vp_transform(gradient_handles['stop_positions'][idx]) + var color := (Color.WHITE + if svs.get_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX, -1) == idx + else Color.WEB_GRAY) + viewport_control.draw_circle(p, 5, gradient_handles["stop_colors"][idx]) + viewport_control.draw_circle(p, 5, color, false, 0.5, true) + + var p1_color := Color.WHITE if svs.has_meta(META_NAME_HOVER_GRADIENT_FROM) else hint_color + var p2_color := Color.WHITE if svs.has_meta(META_NAME_HOVER_GRADIENT_TO) else hint_color + _draw_crosshair(viewport_control, p1 , 8, 8, p1_color, 1) + _draw_crosshair(viewport_control, p2 , 8, 8, p2_color, 1) + if svs.has_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX): + hint_txt = "- Drag to move color stop\n- Right click to remove color stop" + if (svs.has_meta(META_NAME_HOVER_CLOSEST_POINT_ON_GRADIENT_LINE) + and not _is_ctrl_or_cmd_pressed() + and not Input.is_key_pressed(KEY_SHIFT)): + _draw_crosshair(viewport_control, svs.get_meta(META_NAME_HOVER_CLOSEST_POINT_ON_GRADIENT_LINE)) + hint_txt = "- Double click to add color stop here" + if not point_txt.is_empty(): + _draw_point_number(viewport_control, point_hint_pos, point_txt) + + if not _are_hints_enabled() and _am_showing_point_numbers(): + _draw_hint(viewport_control, point_pos_txt, true) + elif _are_hints_enabled() and _am_showing_point_numbers() and point_pos_txt.length(): + hint_txt += "\n\n - " + point_pos_txt + + if not hint_txt.is_empty(): + _draw_hint(viewport_control, hint_txt) + + + +func _set_handle_hover(g_mouse_pos : Vector2, svs : ScalableVectorShape2D) -> void: + var mouse_pos := _vp_transform(g_mouse_pos) + var handles = svs.get_curve_handles() + var gradient_handles = svs.get_gradient_handles() + svs.remove_meta(META_NAME_HOVER_POINT_IDX) + svs.remove_meta(META_NAME_HOVER_CP_IN_IDX) + svs.remove_meta(META_NAME_HOVER_CP_OUT_IDX) + svs.remove_meta(META_NAME_HOVER_GRADIENT_FROM) + svs.remove_meta(META_NAME_HOVER_GRADIENT_TO) + svs.remove_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX) + svs.remove_meta(META_NAME_HOVER_CLOSEST_POINT_ON_GRADIENT_LINE) + for i in range(handles.size()): + var handle = handles[i] + if mouse_pos.distance_to(_vp_transform(handle['point_position'])) < 10: + svs.set_meta(META_NAME_HOVER_POINT_IDX, i) + elif mouse_pos.distance_to(_vp_transform(handle['in_position'])) < 10: + svs.set_meta(META_NAME_HOVER_CP_IN_IDX, i) + elif mouse_pos.distance_to(_vp_transform(handle['out_position'])) < 10: + svs.set_meta(META_NAME_HOVER_CP_OUT_IDX, i) + if not gradient_handles.is_empty() and not _handle_has_hover(svs): + var stop_idx = gradient_handles['stop_positions'].find_custom(func(p): + return mouse_pos.distance_to(_vp_transform(p)) < 6) + if stop_idx > -1: + svs.set_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX, stop_idx) + elif mouse_pos.distance_to(_vp_transform(gradient_handles['fill_from_pos'])) < 20: + svs.set_meta(META_NAME_HOVER_GRADIENT_FROM, true) + elif mouse_pos.distance_to(_vp_transform(gradient_handles['fill_to_pos'])) < 20: + svs.set_meta(META_NAME_HOVER_GRADIENT_TO, true) + else: + var p := Geometry2D.get_closest_point_to_segment(mouse_pos, + _vp_transform(gradient_handles['fill_from_pos']), + _vp_transform(gradient_handles['fill_to_pos'])) + if mouse_pos.distance_to(p) < 10: + svs.set_meta(META_NAME_HOVER_CLOSEST_POINT_ON_GRADIENT_LINE, p) + + var closest_point_on_curve := svs.get_closest_point_on_curve(g_mouse_pos) + if mouse_pos.distance_to(_vp_transform(closest_point_on_curve.point_position)) < 15: + svs.set_meta(META_NAME_HOVER_CLOSEST_POINT, closest_point_on_curve) + + +func _draw_curve(viewport_control : Control, svs : ScalableVectorShape2D, + is_selected := true) -> void: + var color := svs.shape_hint_color if svs.shape_hint_color else Color.LIME_GREEN + if not is_selected: + color = Color(0.5, 0.5, 0.5, 0.2) + _draw_curve_def(viewport_control, svs, color, 1.0, is_selected) + + +func _draw_curve_def(viewport_control : Control, svs : ScalableVectorShape2D, color : Color, + width : float, antialiased : bool) -> void: + if not svs.is_visible_in_tree(): + return + var points = svs.get_poly_points().map(_vp_transform) + var last_p := Vector2.INF + for p : Vector2 in points: + if last_p != Vector2.INF: + viewport_control.draw_line(last_p, p, color, width, antialiased) + last_p = p + if is_instance_valid(svs.line) and svs.line.closed and points.size() > 1: + viewport_control.draw_dashed_line(last_p, points[0], color, width, 5.0, true, antialiased) + + + +func _draw_crosshair(viewport_control : Control, p : Vector2, orbit := 2.0, outer_orbit := 6.0, + color := Color.WHITE, width := 1) -> void: + if not _get_select_mode_button().button_pressed: + return + var line_len = outer_orbit + orbit + viewport_control.draw_line(p - line_len * Vector2.UP, p - orbit * Vector2.UP, Color.WEB_GRAY, width + 1) + viewport_control.draw_line(p - line_len * Vector2.RIGHT, p - orbit * Vector2.RIGHT, Color.WEB_GRAY, width + 1) + viewport_control.draw_line(p - line_len * Vector2.DOWN, p - orbit * Vector2.DOWN, Color.WEB_GRAY, width + 1) + viewport_control.draw_line(p - line_len * Vector2.LEFT, p - orbit * Vector2.LEFT, Color.WEB_GRAY, width + 1) + viewport_control.draw_line(p - line_len * Vector2.UP, p - orbit * Vector2.UP, color, width) + viewport_control.draw_line(p - line_len * Vector2.RIGHT, p - orbit * Vector2.RIGHT, color, width) + viewport_control.draw_line(p - line_len * Vector2.DOWN, p - orbit * Vector2.DOWN, color, width) + viewport_control.draw_line(p - line_len * Vector2.LEFT, p - orbit * Vector2.LEFT, color, width) + + +func _draw_add_point_hint(viewport_control : Control, svs : ScalableVectorShape2D, only_cutout_hints : bool) -> void: + var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position() + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + var p := _vp_transform(mouse_pos) + if _is_ctrl_or_cmd_pressed() and Input.is_key_pressed(KEY_SHIFT): + if svs.has_fine_point(mouse_pos): + _draw_crosshair(viewport_control, p) + _draw_hint(viewport_control, + "- Click to %s %s here (Ctrl+Shift held)\n" % + [OPERATION_NAME_MAP[current_clip_operation]["verb"], SHAPE_NAME_MAP[current_cutout_shape]] + + "- Use mousewheel to to change the shape of your %s (Ctrl+Shift held)\n" % + OPERATION_NAME_MAP[current_clip_operation]["noun"] + + "- Use right click to change the clipping operation (Ctrl+Shift held)" + ) + else: + _draw_hint(viewport_control, + "- Hover over the selected shape to %s %s (Ctrl+Shift held)\n" % + [ + OPERATION_NAME_MAP[current_clip_operation]["verb"], + SHAPE_NAME_MAP[current_cutout_shape] + ] + + "- Use mousewheel to to change the shape of your %s (Ctrl+Shift held)\n" % + OPERATION_NAME_MAP[current_clip_operation]["noun"] + + "- Use right click to change the clipping operation (Ctrl+Shift held)" + ) + elif _is_ctrl_or_cmd_pressed() and not only_cutout_hints: + _draw_crosshair(viewport_control, p) + _draw_hint(viewport_control, "- Click to add point here (Ctrl held)") + elif Input.is_key_pressed(KEY_SHIFT): + _draw_hint(viewport_control, "- Use mousewheel to resize shape (Shift held)") + elif not svs.has_meta(META_NAME_HOVER_CLOSEST_POINT_ON_GRADIENT_LINE): + var hint := "- Hold Ctrl to add points to selected shape (or Cmd for mac) + - Hold Shift to resize shape with mousewheel" + if only_cutout_hints: + hint = "- Hold Shift to resize shape with mousewheel" + if svs.has_fine_point(mouse_pos): + hint += "\n- Double click to subdivide all curve segments + - Hold Ctrl+Shift to %s %s here (or Cmd+Shift for mac)\n" % [ + OPERATION_NAME_MAP[current_clip_operation]["verb"], + SHAPE_NAME_MAP[current_cutout_shape] + ] + _draw_hint(viewport_control, hint) + + +func _draw_closest_point_on_curve(viewport_control : Control, svs : ScalableVectorShape2D) -> void: + if _is_ctrl_or_cmd_pressed() or Input.is_key_pressed(KEY_SHIFT): + _draw_add_point_hint(viewport_control, svs, false) + return + + if svs.has_meta(META_NAME_HOVER_CLOSEST_POINT): + var hint := "" + var md_p : ClosestPointOnCurveMeta = svs.get_meta(META_NAME_HOVER_CLOSEST_POINT) + if svs.is_arc_start(md_p.before_segment - 1): + var arc_start_idx := md_p.before_segment - 1 + var arc := svs.arc_list.get_arc_for_point(arc_start_idx) + var arc_points := Array(svs.tessellate_arc_segment( + svs.curve.get_point_position(arc_start_idx), + arc.radius, arc.rotation_deg, arc.large_arc_flag, arc.sweep_flag, + svs.curve.get_point_position(arc_start_idx + 1), + )).map(func(p): return _vp_transform(svs.to_global(p))) + viewport_control.draw_polyline(arc_points, Color.RED, 3.0, true) + hint = "- Left click to open arc settings" + hint += "\n- Right click to remove arc (straighten this line segment)" + else: + if Input.is_key_pressed(KEY_ALT): + _draw_crosshair(viewport_control, _vp_transform(svs.to_global(svs.get_curve_segment_halfway_point(md_p.before_segment))), 3.0, 8, Color.ANTIQUE_WHITE, 2) + else: + _draw_crosshair(viewport_control, _vp_transform(md_p.point_position)) + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + if svs.curve.point_count > 1: + if Input.is_key_pressed(KEY_ALT): + hint += "\n- Left Click to add point halfway the line (Alt held)" + else: + hint = "- Double click to add point on the line" + hint += "\n- Alt + Click to add point halfway the line" + if md_p.before_segment < svs.curve.point_count: + hint += "\n- Drag to change curve" + hint += "\n- Right click to convert line segment to arc" + else: + _draw_add_point_hint(viewport_control, svs, false) + if not hint.is_empty(): + _draw_hint(viewport_control, hint) + + +func _draw_outline_for_uniform_transforms(viewport_control : Control, svs : ScalableVectorShape2D) -> void: + viewport_control.draw_polyline(svs.get_bounding_box().map(_vp_transform), VIEWPORT_ORANGE, 2.0) + _draw_curve_def(viewport_control, svs, svs.shape_hint_color, 0.5, true) + for idx in svs.curve.point_count: + var p := svs.to_global(svs.curve.get_point_position(idx)) + _draw_crosshair(viewport_control, _vp_transform(p), 2.0, 4.0, Color.WHITE) + var natural_center := svs.to_global(svs.get_center()) + if (_uniform_transform_mode == UniformTransformMode.ROTATE + and _lmb_is_down_inside_viewport + and Input.is_key_pressed(KEY_SHIFT) + ): + natural_center = _stored_natural_center + + _draw_crosshair(viewport_control, _vp_transform(natural_center), 2.0, 4.0, Color.WHITE) + + +func _draw_canvas_for_uniform_translate(viewport_control : Control, svs : ScalableVectorShape2D) -> void: + _draw_outline_for_uniform_transforms(viewport_control, svs) + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + _draw_hint(viewport_control, "- Drag to move all points (left mouse button held)") + else: + _draw_hint(viewport_control, "- Hold left mouse button to start moving all points" + + "\n- Press Q to return to normal editing") + + +func _draw_canvas_for_uniform_rotate(viewport_control : Control, svs : ScalableVectorShape2D) -> void: + _draw_outline_for_uniform_transforms(viewport_control, svs) + if _lmb_is_down_inside_viewport: + var hint_text := "- Drag to rotate all points (left mouse button held)" + if _is_ctrl_or_cmd_pressed(): + hint_text += "\n- Rotating in steps of 5° (Ctrl held)" + else: + hint_text += "\n- Hold Ctrl to rotate in steps of 5°" + if svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + if Input.is_key_pressed(KEY_SHIFT): + hint_text += "\n- Rotating around the natural center in stead of the pivot (Shift held)" + else: + hint_text += "\n- Hold Shift to rotate around the natural center in stead of the pivot" + _draw_hint(viewport_control, hint_text) + else: + _draw_hint(viewport_control, "- Hold left mouse button to start rotating all points" + + "\n- Press Q to return to normal editing") + if _lmb_is_down_inside_viewport: + var rotation_origin = svs.global_position + if (Input.is_key_pressed(KEY_SHIFT) or + svs.shape_type != ScalableVectorShape2D.ShapeType.PATH + ): + rotation_origin = _stored_natural_center + var rotation_target := EditorInterface.get_editor_viewport_2d().get_mouse_position() + if _is_ctrl_or_cmd_pressed(): + var ang := snapped(rotation_origin.angle_to_point(rotation_target), deg_to_rad(5.0)) + var dst := rotation_origin.distance_to(rotation_target) + rotation_target = rotation_origin + Vector2.RIGHT.rotated(ang) * dst + viewport_control.draw_line(_vp_transform(rotation_origin),_vp_transform(rotation_target), + svs.shape_hint_color, 1, true) + + +func _draw_canvas_for_uniform_scale(viewport_control : Control, svs : ScalableVectorShape2D) -> void: + _draw_outline_for_uniform_transforms(viewport_control, svs) + if _lmb_is_down_inside_viewport: + var hint_text := "- Drag to scale all points (left mouse button held)" + if svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + if Input.is_key_pressed(KEY_SHIFT): + hint_text += "\n- Scaling out from natural center (Shift held)" + else: + hint_text += "\n- Hold Shift to scale out from natural center in stead of pivot" + _draw_hint(viewport_control, hint_text) + else: + _draw_hint(viewport_control, "- Hold left mouse button to start scaling all points" + + "\n- Press Q to return to normal editing") + + if _lmb_is_down_inside_viewport: + var origin = svs.global_position + if (Input.is_key_pressed(KEY_SHIFT) or + svs.shape_type != ScalableVectorShape2D.ShapeType.PATH + ): + origin = svs.to_global(svs.get_center()) + var target := EditorInterface.get_editor_viewport_2d().get_mouse_position() + viewport_control.draw_line(_vp_transform(origin),_vp_transform(target), + svs.shape_hint_color, 1, true) + + +func _find_merge_vertices() -> Dictionary[ScalableVectorShape2D, int]: + var vertex_map : Dictionary[ScalableVectorShape2D, int] = {} + for svs : ScalableVectorShape2D in EditorInterface.get_edited_scene_root().find_children("*", "ScalableVectorShape2D"): + var point_was_found_inside_rect := false + for idx in svs.curve.point_count: + var p := svs.to_global(svs.curve.get_point_position(idx)) + var p_inside_rect := _merge_box_rect.abs().has_point(_vp_transform(p)) + if p_inside_rect and not point_was_found_inside_rect: + vertex_map[svs] = idx + point_was_found_inside_rect = true + + return vertex_map + + +func _handle_draw_vertex_merge_box(viewport_control: Control) -> void: + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + _draw_hint(viewport_control, "Drag box around a point of 2 or more ScalableVectorShape2D to merge them") + + viewport_control.draw_rect(_merge_box_rect, Color.LIME, false, 1) + for svs : ScalableVectorShape2D in EditorInterface.get_edited_scene_root().find_children("*", "ScalableVectorShape2D"): + for idx in svs.curve.point_count: + _draw_crosshair( + viewport_control, + _vp_transform(svs.to_global(svs.curve.get_point_position(idx))), + 2.0, 4.0, VIEWPORT_ORANGE, 1 + ) + + var vertex_map := _find_merge_vertices() + for svs : ScalableVectorShape2D in vertex_map.keys(): + _draw_crosshair(viewport_control, _vp_transform( + svs.to_global(svs.curve.get_point_position(vertex_map[svs])) + ), 2.0, 5.0, Color.WHITE, 2) + + if vertex_map.size() > 1: + var entries = "" + for k in vertex_map.keys(): + entries += "\n - " + k.name + _draw_hint(viewport_control, "\nMerge points of:%s" % entries) + + +func _forward_canvas_draw_over_viewport(viewport_control: Control) -> void: + if not _is_editing_enabled(): + return + if not is_instance_valid(EditorInterface.get_edited_scene_root()): + return + if merge_node_toggle_button.button_pressed: + return _handle_draw_vertex_merge_box(viewport_control) + + var current_selection := EditorInterface.get_selection().get_selected_nodes().pop_back() + if _is_svs_valid(current_selection) and _get_select_mode_button().button_pressed: + if _uniform_transform_mode == UniformTransformMode.TRANSLATE: + return _draw_canvas_for_uniform_translate(viewport_control, current_selection) + elif _uniform_transform_mode == UniformTransformMode.SCALE: + return _draw_canvas_for_uniform_scale(viewport_control, current_selection) + elif _uniform_transform_mode == UniformTransformMode.ROTATE: + return _draw_canvas_for_uniform_rotate(viewport_control, current_selection) + + var all_valid_svs_nodes := _find_scalable_vector_shape_2d_nodes().filter(_is_svs_valid) + for result : ScalableVectorShape2D in all_valid_svs_nodes: + if result == current_selection: + viewport_control.draw_polyline(result.get_bounding_box().map(_vp_transform), + VIEWPORT_ORANGE, 2.0) + _draw_curve(viewport_control, result) + _draw_handles(viewport_control, result) + if not _handle_has_hover(result): + if result.shape_type == ScalableVectorShape2D.ShapeType.PATH: + if result.has_meta(META_NAME_HOVER_CLOSEST_POINT): + _draw_closest_point_on_curve(viewport_control, result) + else: + _draw_add_point_hint(viewport_control, result, false) + else: + _draw_add_point_hint(viewport_control, result, true) + elif result.has_meta(META_NAME_SELECT_HINT): + viewport_control.draw_polyline(result.get_bounding_box().map(_vp_transform), + Color.WEB_GRAY, 1.0) + if not(result.line or result.collision_polygon or result.polygon): + _draw_curve(viewport_control, result, false) + + if shape_preview: + var points := Array(shape_preview.tessellate()) + var stroke_width = (_get_default_stroke_width() * EditorInterface.get_editor_viewport_2d() + .get_final_transform().get_scale().x) + if current_selection is Node2D: + points = points.map(current_selection.to_global) + stroke_width *= current_selection.global_scale.x + elif current_selection is Control: + points = points.map(func(p): return current_selection.get_global_transform() * p) + stroke_width *= current_selection.get_global_transform().get_scale().x + points = points.map(_vp_transform) + match _get_default_paint_order(): + PaintOrder.MARKERS_STROKE_FILL, PaintOrder.STROKE_FILL_MARKERS, PaintOrder.STROKE_MARKERS_FILL: + if _is_add_stroke_enabled(): + viewport_control.draw_polyline(points, _get_default_stroke_color(), stroke_width) + if _is_add_fill_enabled(): + viewport_control.draw_polygon(points, [_get_default_fill_color()]) + PaintOrder.MARKERS_FILL_STROKE, PaintOrder.FILL_STROKE_MARKERS, PaintOrder.FILL_MARKERS_STROKE, _: + if _is_add_fill_enabled(): + viewport_control.draw_polygon(points, [_get_default_fill_color()]) + if _is_add_stroke_enabled(): + viewport_control.draw_polyline(points, _get_default_stroke_color(), stroke_width) + + if not _is_add_fill_enabled() and not _is_add_stroke_enabled(): + viewport_control.draw_polyline(points, Color.LIME, 1) + + +func _start_undo_redo_transaction(name := "") -> void: + in_undo_redo_transaction = true + undo_redo_transaction = { + UndoRedoEntry.NAME: name, + UndoRedoEntry.DOS: [], + UndoRedoEntry.UNDOS: [], + UndoRedoEntry.DO_PROPS: [], + UndoRedoEntry.UNDO_PROPS : [] + } + +func _commit_undo_redo_transaction() -> void: + if not in_undo_redo_transaction: + return + in_undo_redo_transaction = false + undo_redo.create_action(undo_redo_transaction[UndoRedoEntry.NAME]) + for do_method in undo_redo_transaction[UndoRedoEntry.DOS]: + undo_redo.callv('add_do_method', do_method) + for do_prop in undo_redo_transaction[UndoRedoEntry.DO_PROPS]: + undo_redo.callv('add_do_property', do_prop) + for undo_method in undo_redo_transaction[UndoRedoEntry.UNDOS]: + undo_redo.callv('add_undo_method', undo_method) + for undo_prop in undo_redo_transaction[UndoRedoEntry.UNDO_PROPS]: + undo_redo.callv('add_undo_property', undo_prop) + undo_redo.commit_action(false) + undo_redo_transaction = { + UndoRedoEntry.NAME: name, + UndoRedoEntry.DOS: [], + UndoRedoEntry.UNDOS: [], + UndoRedoEntry.UNDO_PROPS: [], + UndoRedoEntry.DO_PROPS: [] + } + + +func _on_global_position_for_handle_changed(global_pos : Vector2, meta_name: String, idx : int) -> void: + var cur := EditorInterface.get_selection().get_selected_nodes().pop_back() + if _is_svs_valid(cur): + match(meta_name): + META_NAME_HOVER_CP_IN_IDX: + _update_curve_cp_in_position(cur, global_pos, idx) + META_NAME_HOVER_CP_OUT_IDX: + _update_curve_cp_out_position(cur, global_pos, idx) + META_NAME_HOVER_POINT_IDX: + _update_curve_point_position(cur, global_pos, idx) + update_overlays() + + +func _update_curve_point_position(current_selection : ScalableVectorShape2D, mouse_pos : Vector2, idx : int) -> void: + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Move point on " + str(current_selection)) + if idx == 0 and current_selection.is_curve_closed(): + var idx_1 = current_selection.curve.point_count - 1 + undo_redo_transaction[UndoRedoEntry.UNDOS].append([ + current_selection.curve, 'set_point_position', idx_1, current_selection.curve.get_point_position(idx_1) + ]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([ + current_selection.curve, 'set_point_position', idx, current_selection.curve.get_point_position(idx) + ]) + + undo_redo_transaction[UndoRedoEntry.DOS] = [] + if idx == 0 and current_selection.is_curve_closed(): + var idx_1 = current_selection.curve.point_count - 1 + undo_redo_transaction[UndoRedoEntry.DOS].append([ + current_selection, 'set_global_curve_point_position', mouse_pos, idx_1, + _is_snapped_to_pixel(), _get_snap_resolution() + ]) + current_selection.set_global_curve_point_position(mouse_pos, idx_1, + _is_snapped_to_pixel(), _get_snap_resolution()) + undo_redo_transaction[UndoRedoEntry.DOS].append([ + current_selection, 'set_global_curve_point_position', mouse_pos, idx, + _is_snapped_to_pixel(), _get_snap_resolution() + ]) + current_selection.set_global_curve_point_position(mouse_pos, idx, + _is_snapped_to_pixel(), _get_snap_resolution()) + + +func _update_rect_dimensions(svs : ScalableVectorShape2D, mouse_pos : Vector2) -> void: + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Change rect size on " + str(svs)) + undo_redo_transaction[UndoRedoEntry.UNDO_PROPS] = [[svs, 'size', svs.size]] + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + var top_left := (-svs.size * 0.5).rotated(svs.spin) + svs.offset + svs.size = ((svs.to_local(mouse_pos)) - top_left).rotated(-svs.spin) + undo_redo_transaction[UndoRedoEntry.DO_PROPS] = [[svs, 'size', svs.size]] + + +func _update_rect_corner_radius(svs : ScalableVectorShape2D, mouse_pos : Vector2, prop_name : String, is_symmetrical : bool) -> void: + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Change rect " + prop_name + " on " + str(svs)) + undo_redo_transaction[UndoRedoEntry.UNDO_PROPS] = [ + [svs, 'rx', svs.rx], [svs, 'ry', svs.ry] + ] + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + var top_left := (-svs.size * 0.5).rotated(svs.spin) + svs.offset + if prop_name == 'rx': + svs.rx = svs.to_local(mouse_pos).rotated(-svs.spin).x - top_left.rotated(-svs.spin).x + if is_symmetrical: + svs.ry = svs.rx + if prop_name == 'ry': + svs.ry = svs.to_local(mouse_pos).rotated(-svs.spin).y - top_left.rotated(-svs.spin).y + if is_symmetrical: + svs.rx = svs.ry + + undo_redo_transaction[UndoRedoEntry.DO_PROPS] = [ + [svs, 'rx', svs.rx], + [svs, 'ry', svs.ry] + ] + + +func _update_curve_cp_in_position(current_selection : ScalableVectorShape2D, mouse_pos : Vector2, idx : int) -> void: + if idx == 0: + idx = current_selection.curve.point_count - 1 + + var cp_in_is_cp_out_of_loop_start := (Input.is_key_pressed(KEY_SHIFT) and + not(idx == current_selection.curve.point_count - 1 + and not current_selection.is_curve_closed()) + ) + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Move control point in %d on %s" % [idx, current_selection]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([current_selection.curve, 'set_point_in', idx, current_selection.curve.get_point_in(idx)]) + if cp_in_is_cp_out_of_loop_start: + var idx_1 = 0 if idx == current_selection.curve.point_count - 1 else idx + undo_redo_transaction[UndoRedoEntry.UNDOS].append([current_selection.curve, 'set_point_out', idx_1, current_selection.curve.get_point_out(idx_1)]) + + current_selection.set_global_curve_cp_in_position(mouse_pos, idx, + _is_snapped_to_pixel(), _get_snap_resolution()) + undo_redo_transaction[UndoRedoEntry.DOS] = [[ + current_selection, 'set_global_curve_cp_in_position', mouse_pos, idx, + _is_snapped_to_pixel(), _get_snap_resolution() + ]] + if cp_in_is_cp_out_of_loop_start: + var idx_1 = 0 if idx == current_selection.curve.point_count - 1 else idx + current_selection.curve.set_point_out(idx_1, -current_selection.curve.get_point_in(idx)) + undo_redo_transaction[UndoRedoEntry.DOS].append([current_selection.curve, 'set_point_out', idx_1, -current_selection.curve.get_point_in(idx)]) + + +func _update_gradient_from_position(svs : ScalableVectorShape2D, mouse_pos : Vector2) -> void: + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Move gradient from position for %s" % str(svs)) + undo_redo_transaction[UndoRedoEntry.UNDO_PROPS].append([svs.polygon.texture, 'fill_from', + svs.polygon.texture.fill_from]) + var box := svs.get_bounding_rect() + svs.polygon.texture.fill_from = (svs.to_local(mouse_pos) - box.position) / box.size + undo_redo_transaction[UndoRedoEntry.DO_PROPS] = [[ + svs.polygon.texture, 'fill_from', svs.polygon.texture.fill_from + ]] + + +func _update_gradient_to_position(svs : ScalableVectorShape2D, mouse_pos : Vector2) -> void: + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Move gradient from position for %s" % str(svs)) + undo_redo_transaction[UndoRedoEntry.UNDO_PROPS].append([svs.polygon.texture, 'fill_to', + svs.polygon.texture.fill_to]) + var box := svs.get_bounding_rect() + svs.polygon.texture.fill_to = (svs.to_local(mouse_pos) - box.position) / box.size + undo_redo_transaction[UndoRedoEntry.DO_PROPS] = [[ + svs.polygon.texture, 'fill_to', svs.polygon.texture.fill_to + ]] + + +func _get_gradient_offset(svs : ScalableVectorShape2D, mouse_pos : Vector2) -> float: + var box := svs.get_bounding_rect() + var gradient_tex : GradientTexture2D = svs.polygon.texture + var p := ((svs.to_local(mouse_pos) - box.position) / box.size) + var p1 := Geometry2D.get_closest_point_to_segment(p, gradient_tex.fill_from, gradient_tex.fill_to) + return p1.distance_to(gradient_tex.fill_from) / gradient_tex.fill_from.distance_to(gradient_tex.fill_to) + + +func _update_gradient_stop_color_pos(svs : ScalableVectorShape2D, mouse_pos : Vector2, idx : int) -> void: + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + var new_offset := _get_gradient_offset(svs, mouse_pos) + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Move gradient offset %d on %s" % [idx, svs]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([svs.polygon.texture.gradient, + 'set_offset', idx, svs.polygon.texture.gradient.offsets[idx]]) + undo_redo_transaction[UndoRedoEntry.DOS] = [[ + svs.polygon.texture.gradient, 'set_offset', idx, new_offset + ]] + svs.polygon.texture.gradient.set_offset(idx, new_offset) + + +func _add_color_stop(svs : ScalableVectorShape2D, mouse_pos : Vector2) -> void: + var new_offset := _get_gradient_offset(svs, mouse_pos) + var colors = Array(svs.polygon.texture.gradient.colors) + var offsets = Array(svs.polygon.texture.gradient.offsets) + var stops = {} + for idx in range(colors.size()): + stops[offsets[idx]] = colors[idx] + stops[new_offset] = svs.polygon.texture.gradient.sample(new_offset) + var stop_keys := stops.keys() + stop_keys.sort() + var new_colors = [] + var new_offsets = [] + for offset in stop_keys: + new_colors.append(stops[offset]) + new_offsets.append(offset) + + undo_redo.create_action("Add color stop to %s " % str(svs)) + undo_redo.add_do_property(svs.polygon.texture.gradient, 'colors', new_colors) + undo_redo.add_do_property(svs.polygon.texture.gradient, 'offsets', new_offsets) + undo_redo.add_do_method(svs, 'notify_assigned_node_change') + undo_redo.add_undo_property(svs.polygon.texture.gradient, 'colors', colors) + undo_redo.add_undo_property(svs.polygon.texture.gradient, 'offsets', offsets) + undo_redo.add_undo_method(svs, 'notify_assigned_node_change') + undo_redo.commit_action() + + +func _remove_color_stop(svs : ScalableVectorShape2D, remove_idx : int) -> void: + var colors = Array(svs.polygon.texture.gradient.colors) + var offsets = Array(svs.polygon.texture.gradient.offsets) + var stops = {} + for idx in range(colors.size()): + if idx != remove_idx: + stops[offsets[idx]] = colors[idx] + var stop_keys := stops.keys() + stop_keys.sort() + var new_colors = [] + var new_offsets = [] + for offset in stop_keys: + new_colors.append(stops[offset]) + new_offsets.append(offset) + + undo_redo.create_action("Remove color stop from %s " % str(svs)) + undo_redo.add_do_property(svs.polygon.texture.gradient, 'colors', new_colors) + undo_redo.add_do_property(svs.polygon.texture.gradient, 'offsets', new_offsets) + undo_redo.add_do_method(svs, 'notify_assigned_node_change') + undo_redo.add_undo_property(svs.polygon.texture.gradient, 'colors', colors) + undo_redo.add_undo_property(svs.polygon.texture.gradient, 'offsets', offsets) + undo_redo.add_undo_method(svs, 'notify_assigned_node_change') + undo_redo.commit_action() + +func _update_curve_cp_out_position(current_selection : ScalableVectorShape2D, mouse_pos : Vector2, idx : int) -> void: + if idx == current_selection.curve.point_count - 1: + idx = 0 + + var cp_out_is_cp_in_of_loop_end := (Input.is_key_pressed(KEY_SHIFT) + and not(idx == 0 and not current_selection.is_curve_closed())) + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Move control point out %d on %s" % [idx, current_selection]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([current_selection.curve, 'set_point_out', idx, current_selection.curve.get_point_out(idx)]) + if cp_out_is_cp_in_of_loop_end: + var idx_1 = current_selection.curve.point_count - 1 if idx == 0 else idx + undo_redo_transaction[UndoRedoEntry.UNDOS].append([current_selection.curve, 'set_point_in', idx_1, current_selection.curve.get_point_in(idx_1)]) + + current_selection.set_global_curve_cp_out_position(mouse_pos, idx, + _is_snapped_to_pixel(), _get_snap_resolution()) + undo_redo_transaction[UndoRedoEntry.DOS] = [[ + current_selection, 'set_global_curve_cp_out_position', mouse_pos, idx, + _is_snapped_to_pixel(), _get_snap_resolution() + ]] + if cp_out_is_cp_in_of_loop_end: + var idx_1 = current_selection.curve.point_count - 1 if idx == 0 else idx + current_selection.curve.set_point_in(idx_1, -current_selection.curve.get_point_out(idx)) + undo_redo_transaction[UndoRedoEntry.DOS].append([current_selection.curve, 'set_point_in', idx_1, -current_selection.curve.get_point_out(idx)]) + + +func _set_shape_origin(current_selection : ScalableVectorShape2D, mouse_pos : Vector2) -> void: + undo_redo.create_action("Set origin on %s" % current_selection) + undo_redo.add_do_method(current_selection, 'set_origin', mouse_pos) + undo_redo.add_undo_method(current_selection, 'set_origin', current_selection.global_position) + undo_redo.commit_action() + + +func _get_curve_backup(curve_in : Curve2D) -> Curve2D: + return curve_in.duplicate() + + +func _resize_shape(svs : ScalableVectorShape2D, s : float) -> void: + if svs.shape_type == ScalableVectorShape2D.ShapeType.PATH: + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Resize shape %s" % str(svs)) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([ + svs, 'replace_curve_points', _get_curve_backup(svs.curve)]) + + undo_redo_transaction[UndoRedoEntry.DOS] = [] + for idx in range(svs.curve.point_count): + svs.curve.set_point_position(idx, svs.curve.get_point_position(idx) * s) + svs.curve.set_point_in(idx, svs.curve.get_point_in(idx) * s) + svs.curve.set_point_out(idx, svs.curve.get_point_out(idx) * s) + undo_redo_transaction[UndoRedoEntry.DOS].append([svs.curve, + 'set_point_position', idx, svs.curve.get_point_position(idx) * s]) + undo_redo_transaction[UndoRedoEntry.DOS].append([svs.curve, + 'set_point_in', idx, svs.curve.get_point_in(idx) * s]) + undo_redo_transaction[UndoRedoEntry.DOS].append([svs.curve, + 'set_point_out', idx, svs.curve.get_point_out(idx) * s]) + else: + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Resize shape %s" % str(svs)) + undo_redo_transaction[UndoRedoEntry.UNDO_PROPS] = [[svs, 'size', svs.size]] + undo_redo_transaction[UndoRedoEntry.DO_PROPS] = [[svs, 'size', svs.size * s]] + svs.size *= s + + +func _remove_point_from_curve(current_selection : ScalableVectorShape2D, idx : int) -> void: + var orig_n := current_selection.curve.point_count + if current_selection.is_curve_closed() and idx == 0: + idx = orig_n - 1 + + var backup := _get_curve_backup(current_selection.curve) + undo_redo.create_action("Remove point %d from %s" % [idx, str(current_selection)]) + undo_redo.add_do_method(current_selection.curve, 'set_point_in', 0, Vector2.ZERO) + if orig_n > 2: + undo_redo.add_do_method(current_selection.curve, 'set_point_out', orig_n - 2, Vector2.ZERO) + + var redo_arcs : Array[ScalableArc] = [] + for a : ScalableArc in current_selection.arc_list.arcs: + if a.start_point == idx or a.start_point == idx - 1: + undo_redo.add_do_method(current_selection.arc_list, 'remove_arc_for_point', a.start_point) + redo_arcs.append(a) + + undo_redo.add_do_method(current_selection.curve, 'remove_point', idx) + undo_redo.add_do_method(current_selection.arc_list, 'handle_point_removed_at_index', idx) + undo_redo.add_undo_method(current_selection, 'replace_curve_points', backup) + undo_redo.add_undo_method(current_selection.arc_list, 'handle_point_added_at_index', idx) + for a in redo_arcs: + undo_redo.add_undo_reference(a) + undo_redo.add_undo_method(current_selection.arc_list, 'add_arc', a) + undo_redo.commit_action() + + +func _remove_cp_in_from_curve(current_selection : ScalableVectorShape2D, idx : int) -> void: + if idx == 0: + idx = current_selection.curve.point_count - 1 + undo_redo.create_action("Remove control point in %d from %s " % [idx, str(current_selection)]) + undo_redo.add_do_method(current_selection.curve, 'set_point_in', idx, Vector2.ZERO) + undo_redo.add_undo_method(current_selection.curve, 'set_point_in', idx, current_selection.curve.get_point_in(idx)) + undo_redo.commit_action() + + +func _remove_cp_out_from_curve(current_selection : ScalableVectorShape2D, idx : int) -> void: + if idx == current_selection.curve.point_count - 1: + idx = 0 + undo_redo.create_action("Remove control point out %d from %s " % [idx, str(current_selection)]) + undo_redo.add_do_method(current_selection.curve, 'set_point_out', idx, Vector2.ZERO) + undo_redo.add_undo_method(current_selection.curve, 'set_point_out', idx, current_selection.curve.get_point_out(idx)) + undo_redo.commit_action() + + +func _remove_rounded_corners_from_rect(svs : ScalableVectorShape2D): + undo_redo.create_action("Remove rounded corners from %s " % str(svs)) + undo_redo.add_do_property(svs, 'rx', 0.0) + undo_redo.add_do_property(svs, 'ry', 0.0) + undo_redo.add_undo_property(svs, 'rx', svs.rx) + undo_redo.add_undo_property(svs, 'ry', svs.ry) + undo_redo.commit_action() + + +func _add_point_to_curve(svs : ScalableVectorShape2D, local_pos : Vector2, + cp_in := Vector2.ZERO, cp_out := Vector2.ZERO, idx := -1, do_commit := true) -> void: + undo_redo.create_action("Add point at %s to %s " % [str(local_pos), str(svs)]) + + undo_redo.add_do_method(svs.curve, 'add_point', local_pos, cp_in, cp_out, idx) + if idx < 0: + undo_redo.add_undo_method(svs.curve, 'remove_point', svs.curve.point_count) + else: + undo_redo.add_do_method(svs.arc_list, 'handle_point_added_at_index', idx) + undo_redo.add_undo_method(svs.curve, 'remove_point', idx) + undo_redo.add_undo_method(svs.arc_list, 'handle_point_removed_at_index', idx) + if not do_commit: + return + undo_redo.commit_action() + + +func _create_arc(svs : ScalableVectorShape2D, start_point_idx : int) -> void: + undo_redo.create_action("Remove arc for segment %d on %s " % [start_point_idx, str(svs)]) + undo_redo.add_do_method(svs, 'add_arc', start_point_idx) + undo_redo.add_undo_method(svs.arc_list, 'remove_arc_for_point', start_point_idx) + undo_redo.commit_action() + + +func _remove_arc(svs : ScalableVectorShape2D, start_point_idx : int) -> void: + var redo_arc := svs.arc_list.get_arc_for_point(start_point_idx) + if redo_arc == null: + return + undo_redo.create_action("Remove arc for segment %d on %s " % [start_point_idx, str(svs)]) + undo_redo.add_do_method(svs.arc_list, 'remove_arc_for_point', start_point_idx) + undo_redo.add_undo_method(svs.arc_list, 'add_arc', redo_arc) + undo_redo.add_undo_reference(redo_arc) + undo_redo.commit_action() + + +func _add_point_on_position(svs : ScalableVectorShape2D, pos : Vector2) -> void: + if svs.shape_type != ScalableVectorShape2D.ShapeType.PATH: + return + _add_point_to_curve(svs, svs.to_local(pos)) + + +func _start_cutout_shape(svs : ScalableVectorShape2D, pos : Vector2) -> void: + var new_shape = ScalableVectorShape2D.new() + var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position() + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + new_shape.curve = Curve2D.new() + new_shape.position = svs.to_local(mouse_pos) + new_shape.shape_type = current_cutout_shape + new_shape.curve.add_point(Vector2.ZERO) + + _create_shape(new_shape, EditorInterface.get_edited_scene_root(), "CutoutOf%s" % svs.name, svs) + + +func _add_point_on_curve_segment(svs : ScalableVectorShape2D, subdivide := false) -> void: + if svs.shape_type != ScalableVectorShape2D.ShapeType.PATH: + return + if not svs.has_meta(META_NAME_HOVER_CLOSEST_POINT): + return + var md_closest_point : ClosestPointOnCurveMeta = svs.get_meta(META_NAME_HOVER_CLOSEST_POINT) + if svs.is_arc_start(md_closest_point.before_segment - 1): + return + var placement_point := svs.get_curve_segment_halfway_point(md_closest_point.before_segment) if subdivide else md_closest_point.local_point_position + if md_closest_point.before_segment >= svs.curve.point_count: + _add_point_to_curve(svs, placement_point) + else: + if ( + svs.curve.get_point_out(md_closest_point.before_segment - 1).length() > 0.0 or + svs.curve.get_point_in(md_closest_point.before_segment).length() > 0.0 + ): + # This is a curved segment, so when a point is added, control points are recalculated + var sliced_segment := svs.get_sliced_curve_segment(md_closest_point.before_segment, placement_point) + _add_point_to_curve(svs, placement_point, + Vector2.ZERO, Vector2.ZERO, md_closest_point.before_segment, false) + undo_redo.add_do_method(svs.curve, "set_point_out", md_closest_point.before_segment - 1, sliced_segment.get_point_out(0)) + undo_redo.add_undo_method(svs.curve, "set_point_out", md_closest_point.before_segment -1, svs.curve.get_point_out(md_closest_point.before_segment - 1)) + undo_redo.add_do_method(svs.curve, "set_point_in", md_closest_point.before_segment, sliced_segment.get_point_in(1)) + undo_redo.add_undo_method(svs.curve, "set_point_in", md_closest_point.before_segment, svs.curve.get_point_in(md_closest_point.before_segment)) + undo_redo.add_do_method(svs.curve, "set_point_out", md_closest_point.before_segment, sliced_segment.get_point_out(1)) + undo_redo.add_undo_method(svs.curve, "set_point_out", md_closest_point.before_segment, svs.curve.get_point_out(md_closest_point.before_segment)) + undo_redo.add_do_method(svs.curve, "set_point_in", md_closest_point.before_segment + 1, sliced_segment.get_point_in(2)) + undo_redo.add_undo_reference(svs.curve) + undo_redo.commit_action() + else: + _add_point_to_curve(svs, placement_point, + Vector2.ZERO, Vector2.ZERO, md_closest_point.before_segment) + + +func _subdivide_curve(svs : ScalableVectorShape2D) -> void: + undo_redo.create_action("Subdivide shape %s" % str(svs)) + undo_redo.add_do_property(svs, 'curve', svs.get_subdivided_curve()) + undo_redo.add_undo_property(svs, 'curve', svs.curve.duplicate()) + undo_redo.commit_action() + + +func _drag_curve_segment(svs : ScalableVectorShape2D, mouse_pos : Vector2) -> void: + if svs.shape_type != ScalableVectorShape2D.ShapeType.PATH: + return + if not svs.has_meta(META_NAME_HOVER_CLOSEST_POINT): + return + var md_closest_point : ClosestPointOnCurveMeta = svs.get_meta(META_NAME_HOVER_CLOSEST_POINT) + if svs.is_arc_start(md_closest_point.before_segment - 1) or md_closest_point.before_segment >= svs.curve.point_count or md_closest_point.before_segment < 1: + return + + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + # Compute control points based on mouse position to align middle of segment curve to it + # using the quadratic Bézier control point + var idx : int = md_closest_point.before_segment + var segment_start_point := svs.curve.get_point_position(idx - 1) + var segment_end_point := svs.curve.get_point_position(idx) + var halfway_point := (segment_start_point + segment_end_point) / 2 + var dir := halfway_point.direction_to(svs.to_local(mouse_pos)) + var distance := halfway_point.distance_to(svs.to_local(mouse_pos)) + var quadratic_bezier_control_point := halfway_point + distance * 2 * dir + var new_point_out := (quadratic_bezier_control_point - segment_start_point) * (2.0 / 3.0) + var new_point_in := (quadratic_bezier_control_point - segment_end_point) * (2.0 / 3.0) + + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Change curve segment %d->%d for %s" % [idx - 1, idx, str(svs)]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([svs.curve, 'set_point_in', idx, svs.curve.get_point_in(idx)]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([svs.curve, 'set_point_out', idx - 1, svs.curve.get_point_out(idx - 1)]) + undo_redo_transaction[UndoRedoEntry.DOS] = [[svs.curve, 'set_point_out', idx - 1, new_point_out]] + undo_redo_transaction[UndoRedoEntry.DOS].append([svs.curve, 'set_point_in', idx, new_point_in]) + svs.curve.set_point_out(idx - 1, new_point_out) + svs.curve.set_point_in(idx, new_point_in) + md_closest_point["point_position"] = mouse_pos + svs.set_meta(META_NAME_HOVER_CLOSEST_POINT, md_closest_point) + update_overlays() + + +func _toggle_loop_if_applies(svs : ScalableVectorShape2D, idx : int) -> void: + if svs.shape_type != ScalableVectorShape2D.ShapeType.PATH: + return + if svs.curve.point_count < 3: + return + if idx == 0 or idx == svs.curve.point_count - 1: + if svs.is_curve_closed(): + _remove_point_from_curve(svs, svs.curve.point_count - 1) + else: + _add_point_to_curve(svs, svs.curve.get_point_position(0)) + + +func _get_vp_h_scroll_bar() -> HScrollBar: + var editor_vp := EditorInterface.get_editor_viewport_2d().find_parent("*CanvasItemEditor*") + if editor_vp == null: + return null + return editor_vp.find_child("*HScrollBar*", true, false) + + +func _handle_input_for_uniform_translate(event : InputEvent, svs : ScalableVectorShape2D) -> bool: + var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position() + if event is InputEventMouseButton and (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT: + if (event as InputEventMouseButton).pressed: + _drag_start = mouse_pos + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Translate curve points for %s" % str(svs)) + update_overlays() + return true + + if event is InputEventMouseMotion: + update_overlays() + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + var drag_delta := mouse_pos - _drag_start + if _is_snapped_to_pixel(): + drag_delta = drag_delta.snapped(Vector2.ONE * _get_snap_resolution()) + if drag_delta.abs() > Vector2.ZERO: + _drag_start = mouse_pos + undo_redo_transaction[UndoRedoEntry.DOS].append([svs, 'translate_points_by', drag_delta]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([svs, 'translate_points_by', -drag_delta]) + svs.translate_points_by(drag_delta) + return true + return false + + +func _flip_svs_horizontal(): + var svs := EditorInterface.get_selection().get_selected_nodes().pop_front() + if svs is ScalableVectorShape2D: + undo_redo.create_action("Flip %s horizontally" % str(svs)) + undo_redo.add_do_method(svs, 'flip_points') + undo_redo.add_undo_method(svs, 'flip_points') + undo_redo.commit_action() + + +func _flip_svs_vertical(): + var svs := EditorInterface.get_selection().get_selected_nodes().pop_front() + if svs is ScalableVectorShape2D: + undo_redo.create_action("Flip %s vertically" % str(svs)) + undo_redo.add_do_method(svs, 'flip_points', Vector2(1, -1)) + undo_redo.add_undo_method(svs, 'flip_points', Vector2(1, -1)) + undo_redo.commit_action() + + + +func _handle_input_for_uniform_scale(event : InputEvent, svs : ScalableVectorShape2D) -> bool: + var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position() + if event is InputEventMouseButton and (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT: + if (event as InputEventMouseButton).pressed: + _drag_start = mouse_pos + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Scale curve points for %s" % str(svs)) + update_overlays() + return true + + if event is InputEventMouseMotion: + update_overlays() + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + var drag_delta := mouse_pos - _drag_start + if _is_snapped_to_pixel(): + drag_delta = drag_delta.snapped(Vector2.ONE * _get_snap_resolution()) + if drag_delta.abs() > Vector2.ZERO: + undo_redo_transaction[UndoRedoEntry.DOS].append([svs, 'scale_points_by', _drag_start, mouse_pos, Input.is_key_pressed(KEY_SHIFT)]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([svs, 'scale_points_by', mouse_pos, _drag_start, Input.is_key_pressed(KEY_SHIFT)]) + svs.scale_points_by(_drag_start, mouse_pos, Input.is_key_pressed(KEY_SHIFT)) + _drag_start = mouse_pos + return true + return false + + +func _handle_input_for_uniform_rotate(event : InputEvent, svs : ScalableVectorShape2D) -> bool: + var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position() + if event is InputEventMouseButton and (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT: + if (event as InputEventMouseButton).pressed: + _drag_start = mouse_pos + _prev_uniform_rotate_angle = 0.0 + _stored_natural_center = svs.to_global(svs.get_center()) + if not in_undo_redo_transaction: + _start_undo_redo_transaction("Rotate curve points for %s" % str(svs)) + update_overlays() + return true + + if event is InputEventMouseMotion: + update_overlays() + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + var use_cntr := Input.is_key_pressed(KEY_SHIFT) or svs.shape_type != ScalableVectorShape2D.ShapeType.PATH + var rotation_origin = ( + _stored_natural_center + if use_cntr else + svs.global_position + ) + var rotation_target := EditorInterface.get_editor_viewport_2d().get_mouse_position() + var ang := rotation_origin.angle_to_point(rotation_target) - rotation_origin.angle_to_point(_drag_start) + if _is_ctrl_or_cmd_pressed(): + ang = snappedf(ang, deg_to_rad(5.0)) + if ang != _prev_uniform_rotate_angle: + var drag_delta := ang - _prev_uniform_rotate_angle + if use_cntr: + undo_redo_transaction[UndoRedoEntry.DOS].append([svs, 'rotate_points_by', drag_delta, svs.to_local(rotation_origin)]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([svs, 'rotate_points_by', -drag_delta, svs.to_local(rotation_origin)]) + svs.rotate_points_by(drag_delta, svs.to_local(rotation_origin)) + else: + undo_redo_transaction[UndoRedoEntry.DOS].append([svs, 'rotate_points_by', drag_delta]) + undo_redo_transaction[UndoRedoEntry.UNDOS].append([svs, 'rotate_points_by', -drag_delta]) + svs.rotate_points_by(drag_delta) + + _prev_uniform_rotate_angle = ang + return true + return false + + +func _handle_draw_merge_box_input(event) -> bool: + if event is InputEventMouseButton and (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT: + if event.is_pressed(): + _merge_box_rect.position = _vp_transform(EditorInterface.get_editor_viewport_2d().get_mouse_position()) + else: + _create_svs_vertex_merge_2d() + merge_node_toggle_button.button_pressed = false + update_overlays() + return true + if event is InputEventMouseMotion: + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + _merge_box_rect.size = _vp_transform(EditorInterface.get_editor_viewport_2d().get_mouse_position()) - _merge_box_rect.position + update_overlays() + return true + + +func _forward_canvas_gui_input(event: InputEvent) -> bool: + if merge_node_toggle_button.button_pressed: + return _handle_draw_merge_box_input(event) + + if ( + event is InputEventKey and + (event as InputEventKey).pressed and + (event as InputEventKey).keycode == KEY_M and + _get_select_mode_button().button_pressed + ): + merge_node_toggle_button.button_pressed = true + + if event is InputEventMouseButton and (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT: + _lmb_is_down_inside_viewport = (event as InputEventMouseButton).pressed + if (in_undo_redo_transaction and event is InputEventMouseButton + and event.button_index == MOUSE_BUTTON_LEFT + and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)): + _commit_undo_redo_transaction() + if (in_undo_redo_transaction and event is InputEventKey + and event.keycode == KEY_SHIFT and + not Input.is_key_pressed(KEY_SHIFT)): + _commit_undo_redo_transaction() + if not _is_editing_enabled(): + return false + if not _is_change_pivot_button_active() and not _get_select_mode_button().button_pressed: + return false + if not is_instance_valid(EditorInterface.get_edited_scene_root()): + return false + var current_selection := EditorInterface.get_selection().get_selected_nodes().pop_back() + if _is_svs_valid(current_selection) and _get_select_mode_button().button_pressed: + if _uniform_transform_mode == UniformTransformMode.TRANSLATE: + return _handle_input_for_uniform_translate(event, current_selection) + elif _uniform_transform_mode == UniformTransformMode.SCALE: + return _handle_input_for_uniform_scale(event, current_selection) + elif _uniform_transform_mode == UniformTransformMode.ROTATE: + return _handle_input_for_uniform_rotate(event, current_selection) + + if _is_svs_valid(current_selection) and _is_ctrl_or_cmd_pressed() and Input.is_key_pressed(KEY_SHIFT): + var vp_horiz_scrollbar := _get_vp_h_scroll_bar() + if vp_horiz_scrollbar is HScrollBar: + if not _locking_vp_horizontal_scrollbar: + _vp_horizontal_scrollbar_locked_value = vp_horiz_scrollbar.value + _locking_vp_horizontal_scrollbar = true + vp_horiz_scrollbar.value = _vp_horizontal_scrollbar_locked_value + else: + _locking_vp_horizontal_scrollbar = false + + + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position() + if _is_change_pivot_button_active(): + if _is_svs_valid(current_selection): + _set_shape_origin(current_selection, mouse_pos) + else: + if _is_svs_valid(current_selection) and _handle_has_hover(current_selection): + if event.double_click and current_selection.has_meta(META_NAME_HOVER_POINT_IDX): + _toggle_loop_if_applies(current_selection, current_selection.get_meta(META_NAME_HOVER_POINT_IDX)) + elif (_is_svs_valid(current_selection) and Input.is_key_pressed(KEY_ALT) + and current_selection.shape_type == ScalableVectorShape2D.ShapeType.PATH + and _curve_control_has_hover(current_selection)): + set_global_position_popup_panel.popup_with_value( + _get_hovered_handle_metadata(current_selection), + _is_snapped_to_pixel(), + _get_snap_resolution() + ) + return true + elif _is_svs_valid(current_selection) and _is_ctrl_or_cmd_pressed() and Input.is_key_pressed(KEY_SHIFT): + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + if (not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and + current_selection.has_fine_point(mouse_pos)): + _start_cutout_shape(current_selection, mouse_pos) + return true + elif _is_svs_valid(current_selection) and _is_ctrl_or_cmd_pressed(): + if _is_snapped_to_pixel(): + mouse_pos = mouse_pos.snapped(Vector2.ONE * _get_snap_resolution()) + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + _add_point_on_position(current_selection, mouse_pos) + return true + elif _is_svs_valid(current_selection) and current_selection.has_meta(META_NAME_HOVER_CLOSEST_POINT): + var cp_md : ClosestPointOnCurveMeta = current_selection.get_meta(META_NAME_HOVER_CLOSEST_POINT) + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and current_selection.is_arc_start(cp_md.before_segment - 1): + arc_settings_popup_panel.popup_with_value(current_selection.arc_list.get_arc_for_point(cp_md.before_segment - 1)) + elif Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and Input.is_key_pressed(KEY_ALT): + _add_point_on_curve_segment(current_selection, true) + elif event.double_click: + _add_point_on_curve_segment(current_selection) + return true + elif _is_svs_valid(current_selection) and current_selection.has_meta(META_NAME_HOVER_CLOSEST_POINT_ON_GRADIENT_LINE): + if event.double_click: + _add_color_stop(current_selection, mouse_pos) + return true + elif _is_svs_valid(current_selection) and current_selection.has_fine_point(mouse_pos) and event.double_click: + _subdivide_curve(current_selection) + return true + else: + var results := _find_scalable_vector_shape_2d_nodes_at(mouse_pos) + var refined_result := results.rfind_custom(func(x): return x.has_fine_point(mouse_pos)) + if refined_result > -1 and results[refined_result]: + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + selection_candidate = results[refined_result] + return true + else: + if selection_candidate == results[refined_result]: + EditorInterface.edit_node(results[refined_result]) + return true + var result = results.pop_back() + if is_instance_valid(result): + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + selection_candidate = result + return true + else: + if selection_candidate == result: + EditorInterface.edit_node(result) + return true + return false + + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT: + if _is_svs_valid(current_selection) and _is_ctrl_or_cmd_pressed() and Input.is_key_pressed(KEY_SHIFT): + if not event.is_pressed(): + current_clip_operation += 1 + current_clip_operation = 2 if current_clip_operation < 0 else current_clip_operation + current_clip_operation = 0 if current_clip_operation > 2 else current_clip_operation + return true + if _is_svs_valid(current_selection) and _handle_has_hover(current_selection): + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): + if current_selection.has_meta(META_NAME_HOVER_POINT_IDX) and current_selection.shape_type == ScalableVectorShape2D.ShapeType.PATH: + _remove_point_from_curve(current_selection, current_selection.get_meta(META_NAME_HOVER_POINT_IDX)) + elif current_selection.has_meta(META_NAME_HOVER_CP_IN_IDX): + if current_selection.shape_type == ScalableVectorShape2D.ShapeType.RECT: + _remove_rounded_corners_from_rect(current_selection) + else: + _remove_cp_in_from_curve(current_selection, current_selection.get_meta(META_NAME_HOVER_CP_IN_IDX)) + elif current_selection.has_meta(META_NAME_HOVER_CP_OUT_IDX): + if current_selection.shape_type == ScalableVectorShape2D.ShapeType.RECT: + _remove_rounded_corners_from_rect(current_selection) + else: + _remove_cp_out_from_curve(current_selection, current_selection.get_meta(META_NAME_HOVER_CP_OUT_IDX)) + elif current_selection.has_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX): + _remove_color_stop(current_selection, current_selection.get_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX)) + return true + if _is_svs_valid(current_selection) and current_selection.has_meta(META_NAME_HOVER_CLOSEST_POINT) and not _handle_has_hover(current_selection): + if not Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): + var cp_md = current_selection.get_meta(META_NAME_HOVER_CLOSEST_POINT) + if current_selection.is_arc_start(cp_md.before_segment - 1): + _remove_arc(current_selection, cp_md.before_segment - 1) + else: + _create_arc(current_selection, cp_md.before_segment - 1) + return true + + if (event is InputEventMouseButton and Input.is_key_pressed(KEY_SHIFT) and + event.button_index in [MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN]): + if _is_svs_valid(current_selection): + if _is_ctrl_or_cmd_pressed(): + if not event.is_pressed(): + current_cutout_shape += 1 if event.button_index == MOUSE_BUTTON_WHEEL_DOWN else -1 + current_cutout_shape = 2 if current_cutout_shape < 0 else current_cutout_shape + current_cutout_shape = 0 if current_cutout_shape > 2 else current_cutout_shape + return true + if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + _resize_shape(current_selection, 0.99) + else: + _resize_shape(current_selection, 1.01) + return true + + + if event is InputEventMouseMotion: + var mouse_pos := EditorInterface.get_editor_viewport_2d().get_mouse_position() + for result in _find_scalable_vector_shape_2d_nodes(): + result.remove_meta(META_NAME_SELECT_HINT) + + if _is_svs_valid(current_selection) and not _handle_has_hover(current_selection) and current_selection.has_meta(META_NAME_HOVER_CLOSEST_POINT): + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + _drag_curve_segment(current_selection, mouse_pos) + return true + + if _is_svs_valid(current_selection): + current_selection.remove_meta(META_NAME_HOVER_CLOSEST_POINT) + + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and _is_svs_valid(current_selection): + if _handle_has_hover(current_selection): + if current_selection.has_meta(META_NAME_HOVER_POINT_IDX): + var pt_idx : int = current_selection.get_meta(META_NAME_HOVER_POINT_IDX) + if current_selection.shape_type != ScalableVectorShape2D.ShapeType.PATH: + _update_rect_dimensions(current_selection, mouse_pos) + elif Input.is_key_pressed(KEY_SHIFT): + if pt_idx == 0: + _update_curve_cp_out_position(current_selection, mouse_pos, pt_idx) + else: + _update_curve_cp_in_position(current_selection, mouse_pos, pt_idx) + else: + _update_curve_point_position(current_selection, mouse_pos, pt_idx) + elif current_selection.has_meta(META_NAME_HOVER_CP_IN_IDX): + if current_selection.shape_type == ScalableVectorShape2D.ShapeType.RECT: + _update_rect_corner_radius(current_selection, mouse_pos, "rx", !Input.is_key_pressed(KEY_SHIFT)) + else: + _update_curve_cp_in_position(current_selection, mouse_pos, current_selection.get_meta(META_NAME_HOVER_CP_IN_IDX)) + elif current_selection.has_meta(META_NAME_HOVER_CP_OUT_IDX): + if current_selection.shape_type == ScalableVectorShape2D.ShapeType.RECT: + _update_rect_corner_radius(current_selection, mouse_pos, "ry", !Input.is_key_pressed(KEY_SHIFT)) + else: + _update_curve_cp_out_position(current_selection, mouse_pos, current_selection.get_meta(META_NAME_HOVER_CP_OUT_IDX)) + elif current_selection.has_meta(META_NAME_HOVER_GRADIENT_FROM): + _update_gradient_from_position(current_selection, mouse_pos) + elif current_selection.has_meta(META_NAME_HOVER_GRADIENT_TO): + _update_gradient_to_position(current_selection, mouse_pos) + elif current_selection.has_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX): + _update_gradient_stop_color_pos(current_selection, mouse_pos, + current_selection.get_meta(META_NAME_HOVER_GRADIENT_COLOR_STOP_IDX)) + update_overlays() + return true + else: + for result : ScalableVectorShape2D in _find_scalable_vector_shape_2d_nodes_at(mouse_pos): + result.set_meta(META_NAME_SELECT_HINT, true) + if _is_svs_valid(current_selection): + _set_handle_hover(mouse_pos, current_selection) + update_overlays() + return false + + +static func _is_editing_enabled() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_EDITING_ENABLED): + return ProjectSettings.get_setting(SETTING_NAME_EDITING_ENABLED) + return true + + +static func _are_hints_enabled() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_HINTS_ENABLED): + return ProjectSettings.get_setting(SETTING_NAME_HINTS_ENABLED) + return true + + +static func _am_showing_point_numbers() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_SHOW_POINT_NUMBERS): + return ProjectSettings.get_setting(SETTING_NAME_SHOW_POINT_NUMBERS) + return true + + +static func _get_default_stroke_width() -> float: + if ProjectSettings.has_setting(SETTING_NAME_STROKE_WIDTH): + return ProjectSettings.get_setting(SETTING_NAME_STROKE_WIDTH) + return 10.0 + + +static func _get_default_stroke_color() -> Color: + if ProjectSettings.has_setting(SETTING_NAME_STROKE_COLOR): + return ProjectSettings.get_setting(SETTING_NAME_STROKE_COLOR) + return Color.WHITE + + +static func _get_default_begin_cap() -> Line2D.LineCapMode: + if ProjectSettings.has_setting(SETTING_NAME_DEFAULT_LINE_BEGIN_CAP): + return ProjectSettings.get_setting(SETTING_NAME_DEFAULT_LINE_BEGIN_CAP) + return Line2D.LineCapMode.LINE_CAP_NONE + + +static func _get_default_end_cap() -> Line2D.LineCapMode: + if ProjectSettings.has_setting(SETTING_NAME_DEFAULT_LINE_END_CAP): + return ProjectSettings.get_setting(SETTING_NAME_DEFAULT_LINE_END_CAP) + return Line2D.LineCapMode.LINE_CAP_NONE + + +static func _get_default_joint_mode() -> Line2D.LineJointMode: + if ProjectSettings.has_setting(SETTING_NAME_DEFAULT_LINE_JOINT_MODE): + return ProjectSettings.get_setting(SETTING_NAME_DEFAULT_LINE_JOINT_MODE) + return Line2D.LineJointMode.LINE_JOINT_SHARP + + +static func _get_default_fill_color() -> Color: + if ProjectSettings.has_setting(SETTING_NAME_FILL_COLOR): + return ProjectSettings.get_setting(SETTING_NAME_FILL_COLOR) + return Color.WHITE + + +static func _is_add_stroke_enabled() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_ADD_STROKE_ENABLED): + return ProjectSettings.get_setting(SETTING_NAME_ADD_STROKE_ENABLED) + return true + + +static func _using_line_2d_for_stroke() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_USE_LINE_2D_FOR_STROKE): + return ProjectSettings.get_setting(SETTING_NAME_USE_LINE_2D_FOR_STROKE) + return true + + +static func _is_add_fill_enabled() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_ADD_FILL_ENABLED): + return ProjectSettings.get_setting(SETTING_NAME_ADD_FILL_ENABLED) + return true + + +static func _add_collision_object_type() -> ScalableVectorShape2D.CollisionObjectType: + if ProjectSettings.has_setting(SETTING_NAME_ADD_COLLISION_TYPE): + return ProjectSettings.get_setting(SETTING_NAME_ADD_COLLISION_TYPE) + return ScalableVectorShape2D.CollisionObjectType.NONE + + + +static func _get_default_paint_order() -> PaintOrder: + if ProjectSettings.has_setting(SETTING_NAME_PAINT_ORDER): + return ProjectSettings.get_setting(SETTING_NAME_PAINT_ORDER) + return PaintOrder.FILL_STROKE_MARKERS + + +static func _is_snapped_to_pixel() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_SNAP_TO_PIXEL): + return ProjectSettings.get_setting(SETTING_NAME_SNAP_TO_PIXEL) + return false + + +static func _get_snap_resolution() -> float: + if ProjectSettings.has_setting(SETTING_NAME_SNAP_RESOLUTION): + return ProjectSettings.get_setting(SETTING_NAME_SNAP_RESOLUTION) + return 1.0 + + +static func _is_setting_update_curve_at_runtime() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_CURVE_UPDATE_CURVE_AT_RUNTIME): + return ProjectSettings.get_setting(SETTING_NAME_CURVE_UPDATE_CURVE_AT_RUNTIME) + return true + + +static func _is_making_curve_resources_local_to_scene() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_CURVE_RESOURCE_LOCAL_TO_SCENE): + return ProjectSettings.get_setting(SETTING_NAME_CURVE_RESOURCE_LOCAL_TO_SCENE) + return true + + +static func _use_antialiased_line_2d() -> bool: + if ProjectSettings.has_setting(SETTING_NAME_ANTIALIASED_LINE_2D): + return ProjectSettings.get_setting(SETTING_NAME_ANTIALIASED_LINE_2D) + return false + + +static func _get_default_tolerance_degrees() -> float: + if ProjectSettings.has_setting(SETTING_NAME_CURVE_TOLERANCE_DEGREES): + return ProjectSettings.get_setting(SETTING_NAME_CURVE_TOLERANCE_DEGREES) + return 4.0 + + +static func _get_default_max_stages() -> int: + if ProjectSettings.has_setting(SETTING_NAME_CURVE_MAX_STAGES): + return ProjectSettings.get_setting(SETTING_NAME_CURVE_MAX_STAGES) + return 5 + + +func _exit_tree(): + if _get_select_mode_button().toggled.is_connected(_on_select_mode_toggled): + _get_select_mode_button().toggled.disconnect(_on_select_mode_toggled) + + uniform_transform_edit_buttons.queue_free() + merge_node_toggle_button.queue_free() + remove_inspector_plugin(plugin) + remove_custom_type("DrawablePath2D") + remove_custom_type("ScalableVectorShape2D") + remove_control_from_bottom_panel(scalable_vector_shapes_2d_dock) + scalable_vector_shapes_2d_dock.free() + set_global_position_popup_panel.free() diff --git a/addons/curved_lines_2d/curved_lines_2d.gd.uid b/addons/curved_lines_2d/curved_lines_2d.gd.uid new file mode 100644 index 0000000..0133e1c --- /dev/null +++ b/addons/curved_lines_2d/curved_lines_2d.gd.uid @@ -0,0 +1 @@ +uid://jf8a2a3dnwk0 diff --git a/addons/curved_lines_2d/debug_label_settings.tres b/addons/curved_lines_2d/debug_label_settings.tres new file mode 100644 index 0000000..06c39c7 --- /dev/null +++ b/addons/curved_lines_2d/debug_label_settings.tres @@ -0,0 +1,4 @@ +[gd_resource type="LabelSettings" format=3 uid="uid://cfn4nq1j1xxok"] + +[resource] +font_color = Color(0.52549, 0.533333, 0.552941, 1) diff --git a/addons/curved_lines_2d/drawable_path_2d.gd b/addons/curved_lines_2d/drawable_path_2d.gd new file mode 100644 index 0000000..1bb2b9b --- /dev/null +++ b/addons/curved_lines_2d/drawable_path_2d.gd @@ -0,0 +1,141 @@ +@tool +extends Path2D +## A custom node that extends Path2D so it can be drawn as a Line2D +## Original adapted code: https://www.hedberggames.com/blog/rendering-curves-in-godot +## @deprecated: Use [ScalableVectorShape2D] instead. +class_name DrawablePath2D + +## Emitted when a new set of points was calculated for a connected Line2D, Polygon2D, or CollisionPolygon2D +signal path_changed(new_points : PackedVector2Array) + +## This signal is used internally in editor-mode to tell the DrawablePath2D tool that +## the instance of assigned Line2D, Polygon2D, or CollisionPolygon2D has changed +signal assigned_node_changed() + + +## The Polygon2D controlled by this Path2D +@export var polygon: Polygon2D: + set(_poly): + polygon = _poly + assigned_node_changed.emit() + +## The Line2D controlled by this Path2D +@export var line: Line2D: + set(_line): + line = _line + assigned_node_changed.emit() + +## The CollisionPolygon2D controlled by this Path2D +@export var collision_polygon: CollisionPolygon2D: + set(_poly): + collision_polygon = _poly + assigned_node_changed.emit() + +## Controls whether the path is treated as static (only update in editor) or dynamic (can be updated during runtime) +## If you set this to true, be alert for potential performance issues +@export var update_curve_at_runtime: bool = false + +## Controls the paramaters used to divide up the line in segments. +## These settings are prefilled with the default values. +@export_group("Tesselation settings") +## Controls how many subdivisions a curve segment may face before it is considered approximate enough. +## Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions +## per curve segment. Increase with care! +@export_range(1, 10) var max_stages : int = 5: + set(_max_stages): + max_stages = _max_stages + assigned_node_changed.emit() +## Controls how many degrees the midpoint of a segment may deviate from the real curve, before the +## segment has to be subdivided. +@export_range(0.0, 180.0) var tolerance_degrees := 4.0: + set(_tolerance_degrees): + tolerance_degrees = _tolerance_degrees + assigned_node_changed.emit() + +var lock_assigned_shapes := true + +# Wire up signals at runtime +func _ready(): + if update_curve_at_runtime: + if not curve.changed.is_connected(curve_changed): + curve.changed.connect(curve_changed) + + +# Wire up signals on enter tree for the editor +func _enter_tree(): + if Engine.is_editor_hint(): + if not curve.changed.is_connected(curve_changed): + curve.changed.connect(curve_changed) + if not assigned_node_changed.is_connected(_on_assigned_node_changed): + assigned_node_changed.connect(_on_assigned_node_changed) + # handles update when reparenting + if update_curve_at_runtime: + if not curve.changed.is_connected(curve_changed): + curve.changed.connect(curve_changed) + + +# Clean up signals (ie. when closing scene) to prevent error messages in the editor +func _exit_tree(): + if curve.changed.is_connected(curve_changed): + curve.changed.disconnect(curve_changed) + + +func _on_assigned_node_changed(): + if is_instance_valid(line): + if lock_assigned_shapes: + line.set_meta("_edit_lock_", true) + curve_changed() + if is_instance_valid(polygon): + if lock_assigned_shapes: + polygon.set_meta("_edit_lock_", true) + curve_changed() + if is_instance_valid(collision_polygon): + if lock_assigned_shapes: + collision_polygon.set_meta("_edit_lock_", true) + curve_changed() + + +# Redraw the line based on the new curve, using its tesselate method +func curve_changed(): + if (not is_instance_valid(line) and not is_instance_valid(polygon) + and not is_instance_valid(collision_polygon) + and not path_changed.has_connections()): + # guard against needlessly invoking expensive tesselate operation + return + + var new_points := curve.tessellate(max_stages, tolerance_degrees) + # Fixes cases start- and end-node are so close to each other that + # polygons won't fill and closed lines won't cap nicely + if new_points[0].distance_to(new_points[new_points.size()-1]) < 0.001: + new_points.remove_at(new_points.size() - 1) + if is_instance_valid(line): + line.points = new_points + if is_instance_valid(polygon): + polygon.polygon = new_points + if is_instance_valid(collision_polygon): + collision_polygon.polygon = new_points + path_changed.emit(new_points) + + +func get_bounding_rect() -> Rect2: + var points := curve.tessellate(max_stages, tolerance_degrees) + if points.size() < 1: + # Cannot calculate a center for 0 points + return Rect2(Vector2.ZERO, Vector2.ZERO) + var minx := INF + var miny := INF + var maxx := -INF + var maxy := -INF + for p : Vector2 in points: + minx = p.x if p.x < minx else minx + miny = p.y if p.y < miny else miny + maxx = p.x if p.x > maxx else maxx + maxy = p.y if p.y > maxy else maxy + return Rect2(minx, miny, maxx - minx, maxy - miny) + + +func set_position_to_center() -> void: + var c = get_bounding_rect().get_center() + position += c + for i in range(curve.get_point_count()): + curve.set_point_position(i, curve.get_point_position(i) - c) diff --git a/addons/curved_lines_2d/drawable_path_2d.gd.uid b/addons/curved_lines_2d/drawable_path_2d.gd.uid new file mode 100644 index 0000000..ab6dbcd --- /dev/null +++ b/addons/curved_lines_2d/drawable_path_2d.gd.uid @@ -0,0 +1 @@ +uid://brqrlfnreboqp diff --git a/addons/curved_lines_2d/error_label_settings.tres b/addons/curved_lines_2d/error_label_settings.tres new file mode 100644 index 0000000..7048913 --- /dev/null +++ b/addons/curved_lines_2d/error_label_settings.tres @@ -0,0 +1,4 @@ +[gd_resource type="LabelSettings" format=3 uid="uid://c77jfonujet7g"] + +[resource] +font_color = Color(1, 0, 0, 1) diff --git a/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.gd b/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.gd new file mode 100644 index 0000000..b26445c --- /dev/null +++ b/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.gd @@ -0,0 +1,77 @@ +extends Node2D + + +## Only drawing polygons is fastest +@export var draw_fills := true + +## Drawing strokes with cutouts requires extra compute, but still ok +@export var draw_strokes := true + +## Redrawing navigation is fast, but would slow down agents +@export var draw_navigation := false + +## Redrawing collision polygons is heavy +@export var draw_collision := false + + +var foobar := false +func _input(event): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + add_ellipse(event.position) + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: + add_clip_to_ellipses(event.position) + + +func add_clip_to_ellipses(at_pos: Vector2): + var ellipse : ScalableVectorShape2D = null + for ch in get_children(): + if ch is ScalableVectorShape2D and ch.shape_type == ScalableVectorShape2D.ShapeType.ELLIPSE and ch.clipped_polygon_has_point(at_pos): + ellipse = ch + + if not ellipse: + return + + foobar = not foobar + var rect = ScalableVectorShape2D.new() + rect.name = "ClipRect" + rect.update_curve_at_runtime = true + rect.shape_type = ScalableVectorShape2D.ShapeType.RECT + rect.position = at_pos - ellipse.position + rect.size = Vector2(200, 40) if foobar else Vector2(40, 200) + rect.rx = 20 + rect.ry = 20 + ellipse.add_child(rect, true) + ellipse.add_clip_path(rect) + + +func add_ellipse(at_pos: Vector2): + var ellipse = ScalableVectorShape2D.new() + # make sure it will rerender in game + ellipse.name = "Ellipse" + ellipse.update_curve_at_runtime = true + ellipse.shape_type = ScalableVectorShape2D.ShapeType.ELLIPSE + ellipse.position = at_pos + ellipse.size = Vector2(500, 250) + + if draw_fills: + # assign a Polygon2D as fill + ellipse.polygon = Polygon2D.new() + ellipse.polygon.color = Color.WHITE + ellipse.add_child(ellipse.polygon) + + if draw_strokes: + # assign a Line2D as stroke + ellipse.line = Line2D.new() + ellipse.stroke_color = Color.BLACK + ellipse.add_child(ellipse.line) + + if draw_collision: + # assign a collision object to hold new collision polygons + ellipse.collision_object = StaticBody2D.new() + ellipse.add_child(ellipse.collision_object) + + if draw_navigation: + ellipse.navigation_region = NavigationRegion2D.new() + ellipse.add_child(ellipse.navigation_region) + + add_child(ellipse, true) diff --git a/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.gd.uid b/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.gd.uid new file mode 100644 index 0000000..3d72393 --- /dev/null +++ b/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.gd.uid @@ -0,0 +1 @@ +uid://c8rves0r1i4up diff --git a/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.tscn b/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.tscn new file mode 100644 index 0000000..fda0d8d --- /dev/null +++ b/addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.tscn @@ -0,0 +1,44 @@ +[gd_scene load_steps=4 format=3 uid="uid://c2k8nyelxdgi3"] + +[ext_resource type="Script" uid="uid://c8rves0r1i4up" path="res://addons/curved_lines_2d/examples/add_shapes_programmatically/click_ellipse.gd" id="1_1ehuy"] +[ext_resource type="Script" uid="uid://dr5dl1my0r0rl" path="res://addons/curved_lines_2d/examples/add_shapes_programmatically/label.gd" id="2_a3wah"] + +[sub_resource type="LabelSettings" id="LabelSettings_1ehuy"] +font_size = 32 +outline_size = 4 +outline_color = Color(0, 0, 0, 1) + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ClickEllipse" type="Node2D" parent="."] +script = ExtResource("1_1ehuy") + +[node name="Label" type="Label" parent="."] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -217.0 +offset_top = -22.5 +offset_right = 217.0 +offset_bottom = 22.5 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +text = "- Left click to add an ellipse - + +- Right click to cut a hole in the ellipse -" +label_settings = SubResource("LabelSettings_1ehuy") +horizontal_alignment = 1 +script = ExtResource("2_a3wah") diff --git a/addons/curved_lines_2d/examples/add_shapes_programmatically/label.gd b/addons/curved_lines_2d/examples/add_shapes_programmatically/label.gd new file mode 100644 index 0000000..6548766 --- /dev/null +++ b/addons/curved_lines_2d/examples/add_shapes_programmatically/label.gd @@ -0,0 +1,7 @@ +extends Label + +func _process(delta: float) -> void: + if modulate.a > 0.0: + modulate.a -= delta * 0.25 + else: + queue_free() diff --git a/addons/curved_lines_2d/examples/add_shapes_programmatically/label.gd.uid b/addons/curved_lines_2d/examples/add_shapes_programmatically/label.gd.uid new file mode 100644 index 0000000..3fb04d4 --- /dev/null +++ b/addons/curved_lines_2d/examples/add_shapes_programmatically/label.gd.uid @@ -0,0 +1 @@ +uid://dr5dl1my0r0rl diff --git a/addons/curved_lines_2d/examples/cloud.gd b/addons/curved_lines_2d/examples/cloud.gd new file mode 100644 index 0000000..9625ced --- /dev/null +++ b/addons/curved_lines_2d/examples/cloud.gd @@ -0,0 +1,4 @@ +extends Node2D + +func _ready() -> void: + $AnimationPlayer.play("cloud_doing_cloud_stuff") diff --git a/addons/curved_lines_2d/examples/cloud.gd.uid b/addons/curved_lines_2d/examples/cloud.gd.uid new file mode 100644 index 0000000..4da2c46 --- /dev/null +++ b/addons/curved_lines_2d/examples/cloud.gd.uid @@ -0,0 +1 @@ +uid://376ru33navgn diff --git a/addons/curved_lines_2d/examples/cloud.tscn b/addons/curved_lines_2d/examples/cloud.tscn new file mode 100644 index 0000000..2b6bf20 --- /dev/null +++ b/addons/curved_lines_2d/examples/cloud.tscn @@ -0,0 +1,450 @@ +[gd_scene load_steps=32 format=3 uid="uid://dqxb6wxwmw6r0"] + +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="1_8gu3s"] +[ext_resource type="Script" uid="uid://376ru33navgn" path="res://addons/curved_lines_2d/examples/cloud.gd" id="1_nwkfo"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="2_nwkfo"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="3_oar4j"] + +[sub_resource type="Curve2D" id="Curve2D_m6x0f"] +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 20.1859, -18.275, 0, 0, 0, 0, -1.25378, -25.1621, 0, 0, 0, 0, -7.76143, -26.8937, 0, 0, 0, 0, -18.1859, -21.571, 0, 0, 0, 0, -22.2008, -22.2011, 0, 0, 0, 0, -34.6552, -10.4688, 0, 0, 0, 0, -26.6916, 0.443052, 0, 0, 0, 0, -26.713, 0.72216, 0, 0, 0, 0, -16.9296, 12.1506, 0, 0, 0, 0, -16.9664, 12.6348, 0, 0, 0, 0, -4.51253, 24.367, 0, 0, 0, 0, 3.18721, 21.8227, 0, 0, 0, 0, 13.8984, 27.6159, 0, 0, 0, 0, 26.3522, 15.8836, 0, 0, 0, 0, 25.8708, 12.6639, 0, 0, 0, 0, 29.6017, 4.33186, 0, 0, 0, 0, 29.277, 1.68612, 0, 0, 0, 0, 34.6552, -7.94157, 0, 0, 0, 0, 20.1859, -18.275, 0, 0, 0, 0, 20.1859, -18.275) +} +point_count = 20 + +[sub_resource type="Resource" id="Resource_q0tfb"] +script = ExtResource("2_nwkfo") +start_point = 0 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_m08lf"] +script = ExtResource("2_nwkfo") +start_point = 1 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_h7xxh"] +script = ExtResource("2_nwkfo") +start_point = 2 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_2y863"] +script = ExtResource("2_nwkfo") +start_point = 3 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_el6ml"] +script = ExtResource("2_nwkfo") +start_point = 4 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_pfoxu"] +script = ExtResource("2_nwkfo") +start_point = 5 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_3ghir"] +script = ExtResource("2_nwkfo") +start_point = 6 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_xvmfk"] +script = ExtResource("2_nwkfo") +start_point = 7 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_t7p2c"] +script = ExtResource("2_nwkfo") +start_point = 8 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_upm0f"] +script = ExtResource("2_nwkfo") +start_point = 9 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_jnmgg"] +script = ExtResource("2_nwkfo") +start_point = 10 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_0ig0s"] +script = ExtResource("2_nwkfo") +start_point = 11 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_gou68"] +script = ExtResource("2_nwkfo") +start_point = 12 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_42033"] +script = ExtResource("2_nwkfo") +start_point = 13 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_h1yoj"] +script = ExtResource("2_nwkfo") +start_point = 14 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_8u3ec"] +script = ExtResource("2_nwkfo") +start_point = 15 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_50naw"] +script = ExtResource("2_nwkfo") +start_point = 16 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_a83h2"] +script = ExtResource("2_nwkfo") +start_point = 17 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_61vjn"] +script = ExtResource("3_oar4j") +arcs = Array[ExtResource("2_nwkfo")]([SubResource("Resource_q0tfb"), SubResource("Resource_m08lf"), SubResource("Resource_h7xxh"), SubResource("Resource_2y863"), SubResource("Resource_el6ml"), SubResource("Resource_pfoxu"), SubResource("Resource_3ghir"), SubResource("Resource_xvmfk"), SubResource("Resource_t7p2c"), SubResource("Resource_upm0f"), SubResource("Resource_jnmgg"), SubResource("Resource_0ig0s"), SubResource("Resource_gou68"), SubResource("Resource_42033"), SubResource("Resource_h1yoj"), SubResource("Resource_8u3ec"), SubResource("Resource_50naw"), SubResource("Resource_a83h2")]) + +[sub_resource type="Gradient" id="Gradient_nwkfo"] +offsets = PackedFloat32Array(0, 0.283143, 1) +colors = PackedColorArray(1, 1, 1, 1, 0.988493, 0.967342, 0.967342, 0.928441, 0.859375, 0.600891, 0.600891, 0.12549) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_oar4j"] +gradient = SubResource("Gradient_nwkfo") +width = 69 +height = 57 +fill_from = Vector2(0.482854, 0.914123) +fill_to = Vector2(0.633236, -0.0185821) + +[sub_resource type="Curve2D" id="Curve2D_a6hwq"] +_data = { +"points": PackedVector2Array(0, 0, 0, 5.523, 10, 0, 5.523, 0, -5.523, 0, 0, 10, 0, 5.523, 0, -5.523, -10, 0, -5.523, 0, 5.523, 0, 0, -10, 0, -5.523, 0, 0, 10, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_kh3t1"] +script = ExtResource("3_oar4j") +arcs = Array[ExtResource("2_nwkfo")]([]) + +[sub_resource type="Animation" id="Animation_m6x0f"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("CloudPath:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.816665] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("CloudPath/BubbleCutout:position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(31.2104, -35.3104)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("CloudPath:curve:point_19/position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(20.1859, -18.275)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("CloudPath:curve:point_18/position") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(20.1859, -18.275)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("CloudPath:curve:point_0/position") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(20.1859, -18.275)] +} + +[sub_resource type="Animation" id="Animation_oar4j"] +resource_name = "cloud_doing_cloud_stuff" +length = 3.0 +loop_mode = 1 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("CloudPath:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1.5, 3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0, -0.425622, 0.0] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("CloudPath:visible") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(1.5), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("CloudPath/BubbleCutout:position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 1.5, 3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(19.1408, -16.6223), Vector2(29.3202, -54.9174), Vector2(29.3828, -66.8249)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("CloudPath:curve:point_0/position") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 1.5, 3), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1), +"update": 0, +"values": [Vector2(10.4099, -22.163), Vector2(12.8712, -24.8974), Vector2(13.2506, -25.1345), Vector2(13.6988, -23.5426), Vector2(15.3796, -21.0777), Vector2(16.7565, -18.4755), Vector2(17.7767, -16.9076), Vector2(17.7767, -16.9076), Vector2(17.7767, -16.9076)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("CloudPath:curve:point_18/position") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 1.5, 3), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1), +"update": 0, +"values": [Vector2(28.8791, -13.4321), Vector2(30.3815, -14.554), Vector2(30.6663, -16.2217), Vector2(27.5951, -15.9178), Vector2(26.2874, -15.8419), Vector2(21.5472, -15.8921), Vector2(17.7767, -16.9076), Vector2(17.7767, -16.9076), Vector2(17.7767, -16.9076)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("CloudPath:curve:point_19/position") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 1.5, 3), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1), +"update": 0, +"values": [Vector2(10.4099, -22.163), Vector2(12.8712, -24.8974), Vector2(13.2506, -25.1345), Vector2(13.6988, -23.5426), Vector2(15.3796, -21.0777), Vector2(16.7565, -18.4755), Vector2(17.7767, -16.9076), Vector2(17.7767, -16.9076), Vector2(17.7767, -16.9076)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("CloudPath/Fill:texture:gradient:colors") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0, 1.49), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [PackedColorArray(1, 1, 1, 1, 0.988493, 0.967342, 0.967342, 0.928441, 0.859375, 0.600891, 0.600891, 0.12549), PackedColorArray(1, 1, 1, 1, 0.988493, 0.967342, 0.967342, 0.928441, 0.859375, 0.600891, 0.600891, 0.12549)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("CloudPath/Fill:texture:gradient:offsets") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 1.49), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [PackedFloat32Array(0, 0.283143, 1), PackedFloat32Array(0, 0.283143, 1)] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("CloudPath/Fill:texture:fill_from") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0, 1.49), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0.543707, 0.921161), Vector2(0.344003, 0.898063)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("CloudPath/Fill:texture:fill_to") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0, 1.49), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0.53402, -0.0363871), Vector2(0.85962, 0.0220444)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_q0tfb"] +_data = { +&"RESET": SubResource("Animation_m6x0f"), +&"cloud_doing_cloud_stuff": SubResource("Animation_oar4j") +} + +[node name="Cloud" type="Node2D"] +script = ExtResource("1_nwkfo") +metadata/svg_root = true + +[node name="CloudPath" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(470, 285) +rotation = 0.816665 +scale = Vector2(5.95586, 5.95586) +script = ExtResource("1_8gu3s") +polygon = NodePath("Fill") +line = NodePath("Stroke") +curve = SubResource("Curve2D_m6x0f") +update_curve_at_runtime = true +tolerance_degrees = 15.0 +arc_list = SubResource("Resource_61vjn") +clip_paths = [NodePath("BubbleCutout")] + +[node name="Stroke" type="Line2D" parent="CloudPath"] +self_modulate = Color(1, 1, 1, 0.818878) +points = PackedVector2Array(12.2196, -29.451, 14.9707, -28.1803, 17.279, -26.2821, 18.987, -23.8858, 19.9785, -21.1548, 20.1859, -18.275, 22.4831, -18.5727, 25.5339, -18.3044, 28.4069, -17.3013, 30.9065, -15.6319, 32.8622, -13.41, 34.1408, -10.787, 34.6552, -7.94157, 34.3943, -5.26904, 33.3601, -2.55205, 31.6147, -0.179764, 29.277, 1.68612, 29.6017, 4.33186, 29.5974, 4.96397, 29.0912, 7.81068, 27.8201, 10.437, 25.8708, 12.6639, 25.9755, 13.0191, 26.3522, 15.8836, 26.3522, 17.2784, 25.7615, 20.1106, 24.4128, 22.7023, 22.398, 24.8769, 19.8544, 26.4861, 16.9554, 27.4203, 13.8984, 27.6159, 13.1832, 27.6175, 10.1578, 27.1606, 7.36106, 25.9817, 4.98352, 24.161, 3.18721, 21.8227, 1.38286, 22.9835, -1.46816, 24.0408, -4.51253, 24.367, -5.99311, 24.367, -8.99961, 23.8105, -11.7508, 22.5399, -14.0591, 20.6418, -15.7673, 18.2456, -16.7589, 15.5145, -16.9664, 12.6348, -16.9296, 12.1506, -18.5607, 11.7784, -21.3327, 10.5487, -23.6724, 8.6851, -25.4204, 6.31449, -26.4575, 3.59848, -26.713, 0.72216, -26.6916, 0.443054, -29.1951, -0.681374, -31.5499, -2.52806, -33.3171, -4.88597, -34.3763, -7.59441, -34.6552, -10.4688, -34.6552, -11.8642, -34.0644, -14.6964, -32.7155, -17.288, -30.7006, -19.4625, -28.1569, -21.0716, -25.2578, -22.0057, -22.2008, -22.2011, -21.1836, -22.1683, -18.1859, -21.571, -18.1132, -21.6826, -16.1692, -23.9136, -13.6784, -25.5946, -10.8107, -26.6111, -7.76143, -26.8937, -7.04766, -26.8846, -4.03036, -26.3826, -1.25378, -25.1621, 0.713303, -27.2692, 3.25703, -28.8783, 6.15617, -29.8123, 9.21315, -30.0076) +closed = true +width = 2.64583 +default_color = Color(0, 0, 0, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="ExtraStroke" type="Line2D" parent="CloudPath/Stroke"] +points = PackedVector2Array(32.2329, -45.2588, 33.2258, -45.1072, 34.1842, -44.8608, 35.1029, -44.5246, 35.9771, -44.1035, 36.8016, -43.6026, 37.5714, -43.0269, 38.2815, -42.3815, 38.9269, -41.6714, 39.5026, -40.9016, 40.0035, -40.0771, 40.4246, -39.2029, 40.7608, -38.2842, 41.0072, -37.3258, 41.1588, -36.3329, 41.2104, -35.3104, 41.1588, -34.2879, 41.0072, -33.295, 40.7608, -32.3366, 40.4246, -31.4179, 40.0035, -30.5437, 39.5026, -29.7192, 38.9269, -28.9494, 38.2815, -28.2393, 37.5714, -27.5939, 36.8016, -27.0182, 35.9771, -26.5173, 35.1029, -26.0962, 34.1842, -25.76, 33.2258, -25.5136, 32.2329, -25.362, 31.2104, -25.3104, 30.1879, -25.362, 29.195, -25.5136, 28.2367, -25.76, 27.3179, -26.0962, 26.4437, -26.5173, 25.6192, -27.0182, 24.8494, -27.5939, 24.1393, -28.2393, 23.4939, -28.9494, 22.9182, -29.7192, 22.4173, -30.5437, 21.9962, -31.4179, 21.66, -32.3366, 21.4136, -33.295, 21.262, -34.2879, 21.2104, -35.3104, 21.262, -36.3329, 21.4136, -37.3258, 21.66, -38.2841, 21.9962, -39.2029, 22.4173, -40.0771, 22.9182, -40.9016, 23.4939, -41.6714, 24.1393, -42.3815, 24.8494, -43.0269, 25.6192, -43.6026, 26.4437, -44.1035, 27.3179, -44.5246, 28.2367, -44.8608, 29.195, -45.1072, 30.1879, -45.2588, 31.2104, -45.3104) +closed = true +width = 2.64583 +default_color = Color(0, 0, 0, 1) +metadata/_edit_lock_ = true + +[node name="ExtraStroke2" type="Line2D" parent="CloudPath/Stroke"] +visible = false +points = PackedVector2Array(-21.3879, -22.1816, -20.5724, -22.1084, -19.7643, -21.9818, -19.7163, -21.971, -22.2008, -22.2011) +closed = true +width = 2.64583 +default_color = Color(0, 0, 0, 1) +metadata/_edit_lock_ = true + +[node name="ExtraStroke3" type="Line2D" parent="CloudPath/Stroke"] +visible = false +points = PackedVector2Array(32.2328, -45.2588, 33.2258, -45.1073, 34.1842, -44.8609, 35.1029, -44.5246, 35.9771, -44.1035, 36.8016, -43.6026, 37.5715, -43.027, 38.2816, -42.3815, 38.9269, -41.6714, 39.5026, -40.9016, 40.0035, -40.0771, 40.4246, -39.2029, 40.7609, -38.2842, 41.0073, -37.3258, 41.1588, -36.3329, 41.2104, -35.3104, 41.1588, -34.288, 41.0073, -33.295, 40.7608, -32.3367, 40.4246, -31.4179, 40.0035, -30.5437, 39.5026, -29.7193, 38.9269, -28.9494, 38.2816, -28.2393, 37.5714, -27.5939, 36.8016, -27.0182, 35.9771, -26.5173, 35.103, -26.0963, 34.1842, -25.76, 33.2258, -25.5136, 32.2329, -25.362, 31.2104, -25.3104, 30.1879, -25.362, 29.195, -25.5136, 28.2367, -25.76, 27.3179, -26.0963, 26.4438, -26.5173, 25.6193, -27.0182, 24.8494, -27.5939, 24.1393, -28.2393, 23.4939, -28.9494, 22.9183, -29.7193, 22.4173, -30.5438, 21.9963, -31.4179, 21.66, -32.3366, 21.4136, -33.295, 21.262, -34.2879, 21.2104, -35.3104, 21.262, -36.3329, 21.4136, -37.3258, 21.66, -38.2841, 21.9962, -39.2029, 22.4174, -40.0771, 22.9182, -40.9016, 23.4939, -41.6714, 24.1393, -42.3815, 24.8494, -43.0269, 25.6193, -43.6026, 26.4438, -44.1035, 27.3179, -44.5246, 28.2366, -44.8609, 29.195, -45.1072, 30.1879, -45.2588, 31.2104, -45.3104) +closed = true +width = 2.64583 +default_color = Color(0, 0, 0, 1) +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="CloudPath"] +texture = SubResource("GradientTexture2D_oar4j") +texture_offset = Vector2(34.6552, 30.0076) +polygon = PackedVector2Array(12.2196, -29.451, 14.9707, -28.1803, 17.279, -26.2821, 18.987, -23.8858, 19.9785, -21.1548, 20.1859, -18.275, 22.4831, -18.5727, 25.5339, -18.3044, 28.4069, -17.3013, 30.9065, -15.6319, 32.8622, -13.41, 34.1408, -10.787, 34.6552, -7.94157, 34.3943, -5.26904, 33.3601, -2.55205, 31.6147, -0.179764, 29.277, 1.68612, 29.6017, 4.33186, 29.5974, 4.96397, 29.0912, 7.81068, 27.8201, 10.437, 25.8708, 12.6639, 25.9755, 13.0191, 26.3522, 15.8836, 26.3522, 17.2784, 25.7615, 20.1106, 24.4128, 22.7023, 22.398, 24.8769, 19.8544, 26.4861, 16.9554, 27.4203, 13.8984, 27.6159, 13.1832, 27.6175, 10.1578, 27.1606, 7.36106, 25.9817, 4.98352, 24.161, 3.18721, 21.8227, 1.38286, 22.9835, -1.46816, 24.0408, -4.51253, 24.367, -5.99311, 24.367, -8.99961, 23.8105, -11.7508, 22.5399, -14.0591, 20.6418, -15.7673, 18.2456, -16.7589, 15.5145, -16.9664, 12.6348, -16.9296, 12.1506, -18.5607, 11.7784, -21.3327, 10.5487, -23.6724, 8.6851, -25.4204, 6.31449, -26.4575, 3.59848, -26.713, 0.72216, -26.6916, 0.443054, -29.1951, -0.681374, -31.5499, -2.52806, -33.3171, -4.88597, -34.3763, -7.59441, -34.6552, -10.4688, -34.6552, -11.8642, -34.0644, -14.6964, -32.7155, -17.288, -30.7006, -19.4625, -28.1569, -21.0716, -25.2578, -22.0057, -22.2008, -22.2011, -21.1836, -22.1683, -18.1859, -21.571, -18.1132, -21.6826, -16.1692, -23.9136, -13.6784, -25.5946, -10.8107, -26.6111, -7.76143, -26.8937, -7.04766, -26.8846, -4.03036, -26.3826, -1.25378, -25.1621, 0.713303, -27.2692, 3.25703, -28.8783, 6.15617, -29.8123, 9.21315, -30.0076, 32.2329, -45.2588, 33.2258, -45.1072, 34.1842, -44.8608, 35.1029, -44.5246, 35.9771, -44.1035, 36.8016, -43.6026, 37.5714, -43.0269, 38.2815, -42.3815, 38.9269, -41.6714, 39.5026, -40.9016, 40.0035, -40.0771, 40.4246, -39.2029, 40.7608, -38.2842, 41.0072, -37.3258, 41.1588, -36.3329, 41.2104, -35.3104, 41.1588, -34.2879, 41.0072, -33.295, 40.7608, -32.3366, 40.4246, -31.4179, 40.0035, -30.5437, 39.5026, -29.7192, 38.9269, -28.9494, 38.2815, -28.2393, 37.5714, -27.5939, 36.8016, -27.0182, 35.9771, -26.5173, 35.1029, -26.0962, 34.1842, -25.76, 33.2258, -25.5136, 32.2329, -25.362, 31.2104, -25.3104, 30.1879, -25.362, 29.195, -25.5136, 28.2367, -25.76, 27.3179, -26.0962, 26.4437, -26.5173, 25.6192, -27.0182, 24.8494, -27.5939, 24.1393, -28.2393, 23.4939, -28.9494, 22.9182, -29.7192, 22.4173, -30.5437, 21.9962, -31.4179, 21.66, -32.3366, 21.4136, -33.295, 21.262, -34.2879, 21.2104, -35.3104, 21.262, -36.3329, 21.4136, -37.3258, 21.66, -38.2841, 21.9962, -39.2029, 22.4173, -40.0771, 22.9182, -40.9016, 23.4939, -41.6714, 24.1393, -42.3815, 24.8494, -43.0269, 25.6192, -43.6026, 26.4437, -44.1035, 27.3179, -44.5246, 28.2367, -44.8608, 29.195, -45.1072, 30.1879, -45.2588, 31.2104, -45.3104) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79], [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143]] +metadata/_edit_lock_ = true + +[node name="BubbleCutout" type="Node2D" parent="CloudPath"] +position = Vector2(31.2104, -35.3104) +script = ExtResource("1_8gu3s") +curve = SubResource("Curve2D_a6hwq") +update_curve_at_runtime = true +arc_list = SubResource("Resource_kh3t1") +use_union_in_stead_of_clipping = true +shape_type = 2 +size = Vector2(20, 20) +rx = 10.0 +ry = 10.0 +metadata/_custom_type_script = "uid://de3jpss66xjfh" + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +&"": SubResource("AnimationLibrary_q0tfb") +} diff --git a/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.gd b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.gd new file mode 100644 index 0000000..c4d5640 --- /dev/null +++ b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.gd @@ -0,0 +1,22 @@ +extends Node2D + +@export var is_open := true: + set(flag): + if flag != is_open: + if flag: + $AnimationPlayer.play("open") + else: + $AnimationPlayer.play("close") + is_open = flag + +@onready var _initial_iris_position : Vector2 = $Outline/Iris.position + +func _ready() -> void: + $AnimationPlayer.play("RESET") + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseMotion: + $Outline/Iris.position = _initial_iris_position + ( + position.direction_to(get_local_mouse_position()) * 1.5 + ) diff --git a/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.gd.uid b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.gd.uid new file mode 100644 index 0000000..cc03356 --- /dev/null +++ b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.gd.uid @@ -0,0 +1 @@ +uid://bjguk7v0cas38 diff --git a/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.tscn b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.tscn new file mode 100644 index 0000000..c75f645 --- /dev/null +++ b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.tscn @@ -0,0 +1,197 @@ +[gd_scene load_steps=19 format=3 uid="uid://b7d7mk2ioy617"] + +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="1_l1n7h"] +[ext_resource type="Script" uid="uid://bjguk7v0cas38" path="res://addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.gd" id="1_x8diq"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="2_x8diq"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="3_kjel7"] + +[sub_resource type="Curve2D" id="Curve2D_ng2ve"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 3.3138, 6.5, 0, 3.58995, 0, -3.58995, 0, 0, 6, 0, 3.3138, 0, -3.3138, -6.5, 0, -3.58995, 0, 3.58995, 0, 0, -6, 0, -3.3138, 0, 0, 6.5, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_popqj"] +resource_local_to_scene = true +script = ExtResource("3_kjel7") +arcs = Array[ExtResource("2_x8diq")]([]) + +[sub_resource type="Curve2D" id="Curve2D_uahbu"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 4.9572, 0.476006, 0, 0, 0, 0, 0, 10.7101, 0, 0, 0, 0, -5.12222, -1.52588e-05, 0, 0, 0, 0, 0, -10.7101, 0, 0, 0, 0, 4.9572, 0.476006) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_lovsl"] +script = ExtResource("2_x8diq") +start_point = 0 +radius = Vector2(5.12221, 10.7101) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_shxx8"] +script = ExtResource("2_x8diq") +start_point = 1 +radius = Vector2(5.12221, 10.7101) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_jon1a"] +script = ExtResource("2_x8diq") +start_point = 2 +radius = Vector2(5.12221, 10.7101) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_sm24i"] +script = ExtResource("2_x8diq") +start_point = 3 +radius = Vector2(5.12221, 10.7101) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_kdkpg"] +resource_local_to_scene = true +script = ExtResource("3_kjel7") +arcs = Array[ExtResource("2_x8diq")]([SubResource("Resource_lovsl"), SubResource("Resource_shxx8"), SubResource("Resource_jon1a"), SubResource("Resource_sm24i")]) + +[sub_resource type="Curve2D" id="Curve2D_4mfx8"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 1.92886, 1.62979, 0, 0.900136, 0, -0.900136, 0, 0, 3.49241, 0, 1.92886, 0, -1.92886, -1.62979, 0, -0.900136, 0, 0.900136, 0, 0, -3.49241, 0, -1.92886, 0, 0, 1.62979, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_hq7x2"] +resource_local_to_scene = true +script = ExtResource("3_kjel7") +arcs = Array[ExtResource("2_x8diq")]([]) + +[sub_resource type="Animation" id="Animation_kjel7"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Outline:size") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(13, 12)] +} + +[sub_resource type="Animation" id="Animation_cko43"] +resource_name = "close" +length = 0.2 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Outline:size") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(13, 12), Vector2(13, 3), Vector2(13, 0)] +} + +[sub_resource type="Animation" id="Animation_x8diq"] +resource_name = "open" +length = 0.2 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Outline:size") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(13, 0), Vector2(13, 12)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_ppl4k"] +_data = { +&"RESET": SubResource("Animation_kjel7"), +&"close": SubResource("Animation_cko43"), +&"open": SubResource("Animation_x8diq") +} + +[node name="Eye" type="Node2D"] +script = ExtResource("1_x8diq") + +[node name="Outline" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "line")] +script = ExtResource("1_l1n7h") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 1.5 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ng2ve") +update_curve_at_runtime = true +tolerance_degrees = 10.0 +arc_list = SubResource("Resource_popqj") +use_interect_when_clipping = true +shape_type = 2 +size = Vector2(13, 12) +rx = 6.5 +ry = 6.0 + +[node name="Stroke" type="Line2D" parent="Outline"] +points = PackedVector2Array(6.5, 0, 6.36795, 1.20924, 5.98921, 2.33551, 5.38993, 3.3547, 4.59623, 4.24267, 3.63426, 4.97532, 2.53014, 5.5285, 1.31001, 5.87811, 0, 6, -1.31001, 5.87811, -2.53014, 5.5285, -3.63426, 4.97532, -4.59623, 4.24267, -5.38993, 3.3547, -5.98921, 2.33551, -6.36795, 1.20924, -6.5, 0, -6.36795, -1.20924, -5.98921, -2.33551, -5.38993, -3.3547, -4.59623, -4.24267, -3.63426, -4.97532, -2.53014, -5.5285, -1.31001, -5.87811, 0, -6, 1.31001, -5.87811, 2.53014, -5.5285, 3.63426, -4.97532, 4.59623, -4.24267, 5.38993, -3.3547, 5.98921, -2.33551, 6.36795, -1.20924) +closed = true +width = 1.5 +default_color = Color(0, 0, 0, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Outline"] +polygon = PackedVector2Array(6.5, 0, 6.36795, 1.20924, 5.98921, 2.33551, 5.38993, 3.3547, 4.59623, 4.24267, 3.63426, 4.97532, 2.53014, 5.5285, 1.31001, 5.87811, 0, 6, -1.31001, 5.87811, -2.53014, 5.5285, -3.63426, 4.97532, -4.59623, 4.24267, -5.38993, 3.3547, -5.98921, 2.33551, -6.36795, 1.20924, -6.5, 0, -6.36795, -1.20924, -5.98921, -2.33551, -5.38993, -3.3547, -4.59623, -4.24267, -3.63426, -4.97532, -2.53014, -5.5285, -1.31001, -5.87811, 0, -6, 1.31001, -5.87811, 2.53014, -5.5285, 3.63426, -4.97532, 4.59623, -4.24267, 5.38993, -3.3547, 5.98921, -2.33551, 6.36795, -1.20924) +metadata/_edit_lock_ = true + +[node name="Iris" type="Node2D" parent="Outline" node_paths=PackedStringArray("polygon", "clip_paths")] +position = Vector2(0.145126, -0.35392) +script = ExtResource("1_l1n7h") +polygon = NodePath("Fill") +curve = SubResource("Curve2D_uahbu") +update_curve_at_runtime = true +arc_list = SubResource("Resource_kdkpg") +clip_paths = [NodePath("..")] + +[node name="Fill" type="Polygon2D" parent="Outline/Iris"] +color = Color(0, 0, 0, 1) +polygon = PackedVector2Array(1.16488, -5.52419, 2.38501, -5.17458, 3.48913, -4.6214, 4.4511, -3.88876, 4.65379, -3.66198, 4.7587, -2.99536, 4.84647, -2.27068, 4.90985, -1.53497, 4.94854, -0.791809, 4.96234, -0.0448074, 4.9572, 0.476006, 4.92903, 1.22124, 4.87606, 1.96054, 4.79856, 2.69032, 4.69691, 3.40702, 4.57159, 4.10715, 4.46923, 4.57631, 4.4511, 4.5966, 3.48913, 5.32924, 2.38501, 5.88242, 1.16488, 6.23203, -0.145126, 6.35392, -1.45513, 6.23203, -2.67526, 5.88242, -3.77938, 5.32924, -4.60182, 4.70286, -4.60382, 4.69501, -4.74924, 4.01209, -4.87152, 3.30962, -4.97007, 2.59103, -5.0444, 1.85981, -5.09416, 1.11953, -5.1191, 0.373795, -5.12222, -1.52588e-05, -5.10974, -0.747116, -5.07237, -1.49057, -5.01028, -2.22677, -4.92379, -2.95212, -4.81331, -3.66309, -4.77752, -3.84829, -4.74136, -3.88876, -3.77938, -4.6214, -2.67526, -5.17458, -1.45513, -5.52419, -0.145126, -5.64608) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44]] +metadata/_edit_lock_ = true + +[node name="Pupil" type="Node2D" parent="Outline/Iris" node_paths=PackedStringArray("polygon", "clip_paths")] +position = Vector2(-0.203896, 0.725998) +script = ExtResource("1_l1n7h") +polygon = NodePath("Fill") +curve = SubResource("Curve2D_4mfx8") +update_curve_at_runtime = true +arc_list = SubResource("Resource_hq7x2") +clip_paths = [NodePath("../..")] +shape_type = 2 +size = Vector2(3.25959, 6.98483) +rx = 1.62979 +ry = 3.49242 + +[node name="Fill" type="Polygon2D" parent="Outline/Iris/Pupil"] +polygon = PackedVector2Array(0.0838699, -3.48787, 0.166641, -3.47439, 0.248207, -3.45218, 0.328468, -3.42146, 0.407318, -3.38247, 0.484657, -3.33541, 0.560387, -3.2805, 0.634399, -3.21797, 0.776871, -3.07091, 0.911247, -2.89598, 1.03671, -2.69493, 1.15245, -2.46953, 1.35146, -1.95267, 1.50172, -1.35943, 1.59669, -0.703857, 1.62979, 0, 1.59669, 0.703857, 1.50172, 1.35943, 1.35146, 1.95267, 1.15245, 2.46953, 1.03671, 2.69493, 0.911247, 2.89598, 0.776871, 3.07091, 0.634399, 3.21797, 0.560387, 3.2805, 0.484657, 3.33541, 0.407318, 3.38247, 0.328468, 3.42146, 0.248207, 3.45218, 0.166641, 3.47439, 0.0838699, 3.48787, 0, 3.49242, -0.0838699, 3.48787, -0.166641, 3.47439, -0.248207, 3.45218, -0.328468, 3.42146, -0.407318, 3.38247, -0.484657, 3.33541, -0.560387, 3.2805, -0.634399, 3.21797, -0.776871, 3.07091, -0.911247, 2.89598, -1.03671, 2.69493, -1.15245, 2.46953, -1.35146, 1.95267, -1.50172, 1.35943, -1.59669, 0.703857, -1.62979, 0, -1.59669, -0.703857, -1.50172, -1.35943, -1.35146, -1.95267, -1.15245, -2.46953, -1.03671, -2.69493, -0.911247, -2.89598, -0.776871, -3.07091, -0.634399, -3.21797, -0.560387, -3.2805, -0.484657, -3.33541, -0.407318, -3.38247, -0.328468, -3.42146, -0.248207, -3.45218, -0.166641, -3.47439, -0.0838699, -3.48787, 0, -3.49242) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]] +metadata/_edit_lock_ = true + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +&"": SubResource("AnimationLibrary_ppl4k") +} diff --git a/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.gd b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.gd new file mode 100644 index 0000000..c3f9dc6 --- /dev/null +++ b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.gd @@ -0,0 +1,19 @@ +extends Node2D + + +func _ready() -> void: + $AnimationPlayer.play("dance") + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + if (event as InputEventMouseButton).pressed: + if (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT: + %RightEye.is_open = false + else: + %LeftEye.is_open = false + else: + if (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT: + %RightEye.is_open = true + else: + %LeftEye.is_open = true diff --git a/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.gd.uid b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.gd.uid new file mode 100644 index 0000000..162ded9 --- /dev/null +++ b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.gd.uid @@ -0,0 +1 @@ +uid://cgl7svglo3dea diff --git a/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.tscn b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.tscn new file mode 100644 index 0000000..040f8c7 --- /dev/null +++ b/addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.tscn @@ -0,0 +1,712 @@ +[gd_scene load_steps=32 format=3 uid="uid://clkub62tc5soa"] + +[ext_resource type="Script" uid="uid://cgl7svglo3dea" path="res://addons/curved_lines_2d/examples/fan_art_with_clip_paths/fan_art.gd" id="1_3gxsp"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="2_i2hyy"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="3_w1jjx"] +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="4_i2hyy"] +[ext_resource type="PackedScene" uid="uid://b7d7mk2ioy617" path="res://addons/curved_lines_2d/examples/fan_art_with_clip_paths/eye.tscn" id="5_3gxsp"] + +[sub_resource type="Curve2D" id="Curve2D_vuvrq"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0.601411, 0, 3.889, -2.17783, 0, -0.601411, 0, 0, 4.97791, -1.08891, 0, 0, 0, 0.601411, 4.97791, 1.08891, 0.601411, 0, 0, 0, 3.889, 2.17783, 0, 0, -0.601411, 0, -3.88899, 2.17783, 0, 0.601411, 0, 0, -4.97791, 1.08891, 0, 0, 0, -0.601411, -4.97791, -1.08891, -0.601411, 0, 0, 0, -3.88899, -2.17783, 0, 0, 0.601411, 0, 3.889, -2.17783) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_dovol"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_21j8n"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0.601411, 0, 3.889, -2.17783, 0, -0.601411, 0, 0, 4.97791, -1.08891, 0, 0, 0, 0.601411, 4.97791, 1.08891, 0.601411, 0, 0, 0, 3.889, 2.17783, 0, 0, -0.601411, 0, -3.88899, 2.17783, 0, 0.601411, 0, 0, -4.97791, 1.08891, 0, 0, 0, -0.601411, -4.97791, -1.08891, -0.601411, 0, 0, 0, -3.88899, -2.17783, 0, 0, 0.601411, 0, 3.889, -2.17783) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_ycpci"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_h4krt"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0.601411, 0, 2.21672, -2.02227, 0, -0.902116, 0, 0, 3.30564, -0.388895, 0, 0, 0, 0.902116, 3.30564, 0.388895, 0.601411, 0, 0, 0, 2.21672, 2.02227, 0, 0, -0.601411, 0, -2.21672, 2.02227, 0, 0.902116, 0, 0, -3.30564, 0.388895, 0, 0, 0, -0.902116, -3.30564, -0.388895, -0.601411, 0, 0, 0, -2.21672, -2.02227, 0, 0, 0.601411, 0, 2.21672, -2.02227) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_0ewes"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_7ab47"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -0.133581, 3.61672, 1.8011, -2.20657, -0.325121, -2.56204, -0.350664, 0.0769, 1.32512, 10.2287, 3.3371, 0.398483, 0.601829, -9.16264, -6.3566, 10.6149, 0.293953, -0.394287, 0, 0, -1.1954, -1.54593) +} +point_count = 4 + +[sub_resource type="Resource" id="Resource_0hrpn"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_tdxpr"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 7.04836, -1.1108, -8.5744, -12.482, -7.04836, 0.69072, 1.12537, 8.70163, 3.4256, -11.482, -4.6239, -5.8951, -7.38191, 0.96647, 12.0495, 10.4131, 8.7672, 0.418823, -0.792978, -1.75007, -11.2067, 12.202, -0.0253906, 1.75006, 0, 0, -12.0495, 6.95184, 0, 0, 0, 0, -8.5744, -12.482) +} +point_count = 6 + +[sub_resource type="Resource" id="Resource_m74ci"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_g3rv6"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0.601411, 0, 2.21672, -2.02227, 0, -0.902116, 0, 0, 3.30564, -0.388895, 0, 0, 0, 0.902116, 3.30564, 0.388895, 0.601411, 0, 0, 0, 2.21672, 2.02227, 0, 0, -0.601411, 0, -2.21672, 2.02227, 0, 0.902116, 0, 0, -3.30564, 0.388895, 0, 0, 0, -0.902116, -3.30564, -0.388895, -0.601411, 0, 0, 0, -2.21672, -2.02227, 0, 0, 0.601411, 0, 2.21672, -2.02227) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_d0jpf"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_51t4y"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 3.98345, 3.1908, -0.0833435, -2.16666, -1.81313, -3.07524, -0.343185, 0.10534, 9.75121, 10.4696, 3.19353, -0.866333, -1.87273, -6.4266, 2.95197, 12.3641, 0, 0, 0, 0, -1.46037, 4.69773) +} +point_count = 4 + +[sub_resource type="Resource" id="Resource_li8ts"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_row8l"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -9.78708, -8.52243, 0, 0, 0.4972, -2.30488, 12.2153, -8.52243, -0.374603, -3.94598, 0.24568, 2.58805, 21.1428, -11.554, 0, 0.731804, 0, 0, 15.0023, -7.46409, 0, 0, 0.0072, 0.46875, 15.2492, 8.63489, 2.48367, -0.551971, -8.77592, 1.95033, 10.8159, 10.8457, 7.33499, -0.178818, -7.33499, 0.17881, -11.5157, 13.3975, 0.466721, 1.67137, -0.466721, -1.67134, -21.135, 11.6806, 0, 0, 0, 0, -11.8468, 6.93817, 0, 0, -1.42244, -0.00072, -12.5741, -6.96933, -1.138, 3.60279, 0.955734, -3.02576, -19.7185, -12.448, -0.551308, -2.32829, 0, 0, -9.78708, -8.52243) +} +point_count = 12 + +[sub_resource type="Resource" id="Resource_gw0fs"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_loqdy"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0.730646, 3.175, 0, 1.75355, 0, -1.75355, 0, 0, 1.32291, 0, 0.730646, 0, -0.730646, -3.175, 0, -1.75355, 0, 1.75355, 0, 0, -1.32291, 0, -0.730646, 0, 0, 3.175, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_vpx2b"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Curve2D" id="Curve2D_ojj3e"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 2.91041, -1.4493, 0, 0, 0, 0, -2.9104, -1.45967) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_k4eqw"] +script = ExtResource("2_i2hyy") +start_point = 0 +radius = Vector2(2.91, 2.91) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_mg08f"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([SubResource("Resource_k4eqw")]) + +[sub_resource type="Curve2D" id="Curve2D_3gxsp"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0.962421, 0.10373, 7.96465, 7.6074, -0.943039, 0.46283, 3.6988, -1.82266, 10.9088, 7.05247, 0.202003, 0.237968, 0.551035, -1.52306, 13.0722, 1.2108, 0.672356, 1.36607, -1.39959, -2.82158, 12.8836, -3.28074, 3.31781, -1.32369, -0.486996, -0.85981, 4.555, -5.92528, 1.05902, 0.181267, -1.33433, -0.21921, 2.09208, -7.58379, 0.683876, -0.99881, -0.42185, -0.66139, -1.24394, -6.29514, 0.712204, 0.121849, -1.38154, -0.22882, -3.00931, -7.51441, 0.477531, -1.5675, -2.99989, 0.12759, -6.23972, -5.18826, 0.380814, -2.27859, -0.466242, 2.80298, -13.4357, -1.24465, -3.69995, -0.615288, 2.69186, 0.44086, -6.10427, 5.07213, -1.35339, 1.70671, 0.897379, 1.67127, 0.569206, 2.98385, -2.0579, -0.21862, 0.51173, 0.90311, 5.25782, 5.9822, -1.20955, -0.130371, 0, 0, 7.96464, 7.60741) +} +point_count = 14 + +[sub_resource type="Resource" id="Resource_vuvrq"] +resource_local_to_scene = true +script = ExtResource("3_w1jjx") +arcs = Array[ExtResource("2_i2hyy")]([]) + +[sub_resource type="Animation" id="Animation_i2hyy"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("FanArt/layer1/RightArm:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("FanArt/layer1/LeftArm:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("FanArt/layer1/LeftFoot:position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(82.8819, 165.97)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("FanArt/layer1/LeftFoot:rotation") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("FanArt/layer1/RightFoot:position") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(70.979, 166.323)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("FanArt/layer1/RightFoot:rotation") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("FanArt/layer1/Head:position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(71.8393, 128.359)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("FanArt/layer1/Head:rotation") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("FanArt/layer1/RightArm:position") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(66.7614, 143.412)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("FanArt/layer1/LeftArm:position") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(79.5669, 140.329)] +} + +[sub_resource type="Animation" id="Animation_k4eqw"] +resource_name = "dance" +length = 0.4 +loop_mode = 1 +step = 0.2 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("FanArt/layer1/RightArm:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [2.09829, 0.427068] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("FanArt/layer1/LeftArm:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.295603, -1.14068] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("FanArt/layer1/LeftFoot:position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(84.0486, 164.553), Vector2(80.8486, 164.853)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("FanArt/layer1/LeftFoot:rotation") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [-0.671079, -0.0436613] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("FanArt/layer1/RightFoot:position") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(70.979, 166.323), Vector2(71.879, 164.923)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("FanArt/layer1/RightFoot:rotation") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.0, -0.155044] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("FanArt/layer1/RightArm:curve:point_0/position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(1.8011, -2.20657), Vector2(1.93309, 4.24783)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("FanArt/layer1/Head:position") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(75.4643, 127.859), Vector2(74.0357, 128.288)] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("FanArt/layer1/Head:rotation") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.292313, -0.121693] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_w1jjx"] +_data = { +&"RESET": SubResource("Animation_i2hyy"), +&"dance": SubResource("Animation_k4eqw") +} + +[node name="Node2D" type="Node2D"] + +[node name="FanArt" type="Node2D" parent="."] +script = ExtResource("1_3gxsp") +metadata/svg_root = true + +[node name="layer1" type="Node2D" parent="FanArt"] +position = Vector2(-52.7614, -106.079) +metadata/svg_style = {} + +[node name="RightFoot" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(70.979, 166.323) +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_vuvrq") +update_curve_at_runtime = true +arc_list = SubResource("Resource_dovol") +shape_type = 1 +size = Vector2(9.95583, 4.35567) +rx = 1.08892 +ry = 1.08892 + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/RightFoot"] +points = PackedVector2Array(3.889, -2.17783, 4.00033, -2.17221, 4.10846, -2.15571, 4.21281, -2.12888, 4.31286, -2.09226, 4.40805, -2.04641, 4.49783, -1.99187, 4.58166, -1.92918, 4.65898, -1.8589, 4.72926, -1.78158, 4.79195, -1.69775, 4.84649, -1.60797, 4.89234, -1.51278, 4.92896, -1.41273, 4.95579, -1.30838, 4.97229, -1.20025, 4.97791, -1.08891, 4.97791, 1.08891, 4.97229, 1.20025, 4.95579, 1.30838, 4.92896, 1.41273, 4.89234, 1.51278, 4.84649, 1.60797, 4.79195, 1.69775, 4.72926, 1.78158, 4.65898, 1.8589, 4.58166, 1.92918, 4.49783, 1.99187, 4.40805, 2.04641, 4.31286, 2.09226, 4.21281, 2.12888, 4.10846, 2.15571, 4.00033, 2.17221, 3.889, 2.17783, -3.88899, 2.17783, -4.00033, 2.17221, -4.10845, 2.15571, -4.21281, 2.12888, -4.31286, 2.09226, -4.40805, 2.04641, -4.49783, 1.99187, -4.58166, 1.92918, -4.65898, 1.8589, -4.72926, 1.78158, -4.79195, 1.69775, -4.84649, 1.60797, -4.89234, 1.51278, -4.92896, 1.41273, -4.95579, 1.30838, -4.97229, 1.20025, -4.97791, 1.08891, -4.97791, -1.08891, -4.97229, -1.20025, -4.95579, -1.30838, -4.92896, -1.41273, -4.89234, -1.51278, -4.84649, -1.60797, -4.79195, -1.69775, -4.72926, -1.78158, -4.65898, -1.8589, -4.58166, -1.92918, -4.49783, -1.99187, -4.40805, -2.04641, -4.31286, -2.09226, -4.21281, -2.12888, -4.10845, -2.15571, -4.00033, -2.17221, -3.88899, -2.17783) +closed = true +width = 3.0 +default_color = Color(0, 0, 0, 1) +joint_mode = 2 +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/RightFoot"] +color = Color(0.988235, 0.603922, 0.603922, 1) +polygon = PackedVector2Array(3.889, -2.17783, 4.00033, -2.17221, 4.10846, -2.15571, 4.21281, -2.12888, 4.31286, -2.09226, 4.40805, -2.04641, 4.49783, -1.99187, 4.58166, -1.92918, 4.65898, -1.8589, 4.72926, -1.78158, 4.79195, -1.69775, 4.84649, -1.60797, 4.89234, -1.51278, 4.92896, -1.41273, 4.95579, -1.30838, 4.97229, -1.20025, 4.97791, -1.08891, 4.97791, 1.08891, 4.97229, 1.20025, 4.95579, 1.30838, 4.92896, 1.41273, 4.89234, 1.51278, 4.84649, 1.60797, 4.79195, 1.69775, 4.72926, 1.78158, 4.65898, 1.8589, 4.58166, 1.92918, 4.49783, 1.99187, 4.40805, 2.04641, 4.31286, 2.09226, 4.21281, 2.12888, 4.10846, 2.15571, 4.00033, 2.17221, 3.889, 2.17783, -3.88899, 2.17783, -4.00033, 2.17221, -4.10845, 2.15571, -4.21281, 2.12888, -4.31286, 2.09226, -4.40805, 2.04641, -4.49783, 1.99187, -4.58166, 1.92918, -4.65898, 1.8589, -4.72926, 1.78158, -4.79195, 1.69775, -4.84649, 1.60797, -4.89234, 1.51278, -4.92896, 1.41273, -4.95579, 1.30838, -4.97229, 1.20025, -4.97791, 1.08891, -4.97791, -1.08891, -4.97229, -1.20025, -4.95579, -1.30838, -4.92896, -1.41273, -4.89234, -1.51278, -4.84649, -1.60797, -4.79195, -1.69775, -4.72926, -1.78158, -4.65898, -1.8589, -4.58166, -1.92918, -4.49783, -1.99187, -4.40805, -2.04641, -4.31286, -2.09226, -4.21281, -2.12888, -4.10845, -2.15571, -4.00033, -2.17221, -3.88899, -2.17783) +metadata/_edit_lock_ = true + +[node name="LeftFoot" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(82.8819, 165.97) +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_21j8n") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ycpci") +shape_type = 1 +size = Vector2(9.95583, 4.35567) +rx = 1.08892 +ry = 1.08892 + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/LeftFoot"] +points = PackedVector2Array(3.889, -2.17783, 4.00033, -2.17221, 4.10846, -2.15571, 4.21281, -2.12888, 4.31286, -2.09226, 4.40805, -2.04641, 4.49783, -1.99187, 4.58166, -1.92918, 4.65898, -1.8589, 4.72926, -1.78158, 4.79195, -1.69775, 4.84649, -1.60797, 4.89234, -1.51278, 4.92896, -1.41273, 4.95579, -1.30838, 4.97229, -1.20025, 4.97791, -1.08891, 4.97791, 1.08891, 4.97229, 1.20025, 4.95579, 1.30838, 4.92896, 1.41273, 4.89234, 1.51278, 4.84649, 1.60797, 4.79195, 1.69775, 4.72926, 1.78158, 4.65898, 1.8589, 4.58166, 1.92918, 4.49783, 1.99187, 4.40805, 2.04641, 4.31286, 2.09226, 4.21281, 2.12888, 4.10846, 2.15571, 4.00033, 2.17221, 3.889, 2.17783, -3.88899, 2.17783, -4.00033, 2.17221, -4.10845, 2.15571, -4.21281, 2.12888, -4.31286, 2.09226, -4.40805, 2.04641, -4.49783, 1.99187, -4.58166, 1.92918, -4.65898, 1.8589, -4.72926, 1.78158, -4.79195, 1.69775, -4.84649, 1.60797, -4.89234, 1.51278, -4.92896, 1.41273, -4.95579, 1.30838, -4.97229, 1.20025, -4.97791, 1.08891, -4.97791, -1.08891, -4.97229, -1.20025, -4.95579, -1.30838, -4.92896, -1.41273, -4.89234, -1.51278, -4.84649, -1.60797, -4.79195, -1.69775, -4.72926, -1.78158, -4.65898, -1.8589, -4.58166, -1.92918, -4.49783, -1.99187, -4.40805, -2.04641, -4.31286, -2.09226, -4.21281, -2.12888, -4.10845, -2.15571, -4.00033, -2.17221, -3.88899, -2.17783) +closed = true +width = 3.0 +default_color = Color(0, 0, 0, 1) +joint_mode = 2 +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/LeftFoot"] +color = Color(0.988235, 0.603922, 0.603922, 1) +polygon = PackedVector2Array(3.889, -2.17783, 4.00033, -2.17221, 4.10846, -2.15571, 4.21281, -2.12888, 4.31286, -2.09226, 4.40805, -2.04641, 4.49783, -1.99187, 4.58166, -1.92918, 4.65898, -1.8589, 4.72926, -1.78158, 4.79195, -1.69775, 4.84649, -1.60797, 4.89234, -1.51278, 4.92896, -1.41273, 4.95579, -1.30838, 4.97229, -1.20025, 4.97791, -1.08891, 4.97791, 1.08891, 4.97229, 1.20025, 4.95579, 1.30838, 4.92896, 1.41273, 4.89234, 1.51278, 4.84649, 1.60797, 4.79195, 1.69775, 4.72926, 1.78158, 4.65898, 1.8589, 4.58166, 1.92918, 4.49783, 1.99187, 4.40805, 2.04641, 4.31286, 2.09226, 4.21281, 2.12888, 4.10846, 2.15571, 4.00033, 2.17221, 3.889, 2.17783, -3.88899, 2.17783, -4.00033, 2.17221, -4.10845, 2.15571, -4.21281, 2.12888, -4.31286, 2.09226, -4.40805, 2.04641, -4.49783, 1.99187, -4.58166, 1.92918, -4.65898, 1.8589, -4.72926, 1.78158, -4.79195, 1.69775, -4.84649, 1.60797, -4.89234, 1.51278, -4.92896, 1.41273, -4.95579, 1.30838, -4.97229, 1.20025, -4.97791, 1.08891, -4.97791, -1.08891, -4.97229, -1.20025, -4.95579, -1.30838, -4.92896, -1.41273, -4.89234, -1.51278, -4.84649, -1.60797, -4.79195, -1.69775, -4.72926, -1.78158, -4.65898, -1.8589, -4.58166, -1.92918, -4.49783, -1.99187, -4.40805, -2.04641, -4.31286, -2.09226, -4.21281, -2.12888, -4.10845, -2.15571, -4.00033, -2.17221, -3.88899, -2.17783) +metadata/_edit_lock_ = true + +[node name="RightHand" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(57.9746, 134.821) +rotation = 2.09829 +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_h4krt") +update_curve_at_runtime = true +arc_list = SubResource("Resource_0ewes") +shape_type = 1 +size = Vector2(6.61129, 4.04455) +rx = 1.08892 +ry = 1.63338 + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/RightHand"] +points = PackedVector2Array(2.21672, -2.02227, 2.27276, -2.02015, 2.32806, -2.01384, 2.38256, -2.00346, 2.43619, -1.98909, 2.54054, -1.94884, 2.64059, -1.89392, 2.73578, -1.82514, 2.82556, -1.74333, 2.90939, -1.6493, 2.98671, -1.54388, 3.05699, -1.42789, 3.11968, -1.30214, 3.17422, -1.16747, 3.22007, -1.02469, 3.28352, -0.718085, 3.30564, -0.388895, 3.30564, 0.388895, 3.28352, 0.718085, 3.22007, 1.02469, 3.17422, 1.16747, 3.11968, 1.30214, 3.05699, 1.42789, 2.98671, 1.54388, 2.90939, 1.6493, 2.82556, 1.74333, 2.73578, 1.82514, 2.64059, 1.89392, 2.54054, 1.94884, 2.43618, 1.98909, 2.38256, 2.00346, 2.32806, 2.01384, 2.27276, 2.02015, 2.21672, 2.02227, -2.21672, 2.02227, -2.27276, 2.02015, -2.32806, 2.01384, -2.38256, 2.00346, -2.43619, 1.98909, -2.54054, 1.94884, -2.64059, 1.89392, -2.73578, 1.82514, -2.82556, 1.74333, -2.90939, 1.6493, -2.98671, 1.54388, -3.05699, 1.42789, -3.11968, 1.30214, -3.17422, 1.16747, -3.22007, 1.02469, -3.28352, 0.718085, -3.30564, 0.388895, -3.30564, -0.388895, -3.28352, -0.718085, -3.22007, -1.02469, -3.17422, -1.16747, -3.11968, -1.30214, -3.05699, -1.42789, -2.98671, -1.54388, -2.90939, -1.6493, -2.82556, -1.74333, -2.73578, -1.82514, -2.64059, -1.89392, -2.54054, -1.94884, -2.43618, -1.98909, -2.38256, -2.00346, -2.32806, -2.01384, -2.27276, -2.02015, -2.21672, -2.02227) +closed = true +width = 3.0 +default_color = Color(0, 0, 0, 1) +joint_mode = 2 +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/RightHand"] +color = Color(0.988235, 0.603922, 0.603922, 1) +polygon = PackedVector2Array(2.21672, -2.02227, 2.27276, -2.02015, 2.32806, -2.01384, 2.38256, -2.00346, 2.43619, -1.98909, 2.54054, -1.94884, 2.64059, -1.89392, 2.73578, -1.82514, 2.82556, -1.74333, 2.90939, -1.6493, 2.98671, -1.54388, 3.05699, -1.42789, 3.11968, -1.30214, 3.17422, -1.16747, 3.22007, -1.02469, 3.28352, -0.718085, 3.30564, -0.388895, 3.30564, 0.388895, 3.28352, 0.718085, 3.22007, 1.02469, 3.17422, 1.16747, 3.11968, 1.30214, 3.05699, 1.42789, 2.98671, 1.54388, 2.90939, 1.6493, 2.82556, 1.74333, 2.73578, 1.82514, 2.64059, 1.89392, 2.54054, 1.94884, 2.43618, 1.98909, 2.38256, 2.00346, 2.32806, 2.01384, 2.27276, 2.02015, 2.21672, 2.02227, -2.21672, 2.02227, -2.27276, 2.02015, -2.32806, 2.01384, -2.38256, 2.00346, -2.43619, 1.98909, -2.54054, 1.94884, -2.64059, 1.89392, -2.73578, 1.82514, -2.82556, 1.74333, -2.90939, 1.6493, -2.98671, 1.54388, -3.05699, 1.42789, -3.11968, 1.30214, -3.17422, 1.16747, -3.22007, 1.02469, -3.28352, 0.718085, -3.30564, 0.388895, -3.30564, -0.388895, -3.28352, -0.718085, -3.22007, -1.02469, -3.17422, -1.16747, -3.11968, -1.30214, -3.05699, -1.42789, -2.98671, -1.54388, -2.90939, -1.6493, -2.82556, -1.74333, -2.73578, -1.82514, -2.64059, -1.89392, -2.54054, -1.94884, -2.43618, -1.98909, -2.38256, -2.00346, -2.32806, -2.01384, -2.27276, -2.02015, -2.21672, -2.02227) +metadata/_edit_lock_ = true + +[node name="RightArm" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(66.7614, 143.412) +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_7ab47") +update_curve_at_runtime = true +arc_list = SubResource("Resource_0hrpn") + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/RightArm"] +points = PackedVector2Array(1.8011, -2.20657, 1.24355, 7.71343, 1.32512, 10.2287, -1.39583, 10.6001, -3.7978, 10.7335, -6.3566, 10.6149, -5.94998, 7.44551, -5.25493, 4.79384, -4.38158, 2.63662, -3.44008, 0.950637, -2.54057, -0.287369, -1.79319, -1.10064, -1.51097, -1.35526, -1.30809, -1.51241, -1.2407, -1.55534, -1.21627, -1.56806, -1.19831, -1.575, -1.18702, -1.57621, -1.18263, -1.57174, -1.18536, -1.56163, -1.1954, -1.54593) +width = 3.0 +default_color = Color(0, 0, 0, 1) +joint_mode = 2 +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/RightArm"] +color = Color(0.819608, 0.219608, 0.294118, 0.981982) +polygon = PackedVector2Array(1.8011, -2.20657, 1.24355, 7.71343, 1.32512, 10.2287, -1.39583, 10.6001, -3.7978, 10.7335, -6.3566, 10.6149, -5.94998, 7.44551, -5.25493, 4.79384, -4.38158, 2.63662, -3.44008, 0.950637, -2.54057, -0.287369, -1.79319, -1.10064, -1.51097, -1.35526, -1.30809, -1.51241, -1.2407, -1.55534, -1.21627, -1.56806, -1.19831, -1.575, -1.18702, -1.57621, -1.18263, -1.57174, -1.18536, -1.56163, -1.1954, -1.54593) +metadata/_edit_lock_ = true + +[node name="RemoteTransform2D" type="RemoteTransform2D" parent="FanArt/layer1/RightArm"] +position = Vector2(-3, 11.9167) +remote_path = NodePath("../../RightHand") + +[node name="Cape" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(77.3358, 152.561) +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.0 +begin_cap_mode = 2 +end_cap_mode = 2 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_tdxpr") +update_curve_at_runtime = true +arc_list = SubResource("Resource_m74ci") + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/Cape"] +points = PackedVector2Array(-8.5744, -12.482, -6.32422, -12.7296, -5.45365, -12.743, -4.71705, -12.6972, -4.08761, -12.6032, -3.53856, -12.4716, -1.61024, -11.7878, -1.06119, -11.6316, -0.431751, -11.5031, 0.304853, -11.413, 1.17542, -11.3722, 3.4256, -11.482, 4.59761, -5.21889, 6.4256, 0.517999, 7.58559, 3.18911, 8.90956, 5.72866, 10.3975, 8.13666, 12.0495, 10.4131, 0.940884, 11.827, -4.91234, 12.2351, -11.2067, 12.202, -11.4716, 11.5457, -11.6765, 10.8895, -11.935, 9.57692, -12.04, 8.26438, -12.0495, 6.95184) +closed = true +width = 3.0 +default_color = Color(0, 0, 0, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/Cape"] +color = Color(0.819608, 0.219608, 0.294118, 0.981982) +polygon = PackedVector2Array(-8.5744, -12.482, -6.32422, -12.7296, -5.45365, -12.743, -4.71705, -12.6972, -4.08761, -12.6032, -3.53856, -12.4716, -1.61024, -11.7878, -1.06119, -11.6316, -0.431751, -11.5031, 0.304853, -11.413, 1.17542, -11.3722, 3.4256, -11.482, 4.59761, -5.21889, 6.4256, 0.517999, 7.58559, 3.18911, 8.90956, 5.72866, 10.3975, 8.13666, 12.0495, 10.4131, 0.940884, 11.827, -4.91234, 12.2351, -11.2067, 12.202, -11.4716, 11.5457, -11.6765, 10.8895, -11.935, 9.57692, -12.04, 8.26438, -12.0495, 6.95184) +metadata/_edit_lock_ = true + +[node name="LeftHand" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(82.3584, 154.333) +rotation = 0.015854 +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_g3rv6") +update_curve_at_runtime = true +arc_list = SubResource("Resource_d0jpf") +shape_type = 1 +size = Vector2(6.61129, 4.04455) +rx = 1.08892 +ry = 1.63338 + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/LeftHand"] +points = PackedVector2Array(2.21672, -2.02227, 2.27276, -2.02015, 2.32806, -2.01384, 2.38256, -2.00346, 2.43619, -1.98909, 2.54054, -1.94884, 2.64059, -1.89392, 2.73578, -1.82514, 2.82556, -1.74333, 2.90939, -1.6493, 2.98671, -1.54388, 3.05699, -1.42789, 3.11968, -1.30214, 3.17422, -1.16747, 3.22007, -1.02469, 3.28352, -0.718085, 3.30564, -0.388895, 3.30564, 0.388895, 3.28352, 0.718085, 3.22007, 1.02469, 3.17422, 1.16747, 3.11968, 1.30214, 3.05699, 1.42789, 2.98671, 1.54388, 2.90939, 1.6493, 2.82556, 1.74333, 2.73578, 1.82514, 2.64059, 1.89392, 2.54054, 1.94884, 2.43618, 1.98909, 2.38256, 2.00346, 2.32806, 2.01384, 2.27276, 2.02015, 2.21672, 2.02227, -2.21672, 2.02227, -2.27276, 2.02015, -2.32806, 2.01384, -2.38256, 2.00346, -2.43619, 1.98909, -2.54054, 1.94884, -2.64059, 1.89392, -2.73578, 1.82514, -2.82556, 1.74333, -2.90939, 1.6493, -2.98671, 1.54388, -3.05699, 1.42789, -3.11968, 1.30214, -3.17422, 1.16747, -3.22007, 1.02469, -3.28352, 0.718085, -3.30564, 0.388895, -3.30564, -0.388895, -3.28352, -0.718085, -3.22007, -1.02469, -3.17422, -1.16747, -3.11968, -1.30214, -3.05699, -1.42789, -2.98671, -1.54388, -2.90939, -1.6493, -2.82556, -1.74333, -2.73578, -1.82514, -2.64059, -1.89392, -2.54054, -1.94884, -2.43618, -1.98909, -2.38256, -2.00346, -2.32806, -2.01384, -2.27276, -2.02015, -2.21672, -2.02227) +closed = true +width = 3.0 +default_color = Color(0, 0, 0, 1) +joint_mode = 2 +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/LeftHand"] +color = Color(0.988235, 0.603922, 0.603922, 1) +polygon = PackedVector2Array(2.21672, -2.02227, 2.27276, -2.02015, 2.32806, -2.01384, 2.38256, -2.00346, 2.43619, -1.98909, 2.54054, -1.94884, 2.64059, -1.89392, 2.73578, -1.82514, 2.82556, -1.74333, 2.90939, -1.6493, 2.98671, -1.54388, 3.05699, -1.42789, 3.11968, -1.30214, 3.17422, -1.16747, 3.22007, -1.02469, 3.28352, -0.718085, 3.30564, -0.388895, 3.30564, 0.388895, 3.28352, 0.718085, 3.22007, 1.02469, 3.17422, 1.16747, 3.11968, 1.30214, 3.05699, 1.42789, 2.98671, 1.54388, 2.90939, 1.6493, 2.82556, 1.74333, 2.73578, 1.82514, 2.64059, 1.89392, 2.54054, 1.94884, 2.43618, 1.98909, 2.38256, 2.00346, 2.32806, 2.01384, 2.27276, 2.02015, 2.21672, 2.02227, -2.21672, 2.02227, -2.27276, 2.02015, -2.32806, 2.01384, -2.38256, 2.00346, -2.43619, 1.98909, -2.54054, 1.94884, -2.64059, 1.89392, -2.73578, 1.82514, -2.82556, 1.74333, -2.90939, 1.6493, -2.98671, 1.54388, -3.05699, 1.42789, -3.11968, 1.30214, -3.17422, 1.16747, -3.22007, 1.02469, -3.28352, 0.718085, -3.30564, 0.388895, -3.30564, -0.388895, -3.28352, -0.718085, -3.22007, -1.02469, -3.17422, -1.16747, -3.11968, -1.30214, -3.05699, -1.42789, -2.98671, -1.54388, -2.90939, -1.6493, -2.82556, -1.74333, -2.73578, -1.82514, -2.64059, -1.89392, -2.54054, -1.94884, -2.43618, -1.98909, -2.38256, -2.00346, -2.32806, -2.01384, -2.27276, -2.02015, -2.21672, -2.02227) +metadata/_edit_lock_ = true + +[node name="LeftArm" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(79.5669, 140.329) +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_51t4y") +update_curve_at_runtime = true +arc_list = SubResource("Resource_li8ts") + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/LeftArm"] +points = PackedVector2Array(-0.0833435, -2.16666, 1.40855, -0.83372, 2.87885, 0.721419, 5.6478, 4.1948, 9.75121, 10.4696, 2.95197, 12.3641, 2.2247, 10.1895, 1.47248, 8.45501, 0.732901, 7.11422, 0.0435264, 6.12094, -0.558064, 5.4289, -1.03429, 4.99186, -1.34759, 4.76355, -1.46037, 4.69773) +width = 3.0 +default_color = Color(0, 0, 0, 1) +joint_mode = 2 +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/LeftArm"] +color = Color(0.819608, 0.219608, 0.294118, 0.981982) +polygon = PackedVector2Array(-0.0833435, -2.16666, 1.40855, -0.83372, 2.87885, 0.721419, 5.6478, 4.1948, 9.75121, 10.4696, 2.95197, 12.3641, 2.2247, 10.1895, 1.47248, 8.45501, 0.732901, 7.11422, 0.0435264, 6.12094, -0.558064, 5.4289, -1.03429, 4.99186, -1.34759, 4.76355, -1.46037, 4.69773) +metadata/_edit_lock_ = true + +[node name="RemoteTransform2D" type="RemoteTransform2D" parent="FanArt/layer1/LeftArm"] +position = Vector2(6.75, 12.5833) +rotation = -0.279749 +remote_path = NodePath("../../LeftHand") + +[node name="Head" type="Node2D" parent="FanArt/layer1" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(71.8393, 128.359) +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.1 +line = NodePath("Stroke") +curve = SubResource("Curve2D_row8l") +update_curve_at_runtime = true +arc_list = SubResource("Resource_gw0fs") + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/Head"] +points = PackedVector2Array(-9.78708, -8.52243, 12.2153, -8.52243, 12.2441, -8.63216, 12.2836, -8.74511, 12.3934, -8.97966, 12.5419, -9.22406, 12.7263, -9.47629, 13.1917, -9.99623, 13.7673, -10.5234, 15.1597, -11.535, 16.725, -12.3823, 17.5167, -12.7041, 18.2846, -12.9366, 19.0064, -13.0636, 19.343, -13.0826, 19.6598, -13.0692, 19.9538, -13.0213, 20.0915, -12.9838, 20.2224, -12.937, 20.3463, -12.8806, 20.4628, -12.8143, 20.5715, -12.738, 20.672, -12.6512, 20.7642, -12.5538, 20.8475, -12.4456, 20.9216, -12.3263, 20.9863, -12.1956, 21.0411, -12.0532, 21.0856, -11.899, 21.1197, -11.7327, 21.1428, -11.554, 21.1495, -11.433, 21.1468, -11.3125, 21.135, -11.1927, 21.1143, -11.0735, 21.0478, -10.8376, 20.9495, -10.6052, 20.8219, -10.3768, 20.6674, -10.1528, 20.4883, -9.9338, 20.287, -9.72021, 19.8275, -9.31121, 19.3079, -8.92964, 18.1647, -8.2641, 17.01, -7.75417, 15.9963, -7.43046, 15.59, -7.348, 15.4204, -7.32829, 15.2762, -7.32357, 15.2145, -7.32698, 15.16, -7.33431, 15.113, -7.34563, 15.074, -7.36099, 15.0431, -7.38046, 15.0206, -7.40409, 15.0069, -7.43195, 15.0023, -7.46409, 15.2492, 8.63489, 15.2481, 8.65738, 15.2442, 8.68091, 15.2374, 8.70542, 15.2279, 8.7309, 15.2006, 8.78463, 15.1626, 8.84183, 15.1142, 8.90226, 15.0556, 8.96568, 14.9088, 9.10046, 14.5045, 9.39486, 13.9666, 9.70909, 12.5574, 10.3333, 10.8159, 10.8457, -0.890249, 12.7859, -11.5157, 13.3975, -16.0475, 13.4397, -17.6596, 13.3735, -18.9009, 13.2329, -19.3978, 13.1308, -19.8203, 13.0055, -20.1745, 12.8554, -20.3279, 12.7707, -20.4666, 12.6791, -20.5912, 12.5806, -20.7025, 12.475, -20.8014, 12.3621, -20.8885, 12.2416, -20.9647, 12.1134, -21.0306, 11.9773, -21.135, 11.6806, -21.1495, 11.6012, -21.1494, 11.5199, -21.1353, 11.4368, -21.1076, 11.3519, -21.0667, 11.2654, -21.0132, 11.1773, -20.9474, 11.0878, -20.8699, 10.997, -20.6813, 10.8117, -20.4511, 10.6223, -19.8806, 10.2345, -18.4013, 9.44559, -16.6659, 8.68263, -11.8468, 6.93817, -12.5741, -6.96933, -12.9012, -6.99139, -13.3362, -7.05718, -14.4505, -7.31903, -15.7598, -7.75318, -17.1065, -8.35789, -17.7446, -8.72367, -18.3331, -9.13145, -18.8522, -9.58101, -19.0796, -9.82139, -19.2823, -10.0721, -19.4578, -10.3332, -19.6037, -10.6046, -19.7174, -10.8863, -19.7966, -11.1782, -19.8387, -11.4804, -19.8414, -11.7928, -19.8022, -12.1153, -19.7185, -12.448, -19.6683, -12.5843, -19.6075, -12.7096, -19.5364, -12.8241, -19.4555, -12.9281, -19.3651, -13.0218, -19.2654, -13.1055, -19.1569, -13.1793, -19.04, -13.2435, -18.9149, -13.2984, -18.782, -13.344, -18.4943, -13.4088, -18.1797, -13.4397, -17.841, -13.4385, -17.1026, -13.3472, -16.3015, -13.1495, -15.4602, -12.8599, -14.6011, -12.493, -12.9197, -11.5855, -11.437, -10.5435, -10.8264, -10.0086, -10.3329, -9.48368, -10.1371, -9.22958, -9.97897, -8.98345, -9.86136, -8.74713, -9.81863, -8.63321) +closed = true +width = 3.1 +default_color = Color(0, 0, 0, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/Head"] +color = Color(0.988235, 0.603922, 0.603922, 1) +polygon = PackedVector2Array(-9.78708, -8.52243, 12.2153, -8.52243, 12.2441, -8.63216, 12.2836, -8.74511, 12.3934, -8.97966, 12.5419, -9.22406, 12.7263, -9.47629, 13.1917, -9.99623, 13.7673, -10.5234, 15.1597, -11.535, 16.725, -12.3823, 17.5167, -12.7041, 18.2846, -12.9366, 19.0064, -13.0636, 19.343, -13.0826, 19.6598, -13.0692, 19.9538, -13.0213, 20.0915, -12.9838, 20.2224, -12.937, 20.3463, -12.8806, 20.4628, -12.8143, 20.5715, -12.738, 20.672, -12.6512, 20.7642, -12.5538, 20.8475, -12.4456, 20.9216, -12.3263, 20.9863, -12.1956, 21.0411, -12.0532, 21.0856, -11.899, 21.1197, -11.7327, 21.1428, -11.554, 21.1495, -11.433, 21.1468, -11.3125, 21.135, -11.1927, 21.1143, -11.0735, 21.0478, -10.8376, 20.9495, -10.6052, 20.8219, -10.3768, 20.6674, -10.1528, 20.4883, -9.9338, 20.287, -9.72021, 19.8275, -9.31121, 19.3079, -8.92964, 18.1647, -8.2641, 17.01, -7.75417, 15.9963, -7.43046, 15.59, -7.348, 15.4204, -7.32829, 15.2762, -7.32357, 15.2145, -7.32698, 15.16, -7.33431, 15.113, -7.34563, 15.074, -7.36099, 15.0431, -7.38046, 15.0206, -7.40409, 15.0069, -7.43195, 15.0023, -7.46409, 15.2492, 8.63489, 15.2481, 8.65738, 15.2442, 8.68091, 15.2374, 8.70542, 15.2279, 8.7309, 15.2006, 8.78463, 15.1626, 8.84183, 15.1142, 8.90226, 15.0556, 8.96568, 14.9088, 9.10046, 14.5045, 9.39486, 13.9666, 9.70909, 12.5574, 10.3333, 10.8159, 10.8457, -0.890249, 12.7859, -11.5157, 13.3975, -16.0475, 13.4397, -17.6596, 13.3735, -18.9009, 13.2329, -19.3978, 13.1308, -19.8203, 13.0055, -20.1745, 12.8554, -20.3279, 12.7707, -20.4666, 12.6791, -20.5912, 12.5806, -20.7025, 12.475, -20.8014, 12.3621, -20.8885, 12.2416, -20.9647, 12.1134, -21.0306, 11.9773, -21.135, 11.6806, -21.1495, 11.6012, -21.1494, 11.5199, -21.1353, 11.4368, -21.1076, 11.3519, -21.0667, 11.2654, -21.0132, 11.1773, -20.9474, 11.0878, -20.8699, 10.997, -20.6813, 10.8117, -20.4511, 10.6223, -19.8806, 10.2345, -18.4013, 9.44559, -16.6659, 8.68263, -11.8468, 6.93817, -12.5741, -6.96933, -12.9012, -6.99139, -13.3362, -7.05718, -14.4505, -7.31903, -15.7598, -7.75318, -17.1065, -8.35789, -17.7446, -8.72367, -18.3331, -9.13145, -18.8522, -9.58101, -19.0796, -9.82139, -19.2823, -10.0721, -19.4578, -10.3332, -19.6037, -10.6046, -19.7174, -10.8863, -19.7966, -11.1782, -19.8387, -11.4804, -19.8414, -11.7928, -19.8022, -12.1153, -19.7185, -12.448, -19.6683, -12.5843, -19.6075, -12.7096, -19.5364, -12.8241, -19.4555, -12.9281, -19.3651, -13.0218, -19.2654, -13.1055, -19.1569, -13.1793, -19.04, -13.2435, -18.9149, -13.2984, -18.782, -13.344, -18.4943, -13.4088, -18.1797, -13.4397, -17.841, -13.4385, -17.1026, -13.3472, -16.3015, -13.1495, -15.4602, -12.8599, -14.6011, -12.493, -12.9197, -11.5855, -11.437, -10.5435, -10.8264, -10.0086, -10.3329, -9.48368, -10.1371, -9.22958, -9.97897, -8.98345, -9.86136, -8.74713, -9.81863, -8.63321) +metadata/_edit_lock_ = true + +[node name="Nose" type="Node2D" parent="FanArt/layer1/Head" node_paths=PackedStringArray("polygon")] +position = Vector2(-16.8134, 11.133) +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +curve = SubResource("Curve2D_loqdy") +update_curve_at_runtime = true +arc_list = SubResource("Resource_vpx2b") +shape_type = 2 +size = Vector2(6.35, 2.64583) +rx = 3.175 +ry = 1.32292 + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/Head/Nose"] +color = Color(0, 0, 0, 1) +polygon = PackedVector2Array(3.175, 0, 3.17087, 0.0680788, 3.15861, 0.135264, 3.13842, 0.201472, 3.1105, 0.266619, 3.07505, 0.330624, 3.03226, 0.393402, 2.98235, 0.454871, 2.9255, 0.514947, 2.7918, 0.630589, 2.63277, 0.739663, 2.45, 0.841505, 2.24508, 0.93545, 1.77519, 1.09699, 1.23587, 1.21896, 0.639887, 1.29604, 0, 1.32291, -0.639887, 1.29604, -1.23587, 1.21896, -1.77519, 1.09699, -2.24508, 0.93545, -2.45, 0.841505, -2.63277, 0.739663, -2.7918, 0.630589, -2.9255, 0.514947, -2.98235, 0.454871, -3.03226, 0.393402, -3.07505, 0.330624, -3.1105, 0.266619, -3.13842, 0.201472, -3.15861, 0.135264, -3.17087, 0.0680788, -3.175, 0, -3.17087, -0.0680788, -3.15861, -0.135264, -3.13842, -0.201472, -3.1105, -0.266619, -3.07505, -0.330624, -3.03226, -0.393402, -2.98235, -0.454871, -2.9255, -0.514947, -2.7918, -0.630589, -2.63277, -0.739663, -2.45, -0.841505, -2.24508, -0.93545, -1.77519, -1.09699, -1.23587, -1.21896, -0.639887, -1.29604, 0, -1.32291, 0.639887, -1.29604, 1.23587, -1.21896, 1.77519, -1.09699, 2.24508, -0.93545, 2.45, -0.841505, 2.63277, -0.739663, 2.7918, -0.630589, 2.9255, -0.514947, 2.98235, -0.454871, 3.03226, -0.393402, 3.07505, -0.330624, 3.1105, -0.266619, 3.13842, -0.201472, 3.15861, -0.135264, 3.17087, -0.0680788) +metadata/_edit_lock_ = true + +[node name="Mouth" type="Node2D" parent="FanArt/layer1/Head" node_paths=PackedStringArray("line")] +position = Vector2(-1.8317, 9.702) +script = ExtResource("4_i2hyy") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 1.5875 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ojj3e") +update_curve_at_runtime = true +arc_list = SubResource("Resource_mg08f") + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/Head/Mouth"] +points = PackedVector2Array(2.91041, -1.4493, 2.90296, -1.24629, 2.88136, -1.0443, 2.84573, -0.844306, 2.79624, -0.647285, 2.73312, -0.454196, 2.65668, -0.26598, 2.56731, -0.0835546, 2.46542, 0.0921917, 2.35152, 0.260403, 2.22617, 0.420259, 2.08997, 0.570982, 1.94359, 0.711837, 1.78774, 0.842138, 1.62318, 0.961249, 1.45072, 1.06859, 1.27118, 1.16364, 1.08545, 1.24594, 0.894438, 1.31508, 0.699065, 1.37072, 0.500285, 1.4126, 0.299069, 1.44052, 0.0963949, 1.45433, -0.106748, 1.45397, -0.309372, 1.43943, -0.510488, 1.4108, -0.709117, 1.36821, -0.904291, 1.31187, -1.09506, 1.24205, -1.28049, 1.1591, -1.45969, 1.06341, -1.63177, 0.955451, -1.7959, 0.835753, -1.95129, 0.704898, -2.09717, 0.563522, -2.23283, 0.412315, -2.35761, 0.252013, -2.47091, 0.0833976, -2.57216, -0.0927107, -2.66089, -0.275453, -2.73665, -0.46394, -2.79908, -0.657253, -2.84788, -0.854449, -2.8828, -1.05457, -2.90367, -1.25664, -2.9104, -1.45967) +width = 1.5875 +default_color = Color(0, 0, 0, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="RightEye" parent="FanArt/layer1/Head" instance=ExtResource("5_3gxsp")] +unique_name_in_owner = true +position = Vector2(-7.39712, -0.674786) + +[node name="LeftEye" parent="FanArt/layer1/Head" instance=ExtResource("5_3gxsp")] +unique_name_in_owner = true +position = Vector2(9.25859, -0.465553) + +[node name="Hair2" type="Node2D" parent="FanArt/layer1/Head" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(1.19137, -13.1397) +rotation = -3.02566 +script = ExtResource("4_i2hyy") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 3.1 +line = NodePath("Stroke") +curve = SubResource("Curve2D_3gxsp") +update_curve_at_runtime = true +arc_list = SubResource("Resource_vuvrq") + +[node name="Stroke" type="Line2D" parent="FanArt/layer1/Head/Hair2"] +points = PackedVector2Array(7.96465, 7.6074, 8.3288, 7.63232, 8.69808, 7.62954, 9.07048, 7.59944, 9.44399, 7.5424, 10.1863, 7.34902, 10.9088, 7.05247, 11.5449, 6.68912, 12.072, 6.28792, 12.2976, 6.07565, 12.4993, 5.85694, 12.6783, 5.6328, 12.8357, 5.40424, 13.0902, 4.93787, 13.272, 4.4659, 13.39, 3.99638, 13.4533, 3.53738, 13.4709, 3.09694, 13.4517, 2.68313, 13.3395, 1.96764, 13.1889, 1.45537, 13.1218, 1.2956, 13.0943, 1.24332, 13.0825, 1.22453, 13.0722, 1.2108, 13.2499, 0.63655, 13.3697, 0.0585596, 13.432, -0.519471, 13.4367, -1.09384, 13.384, -1.66085, 13.2742, -2.21681, 13.1073, -2.758, 12.8836, -3.28074, 12.5959, -3.78996, 12.26, -4.25877, 11.8796, -4.68598, 11.4584, -5.07045, 11, -5.411, 10.5081, -5.70646, 9.98646, -5.95568, 9.43863, -6.15749, 8.86833, -6.31072, 8.27921, -6.4142, 7.67495, -6.46678, 7.05923, -6.46729, 6.4357, -6.41456, 5.80804, -6.30742, 5.17992, -6.14472, 4.555, -5.92528, 4.35279, -6.23597, 4.11364, -6.52166, 3.84094, -6.78009, 3.53805, -7.00899, 3.20835, -7.20608, 2.8552, -7.36909, 2.48199, -7.49575, 2.09208, -7.58379, 1.59369, -7.63232, 1.10408, -7.61538, 0.630486, -7.53574, 0.18015, -7.39622, -0.0340367, -7.30488, -0.239696, -7.19961, -0.435924, -7.08076, -0.621817, -6.94869, -0.796469, -6.80374, -0.958977, -6.64627, -1.10844, -6.47662, -1.24394, -6.29514, -1.4117, -6.53242, -1.59759, -6.74754, -1.80011, -6.93945, -2.01774, -7.1071, -2.24899, -7.24947, -2.49233, -7.3655, -2.74628, -7.45416, -3.00931, -7.51441, -3.26801, -7.54322, -3.52518, -7.54445, -3.77953, -7.51903, -4.02975, -7.46791, -4.27455, -7.39201, -4.51264, -7.29226, -4.74273, -7.1696, -4.96352, -7.02496, -5.17371, -6.85926, -5.37202, -6.67344, -5.55714, -6.46844, -5.72779, -6.24519, -5.88266, -6.00461, -6.02047, -5.74764, -6.13992, -5.47521, -6.23972, -5.18826, -7.3946, -5.07563, -8.57612, -4.83867, -9.73447, -4.48521, -10.8199, -4.02308, -11.3196, -3.75372, -11.7825, -3.46012, -12.2022, -3.14328, -12.5725, -2.80418, -12.8873, -2.44378, -13.0219, -2.2559, -13.1402, -2.06307, -13.2415, -1.86541, -13.3251, -1.66304, -13.3901, -1.45608, -13.4357, -1.24465, -13.4662, -0.981663, -13.4708, -0.718553, -13.4506, -0.455753, -13.4063, -0.1937, -13.3389, 0.0671696, -13.2493, 0.326422, -13.0072, 0.838329, -12.6871, 1.33854, -12.2965, 1.82356, -11.8424, 2.28992, -11.3323, 2.73412, -10.1729, 3.54214, -8.87629, 4.21973, -7.50071, 4.73902, -6.10427, 5.07213, -5.10017, 5.17898, -4.11623, 5.17183, -3.16665, 5.05513, -2.26561, 4.83333, -1.42731, 4.51086, -1.03612, 4.31326, -0.665943, 4.09216, -0.318547, 3.84811, 0.00429246, 3.58168, 0.300802, 3.2934, 0.569206, 2.98385, 0.94391, 3.58356, 1.39099, 4.12667, 1.90446, 4.60935, 2.47832, 5.02777, 3.10658, 5.3781, 3.78324, 5.6565, 4.50232, 5.85915, 5.25782, 5.9822, 5.47144, 6.30598, 5.72655, 6.59881, 6.02023, 6.85893, 6.34955, 7.08458, 6.71157, 7.27402, 7.10338, 7.42547, 7.52205, 7.53719) +closed = true +width = 3.1 +default_color = Color(0, 0, 0, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="FanArt/layer1/Head/Hair2"] +color = Color(0.976471, 0.976471, 0.976471, 1) +polygon = PackedVector2Array(7.96465, 7.6074, 8.3288, 7.63232, 8.69808, 7.62954, 9.07048, 7.59944, 9.44399, 7.5424, 10.1863, 7.34902, 10.9088, 7.05247, 11.5449, 6.68912, 12.072, 6.28792, 12.2976, 6.07565, 12.4993, 5.85694, 12.6783, 5.6328, 12.8357, 5.40424, 13.0902, 4.93787, 13.272, 4.4659, 13.39, 3.99638, 13.4533, 3.53738, 13.4709, 3.09694, 13.4517, 2.68313, 13.3395, 1.96764, 13.1889, 1.45537, 13.1218, 1.2956, 13.0943, 1.24332, 13.0825, 1.22453, 13.0722, 1.2108, 13.2499, 0.63655, 13.3697, 0.0585596, 13.432, -0.519471, 13.4367, -1.09384, 13.384, -1.66085, 13.2742, -2.21681, 13.1073, -2.758, 12.8836, -3.28074, 12.5959, -3.78996, 12.26, -4.25877, 11.8796, -4.68598, 11.4584, -5.07045, 11, -5.411, 10.5081, -5.70646, 9.98646, -5.95568, 9.43863, -6.15749, 8.86833, -6.31072, 8.27921, -6.4142, 7.67495, -6.46678, 7.05923, -6.46729, 6.4357, -6.41456, 5.80804, -6.30742, 5.17992, -6.14472, 4.555, -5.92528, 4.35279, -6.23597, 4.11364, -6.52166, 3.84094, -6.78009, 3.53805, -7.00899, 3.20835, -7.20608, 2.8552, -7.36909, 2.48199, -7.49575, 2.09208, -7.58379, 1.59369, -7.63232, 1.10408, -7.61538, 0.630486, -7.53574, 0.18015, -7.39622, -0.0340367, -7.30488, -0.239696, -7.19961, -0.435924, -7.08076, -0.621817, -6.94869, -0.796469, -6.80374, -0.958977, -6.64627, -1.10844, -6.47662, -1.24394, -6.29514, -1.4117, -6.53242, -1.59759, -6.74754, -1.80011, -6.93945, -2.01774, -7.1071, -2.24899, -7.24947, -2.49233, -7.3655, -2.74628, -7.45416, -3.00931, -7.51441, -3.26801, -7.54322, -3.52518, -7.54445, -3.77953, -7.51903, -4.02975, -7.46791, -4.27455, -7.39201, -4.51264, -7.29226, -4.74273, -7.1696, -4.96352, -7.02496, -5.17371, -6.85926, -5.37202, -6.67344, -5.55714, -6.46844, -5.72779, -6.24519, -5.88266, -6.00461, -6.02047, -5.74764, -6.13992, -5.47521, -6.23972, -5.18826, -7.3946, -5.07563, -8.57612, -4.83867, -9.73447, -4.48521, -10.8199, -4.02308, -11.3196, -3.75372, -11.7825, -3.46012, -12.2022, -3.14328, -12.5725, -2.80418, -12.8873, -2.44378, -13.0219, -2.2559, -13.1402, -2.06307, -13.2415, -1.86541, -13.3251, -1.66304, -13.3901, -1.45608, -13.4357, -1.24465, -13.4662, -0.981663, -13.4708, -0.718553, -13.4506, -0.455753, -13.4063, -0.1937, -13.3389, 0.0671696, -13.2493, 0.326422, -13.0072, 0.838329, -12.6871, 1.33854, -12.2965, 1.82356, -11.8424, 2.28992, -11.3323, 2.73412, -10.1729, 3.54214, -8.87629, 4.21973, -7.50071, 4.73902, -6.10427, 5.07213, -5.10017, 5.17898, -4.11623, 5.17183, -3.16665, 5.05513, -2.26561, 4.83333, -1.42731, 4.51086, -1.03612, 4.31326, -0.665943, 4.09216, -0.318547, 3.84811, 0.00429246, 3.58168, 0.300802, 3.2934, 0.569206, 2.98385, 0.94391, 3.58356, 1.39099, 4.12667, 1.90446, 4.60935, 2.47832, 5.02777, 3.10658, 5.3781, 3.78324, 5.6565, 4.50232, 5.85915, 5.25782, 5.9822, 5.47144, 6.30598, 5.72655, 6.59881, 6.02023, 6.85893, 6.34955, 7.08458, 6.71157, 7.27402, 7.10338, 7.42547, 7.52205, 7.53719) +metadata/_edit_lock_ = true + +[node name="AnimationPlayer" type="AnimationPlayer" parent="FanArt"] +root_node = NodePath("../..") +libraries = { +&"": SubResource("AnimationLibrary_w1jjx") +} + +[node name="Camera2D" type="Camera2D" parent="."] +position = Vector2(23, 31.6667) +zoom = Vector2(7, 7) diff --git a/addons/curved_lines_2d/examples/gui.tscn b/addons/curved_lines_2d/examples/gui.tscn new file mode 100644 index 0000000..130ab3e --- /dev/null +++ b/addons/curved_lines_2d/examples/gui.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=7 format=3 uid="uid://0vt4p8wqudyi"] + +[ext_resource type="Script" uid="uid://cd2hrik4wvt1o" path="res://addons/curved_lines_2d/svg_texture_helper.gd" id="1_tkwla"] +[ext_resource type="Script" uid="uid://yh2davxk4fh7" path="res://addons/curved_lines_2d/svg_resource.gd" id="2_fv747"] + +[sub_resource type="Resource" id="Resource_2fobf"] +script = ExtResource("2_fv747") +svg_file_path = "res://addons/curved_lines_2d/tests/01-godot-icon.svg" +render_scale = 1.0 +svg_string = "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4Ij4KICAgIDxyZWN0IHdpZHRoPSIxMjQiIGhlaWdodD0iMTI0IiB4PSIyIiB5PSIyIiBmaWxsPSIjMzYzZDUyIiBzdHJva2U9IiMyMTI1MzIiIHN0cm9rZS13aWR0aD0iNCIKICAgICAgICByeD0iMTQiIC8+CiAgICA8ZyBmaWxsPSIjZmZmIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMi4zMjIgMTIuMzIyKXNjYWxlKC4xMDEpIj4KICAgICAgICA8cGF0aCBkPSJNMTA1IDY3M3YzM3E0MDcgMzU0IDgxNCAwdi0zM3oiIC8+CiAgICAgICAgPHBhdGggZmlsbD0iIzQ3OGNiZiIKICAgICAgICAgICAgZD0ibTEwNSA2NzMgMTUyIDE0cTEyIDEgMTUgMTRsNCA2NyAxMzIgMTAgOC02MXEyLTExIDE1LTE1aDE2MnExMyA0IDE1IDE1bDggNjEgMTMyLTEwIDQtNjdxMy0xMyAxNS0xNGwxNTItMTRWNDI3cTMwLTM5IDU2LTgxLTM1LTU5LTgzLTEwOC00MyAyMC04MiA0Ny00MC0zNy04OC02NCA3LTUxIDgtMTAyLTU5LTI4LTEyMy00Mi0yNiA0My00NiA4OS00OS03LTk4IDAtMjAtNDYtNDYtODktNjQgMTQtMTIzIDQyIDEgNTEgOCAxMDItNDggMjctODggNjQtMzktMjctODItNDctNDggNDktODMgMTA4IDI2IDQyIDU2IDgxem0wIDMzdjM5YzAgMjc2IDgxMyAyNzYgODE0IDB2LTM5bC0xMzQgMTItNSA2OXEtMiAxMC0xNCAxM2wtMTYyIDExcS0xMiAwLTE2LTExbC0xMC02NUg0NDZsLTEwIDY1cS00IDExLTE2IDExbC0xNjItMTFxLTEyLTMtMTQtMTNsLTUtNjl6IiAvPgogICAgICAgIDxwYXRoIGQ9Ik00ODMgNjAwYzAgMzQgNTggMzQgNTggMHYtODZjMC0zNC01OC0zNC01OCAweiIgLz4KICAgICAgICA8Y2lyY2xlIGN4PSI3MjUiIGN5PSI1MjYiIHI9IjkwIiAvPgogICAgICAgIDxjaXJjbGUgY3g9IjI5OSIgY3k9IjUyNiIgcj0iOTAiIC8+CiAgICA8L2c+CiAgICA8ZyBmaWxsPSIjNDE0MDQyIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMi4zMjIgMTIuMzIyKXNjYWxlKC4xMDEpIj4KICAgICAgICA8Y2lyY2xlIGN4PSIzMDciIGN5PSI1MzIiIHI9IjYwIiAvPgogICAgICAgIDxjaXJjbGUgY3g9IjcxNyIgY3k9IjUzMiIgcj0iNjAiIC8+CiAgICA8L2c+Cjwvc3ZnPg==" +original_size = Vector2(128, 128) +metadata/_custom_type_script = "uid://yh2davxk4fh7" + +[sub_resource type="Resource" id="Resource_tkwla"] +script = ExtResource("2_fv747") +svg_file_path = "res://addons/curved_lines_2d/tests/fan_art.svg" +render_scale = 1.0 +svg_string = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB3aWR0aD0iNDUuNDAzMTYiCiAgIGhlaWdodD0iNjMuMTk5MjQ1IgogICB2aWV3Qm94PSIwIDAgNDUuNDAzMTU0IDYzLjE5OTI0NCIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnMSIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4zLjIgKDA5MWUyMGUsIDIwMjMtMTEtMjUsIGN1c3RvbSkiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImZhbl9hcnQuc3ZnIgogICB4bWw6c3BhY2U9InByZXNlcnZlIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0ibmFtZWR2aWV3MSIKICAgICBwYWdlY29sb3I9IiM1MDUwNTAiCiAgICAgYm9yZGVyY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMSIKICAgICBpbmtzY2FwZTpzaG93cGFnZXNoYWRvdz0iMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIKICAgICBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIxIgogICAgIGlua3NjYXBlOmRlc2tjb2xvcj0iIzUwNTA1MCIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6em9vbT0iMTguMTgyMjQ3IgogICAgIGlua3NjYXBlOmN4PSIzMi40NDkyMzUiCiAgICAgaW5rc2NhcGU6Y3k9IjMxLjI2Njc2MyIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiIC8+PGRlZnMKICAgICBpZD0iZGVmczEiPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgxIj48ZWxsaXBzZQogICAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6c3Ryb2tlIG1hcmtlcnMgZmlsbCIKICAgICAgICAgaWQ9ImVsbGlwc2UyIgogICAgICAgICBpbmtzY2FwZTpsYWJlbD0iUmlnaHRFeWUiCiAgICAgICAgIGN5PSIxMjkuMzQ3MjYiCiAgICAgICAgIGN4PSI2NS43ODg5OTQiCiAgICAgICAgIHJ4PSI2LjMzMDYwNDEiCiAgICAgICAgIHJ5PSI1Ljg1MDgyNDQiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMiI+PGVsbGlwc2UKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS41O3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICAgIGlkPSJlbGxpcHNlMyIKICAgICAgICAgaW5rc2NhcGU6bGFiZWw9IkxlZnRFeWUiCiAgICAgICAgIGN5PSIxMjguNTYxNzQiCiAgICAgICAgIGN4PSI4Mi43ODU1MjIiCiAgICAgICAgIHJ4PSI2LjMzMDYwNDEiCiAgICAgICAgIHJ5PSI1LjY5NTI2NDMiIC8+PC9jbGlwUGF0aD48L2RlZnM+PGcKICAgICBpbmtzY2FwZTpsYWJlbD0iSGVhZCIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTUyLjc2MTQyNSwtMTA2LjA3OTI1KSI+PHJlY3QKICAgICAgIHN0eWxlPSJmaWxsOiNmYzlhOWE7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjM7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjgwO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBpZD0icmVjdDMiCiAgICAgICB3aWR0aD0iOS45NTU4MzA2IgogICAgICAgaGVpZ2h0PSI0LjM1NTY3MjgiCiAgICAgICB4PSI2OC4yMDEwODgiCiAgICAgICB5PSIxNjMuMTQ0OTciCiAgICAgICByeD0iMS4wODg5MTg4IgogICAgICAgcnk9IjEuMDg4OTE3NyIgLz48cmVjdAogICAgICAgc3R5bGU9ImZpbGw6I2ZjOWE5YTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6ODA7cGFpbnQtb3JkZXI6c3Ryb2tlIG1hcmtlcnMgZmlsbCIKICAgICAgIGlkPSJyZWN0MiIKICAgICAgIHdpZHRoPSI5Ljk1NTgzMDYiCiAgICAgICBoZWlnaHQ9IjQuMzU1NjcyOCIKICAgICAgIHg9IjI3LjAzODcyNyIKICAgICAgIHk9IjE3OC43MDYzOCIKICAgICAgIHJ4PSIxLjA4ODkxODgiCiAgICAgICByeT0iMS4wODg5MTc3IgogICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTE2LjM1MjUyNikiIC8+PHJlY3QKICAgICAgIHN0eWxlPSJmaWxsOiNmYzlhOWE7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjM7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjgwO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBpZD0icmVjdDEiCiAgICAgICB3aWR0aD0iNi42MTEyODg1IgogICAgICAgaGVpZ2h0PSI0LjA0NDU0NjYiCiAgICAgICB4PSI0OC41ODAxNTgiCiAgICAgICB5PSIxNTcuNTEwMzEiCiAgICAgICByeT0iMS42MzMzNzgxIgogICAgICAgcng9IjEuMDg4OTE4OCIKICAgICAgIHRyYW5zZm9ybT0icm90YXRlKC00LjMxODU3NDkpIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IlJpZ2h0aGFuZCIgLz48cGF0aAogICAgICAgaWQ9IlJpZ2h0QXJtIgogICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOiNkMTM4NGI7ZmlsbC1vcGFjaXR5OjAuOTgxOTgyO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDozO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjgwO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBkPSJtIDY3Ljg5NDk1MywxNDQuNDYyNDYgYyA0LjAzNTMsMy4yMzc5MSAtMS4zNjM0Niw1Ljk2NTI1IDAuMTkxNTM4LDkuMTc4NzUgLTAuMzUwNjY0LDAuMDc2OSAtNC4zNDQ2MTgsMC43ODQ3MiAtNy42ODE3MjEsMC4zODYyMyAwLjYwMTgyOSwtOS4xNjI2NCA1LjQ1NTE2LC0xMi41NTUxNCA1LjE2MTIwMywtMTIuMTYwODYiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9IjAuMTU5NzIxNjYiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjYuMzU3Nzg0NiIgLz48cGF0aAogICAgICAgaWQ9IkNhcGUiCiAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6I2QxMzg0YjtmaWxsLW9wYWNpdHk6MC45ODE5ODI7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjM7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjgwO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBkPSJtIDY2LjU5NTgzOSwxNDIuNTE3NjUgYyA3LjA0ODM2LC0xLjExMDggOC44ODU0NjcsLTEuNTAxNDEgMTUuOTMzODI3LC0yLjE5MjEzIDIuNjkwNTQzLDUuODY2MiAxLjYzODk3NSwxNC40NjYwNyAxLjYzODk3NSwxNC40NjYwNyAwLDAgMi40ODg2MjIsNi4yNjQ5MyA1LjIxNjcxMiw4LjE4MjE4IC03LjM4MTkwNiwwLjk2NjQ3IC0xNC40ODg5OTQsMi4yMDc3NiAtMjMuMjU2MTkzLDEuNzg4OTQgLTAuNzkyOTc4LC0xLjc1MDA3IC0wLjg2ODIyNSwtMy41MDAxNCAtMC44NDI4MzEsLTUuMjUwMiB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjIiAvPjxyZWN0CiAgICAgICBzdHlsZT0iZmlsbDojZmM5YTlhO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDozO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo4MDtwYWludC1vcmRlcjpzdHJva2UgbWFya2VycyBmaWxsIgogICAgICAgaWQ9IkxlZnRIYW5kIgogICAgICAgd2lkdGg9IjYuNjExMjg4NSIKICAgICAgIGhlaWdodD0iNC4wNDQ1NDY2IgogICAgICAgeD0iNTAuODk5MTYyIgogICAgICAgeT0iMTY1LjkxMzQ4IgogICAgICAgcnk9IjEuNjMzMzc4MSIKICAgICAgIHJ4PSIxLjA4ODkxODgiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtMTEuNDY0NDU4KSIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJMZWZ0SGFuZCIgLz48cGF0aAogICAgICAgaWQ9IkxlZnRBcm0iCiAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6I2QxMzg0YjtmaWxsLW9wYWNpdHk6MC45ODE5ODI7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6ODA7cGFpbnQtb3JkZXI6c3Ryb2tlIG1hcmtlcnMgZmlsbCIKICAgICAgIGQ9Im0gODEuNzc3OTI0LDEzOS44ODc5OCBjIDQuMjg3MDk3LDIuODk2MyA2LjAwNDg2NCw4Ljc1MTg2IDcuODE4MDAzLDExLjgyNzExIC0wLjM0MzE4NSwwLjEwNTM0IC0zLjYwNTcwNCwxLjAyODE2IC02Ljc5OTI0MywxLjg5NDQ4IC0xLjg3MjczNCwtNi40MjY2IC0zLjIyMjY2NCwtMTAuMDEzIC0zLjIyMjY2NCwtMTAuMDEzIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMC41NzY1NjUzNCIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteT0iNi40NTIyNzg3IiAvPjxwYXRoCiAgICAgICBpZD0iSGVhZCIKICAgICAgIHN0eWxlPSJmaWxsOiNmYzlhOWE7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjMuMTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjpzdHJva2UgbWFya2VycyBmaWxsIgogICAgICAgZD0ibSA2NS42NzcyMzIsMTE5LjMzNjE4IGggMjIuMDAyMzM0IGMgMC40OTcyLC0yLjMwNDg4IDguNTUyOTU3LC02Ljk3NzU4IDguOTI3NTU3LC0zLjAzMTYgMC4yNDU2OCwyLjU4ODA1IC02LjE0MDU2NSw0LjgyMTc1IC02LjE0MDU2NSw0LjA4OTk0IGwgMC4yNDY5NTEsMTYuMDk4OTcgYyAwLjAwNzIsMC40Njg3NSAtMS45NDk2NzIsMS42NTg4MiAtNC40MzMzMzMsMi4yMTA3OCAtOC43NzU5MTksMS45NTAzMyAtMTQuOTk2NjEzLDIuMzczMDIgLTIyLjMzMTYwMywyLjU1MTgzIC03LjMzNDk5LDAuMTc4ODEgLTkuMTUyNTg4LC0wLjA0NTUgLTkuNjE5MzA5LC0xLjcxNjg4IC0wLjQ2NjcyMSwtMS42NzEzNCA5LjI4ODI0NSwtNC43NDI0NyA5LjI4ODI0NSwtNC43NDI0NyBMIDYyLjg5MDI0LDEyMC44ODkyOCBjIC0xLjQyMjQzOCwtNy4yZS00IC04LjI4MjQ3NCwtMS44NzU4NiAtNy4xNDQ0NzcsLTUuNDc4NjUgMC45NTU3MzQsLTMuMDI1NzYgOS4zODAxNTgsMS41OTcyNyA5LjkzMTQ2OSwzLjkyNTU1IHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjc2Nzc3p6Y2NzYyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJIZWFkIiAvPjxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjU4NzU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6c3Ryb2tlIG1hcmtlcnMgZmlsbCIKICAgICAgIGlkPSJOb3NlIgogICAgICAgY3g9IjU4LjY1MDkwNiIKICAgICAgIGN5PSIxMzguOTkyMzkiCiAgICAgICByeD0iMy4xNzUiCiAgICAgICByeT0iMS4zMjI5MTY2IgogICAgICAgaW5rc2NhcGU6bGFiZWw9Ik5vc2UiIC8+PGVsbGlwc2UKICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuNTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjpzdHJva2UgbWFya2VycyBmaWxsIgogICAgICAgaWQ9IlJpZ2h0RXllIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IlJpZ2h0RXllIgogICAgICAgY3k9IjEyOS4zNDcyNiIKICAgICAgIGN4PSI2NS43ODg5OTQiCiAgICAgICByeD0iNi4zMzA2MDQxIgogICAgICAgcnk9IjUuNTc4NTk0NyIgLz48cGF0aAogICAgICAgaWQ9IlJpZ2h0SXJpcyIKICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLXdpZHRoOjEuMDU4MzM7c3Ryb2tlLW1pdGVybGltaXQ6ODA7cGFpbnQtb3JkZXI6c3Ryb2tlIG1hcmtlcnMgZmlsbCIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJJcmlzIgogICAgICAgZD0ibSA3MC41MDMxNzUsMTI5Ljc5NTEyIGEgNS4xMjIyMTI0LDEwLjcxMDA4MSAwIDAgMSAtNS4xMjIyMTIsMTAuNzEwMDggNS4xMjIyMTI0LDEwLjcxMDA4MSAwIDAgMSAtNS4xMjIyMTMsLTEwLjcxMDA4IDUuMTIyMjEyNCwxMC43MTAwODEgMCAwIDEgNS4xMjIyMTMsLTEwLjcxMDA4IDUuMTIyMjEyNCwxMC43MTAwODEgMCAwIDEgNS4xMjIyMTIsMTAuNzEwMDggeiIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDEpIiAvPjxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBpZD0iUmlnaHRQdXBpbCIKICAgICAgIGN4PSI2NS4yNjQ1NTciCiAgICAgICBjeT0iMTI5Ljg1MzMyIgogICAgICAgcng9IjEuNjI5Nzk0OCIKICAgICAgIHJ5PSIzLjQ5MjQxNzMiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iUHVwaWwiIC8+PGVsbGlwc2UKICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuNTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjpzdHJva2UgbWFya2VycyBmaWxsIgogICAgICAgaWQ9IkxlZnRFeWUiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iTGVmdEV5ZSIKICAgICAgIGN5PSIxMjguNTYxNzQiCiAgICAgICBjeD0iODIuNzg1NTIyIgogICAgICAgcng9IjYuMzMwNjA0MSIKICAgICAgIHJ5PSI1LjY0MDI2NTUiIC8+PHBhdGgKICAgICAgIGlkPSJIYWlyIgogICAgICAgc3R5bGU9ImZpbGw6I2Y5ZjlmOTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6My4xO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBkPSJtIDgzLjUyNjk0NSwxMjIuODcxNzcgYyAwLjk2MjQyMSwwLjEwMzczIDIuMDAxMTU5LC0wLjA5MjEgMi45NDQyMDEsLTAuNTU0OTMgMy42OTg4MDIsLTEuODIyNjYgMi4zNjUzNTIsLTUuNjAzNyAyLjE2MzM0OCwtNS44NDE2NyAwLjU1MTAzNSwtMS41MjMwNiAwLjQ4Mzc0OCwtMy4xMjU0NyAtMC4xODg2MDUsLTQuNDkxNTQgLTEuMzk5NTkyLC0yLjgyMTU4IC01LjAxMDc3MiwtMy45NjgyMyAtOC4zMjg1ODQsLTIuNjQ0NTQgLTAuNDg2OTk2LC0wLjg1OTgxIC0xLjQwMzg5NywtMS40NzcyNCAtMi40NjI5MiwtMS42NTg1MSAtMS4zMzQzMjgsLTAuMjE5MjEgLTIuNjUyMTQyLDAuMjg5ODMgLTMuMzM2MDE4LDEuMjg4NjQgLTAuNDIxODUsLTAuNjYxMzkgLTEuMDUzMTU5LC0xLjA5NzQyIC0xLjc2NTM2OCwtMS4yMTkyNyAtMS4zODE1MzUsLTAuMjI4ODIgLTIuNzUyODc4LDAuNzU4NjYgLTMuMjMwNDA0LDIuMzI2MTYgLTIuOTk5ODg1LDAuMTI3NTkgLTYuODE1MTc2LDEuNjY1MDIgLTcuMTk1OTksMy45NDM2IC0wLjQ2NjI0MiwyLjgwMjk4IDMuNjMxNDg0LDUuNzAxNDkgNy4zMzE0MzMsNi4zMTY3OCAyLjY5MTg1OCwwLjQ0MDg2IDUuMzIwMDg3LC0wLjM4MTU3IDYuNjczNDc4LC0yLjA4ODI4IDAuODk3Mzc5LDEuNjcxMjcgMi42MzA3MTMsMi43Nzk3MyA0LjY4ODYxNSwyLjk5ODM1IDAuNTExNzMsMC45MDMxMSAxLjQ5NzI2NSwxLjQ5NDg0IDIuNzA2ODE0LDEuNjI1MjEgeiIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJIYWlyIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJzY2NjY2NjY2NjY2NjcyIgLz48cGF0aAogICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuNTg3NTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjpzdHJva2UgbWFya2VycyBmaWxsIgogICAgICAgaWQ9Ik1vdXRoIgogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgc29kaXBvZGk6Y3g9IjczLjYzMjYyMiIKICAgICAgIHNvZGlwb2RpOmN5PSIxMzYuMTExMjgiCiAgICAgICBzb2RpcG9kaTpyeD0iMi45MTA0MTY2IgogICAgICAgc29kaXBvZGk6cnk9IjIuOTEwNDE2NiIKICAgICAgIHNvZGlwb2RpOnN0YXJ0PSIwIgogICAgICAgc29kaXBvZGk6ZW5kPSIzLjE0NTI5MTIiCiAgICAgICBzb2RpcG9kaTphcmMtdHlwZT0iYXJjIgogICAgICAgZD0ibSA3Ni41NDMwMzgsMTM2LjExMTI4IGEgMi45MTA0MTY2LDIuOTEwNDE2NiAwIDAgMSAtMS40NTgzMTYsMi41MjIyOSAyLjkxMDQxNjYsMi45MTA0MTY2IDAgMCAxIC0yLjkxMzUxOSwtMC4wMDUgMi45MTA0MTY2LDIuOTEwNDE2NiAwIDAgMSAtMS40NDg5NzgsLTIuNTI3NjYiCiAgICAgICBzb2RpcG9kaTpvcGVuPSJ0cnVlIgogICAgICAgaW5rc2NhcGU6bGFiZWw9Ik1vdXRoIiAvPjxwYXRoCiAgICAgICBpZD0iTGVmdElyaXMiCiAgICAgICBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLXdpZHRoOjEuMDU4MzM7c3Ryb2tlLW1pdGVybGltaXQ6ODA7cGFpbnQtb3JkZXI6c3Ryb2tlIG1hcmtlcnMgZmlsbCIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJJcmlzIgogICAgICAgZD0ibSA4Ny45MjY0NDcsMTI4LjYwMjk1IGEgNS4xMjIyMTI0LDEwLjcxMDA4MSAwIDAgMSAtNS4xMjIyMTIsMTAuNzEwMDggNS4xMjIyMTI0LDEwLjcxMDA4MSAwIDAgMSAtNS4xMjIyMTMsLTEwLjcxMDA4IDUuMTIyMjEyNCwxMC43MTAwODEgMCAwIDEgNS4xMjIyMTMsLTEwLjcxMDA3IDUuMTIyMjEyNCwxMC43MTAwODEgMCAwIDEgNS4xMjIyMTIsMTAuNzEwMDcgeiIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDIpIiAvPjxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBpZD0iTGVmdFB1cGlsIgogICAgICAgY3g9IjgyLjYwMDI4MSIKICAgICAgIGN5PSIxMjkuMzI5NDIiCiAgICAgICByeD0iMS42Mjk3OTQ4IgogICAgICAgcnk9IjMuNDkyNDE3MyIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJQdXBpbCIgLz48L2c+PC9zdmc+Cg==" +original_size = Vector2(45, 63) + +[sub_resource type="Resource" id="Resource_fv747"] +script = ExtResource("2_fv747") +svg_file_path = "res://addons/curved_lines_2d/tests/snail_concept.svg" +render_scale = 1.0 +svg_string = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB3aWR0aD0iOTAuMjE2MjU1IgogICBoZWlnaHQ9IjkxLjY2MTcxMyIKICAgdmlld0JveD0iMCAwIDIzLjg2OTcxOCAyNC4yNTIxNjEiCiAgIHZlcnNpb249IjEuMSIKICAgaWQ9InN2ZzEiCiAgIGlua3NjYXBlOnZlcnNpb249IjEuMy4yICgwOTFlMjBlLCAyMDIzLTExLTI1LCBjdXN0b20pIgogICBzb2RpcG9kaTpkb2NuYW1lPSJzbmFpbF9jb25jZXB0LnN2ZyIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJuYW1lZHZpZXcxIgogICAgIHBhZ2Vjb2xvcj0iIzUwNTA1MCIKICAgICBib3JkZXJjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJvcGFjaXR5PSIxIgogICAgIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIwIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjEiCiAgICAgaW5rc2NhcGU6ZGVza2NvbG9yPSIjNTA1MDUwIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTp6b29tPSIzLjA3NTIyNDUiCiAgICAgaW5rc2NhcGU6Y3g9IjE1LjYwODYxNyIKICAgICBpbmtzY2FwZTpjeT0iMTEwLjM5ODQ1IgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImcyNCIgLz4KICA8ZGVmcwogICAgIGlkPSJkZWZzMSI+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQ1IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50NTYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45MTI4NzU4OCwwLDAsMC45MTI4NzU4OCwxNDkuMTYzODcsOTEuMTUzOTI1KSIKICAgICAgIGN4PSIxNS45ODEzODYiCiAgICAgICBjeT0iMTUuMDc3OTk3IgogICAgICAgZng9IjE1Ljk4MTM4NiIKICAgICAgIGZ5PSIxNS4wNzc5OTciCiAgICAgICByPSIyLjIyMTkyNjkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZiYzhjODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMC4xNzQ1NzI5IgogICAgICAgICBpZD0ic3RvcDQ1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmI3YzdiO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjMyMjY1MzI5IgogICAgICAgICBpZD0ic3RvcDQ3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTMwNjA5O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjY3MzUwNzQ1IgogICAgICAgICBpZD0ic3RvcDQ2IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUtMyIKICAgICAgIHgxPSI1NS44NDA3ODYiCiAgICAgICB5MT0iMzQuMDY1NDg3IgogICAgICAgeDI9IjY4LjYzODkyNCIKICAgICAgIHkyPSIzOC4zNjczNDQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoODMuNjQwMTgsMTExLjkxMDY4KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhN2UwOTY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzZhYjUxNDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMC4xNjU4NDk4NSIKICAgICAgICAgaWQ9InN0b3A1LTMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxYzY3MDg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAuNTgzNjQzMDgiCiAgICAgICAgIGlkPSJzdG9wNi0wIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDUiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQ1NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjkxMjg3NTg4LDAsMCwwLjkxMjg3NTg4LDEyNC45MTcxNywxMTYuODQwMzIpIgogICAgICAgY3g9IjE1Ljk4MTM4NiIKICAgICAgIGN5PSIxNS4wNzc5OTciCiAgICAgICBmeD0iMTUuOTgxMzg2IgogICAgICAgZnk9IjE1LjA3Nzk5NyIKICAgICAgIHI9IjIuMjIxOTI2OSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1NCIKICAgICAgIHgxPSI3My4zMTI1MzEiCiAgICAgICB5MT0iMTUuMTczMjU3IgogICAgICAgeDI9Ijc0LjQxMjc2NiIKICAgICAgIHkyPSIxNy4wNTgzNjEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMuMzYzMzc1NCwwLjE0NzIxNzQ4KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmJkZGRkO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmI3YzdiO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDU0IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEzNi41MjQ5OSwtMTI3LjYyODczKSI+CiAgICA8Y2lyY2xlCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNmMzNTM1O3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpZD0iY2lyY2xlNTUiCiAgICAgICBjeD0iMTY0LjA2MzMxIgogICAgICAgY3k9IjEwNS4zNjgiCiAgICAgICByPSIxLjc4NjgxMTYiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSg5LjA4MjIyNDcpIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMS4xMzAxNDg3IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSItNi43NzU4OTIyIiAvPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoNTQiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMWM2NzA4O3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBkPSJtIDE0NC43ODUxNCwxMzIuMDYwNzYgYyAtMC4zODU3OCwtMS4wNTM3IDEuNzIxOTUsLTEuMzY5MzkgMS43NDQ4MSwtMC4zNzE4NSAwLjAyNjQsMS4yODY0IDAuMTQ1MzcsMS42OTU5OSAtMC4xMDAxLDIuNDQxNzMgLTAuMjAzNjQsMC42NjczMyAtMC41NTc3OSwwLjcwOTQ3IC0xLjAwMzkxLDAuMzY5NTcgLTAuMjg0MjUsLTAuNDgzNDMgLTAuMzU2ODksLTEuNTE1MTkgLTAuNjQwOCwtMi40Mzk0NSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTEuNDE2MjI5IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSItMy44MjM3OTUyIiAvPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoNTMiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMWM2NzA4O3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBkPSJtIDE0NC45NDcxNSwxMzQuMTMxNTcgYyAwLjAzMDYsLTEuMTIxNjggMi4xMDEyOSwtMC41ODc0IDEuNzU0MTgsMC4zNDgwOCAtMC40NTA1MiwxLjIwNTIxIC0wLjQ5MTE2LDEuNjI5OCAtMC45OTQ2NiwyLjIzMjE5IC0wLjQzNTY2LDAuNTQ0OTggLTAuNzgwMzQsMC40NTMzNiAtMS4wNjk0MywtMC4wMjczIDAuMDk5OCwtMC44MjQ5OCAwLjM2OTMsLTEuMzk2NjEgMC4zMDk5LC0yLjU1MzAzIHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMS40NDUxNDY5IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSItMS40Mjg0NTciIC8+CiAgICA8Y2lyY2xlCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50NTYpO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjI2NDU4MztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaWQ9ImNpcmNsZTU2IgogICAgICAgY3g9IjE2NC4xMDYzNCIKICAgICAgIGN5PSIxMDUuMzg5NSIKICAgICAgIHI9IjEuNzg2ODExNiIKICAgICAgIHRyYW5zZm9ybT0icm90YXRlKDkuMDgyMjI0NykiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii0xLjE2OTIzMjUiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii02Ljc0Nzg2MjIiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGg0MiIKICAgICAgIHN0eWxlPSJmaWxsOiM3YmM5NTY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuNTI5MTY3O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBkPSJtIDE0NC43ODE3NCwxMzIuMDgyIGMgLTAuMzg1NzgsLTEuMDUzNyAxLjcyMTk1LC0xLjM2OTM5IDEuNzQ0ODEsLTAuMzcxODUgMC4wMjY0LDEuMjg2NCAwLjE0NTM4LDEuNjk1OTkgLTAuMTAwMSwyLjQ0MTcyIC0wLjIwMzYzLDAuNjY3MzQgLTAuNTU3NzgsMC43MDk0NyAtMS4wMDM5LDAuMzY5NTggLTAuMjg0MjYsLTAuNDgzNDMgLTAuMzU2ODksLTEuNTE1MiAtMC42NDA4MSwtMi40Mzk0NSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTEuNDEyODMzIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSItMy44MDI1NTcyIiAvPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoNDMiCiAgICAgICBzdHlsZT0iZmlsbDojOWVkYTgzO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjUyOTE2NztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgZD0ibSAxNDQuOTQ4MDIsMTM0LjI2MjQgYyAwLjAzMDYsLTEuMTIxNjggMi4xMDEyOSwtMC41ODc0IDEuNzU0MTgsMC4zNDgwOCAtMC40NTA1MiwxLjIwNTIxIC0wLjQ5MTE2LDEuNjI5OCAtMC45OTQ2NywyLjIzMjE5IC0wLjQzNTY1LDAuNTQ0OTggLTAuNzgwMzMsMC40NTMzNyAtMS4wNjk0MiwtMC4wMjcyIDAuMDk5OCwtMC44MjQ5NyAwLjM2OTMsLTEuMzk2NjEgMC4zMDk5LC0yLjU1MzAzIHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMS40NDYwMTQ5IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSItMS4yOTc2MjQzIiAvPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNmMzNTM1O3N0cm9rZS13aWR0aDoxLjU4NzU7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGQ9Im0gMTQ3LjM3MzExLDEzNi43NDA3OSBjIDEuNDU5NjMsNC4zNDAxNCAwLjQxMjY4LDUuMTQ5MzIgLTIuNzkzNDksNC43OTU2OSAtMS4zOTc4MSwtMC4wNTM5IC0xLjQ5MTkzLDAuNTc4MzkgLTQuMTUxODUsLTIuMDMxMDIgLTAuNDAwMzksLTEuNzYzNjIgMS4zNDI4LC0zLjQ2OTYxIDMuMzkwNzgsLTMuODg3MjcgMi4xMDQxMiwtMC4zMTM4NiAyLjIyMTksLTAuMTM2NTggMy41NTQ1NiwxLjEyMjYgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGgxNCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiM2YzM1MzU7c3Ryb2tlLXdpZHRoOjEuNTg3NTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gMTQ3Ljk5NzM1LDE0MS4wNjIzMiBjIC0xLjM2MTE5LDAuMDIwNiAtMi4yODIwMiwwLjA0NDIgLTMuOTM5ODEsMC4zNzcyMyBsIC0xLjgyMjYzLDAuMDY4MiBjIC0xLjg2MTU1LDAuMTUwMDQgLTMuOTA3MjIsMS41NTA2MiAtNC43OTY2LDQuOTk3NjMgLTAuNjc5OTQsMi42MzUyNiAxLjUzMTI3LDUuMDc1MjcgNS4wMTE1OCw0LjQ5NzQgNC4yMTQ2OCwtMC42OTk4IDE1LjQyMzQ2LDAuNzEwNDkgMTcuMDU2MzIsLTAuNDUzNzIgLTAuMDczNywtMC4zMzMwMiAtMC41MTI5OSwtMC42MDc2OSAtMS4xODMzOSwtMC44NTUyNCAtMC40OTg4NCwtMC45NzI1NiAtMS4xMDAyNiwtMS41MzYzNSAtMS44MjA1NiwtMS45MzQyNSAtMC40OTg1NSwtMS41NzA1NiAtMi40ODc0OSwtMC41Mjc5MSAtNC40NjAxOSwtMi42NDI3MyAtMS43NDgzMiwtMS42ODE1NiAtMS4yNzg1OCwtMi43NjIzNSAtNC4wNDQ3MiwtNC4wNTQ1MyB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2Nzc2NjY2NjIiAvPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoMi00IgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDUtMyk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuMDU4MzM7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDE1OS41MDYyMSwxNTAuNTQ5MDYgYyAwLjU4NDUxLDIuMjE2NTggLTEyLjg0MTg0LC0wLjI0NTkgLTE3LjA1NjUyLDAuNDUzOSAtMy40ODAzMSwwLjU3Nzg3IC01LjY5MTI3LC0xLjg2MjM3IC01LjAxMTM0LC00LjQ5NzY0IDEuODM0OTUsLTcuMTExNzkgOC41OTQ1NSwtNS41Mjc5OCA4LjQ5NTg0LC0yLjE3NDY0IC0wLjEyNjczLDQuMzA1MjUgMTMuMTMyNDgsNC4yMzEyMiAxMy41NzIwMiw2LjIxODM4IHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNzc3NjIiAvPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoOS04IgogICAgICAgc3R5bGU9ImZpbGw6I2ZiN2M3YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzkwNDc0NztzdHJva2Utd2lkdGg6MC4yNjQ1ODM7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjAuNTA2NjA4O3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBkPSJtIDE1OC4zNTAyNywxNDkuNjE0NTMgYyAxLjY0ODY2LDEuMzQ1IC0xMy4xMDE4MywwLjQyMjI0IC0xNS4zNTMwOCwwLjUyOTMxIC01LjM4NzAxLC0wLjE3MTUgLTQuNTg0MDcsLTUuNjIyMzkgLTMuMzEyNzMsLTYuOTUwOTYgMy40ODA3MiwtNS4yMTA3MSAxMS43NTI2MSwxLjY1MzQ4IDEyLjYyNjg4LDIuOTA4OTMgMi44Njk4NCwxLjE2NDc4IDQuNzgwNjIsMS4wMDQwNCA2LjAzODkzLDMuNTEyNzIgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGgxMC04IgogICAgICAgc3R5bGU9ImZpbGw6I2EzMDYwOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS4wNTgzMztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gMTU2LjU0NDY3LDE0Ny43ODUxMyBjIC0wLjE2NzE0LDEuMzg5MDcgLTkuMzQxOTMsLTUuNjI5MDggLTguMDE2MDksLTIuMTg4OTYgLTEuODU0MSwtMC45MTU5IC0yLjUzNjY5LC0yLjc2MjI1IC0wLjEyNzc2LC0yLjIwODkzIC0wLjA2NDUsLTEuNzk3MSAtNC4yNzkwMywwLjE1NDI5IC00LjM0MzA5LC0yLjA3NjU5IDEuNjU3NzksLTAuMzMyOTkgMi41NzgyMiwtMC4zNTcwMyAzLjkzOTQxLC0wLjM3NzU5IDIuNzY2MTQsMS4yOTIxOSAyLjI5NjQyLDIuMzczMjUgNC4wNDQ3NCw0LjA1NDgyIDIuMDM0MiwyLjE4MDc1IDQuMDg2MDUsMS4wMDM5MiA0LjUwMjc5LDIuNzk3MjUgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InBhdGgxMSIKICAgICAgIGN4PSIxNDMuNzU1NTIiCiAgICAgICBjeT0iMTQzLjA2NjUxIgogICAgICAgcng9IjEuMDUzOTU0MiIKICAgICAgIHJ5PSIwLjYwMjI1OTUyIiAvPgogICAgPGVsbGlwc2UKICAgICAgIHN0eWxlPSJmaWxsOiNhMzA2MDk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuMDYzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InBhdGgxMi0xIgogICAgICAgY3g9IjE1MS4yMTIxIgogICAgICAgY3k9IjE2Ni4yOTkxOSIKICAgICAgIHJ4PSIwLjY1MDk4ODY0IgogICAgICAgcnk9IjAuNDA4Njc2MTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjk5MTIyNzksLTAuMTMyMTYzNzIsMCwxLDAsMCkiIC8+CiAgICA8Y2lyY2xlCiAgICAgICBzdHlsZT0iZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InBhdGgxMy0yIgogICAgICAgY3g9IjE0Ni42Mzc3NiIKICAgICAgIGN5PSIxNDUuMzY4MDEiCiAgICAgICByPSIwLjQ1MTY5NDY3IiAvPgogICAgPGVsbGlwc2UKICAgICAgIHN0eWxlPSJmaWxsOiNhMzA2MDk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuNzUzNzg3O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9ImVsbGlwc2UxMyIKICAgICAgIGN4PSIxNDcuODIwNzciCiAgICAgICBjeT0iMTQ2LjY1ODU3IgogICAgICAgcng9IjAuNTE2MjIyNDgiCiAgICAgICByeT0iMC42MjM3Njg4MSIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjg5NDQ1MjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJjaXJjbGUxMyIKICAgICAgIGN4PSIxNDYuMDc4NTIiCiAgICAgICBjeT0iMTQzLjIxNzA5IgogICAgICAgcng9IjAuNDUxNjk0NjciCiAgICAgICByeT0iMC4zMjI2MzkwNSIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjc1Mzc4NztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJlbGxpcHNlMTQiCiAgICAgICBjeD0iMTQ3LjgyMDc3IgogICAgICAgY3k9IjE0Ni42NTg1NyIKICAgICAgIHJ4PSIwLjUxNjIyMjQ4IgogICAgICAgcnk9IjAuNjIzNzY4ODEiIC8+CiAgICA8ZWxsaXBzZQogICAgICAgc3R5bGU9ImZpbGw6I2EzMDYwOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC43Njk1NTg7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0iZWxsaXBzZTE1IgogICAgICAgY3g9Ii02Ny4yNzYyMTUiCiAgICAgICBjeT0iMTgyLjM1NTA0IgogICAgICAgcng9IjAuNDQwNDU4NzQiCiAgICAgICByeT0iMC43NjE5NzQ3NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMTczMDUyNTEsLTAuOTg0OTEyNiwwLjg5NjE2ODEyLDAuNDQzNzE0NjYsMCwwKSIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjg0ODc2OTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJlbGxpcHNlMTYiCiAgICAgICBjeD0iLTE3NS4zMTQzNiIKICAgICAgIGN5PSI1NC43MzE2NyIKICAgICAgIHJ4PSIwLjYyNDA0NTkxIgogICAgICAgcnk9IjAuNjU0MjIzNzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMC41NjQ0NzAyMiwtMC44MjU0NTM0MywwLjk5ODA2MDIzLDAuMDYyMjU1ODEsMCwwKSIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjg5NDQ1MjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJlbGxpcHNlMTciCiAgICAgICBjeD0iMTQ5LjM5MDk1IgogICAgICAgY3k9IjE0Ny40MzI5MSIKICAgICAgIHJ4PSIwLjQ1MTY5NDY3IgogICAgICAgcnk9IjAuMzIyNjM5MDUiIC8+CiAgICA8ZWxsaXBzZQogICAgICAgc3R5bGU9ImZpbGw6I2EzMDYwOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC44OTQ0NTI7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0iZWxsaXBzZTE4IgogICAgICAgY3g9IjE0My43MTI1MSIKICAgICAgIGN5PSIxNDQuMzc4NTkiCiAgICAgICByeD0iMC40NTE2OTQ2NyIKICAgICAgIHJ5PSIwLjMyMjYzOTA1IiAvPgogICAgPGVsbGlwc2UKICAgICAgIHN0eWxlPSJmaWxsOiNhMzA2MDk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuODk0NDUyO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9ImVsbGlwc2UxOSIKICAgICAgIGN4PSIxNDQuNjgwNDIiCiAgICAgICBjeT0iMTQ0LjkzNzg0IgogICAgICAgcng9IjAuNDUxNjk0NjciCiAgICAgICByeT0iMC4zMjI2MzkwNSIgLz4KICAgIDxjaXJjbGUKICAgICAgIHN0eWxlPSJmaWxsOiNhMzA2MDk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuNjA0NzY7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0iZWxsaXBzZTIwIgogICAgICAgY3g9IjE0NS4yMzk2NyIKICAgICAgIGN5PSIxNDQuMDU1OTUiCiAgICAgICByPSIwLjI1ODExMTI0IiAvPgogICAgPGNpcmNsZQogICAgICAgc3R5bGU9ImZpbGw6I2EzMDYwOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC42MDQ3NjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJjaXJjbGUyMCIKICAgICAgIGN4PSIxNDUuOTA2NDUiCiAgICAgICBjeT0iMTQ0LjE2MzUiCiAgICAgICByPSIwLjI1ODExMTI0IiAvPgogICAgPGNpcmNsZQogICAgICAgc3R5bGU9ImZpbGw6I2EzMDYwOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC42MDQ3NjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJjaXJjbGUyMSIKICAgICAgIGN4PSIxNDUuMDI0NTciCiAgICAgICBjeT0iMTQ2LjEyMDgzIgogICAgICAgcj0iMC4yNTgxMTEyNCIgLz4KICAgIDxjaXJjbGUKICAgICAgIHN0eWxlPSJmaWxsOiNhMzA2MDk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuNjA0NzY7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpZD0iY2lyY2xlMjIiCiAgICAgICBjeD0iMTQzLjI2MDgiCiAgICAgICBjeT0iMTQ1LjU2MTYiCiAgICAgICByPSIwLjI1ODExMTI0IiAvPgogICAgPGNpcmNsZQogICAgICAgc3R5bGU9ImZpbGw6I2EzMDYwOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC42MDQ3NjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJjaXJjbGUyMyIKICAgICAgIGN4PSIxNDEuOTI3MjMiCiAgICAgICBjeT0iMTQ0LjMzNTU3IgogICAgICAgcj0iMC4yNTgxMTEyNCIgLz4KICAgIDxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjA2MztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlkPSJlbGxpcHNlMjMiCiAgICAgICBjeD0iMTQzLjYxNzIzIgogICAgICAgY3k9IjE2My45ODMzNSIKICAgICAgIHJ4PSIwLjY1MDk4ODY0IgogICAgICAgcnk9IjAuNDA4Njc2MTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjk5MTIyNzksLTAuMTMyMTYzNzIsMCwxLDAsMCkiIC8+CiAgICA8Y2lyY2xlCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNmMzNTM1O3N0cm9rZS13aWR0aDoxLjA1ODMzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpZD0icGF0aDQ1IgogICAgICAgY3g9IjEzOS43MDkwOCIKICAgICAgIGN5PSIxMzEuMDU0NCIKICAgICAgIHI9IjEuNzg2ODExNiIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDUxIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzFjNjcwODtzdHJva2Utd2lkdGg6MS4wNTgzMztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgZD0ibSAxNDAuMTQyMTYsMTMyLjc0Njc0IGMgLTAuOTg0NDUsLTAuNTM4NDcgMC4zOTMwOSwtMi4xNjQ2OCAxLjA2NzU0LC0xLjQyOTMzIDAuODY3NDEsMC45NTAzMiAxLjIyNjgsMS4xODAwMiAxLjUzMzQ5LDEuOTAyNzQgMC4yODY1MSwwLjYzNjE3IDAuMDQ3OSwwLjkwMTIxIC0wLjUxMTY5LDAuOTM5NDcgLTAuNTMyMzUsLTAuMTc2MzggLTEuMjY2NzksLTAuOTA0NjcgLTIuMDg5MzQsLTEuNDEyODggeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9IjAuOTQ5NzcyODYiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii0wLjkxMTM0NTgiIC8+CiAgICA8Y2lyY2xlCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50NTQpO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjI2NDU4MztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaWQ9ImNpcmNsZTU0IgogICAgICAgY3g9IjEzOS44NTk2NSIKICAgICAgIGN5PSIxMzEuMDc1OSIKICAgICAgIHI9IjEuNzg2ODExNiIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDUyIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzFjNjcwODtzdHJva2Utd2lkdGg6MS4wNTgzMztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgZD0ibSAxNDEuNzY2MDEsMTM0LjE3NDE0IGMgLTAuNzE2MDUsLTAuODYzOTMgMS4xOTM2OCwtMS44MjYzNSAxLjU0ODkzLC0wLjg5MzkzIDAuNDU1MTksMS4yMDM0NiAwLjcwNDM2LDEuNTQ5NjQgMC43MjI1LDIuMzM0NTMgMC4wMzE0LDAuNjk3MDEgLTAuMjg4MzEsMC44NTUxOSAtMC44MjI0MywwLjY4NDEyIC0wLjQ2ODQ4LC0wLjY4NjM1IC0wLjY0MjM5LC0xLjI5MzkyIC0xLjQ0OSwtMi4xMjQ3MiB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDM5IgogICAgICAgc3R5bGU9ImZpbGw6IzdiYzk1NjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC41MjkxNjc7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGQ9Im0gMTQwLjUwNzgyLDEzMi45ODMzNCBjIC0wLjk4NDQ2LC0wLjUzODQ3IDAuMzkzMDksLTIuMTY0NjcgMS4wNjc1NCwtMS40MjkzMyAwLjg2NzQxLDAuOTUwMzIgMS4yMjY4LDEuMTgwMDIgMS41MzM0OSwxLjkwMjc1IDAuMjg2NTEsMC42MzYxNiAwLjA0NzksMC45MDEyIC0wLjUxMTY5LDAuOTM5NDYgLTAuNTMyMzUsLTAuMTc2MzggLTEuMjY2NzksLTAuOTA0NjcgLTIuMDg5MzQsLTEuNDEyODggeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9IjAuOTQ5NzcyODYiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii0wLjkxMTM0NTgiIC8+CiAgICA8ZwogICAgICAgaWQ9ImcyNCIKICAgICAgIHRyYW5zZm9ybT0icm90YXRlKC05LjY2NTE3ODUsODI0LjgyMTQxLC0zNDcuMzc0OTkpIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgyMyIKICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQ1NCk7c3Ryb2tlLXdpZHRoOjEuMDU4MzM7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTgiCiAgICAgICAgIGQ9Im0gNzUuODQ2OTE5LDE2LjM5MDgwMyBjIDAuNzEwMjQsNC41MjM1ODcgLTAuNDU3NzA3LDUuMTQ1NTEyIC0zLjU1ODk4OCw0LjI1ODYxOCAtMS4zNjg5MjgsLTAuMjg3NzcxIC0xLjU2Nzg1OSwwLjMxOTY5NSAtMy43NTE5MzgsLTIuNjk5MjUgLTAuMDk4NjEsLTEuODA1ODEgMS45MDYyNTksLTMuMTk0OTIyIDMuOTk1Mjg4LC0zLjI2MjgxNiAyLjEyNjk1MiwwLjA0Mzg2IDIuMjEzMywwLjIzODM5MiAzLjMxNTYzOCwxLjcwMzQ0OCB6IgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPgogICAgICA8cGF0aAogICAgICAgICBpZD0iZWxsaXBzZTI0IgogICAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6I2EzMDYwOTtzdHJva2Utd2lkdGg6MS4wNTgzMztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5OCIKICAgICAgICAgZD0ibSA3Ni4wMTE1MjEsMTkuMDkxNjggYyAwLDAuNTMwNDI1IC0wLjE0MDgzOCwxLjQwMzc1MyAtMC44MzA3NjcsMS43MjMzODMgLTAuNTg0OTc1LDAuMzIzMjg0IC0xLjk1NjI5MiwwLjI2MzkxMSAtMy40OTI0NCwtMC4yNTY1MTIgMC4xMDYyMzQsLTAuOTY3MDExIDAuNDQ3NzM5LC0xLjQ5Mzc5IDAuODM1ODQ0LC0xLjY3NTI0OSAwLjExNTI4NiwwLjAwNDIgMC42MjY0NCwwLjg5NDg3NiAyLjIwODE3LDAuNjc2MDQxIC0wLjA5NTc1LC0wLjQ0Njk0NyAtMS4yMTc4NzUsMC4xMjQ2NjEgLTAuOTk3OTA5LC0xLjQ4MjY1NCAxLjAwOTE3NiwtMS4yODQ3NjUgMi4yNzcxMDIsLTAuMTI1MzczIDIuMjc3MTAyLDEuMDE0OTg4IHoiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0ic2NjY2Njc3MiIC8+CiAgICAgIDxlbGxpcHNlCiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7ZmlsbDojYTMwNjA5O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjg5NDQ1MjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9ImVsbGlwc2UyNSIKICAgICAgICAgY3g9Ijc1LjE5MTQzNyIKICAgICAgICAgY3k9IjQuODQwMjE1NyIKICAgICAgICAgcng9IjAuNDUxNjk0NjciCiAgICAgICAgIHJ5PSIwLjMyMjYzOTA1IgogICAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSg5LjY2NTE3ODUpIiAvPgogICAgICA8ZWxsaXBzZQogICAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6I2EzMDYwOTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC41MTQzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0iZWxsaXBzZTI2IgogICAgICAgICBjeD0iNzYuMjg4NDA2IgogICAgICAgICBjeT0iMy45MTUzMTU5IgogICAgICAgICByeD0iMC4zODcxNjY4NiIKICAgICAgICAgcnk9IjAuMzg3MTY2ODMiCiAgICAgICAgIHRyYW5zZm9ybT0icm90YXRlKDkuNjY1MTc4NSkiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJlbGxpcHNlMjciCiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7ZmlsbDojYTMwNjA5O3N0cm9rZS13aWR0aDowLjUxNDM7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTgiCiAgICAgICAgIGQ9Im0gNzUuOTY5NDAzLDE3LjI1ODk2OCBjIDAuMDc4MTUsMC40MzI2NjMgLTAuMTIyODUsMC41MTgzNTEgLTAuMzU3ODA3LDAuNDM1NDQ1IC0wLjIwMTY0MSwtMC4wNzExNSAtMC4zNTI1NjksLTAuMjM1ODgyIC0wLjMxNjY2OSwtMC40NDY2NzMgMC4wMzU5LC0wLjIxMDc5MSAwLjIzNTg4MiwtMC4zNTI1NjkgMC40NDY2NzMsLTAuMzE2NjcgMC4yMDg1MzcsMC4wMzU1MiAwLjIxMjYwMSwwLjEwODQwNCAwLjIyNzgwMywwLjMyNzg5OCB6IgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNzc3NjIiAvPgogICAgICA8cGF0aAogICAgICAgICBpZD0iZWxsaXBzZTI4IgogICAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6I2EzMDYwOTtzdHJva2Utd2lkdGg6MC41MTQzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4IgogICAgICAgICBkPSJtIDc1LjQ2MjkyLDE1Ljg3NTY0NCBjIC0wLjAzNTksMC4yMTA3OTEgLTAuMDg5MjksMC4yNjE4MjMgLTAuMzAwMDc4LDAuMjI1OTIzIC0wLjIxMDc5MSwtMC4wMzU5IC0wLjM1MjU2OSwtMC4yMzU4ODEgLTAuMzE2NjcsLTAuNDQ2NjcyIDAuMDM1OSwtMC4yMTA3OTIgMC4wNjAxNCwtMC4yMzc4NTkgMC4yNzA5MjUsLTAuMjAxOTYxIDAuMTA4NzQ0LDAuMTM3NTY2IDAuMjY0Mjg0LDAuMzA3MTk4IDAuMzQ1ODIzLDAuNDIyNzEgeiIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjc3NjYyIgLz4KICAgIDwvZz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDM4IgogICAgICAgc3R5bGU9ImZpbGw6IzllZGE4MztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC41MjkxNjc7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGQ9Im0gMTQxLjkxNjU3LDEzNC40MzIyNiBjIC0wLjcxNjA0LC0wLjg2Mzk0IDEuMTkzNjksLTEuODI2MzYgMS41NDg5NCwtMC44OTM5NCAwLjQ1NTE4LDEuMjAzNDYgMC43MDQzNSwxLjU0OTY0IDAuNzIyNDksMi4zMzQ1MyAwLjAzMTQsMC42OTcwMSAtMC4yODgzLDAuODU1MTkgLTAuODIyNDMsMC42ODQxMiAtMC40Njg0NywtMC42ODYzNSAtMC42NDIzOCwtMS4yOTM5MiAtMS40NDksLTIuMTI0NzEgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgPC9nPgo8L3N2Zz4K" +original_size = Vector2(90, 92) +metadata/_custom_type_script = "uid://yh2davxk4fh7" + +[sub_resource type="Resource" id="Resource_l4vqo"] +script = ExtResource("2_fv747") +svg_file_path = "res://addons/curved_lines_2d/tests/rat_concept_art.svg" +render_scale = 1.0 +svg_string = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB3aWR0aD0iMTIwLjAyMjA5IgogICBoZWlnaHQ9Ijc2LjM3MDMzOCIKICAgdmlld0JveD0iMCAwIDMxLjc1NTg0MyAyMC4yMDYzMTgiCiAgIHZlcnNpb249IjEuMSIKICAgaWQ9InN2ZzEiCiAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgIGlua3NjYXBlOnZlcnNpb249IjEuMy4yICgwOTFlMjBlLCAyMDIzLTExLTI1LCBjdXN0b20pIgogICBzb2RpcG9kaTpkb2NuYW1lPSJyYXRfY29uY2VwdC5zdmciCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0ibmFtZWR2aWV3MSIKICAgICBwYWdlY29sb3I9IiM1MDUwNTAiCiAgICAgYm9yZGVyY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMSIKICAgICBpbmtzY2FwZTpzaG93cGFnZXNoYWRvdz0iMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIKICAgICBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIxIgogICAgIGlua3NjYXBlOmRlc2tjb2xvcj0iIzUwNTA1MCIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6em9vbT0iNS42NTY4NTQzIgogICAgIGlua3NjYXBlOmN4PSI3Ny42MDQ5NjkiCiAgICAgaW5rc2NhcGU6Y3k9IjM0LjczNjYyMSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiIC8+PGRlZnMKICAgICBpZD0iZGVmczEiPjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDEiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZjkwOTA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDEiIC8+PHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzZjM2QzZDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0MiIgLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM2YzNkM2Q7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzYiIC8+PHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmOTA5MDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzOSIgLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzQiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0MzQzMzU7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzQiIC8+PHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzViNWI0YjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNSIgLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjgiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM1ODU4NGE7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjgiIC8+PHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6Izc2NzY2MjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyOSIgLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50OSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyI+PHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzdhN2E2ZTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A5IiAvPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM2NjY2NTc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTIiIC8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj48c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzY3NjVkO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3IiAvPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyZTJlMjM7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzgiIC8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDEwIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj48c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojN2E3YTZlO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjQ5NDQyMzgxIgogICAgICAgICBpZD0ic3RvcDEwIiAvPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0ZDRkM2M7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTEiIC8+PC9saW5lYXJHcmFkaWVudD48cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDEwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MTEiCiAgICAgICBjeD0iMTA4Ljg1ODI4IgogICAgICAgY3k9IjE4Ni40ODc0IgogICAgICAgZng9IjEwOC44NTgyOCIKICAgICAgIGZ5PSIxODYuNDg3NCIKICAgICAgIHI9IjQuNjI2MDkiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0xLjEzNzk2NzMsMS42Mjc0NDAxLC0xLjQ0ODgwNDcsLTEuMDEzMDU4OCw1MDMuNjc2NDgsMTU4LjE2MzUzKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOCIKICAgICAgIHgxPSIxMDUuMDU3ODgiCiAgICAgICB5MT0iMTg0Ljc1MzkyIgogICAgICAgeDI9IjkzLjczNjg1NSIKICAgICAgIHkyPSIxOTAuOTQ0MjciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4zMTgzOTksMC4zMDc0NzYyNywtMC4zMTc0NjgyMywxLjM2MTI0MjYsMzAuNzMzODczLC0xMzUuNzgyOTQpIiAvPjxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50OSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDEyIgogICAgICAgY3g9IjEwOC43ODU3NiIKICAgICAgIGN5PSIxNTcuMjQxODQiCiAgICAgICBmeD0iMTA4Ljc4NTc2IgogICAgICAgZnk9IjE1Ny4yNDE4NCIKICAgICAgIHI9IjAuNjA4ODYxMDkiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuMDgxMDMzNywtMC42MzY2MjMzMywwLjcxMDY5NTQ2LDIuMzIzMTY1MiwtMjI3LjY4ODY3LC0xNTIuMzYwNzYpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI5IgogICAgICAgeDE9IjEwNi44NDMzMSIKICAgICAgIHkxPSIxNjAuMzA1MzMiCiAgICAgICB4Mj0iMTIwLjc5NDQyIgogICAgICAgeTI9IjE2MC4zMDUzMyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjY3MzU3MTEyLDAsMCwwLjY3MzU3MTEyLDI4LjczMzA0NSw0NS4zMzA5NDIpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNSIKICAgICAgIHgxPSI5NS4wODgyMzQiCiAgICAgICB5MT0iMTU4LjU4OTY1IgogICAgICAgeDI9IjEwMy41ODU3NCIKICAgICAgIHkyPSIxNTQuNzU0MzMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC42NzM1NzExMiwwLDAsMC42NzM1NzExMiwyOC43MzMwNDUsNDUuMzMwOTQyKSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM2IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkiCiAgICAgICB4MT0iOTIuMzU2NjA2IgogICAgICAgeTE9IjE1NS4yMDY3NyIKICAgICAgIHgyPSI5OC4yNDAzNTYiCiAgICAgICB5Mj0iMTQxLjY0Njg3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNjczNTcxMTIsMCwwLDAuNjczNTcxMTIsMjguMTUwMjE0LDQ1LjYxNDQ4MSkiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQyIgogICAgICAgeDE9IjExOC44NDQwOSIKICAgICAgIHkxPSIxNTEuNDUxMzUiCiAgICAgICB4Mj0iMTE0LjUxNTI2IgogICAgICAgeTI9IjE0My4zNTk3NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjY3MzU3MTEyLDAsMCwwLjY3MzU3MTEyLDI4LjczMzA0NSw0NS4zMzA5NDIpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzYiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0OCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjY3MzU3MTEyLDAsMCwwLjY3MzU3MTEyLDI4LjE1MDIxNCw0NS42MTQ0ODEpIgogICAgICAgeDE9IjkyLjM1NjYwNiIKICAgICAgIHkxPSIxNTUuMjA2NzciCiAgICAgICB4Mj0iOTguMjQwMzU2IgogICAgICAgeTI9IjE0MS42NDY4NyIgLz48L2RlZnM+PGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTg4LjAyMjM3NywtMTM4Ljg2OTI3KSI+PHBhdGgKICAgICAgIGlkPSJwYXRoMzIiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNjczMzMxO3N0cm9rZS13aWR0aDowLjUzNDY0NztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItOC4yODE4MTA0IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSI1LjE1NzQwNiIKICAgICAgIGQ9Im0gMTA2LjczMjQzLDE1Ny41MjUzMSBjIC0wLjIzNDMxLC0wLjI2NzE1IC0xLjA4MjAzLC0wLjAzNDggLTEuMzAyODYsMC4xOTMyMiAtMC4yNDc3MywtMC4xNjEzNiAtMC4xOTE5MywtMC45MTY3OSAtMC4yMDUzMSwtMS4xMTc5NSAwLjEzODUxLC0wLjE4Mjg0IDAuNTQ3LC0wLjc3NDMyIDEuMTMzNDEsLTAuODk4MDMgMC44NjA5NywwLjQxNDQ5IDEuNTk4ODQsMC40ODExMiAyLjE3NTgzLDAuNDE1MzcgMC44MTI1MSwwLjA2MzcgMS4xMjUxNiwwLjM2MDcxIDEuNDY1NTQsMC40NTk0NiAtMC41NjIwNiwwLjIwMzI4IC0xLjAxOTk4LDAuMzcxMjMgLTAuNjM3MjgsMC41NzYyNyAtMS43NzU4MywtMC4yMDUxIC0yLjI3MTUyLDAuMDk2OSAtMi42Mjk0OCwwLjM3MDY4IHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjYyIgLz48cGF0aAogICAgICAgaWQ9InBhdGgzMSIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiM1NzU3NGU7c3Ryb2tlLXdpZHRoOjEuMDY5Mjk7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTIuNDUzMzAyIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSIwLjk4ODc3NzMyIgogICAgICAgZD0ibSAxMDcuMzQ3NCwxNTYuNDU5OTcgYyAtNi4yODAzOSwxLjY3NTgzIC0xMC42MjE4NjMsLTEuMDY5ODYgLTExLjA1NiwtNC40NzU5NSAtMC4xMjU3OTYsLTIuNjEzNiAzLjI2MzA2MSwtNS4yMzk2NSA1LjIzMjUsLTQuMTQ1OSAxLjI0NTUyLDAuOTA4MjkgMi41NzkzMSwyLjE0NTMxIDIuNDQ2NCw1LjA3Mjk5IDEuMDU5NzIsMS42MzE4MiAzLjY1MDEzLDMuMzEwMzUgMy4zNzcxLDMuNTQ4ODYgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMjQiCiAgICAgICBzdHlsZT0iZmlsbDojMzgzODJiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZS13aWR0aDowLjc2NzIxMTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMi40NTMzMDIiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjAuOTg4Nzc3MzIiCiAgICAgICBkPSJtIDEwNy4zNDc0LDE1Ni40NTk5NyBjIC02LjI4MDM5LDEuNjc1ODMgLTEwLjYyMTg2MywtMS4wNjk4NiAtMTEuMDU2LC00LjQ3NTk1IC0wLjEyNTc5NiwtMi42MTM2IDMuMjYzMDYxLC01LjIzOTY1IDUuMjMyNSwtNC4xNDU5IDEuMjQ1NTIsMC45MDgyOSAyLjU3OTMxLDIuMTQ1MzEgMi40NDY0LDUuMDcyOTkgMS4wNTk3MiwxLjYzMTgyIDMuNjUwMTMsMy4zMTAzNSAzLjM3NzEsMy41NDg4NiB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz48cGF0aAogICAgICAgaWQ9InBhdGgyNSIKICAgICAgIHN0eWxlPSJmaWxsOiNmZjkwOTA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjAuOTAyOTIyO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii04LjI4MTgwODUiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjUuMTU3NDA2IgogICAgICAgZD0ibSAxMDYuOTU1MjEsMTU3LjUyNTMxIGMgLTAuMjM0MzEsLTAuMjY3MTUgLTEuMDgyMDMsLTAuMDM0OCAtMS4zMDI4NiwwLjE5MzIyIC0wLjI0NzczLC0wLjE2MTM2IC0wLjE5MTkzLC0wLjkxNjc5IC0wLjIwNTMxLC0xLjExNzk1IDAuMTM4NTEsLTAuMTgyODQgMC41NDcsLTAuNzc0MzIgMS4xMzM0MSwtMC44OTgwMyAwLjg2MDk3LDAuNDE0NDkgMS41OTg4NCwwLjQ4MTEyIDIuMTc1ODMsMC40MTUzNyAwLjgxMjUxLDAuMDYzNyAxLjEyNTE2LDAuMzYwNzEgMS40NjU1MywwLjQ1OTQ2IC0wLjU2MjA1LDAuMjAzMjggLTEuMDE5OTcsMC4zNzEyMyAtMC42MzcyNywwLjU3NjI3IC0xLjc3NTgzLC0wLjIwNTEgLTIuMjcxNTIsMC4wOTY5IC0yLjYyOTQ5LDAuMzcwNjggeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDMwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU3NTc0ZTtzdHJva2Utd2lkdGg6MS4wNjkyOTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjpzdHJva2UgbWFya2VycyBmaWxsIgogICAgICAgZD0ibSAxMTEuNTE3NDMsMTUwLjMyMTM5IGMgLTAuMzUzNjMsMS42MDEzNCAtMC42MjU3MywzLjUxNzA4IC0zLjE0NTYsMy43NjIxOCAtMS45NTk2MywwLjAxODcgLTEyLjczMTczNiwwLjUwMTc0IC0xNS41NTYyNjgsMC4xMDMyNyAtMS41MzI2OTIsLTAuODAwMjkgLTMuNzQwODg4LC0yLjM4MzI4IC0wLjk1MTUyNSwtNi40ODM4NiAxLjgyMTAxNywtMi4zNjE3MiA0LjQ0NDQ3MiwtMy4zMjE3OCA4LjExNDE5NSwtMy40MDU3OCA0LjUzMDY1OCwwLjM1Mjg3IDkuNTY0MTQ4LDMuNzE5NyAxMS41MzkxOTgsNi4wMjQxOSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NDgpO3N0cm9rZTojNjczMzMxO3N0cm9rZS13aWR0aDoxLjA2OTI5O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii05LjAxMDY0MjgiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii00Ljk0Mjc4MzMiCiAgICAgICBkPSJtIDkzLjYzODk3LDE0MS44MDcxNyBjIC0xLjgxODExOSwxLjA3ODQ4IC0zLjc0ODQyNyw0LjQ3MDY3IC0yLjQ3MTY4OCw3LjE1NTY3IDAuMTEzNzksMC44NjQ1NyAwLjMzMjI1NCwxLjUyMDg0IC0wLjYxMTIzMiwyLjExMjkxIC0zLjU4NzM3OCwtMS4yMzc4OSAtMi4yMTYyMDksLTguMTQ3OTQgMy4wOTIwMDYsLTEwLjM0NzQ2IDIuOTkzODE3LC0xLjI0MDUzIDE3LjQ4NTc2NCwtMS41MTAzNCAxNy41ODg4NjQsLTEuMjE0OTcgLTAuMjExNjgsMC4zNjk0MSAtMTUuMzAyOTA0LDAuOTMyNDYgLTE3LjU5Nzk1LDIuMjkzODUgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0ic2Njc2NzIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDI3IgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzY3MzMzMTtzdHJva2Utd2lkdGg6MC41MzQ2NDc7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTEuNDU1NzE1MyIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteT0iMC4zNTg4NDI4IgogICAgICAgZD0ibSAxMTIuMTczNTEsMTU2LjkwNTYzIGMgLTAuMTkzMDQsLTAuMjk4MzMgLTEuMDY1NTEsLTAuMTkxNTMgLTEuMzE3MTEsMC4wMDIgLTAuMjIxNjgsLTAuMTk1NjIgLTAuMDU2OCwtMC45MzQ5NCAtMC4wNDA4LC0xLjEzNTkxIDAuMTYzNTksLTAuMTYwOCAwLjY1MzYzLC0wLjY4NjcgMS4yNTE3OSwtMC43MjM5NiAwLjc5MTY2LDAuNTM1MTEgMS41MTIwNSwwLjcwODE1IDIuMDkyNDYsMC43MjY4OCAwLjc5NDY2LDAuMTgxIDEuMDYwODcsMC41MjAyNSAxLjM4MzMsMC42NjczNyAtMC41ODU2MSwwLjExOTUyIC0xLjA2MzA2LDAuMjE5MiAtMC43MTQxOCwwLjQ3NzY0IC0xLjcyNzI0LC0wLjQ2MDc2IC0yLjI2MTUzLC0wLjIzMzk3IC0yLjY1NTQ1LC0wLjAxNSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMjYiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNTc1NzRlO3N0cm9rZS13aWR0aDoxLjA2OTI5O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii0yLjM1MzI1MjMiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjEuMDg0ODQ0MSIKICAgICAgIGQ9Im0gMTEyLjYwNzk0LDE1NS43NDAyNyBjIC01LjA4MzgsMS4wNjc4MiAtOC40MjQ3NSwwLjI3MDUgLTkuMDg2MzYsLTEuOTA2NyAtMS4zMDk1LC00LjMwOTA2IDQuNDQ0OSwtNC44NzE0MyA0Ljk1ODk3LC0zLjEzNTYyIDEuMTMwMjcsMy44MTY2IDQuOTYwMDUsNC43MDcwNiA0LjEyNzM5LDUuMDQyMzIgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY3NzYyIgLz48cGF0aAogICAgICAgaWQ9InBhdGgxOCIKICAgICAgIHN0eWxlPSJmaWxsOiM0YzRjM2Y7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjAuNzY3MjExO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii0yLjM1MzI1MjMiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjEuMDg0ODQ0MSIKICAgICAgIGQ9Im0gMTEyLjYwNzk0LDE1NS43NDAyNyBjIC01LjA4MzgsMS4wNjc4MiAtOC40MjQ3NSwwLjI3MDUgLTkuMDg2MzYsLTEuOTA2NyAtMS4zMDk1LC00LjMwOTA2IDQuNDQ0OSwtNC44NzE0MyA0Ljk1ODk3LC0zLjEzNTYyIDEuMTMwMjcsMy44MTY2IDQuOTYwMDUsNC43MDcwNiA0LjEyNzM5LDUuMDQyMzIgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY3NzYyIgLz48cGF0aAogICAgICAgaWQ9InBhdGgxOSIKICAgICAgIHN0eWxlPSJmaWxsOiNmNThiOGI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjAuOTAyOTIyO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii0xLjQ1NTcxNTMiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjAuMzU4ODQyOCIKICAgICAgIGQ9Im0gMTEyLjE3MzUxLDE1Ni45MDU2MyBjIC0wLjE5MzA0LC0wLjI5ODMzIC0xLjA2NTUxLC0wLjE5MTUzIC0xLjMxNzExLDAuMDAyIC0wLjIyMTY4LC0wLjE5NTYyIC0wLjA1NjgsLTAuOTM0OTQgLTAuMDQwOCwtMS4xMzU5MSAwLjE2MzU5LC0wLjE2MDggMC42NTM2MywtMC42ODY3IDEuMjUxNzksLTAuNzIzOTYgMC43OTE2NiwwLjUzNTExIDEuNTEyMDUsMC43MDgxNSAyLjA5MjQ2LDAuNzI2ODggMC43OTQ2NiwwLjE4MSAxLjA2MDg3LDAuNTIwMjUgMS4zODMzLDAuNjY3MzcgLTAuNTg1NjEsMC4xMTk1MiAtMS4wNjMwNiwwLjIxOTIgLTAuNzE0MTgsMC40Nzc2NCAtMS43MjcyNCwtMC40NjA3NiAtMi4yNjE1MywtMC4yMzM5NyAtMi42NTU0NSwtMC4wMTUgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDEyIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzU3NTc0ZTtzdHJva2Utd2lkdGg6MS4wNjkyOTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSIxLjM4NzIyOTkiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjAuOTY1ODA2MzciCiAgICAgICBkPSJtIDExMi4xOTU3NSwxNDYuMDk1MTUgYyAtMS4xMjI5NCwtMC4xNjczOSAtMi4xNDIyMSwtMC43MTIzIC0zLjEzMTY2LC0xLjM2NjA1IDAuMDkyOCwtMS4xODM0NSAwLjI1MzM1LC0yLjIyMjk2IDAuOTAwMzEsLTMuMjYxMTcgMS43MTY1NCwtMS42OTUyOCAyLjExMTA4LDMuNzQ0OTkgMi4yMzEzNSw0LjYyNzIyIHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoOSIKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQxMik7c3Ryb2tlLXdpZHRoOjAuMTg3NDk1O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9IjEuMzg3MjI5OSIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteT0iMC45NjU4MDYzNyIKICAgICAgIGQ9Im0gMTEyLjE5NTc1LDE0Ni4wOTUxNSBjIC0wLjc5NTUzLDAuNDE3MjYgLTIuMTQyMjEsLTAuNzEyMyAtMy4xMzE2NiwtMS4zNjYwNSAwLjA5MjgsLTEuMTgzNDUgMC4yNTMzNSwtMi4yMjI5NiAwLjkwMDMxLC0zLjI2MTE3IDEuNzE2NTQsLTEuNjk1MjggMi4xMTEwOCwzLjc0NDk5IDIuMjMxMzUsNC42MjcyMiB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDE1IgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU3NTc0ZTtzdHJva2Utd2lkdGg6MS4wNjkyOTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgZD0ibSAxMDcuNTA1NTQsMTUzLjE2ODkgYyAtMS4wNzM3OCwtMS41NTc4MyAtMS45MjYxMywtNS4yMjE4NCAtMC45MDU3OCwtNi4wMDk5MiAwLjkzNzg4LC0xLjE1MzM1IDQuMDc3OTgsLTIuMjQ1MyA1LjQ4NTQ2LC0xLjk4MjI3IDEuMzk5ODYsMC43NTI2MiAyLjA5MjM0LDEuMzEzOCAzLjgxMjQ4LDIuOTEyNzkgMS4wNTM4NiwxLjQ1NzA1IDEuNjczMTQsMS44MzI4NiAzLjIxODk2LDIuODEyMiAtMS4zOTA3NywzLjQ3MjM3IC0xMC41NTY1NSwzLjk2ODA0IC0xMS42MTExMiwyLjI2NzIgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDI4IgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzY3MzMzMTtzdHJva2Utd2lkdGg6MC41MzQ2NDc7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTEuNDU1NzE3MyIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteT0iMC4zNTg4NDM0OCIKICAgICAgIGQ9Im0gMTA5LjQxODgyLDE1Ny4xNTQ1IGMgLTAuMTkzMDUsLTAuMjk4MzQgLTEuMDY1NTIsLTAuMTkxNTQgLTEuMzE3MTIsMC4wMDIgLTAuMjIxNjgsLTAuMTk1NjMgLTAuMDU2OCwtMC45MzQ5NSAtMC4wNDA4LC0xLjEzNTkyIDAuMTYzNTksLTAuMTYwNzkgMC42NTM2NCwtMC42ODY3IDEuMjUxNzksLTAuNzIzOTUgMC43OTE2NywwLjUzNTEgMS41MTIwNSwwLjcwODE1IDIuMDkyNDcsMC43MjY4NyAwLjc5NDY1LDAuMTgxMDEgMS4wNjA4NiwwLjUyMDI1IDEuMzgzMywwLjY2NzM3IC0wLjU4NTYyLDAuMTE5NTMgLTEuMDYzMDcsMC4yMTkyMSAtMC43MTQxOSwwLjQ3NzY0IC0xLjcyNzI0LC0wLjQ2MDc2IC0yLjI2MTUyLC0wLjIzMzk3IC0yLjY1NTQ1LC0wLjAxNSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMjkiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNTc1NzRlO3N0cm9rZS13aWR0aDoxLjA2OTI5O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii0yLjM1MzI1MTYiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjEuMDg0ODQ0NCIKICAgICAgIGQ9Im0gMTA5Ljk3OTI2LDE1Ni4wNTIxNCBjIC01LjA4MzgsMS4wNjc4MyAtOC40MjQ3NSwwLjI3MDUxIC05LjA4NjM2LC0xLjkwNjY5IC0xLjMwOTQ5NSwtNC4zMDkwNyA0LjQ0NDksLTQuODcxNDMgNC45NTg5NywtMy4xMzU2MiAxLjEzMDI4LDMuODE2NiA0Ljk2MDA1LDQuNzA3MDYgNC4xMjczOSw1LjA0MjMxIHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNzc2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNmMzNTM1O3N0cm9rZS13aWR0aDowLjUzNDY0NztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItOC4yODE4MDg2IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSI1LjE1NzQwNCIKICAgICAgIGQ9Im0gMTAyLjQ2NzMsMTU4LjE5Nzk5IGMgLTAuMjM0MzEsLTAuMjY3MTUgLTEuMDgyMDMsLTAuMDM0OCAtMS4zMDI4NiwwLjE5MzIyIC0wLjI0NzczLC0wLjE2MTM2IC0wLjE5MTkzLC0wLjkxNjc5IC0wLjIwNTMxLC0xLjExNzk1IDAuMTM4NTEsLTAuMTgyODQgMC41NDcsLTAuNzc0MzIgMS4xMzM0MSwtMC44OTgwMyAwLjg2MDk3LDAuNDE0NSAxLjU5ODg0LDAuNDgxMTIgMi4xNzU4MywwLjQxNTM3IDAuODEyNTEsMC4wNjM3IDEuMTI1MTYsMC4zNjA3MSAxLjQ2NTUzLDAuNDU5NDYgLTAuNTYyMDUsMC4yMDMyOCAtMS4wMTk5NywwLjM3MTIzIC0wLjYzNzI3LDAuNTc2MjcgLTEuNzc1ODMsLTAuMjA1MSAtMi4yNzE1MiwwLjA5NjkgLTIuNjI5NDksMC4zNzA2OCB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMzMiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNTc1NzRlO3N0cm9rZS13aWR0aDoxLjA2OTI5O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii0yLjQ1MzMwMTYiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjAuOTg4Nzc3NiIKICAgICAgIGQ9Im0gMTAyLjY0Mzk2LDE1Ny4wMzA4NCBjIC02LjI4MDM4LDEuNjc1ODMgLTEwLjYyMTg0NiwtMS4wNjk4NiAtMTEuMDU1OTg2LC00LjQ3NTk2IC0wLjEyNTc5MiwtMi42MTM1OSAzLjI2MzA1OCwtNS4yMzk2NSA1LjIzMjQ4OSwtNC4xNDU5IDEuMjQ1NTIxLDAuOTA4MyAyLjU3OTMxMywyLjE0NTMyIDIuNDQ2NDA0LDUuMDcyOTkgMS4wNTk3MjMsMS42MzE4MiAzLjY1MDEyMywzLjMxMDM2IDMuMzc3MDkzLDMuNTQ4ODcgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMzciCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZS13aWR0aDowLjM2Mzk2MTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtwYWludC1vcmRlcjpzdHJva2UgbWFya2VycyBmaWxsIgogICAgICAgZD0ibSAxMTEuNTE3NDMsMTUwLjMyMTM5IGMgLTAuMzUzNjMsMS42MDEzNCAtMC42MjU3MywzLjUxNzA4IC0zLjE0NTYsMy43NjIxOCAtMS45NTk2MywwLjAxODcgLTEyLjczMTczNiwwLjUwMTc0IC0xNS41NTYyNjgsMC4xMDMyNyAtMS41MzI2OTIsLTAuODAwMjkgLTMuNzQwODg4LC0yLjM4MzI4IC0wLjk1MTUyNSwtNi40ODM4NiAxLjgyMTAxNywtMi4zNjE3MiA0LjQ0NDQ3MiwtMy4zMjE3OCA4LjExNDE5NSwtMy40MDU3OCA0LjUzMDY1OCwwLjM1Mjg3IDkuNTY0MTQ4LDMuNzE5NyAxMS41MzkxOTgsNi4wMjQxOSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoNiIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM1NzU3NGU7c3Ryb2tlLXdpZHRoOjEuMDY5Mjk7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGQ9Im0gMTA5LjY3MzY1LDE0NC40NzgyOSBjIDAuMjg1NzksMS4zNTYyIDAuMDI0MiwyLjcwMjA0IC0wLjg2NzIsMy4xMDI0NiAtMC4zNjU3MywwLjE5NTgzIC0xLjUyMDU2LC0wLjU5NTU1IC0yLjMzNzI4LC0wLjc5NTM3IC0wLjcwNzU2LC0wLjMwMjU5IC0xLjg1ODU1LC0wLjk0ODQzIC0yLjQ2MDM0LC0yLjU5NTEzIC0wLjQwMzEsLTEuNzQ3NzQgMC42MDgzMywtMi40MzgzMiAxLjkwMTI1LC0yLjgwMDIgMS4yOTI5MywtMC4zNjE4OCAzLjMwMDM5LDEuMzU1NDMgMy43NjM1NywzLjA4ODI0IHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NzYyIgLz48cGF0aAogICAgICAgaWQ9InBhdGgxIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDExKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS4xNzQ0ODtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGQ9Im0gMTA3LjUwNTU0LDE1My4xNjg5IGMgLTEuMDczNzgsLTEuNTU3ODMgLTEuOTI2MTMsLTUuMjIxODQgLTAuOTA1NzgsLTYuMDA5OTIgMC45Mzc4OCwtMS4xNTMzNSA0LjA3Nzk4LC0yLjI0NTMgNS40ODU0NiwtMS45ODIyNyAxLjM5OTg2LDAuNzUyNjIgMi4wOTIzNCwxLjMxMzggMy44MTI0OCwyLjkxMjc5IDEuMDUzODYsMS40NTcwNSAxLjY3MzE0LDEuODMyODYgMy4yMTg5NiwyLjgxMjIgLTEuMzkwNzcsMy40NzIzNyAtMTAuNTU2NTUsMy45NjgwNCAtMTEuNjExMTIsMi4yNjcyIHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjYyIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTUuMzI0NzM5NCIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteT0iLTAuNjk0NTMxMjMiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoNyIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiM0MzQzNDM7c3Ryb2tlLXdpZHRoOjAuMzY1MzEzO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBkPSJtIDExMS42NDk1OCwxNDguMTU4ODkgYyAwLjE1ODA5LC0wLjc4OTgyIDAuODU2MTUsLTEuNDExMjEgMS42MDc5OCwtMS4zMTA5NiAwLjM0NjEsMC4wNDYzIDEuMjc5NzYsMC42ODQxMiAxLjQxNzIzLDEuNTUzNDggMC4xMDk5MywwLjY5NTEyIC0xLjI3ODI1LDEuMzgxOTEgLTEuNDIxMDMsMS40ODA4MSAtMC45NjYyLC0wLjAzODcgLTEuMTk1MzMsLTAuNDgyODkgLTEuNjA0MTgsLTEuNzIzMzMgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY3NzY2MiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9IjAuODM5NjU3MDkiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii0wLjI2MjMzNzA1IiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDEwIgogICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xODM0MzI7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjAuNTc5MjY4O3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBkPSJtIDExMS44NDUzMSwxNDguMDc5NTcgYyAwLjE0ODA4LC0wLjczOTkxIDAuODAyMDMsLTEuMzIxOTkgMS41MDYzNSwtMS4yMjgwOSAwLjMyNDI0LDAuMDQzMiAxLjE5ODg1LDAuNjQwODggMS4zMjc2NCwxLjQ1NTI5IDAuMTAyOTksMC42NTExOSAtMS4xOTc0NiwxLjI5NDU2IC0xLjMzMTE5LDEuMzg3MjEgLTEuMDk1NDUsLTAuMDExOCAtMS4yMTU1LC0wLjQ0MDQ0IC0xLjUwMjgsLTEuNjE0NDEgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY3NzY2MiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9IjAuNzg2NTQ4NjYiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii0wLjI0NjY0NDIzIiAvPjxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjcyNjYwODtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaWQ9ImVsbGlwc2U4IgogICAgICAgcnk9IjAuOTc0MTI1NDQiCiAgICAgICByeD0iMC45MDkwMTMzOSIKICAgICAgIGN5PSIxODQuOTQ4MzgiCiAgICAgICBjeD0iLTI0LjQ1MjkyMyIKICAgICAgIHRyYW5zZm9ybT0icm90YXRlKC00NC45NzcxNTEpIiAvPjxlbGxpcHNlCiAgICAgICBzdHlsZT0iZmlsbDojZjNmM2YzO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjI1Njk2OTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaWQ9InBhdGg4IgogICAgICAgY3g9Ijk1LjkxNTU3MyIKICAgICAgIGN5PSIxNTkuNjU4NzIiCiAgICAgICByeD0iMC40MzI2Nzg2MSIKICAgICAgIHJ5PSIwLjE2ODI2MzkiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtNi41NjkyMDg4KSIgLz48cGF0aAogICAgICAgaWQ9InBhdGgzNiIKICAgICAgIHN0eWxlPSJmaWxsOiNmNThiOGI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjAuMjg2NDQ4O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3BhaW50LW9yZGVyOnN0cm9rZSBtYXJrZXJzIGZpbGwiCiAgICAgICBkPSJtIDExOC45NTQ4NywxNTAuNTEzMTUgYyAwLjU5MTAzLC0wLjA2MjggMC4yNzMyNCwwLjg4MTE4IC0wLjEyMzkyLDEuMjYyMDcgLTAuMzk3MTcsMC4zODA5IC0wLjk4NTYxLDAuNDMzNDEgLTEuMzE0MzMsMC4xMTcyOSAtMC4zMjg3MSwtMC4zMTYxNCAtMC4zMjE5OCwtMC45Mzk2MSAwLjEyMzkyLC0xLjI2MjA3IDAuMzY5ODksLTAuMjY3NDggMC44ODc3OCwtMC4wNzIgMS4zMTQzMywtMC4xMTcyOSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJzc3NzcyIgLz48cGF0aAogICAgICAgaWQ9InBhdGgyIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDQyKTtzdHJva2U6Izc2NzY2NTtzdHJva2Utd2lkdGg6MC4yOTM2MjE7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3N0cm9rZS1vcGFjaXR5OjE7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGQ9Im0gMTA5LjY3MzY1LDE0NC40NzgyOSBjIDAuMjg1NzksMS4zNTYyIDAuMDI0MiwyLjcwMjA0IC0wLjg2NzIsMy4xMDI0NiAtMC4zNjU3MywwLjE5NTgzIC0xLjUyMDU2LC0wLjU5NTU1IC0yLjMzNzI4LC0wLjc5NTM3IC0wLjcwNzU2LC0wLjMwMjU5IC0xLjg1ODU1LC0wLjk0ODQzIC0yLjQ2MDM0LC0yLjU5NTEzIC0wLjQwMzEsLTEuNzQ3NzQgMC42MDgzMywtMi40MzgzMiAxLjkwMTI1LC0yLjgwMDIgMS4yOTI5MywtMC4zNjE4OCAzLjMwMDM5LDEuMzU1NDMgMy43NjM1NywzLjA4ODI0IHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NzYyIgLz48cGF0aAogICAgICAgaWQ9InBhdGgzIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2Utd2lkdGg6MS4xNzQ0ODtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgZD0ibSAxMDkuODg3ODgsMTQ1LjY2ODU1IGMgLTAuMDUyMSwwLjY2NzU5IC0wLjM1NjQ2LDEuMjU1ODggLTAuODI0MTgsMS4zMjAyIC0wLjU0ODEsLTAuMDg3IC0xLjAxNjY4LC0wLjgwNzM0IC0xLjAwMDcsLTAuNzI2MDIgLTAuMzg1MzcsLTAuMzU5NTQgLTAuNDkyMjksLTAuNzAyNTEgLTAuNjMyMTcsLTEuNDk2OTIgMC4wNTA5LC0wLjg2NTAzIDAuNDg0MDQsLTEuMDQ5MTcgMS4xMzI2NCwtMS4wNDA5OSAwLjY0ODU5LDAuMDA4IDEuMzQ1NSwxLjA3NzQ0IDEuMzI0NDEsMS45NDM3MyB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2Njc2MiIC8+PGVsbGlwc2UKICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjAuNjg4NTI1O3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDo0LjQ3NTY0O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtzdHJva2Utb3BhY2l0eToxO3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpZD0icGF0aDEzIgogICAgICAgY3g9IjEyMC4zOTE3OCIKICAgICAgIGN5PSIxNDkuNzU3ODQiCiAgICAgICByeD0iMC4xNzMwNzIyNSIKICAgICAgIHJ5PSIwLjIzMDc2Mjk5IgogICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoMC43MjI1NjQ2NikiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMTYiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MjkpO3N0cm9rZS13aWR0aDowLjc2NzIxMTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMi4zNTMyNTE2IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSIxLjA4NDg0NDQiCiAgICAgICBkPSJtIDEwOS45NzkyNiwxNTYuMDUyMTQgYyAtNS4wODM4LDEuMDY3ODMgLTguNDI0NzUsMC4yNzA1MSAtOS4wODYzNiwtMS45MDY2OSAtMS4zMDk0OTUsLTQuMzA5MDcgNC40NDQ5LC00Ljg3MTQzIDQuOTU4OTcsLTMuMTM1NjIgMS4xMzAyOCwzLjgxNjYgNC45NjAwNSw0LjcwNzA2IDQuMTI3MzksNS4wNDIzMSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjc3NjIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDE3IgogICAgICAgc3R5bGU9ImZpbGw6I2ZmOTA5MDtmaWxsLW9wYWNpdHk6MTtzdHJva2Utd2lkdGg6MC45MDI5MjI7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTEuNDU1NzE3MyIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteT0iMC4zNTg4NDM0OCIKICAgICAgIGQ9Im0gMTA5LjQxODgyLDE1Ny4xNTQ1IGMgLTAuMTkzMDUsLTAuMjk4MzQgLTEuMDY1NTIsLTAuMTkxNTQgLTEuMzE3MTIsMC4wMDIgLTAuMjIxNjgsLTAuMTk1NjMgLTAuMDU2OCwtMC45MzQ5NSAtMC4wNDA4LC0xLjEzNTkyIDAuMTYzNTksLTAuMTYwNzkgMC42NTM2NCwtMC42ODY3IDEuMjUxNzksLTAuNzIzOTUgMC43OTE2NywwLjUzNTEgMS41MTIwNSwwLjcwODE1IDIuMDkyNDcsMC43MjY4NyAwLjc5NDY1LDAuMTgxMDEgMS4wNjA4NiwwLjUyMDI1IDEuMzgzMywwLjY2NzM3IC0wLjU4NTYyLDAuMTE5NTMgLTEuMDYzMDcsMC4yMTkyMSAtMC43MTQxOSwwLjQ3NzY0IC0xLjcyNzI0LC0wLjQ2MDc2IC0yLjI2MTUyLC0wLjIzMzk3IC0yLjY1NTQ1LC0wLjAxNSB6IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiIC8+PHBhdGgKICAgICAgIGlkPSJwYXRoMjAiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzUpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZS13aWR0aDowLjc2NzIxMTtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLW1pdGVybGltaXQ6ODA7c3Ryb2tlLWRhc2hvZmZzZXQ6Mi4wOTk5ODtwYWludC1vcmRlcjptYXJrZXJzIGZpbGwgc3Ryb2tlIgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItMi40NTMzMDE2IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci15PSIwLjk4ODc3NzYiCiAgICAgICBkPSJtIDEwMi42NDM5NiwxNTcuMDMwODQgYyAtNi4yODAzOCwxLjY3NTgzIC0xMC42MjE4NDYsLTEuMDY5ODYgLTExLjA1NTk4NiwtNC40NzU5NiAtMC4xMjU3OTIsLTIuNjEzNTkgMy4yNjMwNTgsLTUuMjM5NjUgNS4yMzI0ODksLTQuMTQ1OSAxLjI0NTUyMSwwLjkwODMgMi41NzkzMTMsMi4xNDUzMiAyLjQ0NjQwNCw1LjA3Mjk5IDEuMDU5NzIzLDEuNjMxODIgMy42NTAxMjMsMy4zMTAzNiAzLjM3NzA5MywzLjU0ODg3IHoiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDIxIgogICAgICAgc3R5bGU9ImZpbGw6I2ZmOTA5MDtmaWxsLW9wYWNpdHk6MTtzdHJva2Utd2lkdGg6MC45MDI5MjI7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1taXRlcmxpbWl0OjgwO3N0cm9rZS1kYXNob2Zmc2V0OjIuMDk5OTg7cGFpbnQtb3JkZXI6bWFya2VycyBmaWxsIHN0cm9rZSIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteD0iLTguMjgxODA4NiIKICAgICAgIGlua3NjYXBlOnRyYW5zZm9ybS1jZW50ZXIteT0iNS4xNTc0MDQiCiAgICAgICBkPSJtIDEwMi40NjczLDE1OC4xOTc5OSBjIC0wLjIzNDMxLC0wLjI2NzE1IC0xLjA4MjAzLC0wLjAzNDggLTEuMzAyODYsMC4xOTMyMiAtMC4yNDc3MywtMC4xNjEzNiAtMC4xOTE5MywtMC45MTY3OSAtMC4yMDUzMSwtMS4xMTc5NSAwLjEzODUxLC0wLjE4Mjg0IDAuNTQ3LC0wLjc3NDMyIDEuMTMzNDEsLTAuODk4MDMgMC44NjA5NywwLjQxNDUgMS41OTg4NCwwLjQ4MTEyIDIuMTc1ODMsMC40MTUzNyAwLjgxMjUxLDAuMDYzNyAxLjEyNTE2LDAuMzYwNzEgMS40NjU1MywwLjQ1OTQ2IC0wLjU2MjA1LDAuMjAzMjggLTEuMDE5OTcsMC4zNzEyMyAtMC42MzcyNywwLjU3NjI3IC0xLjc3NTgzLC0wLjIwNTEgLTIuMjcxNTIsMC4wOTY5IC0yLjYyOTQ5LDAuMzcwNjggeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjIiAvPjxwYXRoCiAgICAgICBpZD0icGF0aDM1IgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM5KTtzdHJva2Utd2lkdGg6MC4wNDcxNTI4O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbWl0ZXJsaW1pdDo4MDtzdHJva2UtZGFzaG9mZnNldDoyLjA5OTk4O3BhaW50LW9yZGVyOm1hcmtlcnMgZmlsbCBzdHJva2UiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXg9Ii05LjAxMDY0MjgiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9Ii00Ljk0Mjc4MzMiCiAgICAgICBkPSJtIDkzLjYzODk3LDE0MS44MDcxNyBjIC0xLjgxODExOSwxLjA3ODQ4IC0zLjc0ODQyNyw0LjQ3MDY3IC0yLjQ3MTY4OCw3LjE1NTY3IDAuMTEzNzksMC44NjQ1NyAwLjMzMjI1NCwxLjUyMDg0IC0wLjYxMTIzMiwyLjExMjkxIC0zLjU4NzM3OCwtMS4yMzc4OSAtMi4yMTYyMDksLTguMTQ3OTQgMy4wOTIwMDYsLTEwLjM0NzQ2IDIuOTkzODE3LC0xLjI0MDUzIDE3LjQ4NTc2NCwtMS41MTAzNCAxNy41ODg4NjQsLTEuMjE0OTcgLTAuMjExNjgsMC4zNjk0MSAtMTUuMzAyOTA0LDAuOTMyNDYgLTE3LjU5Nzk1LDIuMjkzODUgeiIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0ic2Njc2NzIiAvPjwvZz48L3N2Zz4K" +original_size = Vector2(120, 76) +metadata/_custom_type_script = "uid://yh2davxk4fh7" + +[node name="GUI" type="HFlowContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TextureRect" type="TextureRect" parent="."] +custom_minimum_size = Vector2(180, 130) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="SVGTextureHelper" type="Node" parent="TextureRect"] +script = ExtResource("1_tkwla") +svg_resource = SubResource("Resource_2fobf") +target_property = "texture" +metadata/_custom_type_script = "uid://cd2hrik4wvt1o" + +[node name="Button" type="Button" parent="."] +custom_minimum_size = Vector2(310, 128) +layout_mode = 2 +text = "SVG Icon Button" +expand_icon = true + +[node name="IconSVGTextureHelper" type="Node" parent="Button"] +script = ExtResource("1_tkwla") +svg_resource = SubResource("Resource_tkwla") +target_property = "icon" + +[node name="TextureButton" type="TextureButton" parent="."] +custom_minimum_size = Vector2(240, 260) +layout_mode = 2 +ignore_texture_size = true +stretch_mode = 5 + +[node name="SVGTextureHelperForNormal" type="Node" parent="TextureButton"] +script = ExtResource("1_tkwla") +svg_resource = SubResource("Resource_fv747") +target_property = "texture_normal" +metadata/_custom_type_script = "uid://cd2hrik4wvt1o" + +[node name="SVGTextureHelperForHover" type="Node" parent="TextureButton"] +script = ExtResource("1_tkwla") +svg_resource = SubResource("Resource_l4vqo") +target_property = "texture_hover" +metadata/_custom_type_script = "uid://cd2hrik4wvt1o" diff --git a/addons/curved_lines_2d/examples/heart_icon.gd b/addons/curved_lines_2d/examples/heart_icon.gd new file mode 100644 index 0000000..ccba5c1 --- /dev/null +++ b/addons/curved_lines_2d/examples/heart_icon.gd @@ -0,0 +1,4 @@ +extends Node2D + +func _ready() -> void: + $AnimationPlayer.play("heart_beat") diff --git a/addons/curved_lines_2d/examples/heart_icon.gd.uid b/addons/curved_lines_2d/examples/heart_icon.gd.uid new file mode 100644 index 0000000..7dd0373 --- /dev/null +++ b/addons/curved_lines_2d/examples/heart_icon.gd.uid @@ -0,0 +1 @@ +uid://bq71tj10w4224 diff --git a/addons/curved_lines_2d/examples/heart_icon.tscn b/addons/curved_lines_2d/examples/heart_icon.tscn new file mode 100644 index 0000000..f780b10 --- /dev/null +++ b/addons/curved_lines_2d/examples/heart_icon.tscn @@ -0,0 +1,725 @@ +[gd_scene load_steps=17 format=3 uid="uid://c6dfjd23olqhh"] + +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="1_0qe1d"] +[ext_resource type="Script" uid="uid://bq71tj10w4224" path="res://addons/curved_lines_2d/examples/heart_icon.gd" id="1_7bfrm"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="3_0mo18"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="4_2kl3k"] + +[sub_resource type="Curve2D" id="Curve2D_jr52a"] +_data = { +"points": PackedVector2Array(0, 0, 8.8368, 0, 110, 0, 0, -8.8368, 0, 0, 126, 16, 0, 0, 0, 8.8368, 126, 110, 8.8368, 0, 0, 0, 110, 126, 0, 0, -8.8368, 0, 16, 126, 0, 8.8368, 0, 0, 0, 110, 0, 0, 0, -8.8368, 0, 16, -8.8368, 0, 0, 0, 16, 0, 0, 0, 0, 0, 110, 0) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_0f505"] +script = ExtResource("4_2kl3k") +arcs = Array[ExtResource("3_0mo18")]([]) + +[sub_resource type="Curve2D" id="Curve2D_2027v"] +_data = { +"points": PackedVector2Array(0, 0, 29.2, -50, 0.973248, -28.9963, 94.8, -57.4, -88.8, -44.5, 0.617999, 42.92, -42.8, -54.2, 0, 0, 0.973248, -28.9963) +} +point_count = 3 + +[sub_resource type="Resource" id="Resource_tok2d"] +script = ExtResource("4_2kl3k") +arcs = Array[ExtResource("3_0mo18")]([]) + +[sub_resource type="Gradient" id="Gradient_ygkck"] +colors = PackedColorArray(0.60933, 0.60933, 0.60933, 1, 1, 1, 1, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_gpl51"] +gradient = SubResource("Gradient_ygkck") +width = 100 +height = 89 + +[sub_resource type="Curve2D" id="Curve2D_bi08n"] +_data = { +"points": PackedVector2Array(0, 0, 21.7271, 20.9769, 13.3388, -11.7091, 14.937, 28.6102, -14.937, -28.6102, -14.6612, 16.2909, -10.3688, -18.3229, 0, 0, 13.3388, -11.7091) +} +point_count = 3 + +[sub_resource type="Resource" id="Resource_35n4y"] +script = ExtResource("4_2kl3k") +arcs = Array[ExtResource("3_0mo18")]([]) + +[sub_resource type="Gradient" id="Gradient_42wa7"] +offsets = PackedFloat32Array(0, 0.529197) +colors = PackedColorArray(0.313726, 0.572549, 1, 1, 0.117647, 0.494118, 0.831373, 0) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_2eynm"] +gradient = SubResource("Gradient_42wa7") +width = 38 +height = 46 +fill = 1 +fill_from = Vector2(0.542735, 0.320513) +fill_to = Vector2(0.957265, 1) + +[sub_resource type="Animation" id="Animation_7bfrm"] +resource_name = "heart_beat" +loop_mode = 2 +step = 0.5 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Heart:curve:point_0/position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0.973248, -28.9963), Vector2(1.25, -16.75)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Heart:curve:point_0/out") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(29.2, -50), Vector2(38.7768, 0.7463)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Heart:curve:point_1/position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0.617999, 42.92), Vector2(2, 27)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Heart:curve:point_1/in") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(94.8, -57.4), Vector2(31.132, -0.919998)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Heart:curve:point_1/out") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-88.8, -44.5), Vector2(-31.132, 0.919998)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Heart:curve:point_2/position") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0.973248, -28.9963), Vector2(1.25, -16.75)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Heart:curve:point_2/in") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-42.8, -54.2), Vector2(-38.7768, -0.7463)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Heart/Fill:color") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(0.278431, 0.54902, 0.74902, 1), Color(0.756863, 0.54902, 0.74902, 1)] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Heart/ScalableVectorShape2D:curve:point_0/position") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(13.3388, -11.7091), Vector2(26.2659, 31.7503)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Heart/ScalableVectorShape2D:curve:point_0/out") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(21.7271, 20.9769), Vector2(16.3979, 15.8317)] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Heart/ScalableVectorShape2D:curve:point_1/position") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-14.6612, 16.2909), Vector2(-3.46613, 40.8997)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Heart/ScalableVectorShape2D:curve:point_1/in") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(14.937, 28.6102), Vector2(11.2732, 21.5927)] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Heart/ScalableVectorShape2D:curve:point_1/out") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-14.937, -28.6102), Vector2(-11.2732, -21.5927)] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("Heart/ScalableVectorShape2D:curve:point_2/position") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(13.3388, -11.7091), Vector2(26.2659, 31.7503)] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("Heart/ScalableVectorShape2D:curve:point_2/in") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-10.3688, -18.3229), Vector2(-7.82554, -13.8287)] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("Heart/ScalableVectorShape2D/Polygon2D:color") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0, 0.55, 1), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0.690196), Color(1, 1, 1, 0)] +} +tracks/16/type = "value" +tracks/16/imported = false +tracks/16/enabled = true +tracks/16/path = NodePath("Heart/Stroke:default_color") +tracks/16/interp = 1 +tracks/16/loop_wrap = true +tracks/16/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(0.129412, 0.145098, 0.196078, 1), Color(0.31, 0.2263, 0.30721, 1)] +} +tracks/17/type = "value" +tracks/17/imported = false +tracks/17/enabled = true +tracks/17/path = NodePath("Heart/Stroke:width") +tracks/17/interp = 1 +tracks/17/loop_wrap = true +tracks/17/keys = { +"times": PackedFloat32Array(0, 0.75, 1), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [6.0, 10.0, 8.0] +} +tracks/18/type = "value" +tracks/18/imported = false +tracks/18/enabled = true +tracks/18/path = NodePath(".:curve:point_0/position") +tracks/18/interp = 1 +tracks/18/loop_wrap = true +tracks/18/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(110, 0), Vector2(110, 0)] +} +tracks/19/type = "value" +tracks/19/imported = false +tracks/19/enabled = true +tracks/19/path = NodePath(".:curve:point_0/out") +tracks/19/interp = 1 +tracks/19/loop_wrap = true +tracks/19/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(8.8368, 0), Vector2(8.8368, 0)] +} +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath(".:curve:point_1/position") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(126, 16), Vector2(126, 16)] +} +tracks/21/type = "value" +tracks/21/imported = false +tracks/21/enabled = true +tracks/21/path = NodePath(".:curve:point_1/in") +tracks/21/interp = 1 +tracks/21/loop_wrap = true +tracks/21/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, -8.8368), Vector2(0, -8.8368)] +} +tracks/22/type = "value" +tracks/22/imported = false +tracks/22/enabled = true +tracks/22/path = NodePath(".:curve:point_1/out") +tracks/22/interp = 1 +tracks/22/loop_wrap = true +tracks/22/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(-14.3333, 36.3333)] +} +tracks/23/type = "value" +tracks/23/imported = false +tracks/23/enabled = true +tracks/23/path = NodePath(".:curve:point_2/position") +tracks/23/interp = 1 +tracks/23/loop_wrap = true +tracks/23/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(126, 110), Vector2(126, 110)] +} +tracks/24/type = "value" +tracks/24/imported = false +tracks/24/enabled = true +tracks/24/path = NodePath(".:curve:point_2/in") +tracks/24/interp = 1 +tracks/24/loop_wrap = true +tracks/24/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(-14.3333, -26.3333)] +} +tracks/25/type = "value" +tracks/25/imported = false +tracks/25/enabled = true +tracks/25/path = NodePath(".:curve:point_2/out") +tracks/25/interp = 1 +tracks/25/loop_wrap = true +tracks/25/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 8.8368), Vector2(0, 8.8368)] +} +tracks/26/type = "value" +tracks/26/imported = false +tracks/26/enabled = true +tracks/26/path = NodePath(".:curve:point_3/position") +tracks/26/interp = 1 +tracks/26/loop_wrap = true +tracks/26/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(110, 126), Vector2(110, 126)] +} +tracks/27/type = "value" +tracks/27/imported = false +tracks/27/enabled = true +tracks/27/path = NodePath(".:curve:point_3/in") +tracks/27/interp = 1 +tracks/27/loop_wrap = true +tracks/27/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(8.8368, 0), Vector2(8.8368, 0)] +} +tracks/28/type = "value" +tracks/28/imported = false +tracks/28/enabled = true +tracks/28/path = NodePath(".:curve:point_3/out") +tracks/28/interp = 1 +tracks/28/loop_wrap = true +tracks/28/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(-29.3333, -17.6667)] +} +tracks/29/type = "value" +tracks/29/imported = false +tracks/29/enabled = true +tracks/29/path = NodePath(".:curve:point_4/position") +tracks/29/interp = 1 +tracks/29/loop_wrap = true +tracks/29/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(16, 126), Vector2(16, 126)] +} +tracks/30/type = "value" +tracks/30/imported = false +tracks/30/enabled = true +tracks/30/path = NodePath(".:curve:point_4/in") +tracks/30/interp = 1 +tracks/30/loop_wrap = true +tracks/30/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(33.3333, -17.6667)] +} +tracks/31/type = "value" +tracks/31/imported = false +tracks/31/enabled = true +tracks/31/path = NodePath(".:curve:point_4/out") +tracks/31/interp = 1 +tracks/31/loop_wrap = true +tracks/31/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-8.8368, 0), Vector2(-8.8368, 0)] +} +tracks/32/type = "value" +tracks/32/imported = false +tracks/32/enabled = true +tracks/32/path = NodePath(".:curve:point_5/position") +tracks/32/interp = 1 +tracks/32/loop_wrap = true +tracks/32/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 110), Vector2(0, 110)] +} +tracks/33/type = "value" +tracks/33/imported = false +tracks/33/enabled = true +tracks/33/path = NodePath(".:curve:point_5/in") +tracks/33/interp = 1 +tracks/33/loop_wrap = true +tracks/33/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 8.8368), Vector2(0, 8.8368)] +} +tracks/34/type = "value" +tracks/34/imported = false +tracks/34/enabled = true +tracks/34/path = NodePath(".:curve:point_5/out") +tracks/34/interp = 1 +tracks/34/loop_wrap = true +tracks/34/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(18, -27.3333)] +} +tracks/35/type = "value" +tracks/35/imported = false +tracks/35/enabled = true +tracks/35/path = NodePath(".:curve:point_6/position") +tracks/35/interp = 1 +tracks/35/loop_wrap = true +tracks/35/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 16), Vector2(0, 16)] +} +tracks/36/type = "value" +tracks/36/imported = false +tracks/36/enabled = true +tracks/36/path = NodePath(".:curve:point_6/in") +tracks/36/interp = 1 +tracks/36/loop_wrap = true +tracks/36/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(18, 35.3333)] +} +tracks/37/type = "value" +tracks/37/imported = false +tracks/37/enabled = true +tracks/37/path = NodePath(".:curve:point_6/out") +tracks/37/interp = 1 +tracks/37/loop_wrap = true +tracks/37/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, -8.8368), Vector2(0, -8.8368)] +} +tracks/38/type = "value" +tracks/38/imported = false +tracks/38/enabled = true +tracks/38/path = NodePath(".:curve:point_7/position") +tracks/38/interp = 1 +tracks/38/loop_wrap = true +tracks/38/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(16, 0), Vector2(16, 0)] +} +tracks/39/type = "value" +tracks/39/imported = false +tracks/39/enabled = true +tracks/39/path = NodePath(".:curve:point_7/in") +tracks/39/interp = 1 +tracks/39/loop_wrap = true +tracks/39/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-8.8368, 0), Vector2(-8.8368, 0)] +} +tracks/40/type = "value" +tracks/40/imported = false +tracks/40/enabled = true +tracks/40/path = NodePath(".:curve:point_7/out") +tracks/40/interp = 1 +tracks/40/loop_wrap = true +tracks/40/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(30, 25)] +} +tracks/41/type = "value" +tracks/41/imported = false +tracks/41/enabled = true +tracks/41/path = NodePath(".:curve:point_8/position") +tracks/41/interp = 1 +tracks/41/loop_wrap = true +tracks/41/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(110, 0), Vector2(110, 0)] +} +tracks/42/type = "value" +tracks/42/imported = false +tracks/42/enabled = true +tracks/42/path = NodePath(".:curve:point_8/in") +tracks/42/interp = 1 +tracks/42/loop_wrap = true +tracks/42/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(-32.6667, 25)] +} +tracks/43/type = "value" +tracks/43/imported = false +tracks/43/enabled = true +tracks/43/path = NodePath("Heart/Fill:texture:gradient:colors") +tracks/43/interp = 1 +tracks/43/loop_wrap = true +tracks/43/keys = { +"times": PackedFloat32Array(0, 0.47, 1), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [PackedColorArray(0.60933, 0.60933, 0.60933, 1, 1, 1, 1, 1), PackedColorArray(0.60933, 0.60933, 0.60933, 1, 0, 0, 0, 1, 1, 1, 1, 1), PackedColorArray(0.60933, 0.60933, 0.60933, 1, 0, 0, 0, 1, 1, 1, 1, 1)] +} +tracks/44/type = "value" +tracks/44/imported = false +tracks/44/enabled = true +tracks/44/path = NodePath("Heart/Fill:texture:gradient:offsets") +tracks/44/interp = 1 +tracks/44/loop_wrap = true +tracks/44/keys = { +"times": PackedFloat32Array(0, 0.47, 1), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [PackedFloat32Array(0, 1), PackedFloat32Array(0, 0.503953, 1), PackedFloat32Array(0, 0.503953, 1)] +} +tracks/45/type = "value" +tracks/45/imported = false +tracks/45/enabled = true +tracks/45/path = NodePath("Heart/Fill:texture:fill_from") +tracks/45/interp = 1 +tracks/45/loop_wrap = true +tracks/45/keys = { +"times": PackedFloat32Array(0, 0.47, 1), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(0, 0), Vector2(0.664692, -0.211429)] +} +tracks/46/type = "value" +tracks/46/imported = false +tracks/46/enabled = true +tracks/46/path = NodePath("Heart/Fill:texture:fill_to") +tracks/46/interp = 1 +tracks/46/loop_wrap = true +tracks/46/keys = { +"times": PackedFloat32Array(0, 0.47, 1), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(1, 0), Vector2(1, 0), Vector2(0.46501, 1.12571)] +} +tracks/47/type = "value" +tracks/47/imported = false +tracks/47/enabled = true +tracks/47/path = NodePath("Fill:color") +tracks/47/interp = 1 +tracks/47/loop_wrap = true +tracks/47/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(0.211765, 0.239216, 0.321569, 1), Color(0.2, 0.08, 0.134, 1)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_7bfrm"] +_data = { +&"heart_beat": SubResource("Animation_7bfrm") +} + +[node name="Node2D" type="Node2D"] +script = ExtResource("1_7bfrm") + +[node name="Rectangle" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "line")] +position = Vector2(-254, -260) +scale = Vector2(4, 4) +script = ExtResource("1_0qe1d") +polygon = NodePath("Fill") +line = NodePath("Stroke") +curve = SubResource("Curve2D_jr52a") +update_curve_at_runtime = true +arc_list = SubResource("Resource_0f505") + +[node name="Fill" type="Polygon2D" parent="Rectangle"] +show_behind_parent = true +color = Color(0.211765, 0.239216, 0.321569, 1) +polygon = PackedVector2Array(110, 0, 111.636, 0.0826035, 113.225, 0.325053, 114.758, 0.719307, 116.228, 1.25733, 117.627, 1.93106, 118.946, 2.73248, 120.178, 3.65354, 121.314, 4.6862, 122.346, 5.82241, 123.268, 7.05414, 124.069, 8.37334, 124.743, 9.77197, 125.281, 11.242, 125.675, 12.7754, 125.917, 14.3641, 126, 16, 126, 110, 125.917, 111.636, 125.675, 113.225, 125.281, 114.758, 124.743, 116.228, 124.069, 117.627, 123.268, 118.946, 122.346, 120.178, 121.314, 121.314, 120.178, 122.346, 118.946, 123.268, 117.627, 124.069, 116.228, 124.743, 114.758, 125.281, 113.225, 125.675, 111.636, 125.917, 110, 126, 16, 126, 14.3641, 125.917, 12.7754, 125.675, 11.242, 125.281, 9.77197, 124.743, 8.37334, 124.069, 7.05414, 123.268, 5.82241, 122.346, 4.6862, 121.314, 3.65354, 120.178, 2.73248, 118.946, 1.93106, 117.627, 1.25733, 116.228, 0.719307, 114.758, 0.325053, 113.225, 0.0826035, 111.636, 0, 110, 0, 16, 0.0826035, 14.3641, 0.325053, 12.7754, 0.719307, 11.242, 1.25733, 9.77197, 1.93106, 8.37334, 2.73248, 7.05414, 3.65354, 5.82241, 4.6862, 4.6862, 5.82241, 3.65354, 7.05414, 2.73248, 8.37334, 1.93106, 9.77197, 1.25733, 11.242, 0.719307, 12.7754, 0.325053, 14.3641, 0.0826035, 16, 0) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Rectangle"] +show_behind_parent = true +points = PackedVector2Array(110, 0, 111.636, 0.0826035, 113.225, 0.325053, 114.758, 0.719307, 116.228, 1.25733, 117.627, 1.93106, 118.946, 2.73248, 120.178, 3.65354, 121.314, 4.6862, 122.346, 5.82241, 123.268, 7.05414, 124.069, 8.37334, 124.743, 9.77197, 125.281, 11.242, 125.675, 12.7754, 125.917, 14.3641, 126, 16, 126, 110, 125.917, 111.636, 125.675, 113.225, 125.281, 114.758, 124.743, 116.228, 124.069, 117.627, 123.268, 118.946, 122.346, 120.178, 121.314, 121.314, 120.178, 122.346, 118.946, 123.268, 117.627, 124.069, 116.228, 124.743, 114.758, 125.281, 113.225, 125.675, 111.636, 125.917, 110, 126, 16, 126, 14.3641, 125.917, 12.7754, 125.675, 11.242, 125.281, 9.77197, 124.743, 8.37334, 124.069, 7.05414, 123.268, 5.82241, 122.346, 4.6862, 121.314, 3.65354, 120.178, 2.73248, 118.946, 1.93106, 117.627, 1.25733, 116.228, 0.719307, 114.758, 0.325053, 113.225, 0.0826035, 111.636, 0, 110, 0, 16, 0.0826035, 14.3641, 0.325053, 12.7754, 0.719307, 11.242, 1.25733, 9.77197, 1.93106, 8.37334, 2.73248, 7.05414, 3.65354, 5.82241, 4.6862, 4.6862, 5.82241, 3.65354, 7.05414, 2.73248, 8.37334, 1.93106, 9.77197, 1.25733, 11.242, 0.719307, 12.7754, 0.325053, 14.3641, 0.0826035, 16, 0) +closed = true +width = 4.0 +default_color = Color(0.129412, 0.145098, 0.196078, 1) +metadata/_edit_lock_ = true + +[node name="Heart" type="Node2D" parent="Rectangle" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(63.5, 65) +script = ExtResource("1_0qe1d") +polygon = NodePath("Fill") +line = NodePath("Stroke") +curve = SubResource("Curve2D_2027v") +update_curve_at_runtime = true +arc_list = SubResource("Resource_tok2d") + +[node name="Fill" type="Polygon2D" parent="Rectangle/Heart"] +show_behind_parent = true +color = Color(0.278431, 0.54902, 0.74902, 1) +texture = SubResource("GradientTexture2D_gpl51") +texture_offset = Vector2(49.9895, 46.9503) +texture_rotation = -0.488692 +polygon = PackedVector2Array(0.973248, -28.9963, 3.81036, -33.352, 6.82277, -37.059, 9.97457, -40.1395, 13.2299, -42.6159, 16.5527, -44.5104, 18.2283, -45.2463, 19.9073, -45.8452, 21.5852, -46.3097, 23.2576, -46.6426, 24.9199, -46.8468, 26.5677, -46.925, 28.1966, -46.88, 29.8019, -46.7145, 31.3792, -46.4315, 32.9241, -46.0335, 34.4319, -45.5235, 35.8984, -44.9043, 37.3189, -44.1785, 38.689, -43.349, 40.0041, -42.4185, 41.2599, -41.3899, 43.5752, -39.0494, 45.5991, -36.3498, 47.2956, -33.3131, 48.6288, -29.9619, 49.5629, -26.3183, 50.0618, -22.4045, 50.0898, -18.243, 49.6108, -13.8558, 48.5891, -9.26542, 46.9886, -4.49398, 44.7735, 0.436201, 41.9079, 5.50286, 38.3559, 10.6837, 34.0815, 15.9565, 29.0489, 21.299, 16.5653, 32.1038, 0.617999, 42.92, -14.482, 34.1835, -26.6175, 24.8304, -31.6371, 20.0018, -35.9917, 15.1141, -39.7068, 10.1988, -42.8077, 5.28776, -45.32, 0.412537, -47.2688, -4.39518, -48.6798, -9.10373, -49.5782, -13.6814, -49.9895, -18.0967, -49.939, -22.3177, -49.4521, -26.3129, -48.5544, -30.0507, -47.2711, -33.4992, -45.6276, -36.6269, -44.6787, -38.0606, -43.6494, -39.4022, -42.5427, -40.6478, -41.3618, -41.7933, -40.11, -42.8349, -38.7903, -43.7686, -37.406, -44.5904, -35.9602, -45.2964, -34.4562, -45.8825, -32.897, -46.345, -31.2859, -46.6797, -29.626, -46.8828, -27.9205, -46.9503, -26.1727, -46.8782, -24.3855, -46.6625, -22.5624, -46.2994, -20.7063, -45.7848, -18.8205, -45.1148, -14.9725, -43.2927, -11.0437, -40.8015, -7.05955, -37.6094, -3.04543, -33.6849) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Rectangle/Heart"] +show_behind_parent = true +points = PackedVector2Array(0.973248, -28.9963, 3.81036, -33.352, 6.82277, -37.059, 9.97457, -40.1395, 13.2299, -42.6159, 16.5527, -44.5104, 18.2283, -45.2463, 19.9073, -45.8452, 21.5852, -46.3097, 23.2576, -46.6426, 24.9199, -46.8468, 26.5677, -46.925, 28.1966, -46.88, 29.8019, -46.7145, 31.3792, -46.4315, 32.9241, -46.0335, 34.4319, -45.5235, 35.8984, -44.9043, 37.3189, -44.1785, 38.689, -43.349, 40.0041, -42.4185, 41.2599, -41.3899, 43.5752, -39.0494, 45.5991, -36.3498, 47.2956, -33.3131, 48.6288, -29.9619, 49.5629, -26.3183, 50.0618, -22.4045, 50.0898, -18.243, 49.6108, -13.8558, 48.5891, -9.26542, 46.9886, -4.49398, 44.7735, 0.436201, 41.9079, 5.50286, 38.3559, 10.6837, 34.0815, 15.9565, 29.0489, 21.299, 16.5653, 32.1038, 0.617999, 42.92, -14.482, 34.1835, -26.6175, 24.8304, -31.6371, 20.0018, -35.9917, 15.1141, -39.7068, 10.1988, -42.8077, 5.28776, -45.32, 0.412537, -47.2688, -4.39518, -48.6798, -9.10373, -49.5782, -13.6814, -49.9895, -18.0967, -49.939, -22.3177, -49.4521, -26.3129, -48.5544, -30.0507, -47.2711, -33.4992, -45.6276, -36.6269, -44.6787, -38.0606, -43.6494, -39.4022, -42.5427, -40.6478, -41.3618, -41.7933, -40.11, -42.8349, -38.7903, -43.7686, -37.406, -44.5904, -35.9602, -45.2964, -34.4562, -45.8825, -32.897, -46.345, -31.2859, -46.6797, -29.626, -46.8828, -27.9205, -46.9503, -26.1727, -46.8782, -24.3855, -46.6625, -22.5624, -46.2994, -20.7063, -45.7848, -18.8205, -45.1148, -14.9725, -43.2927, -11.0437, -40.8015, -7.05955, -37.6094, -3.04543, -33.6849) +closed = true +width = 6.0 +default_color = Color(0.129412, 0.145098, 0.196078, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 +metadata/_edit_lock_ = true + +[node name="ScalableVectorShape2D" type="Node2D" parent="Rectangle/Heart" node_paths=PackedStringArray("polygon")] +position = Vector2(27.75, -24) +rotation = 0.785015 +scale = Vector2(0.564941, 0.868743) +script = ExtResource("1_0qe1d") +polygon = NodePath("Polygon2D") +curve = SubResource("Curve2D_bi08n") +update_curve_at_runtime = true +arc_list = SubResource("Resource_35n4y") +shape_hint_color = Color(0.196078, 0.803922, 0.196078, 0.27451) +metadata/_custom_type_script = "uid://de3jpss66xjfh" + +[node name="Polygon2D" type="Polygon2D" parent="Rectangle/Heart/ScalableVectorShape2D"] +show_behind_parent = true +texture = SubResource("GradientTexture2D_2eynm") +texture_offset = Vector2(18.5124, 19.1769) +polygon = PackedVector2Array(13.3388, -11.7091, 15.2125, -9.70198, 16.769, -7.62344, 18.0223, -5.48791, 18.9864, -3.30984, 19.6753, -1.10369, 20.1029, 1.11611, 20.2833, 3.3351, 20.2304, 5.53884, 19.9583, 7.71288, 19.4808, 9.84278, 18.812, 11.9141, 17.9659, 13.9123, 16.9565, 15.8231, 15.7977, 17.632, 14.5034, 19.3244, 13.0878, 20.8861, 11.5648, 22.3024, 9.94837, 23.5591, 8.25247, 24.6415, 6.49111, 25.5354, 4.67827, 26.2262, 2.82794, 26.6995, 0.954094, 26.9408, -0.929278, 26.9357, -1.87017, 26.8363, -2.8082, 26.6698, -3.74161, 26.4345, -4.66867, 26.1285, -5.58763, 25.7502, -6.49673, 25.2976, -8.27837, 24.1624, -9.99963, 22.7086, -11.6465, 20.9217, -13.205, 18.7873, -14.6612, 16.2909, -15.9245, 13.6414, -16.9222, 11.0603, -17.6671, 8.55233, -18.1719, 6.12199, -18.4494, 3.77392, -18.5124, 1.51271, -18.3736, -0.657024, -18.0459, -2.73069, -17.5418, -4.70367, -16.8743, -6.57138, -16.0561, -8.32921, -15.0999, -9.97255, -14.0185, -11.4968, -12.8247, -12.8974, -11.5312, -14.1696, -10.1509, -15.309, -8.69637, -16.3109, -7.18048, -17.1707, -5.61599, -17.8837, -4.01564, -18.4455, -2.39221, -18.8513, -0.758465, -19.0967, 0.872844, -19.1769, 2.48895, -19.0874, 4.07708, -18.8236, 5.62449, -18.3808, 7.11839, -17.7545, 8.54605, -16.9401, 9.89467, -15.933, 11.1515, -14.7285, 12.3038, -13.3221) +metadata/_edit_lock_ = true + +[node name="Camera2D" type="Camera2D" parent="."] + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +root_node = NodePath("../Rectangle") +libraries = { +&"": SubResource("AnimationLibrary_7bfrm") +} diff --git a/addons/curved_lines_2d/examples/pinball/butterfly.scn b/addons/curved_lines_2d/examples/pinball/butterfly.scn new file mode 100644 index 0000000..f66670b Binary files /dev/null and b/addons/curved_lines_2d/examples/pinball/butterfly.scn differ diff --git a/addons/curved_lines_2d/examples/pinball/chasing_light.gd b/addons/curved_lines_2d/examples/pinball/chasing_light.gd new file mode 100644 index 0000000..06429d1 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/chasing_light.gd @@ -0,0 +1,26 @@ +extends CharacterBody2D + +@onready var navigation_agent := $NavigationAgent2D + +func _ready(): + set_physics_process(false) + call_deferred("on_nav_serv_ready") + + +func on_nav_serv_ready(): + await get_tree().physics_frame + set_physics_process(true) + + +func _physics_process(_delta: float) -> void: + var pinball = get_tree().get_first_node_in_group("pinballs") + if not is_instance_valid(pinball): + return + var target_pos : Vector2 = pinball.position + navigation_agent.target_position = target_pos + var current_agent_position = global_position + var next_path_position = navigation_agent.get_next_path_position() + velocity = current_agent_position.direction_to(next_path_position) * 600 + navigation_agent.set_velocity_forced(velocity) + move_and_slide() + diff --git a/addons/curved_lines_2d/examples/pinball/chasing_light.gd.uid b/addons/curved_lines_2d/examples/pinball/chasing_light.gd.uid new file mode 100644 index 0000000..4ebb244 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/chasing_light.gd.uid @@ -0,0 +1 @@ +uid://cqncbgw8tm4cf diff --git a/addons/curved_lines_2d/examples/pinball/chasing_light.tscn b/addons/curved_lines_2d/examples/pinball/chasing_light.tscn new file mode 100644 index 0000000..8068051 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/chasing_light.tscn @@ -0,0 +1,31 @@ +[gd_scene load_steps=5 format=3 uid="uid://de7qp86gcbt0j"] + +[ext_resource type="Script" uid="uid://cqncbgw8tm4cf" path="res://chasing_light.gd" id="1_5swdf"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_qxspa"] +radius = 18.0 + +[sub_resource type="Gradient" id="Gradient_xagdg"] +offsets = PackedFloat32Array(0, 0.727273) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_tuwup"] +gradient = SubResource("Gradient_xagdg") +fill = 1 +fill_from = Vector2(0.5, 0.5) + +[node name="ChasingLight" type="CharacterBody2D"] +z_index = -1 +collision_layer = 2 +collision_mask = 2 +motion_mode = 1 +script = ExtResource("1_5swdf") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("CircleShape2D_qxspa") + +[node name="PointLight2D" type="PointLight2D" parent="."] +energy = 2.0 +texture = SubResource("GradientTexture2D_tuwup") + +[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."] diff --git a/addons/curved_lines_2d/examples/pinball/flipper.gd b/addons/curved_lines_2d/examples/pinball/flipper.gd new file mode 100644 index 0000000..937f1cf --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/flipper.gd @@ -0,0 +1,26 @@ +extends Node2D + +@export var flipping_up := false +@export var min_rotation := 0.0 +@export var max_rotation := 45.0 +@export var base_acceleration := 3.0 + +var acceleration = 0.0 + +func _physics_process(delta: float) -> void: + if flipping_up: + if $AnimatableBody2D.rotation > deg_to_rad(min_rotation) + 0.01: + if acceleration == 0: + acceleration = 2 * base_acceleration + $AnimatableBody2D.rotation -= acceleration * delta + acceleration += base_acceleration + else: + $AnimatableBody2D.rotation = deg_to_rad(min_rotation) + acceleration = 0.0 + else: + if $AnimatableBody2D.rotation < deg_to_rad(max_rotation) - 0.01: + $AnimatableBody2D.rotation += acceleration * delta + acceleration = base_acceleration * 4 + else: + $AnimatableBody2D.rotation = deg_to_rad(max_rotation) + acceleration = 0.0 diff --git a/addons/curved_lines_2d/examples/pinball/flipper.gd.uid b/addons/curved_lines_2d/examples/pinball/flipper.gd.uid new file mode 100644 index 0000000..73be6dd --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/flipper.gd.uid @@ -0,0 +1 @@ +uid://dl0gawkliv8ak diff --git a/addons/curved_lines_2d/examples/pinball/flipper.tscn b/addons/curved_lines_2d/examples/pinball/flipper.tscn new file mode 100644 index 0000000..33fddcb --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/flipper.tscn @@ -0,0 +1,40 @@ +[gd_scene load_steps=7 format=3 uid="uid://c4qvvoxq5w28e"] + +[ext_resource type="Script" uid="uid://dl0gawkliv8ak" path="res://addons/curved_lines_2d/examples/pinball/flipper.gd" id="1_k5dyu"] +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="1_mhtlv"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="2_k5dyu"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="3_muof8"] + +[sub_resource type="Curve2D" id="Curve2D_0bqc8"] +_data = { +"points": PackedVector2Array(0, 0, 24, 24, 192, -31.5, 40, 0.5, -17.6736, 0, 0, 32.5, 0, 17.6736, 0, -17.6736, -32, 0, -17.6736, 0, 0, 0, 0, -31.5, 0, 0, 0, 0, 192, -31.5) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_r6cs1"] +script = ExtResource("3_muof8") +arcs = Array[ExtResource("2_k5dyu")]([]) + +[node name="Flipper" type="Node2D"] +script = ExtResource("1_k5dyu") +metadata/_edit_horizontal_guides_ = [-33.0] + +[node name="AnimatableBody2D" type="AnimatableBody2D" parent="."] +position = Vector2(0, -0.5) +rotation = 0.785398 +metadata/_edit_lock_ = true + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="AnimatableBody2D"] +polygon = PackedVector2Array(192, -31.5, 192.98, -30.3631, 193.674, -29.2034, 194.091, -28.0222, 194.238, -26.8207, 194.123, -25.6003, 193.753, -24.3623, 193.137, -23.1081, 192.281, -21.8389, 191.194, -20.556, 189.883, -19.2608, 186.621, -16.6388, 182.556, -13.9832, 177.75, -11.3047, 152.344, -0.571289, 120, 9.6875, 50.25, 26.0859, 20.7188, 30.8779, 0, 32.5, -3.27189, 32.3292, -6.44926, 31.8284, -9.516, 31.0152, -12.456, 29.9072, -15.2533, 28.5219, -17.8917, 26.8768, -20.3552, 24.9895, -22.6276, 22.8776, -24.6929, 20.5585, -26.535, 18.0499, -28.1379, 15.3693, -29.4853, 12.5342, -30.5614, 9.56214, -31.3499, 6.47074, -31.8348, 3.27751, -32, 0, -31.8348, -3.26628, -31.3499, -6.42777, -30.5614, -9.46986, -29.4853, -12.3779, -28.1379, -15.1374, -26.535, -17.7335, -24.6929, -20.1518, -22.6276, -22.3776, -20.3552, -24.3963, -17.8917, -26.1932, -15.2533, -27.7538, -12.456, -29.0635, -9.516, -30.1075, -6.44926, -30.8714, -3.27189, -31.3404, 0, -31.5) +metadata/_edit_lock_ = true + +[node name="Circle" type="Node2D" parent="AnimatableBody2D" node_paths=PackedStringArray("polygon", "collision_object")] +script = ExtResource("1_mhtlv") +polygon = NodePath("Fill") +collision_object = NodePath("..") +curve = SubResource("Curve2D_0bqc8") +arc_list = SubResource("Resource_r6cs1") + +[node name="Fill" type="Polygon2D" parent="AnimatableBody2D/Circle"] +polygon = PackedVector2Array(192, -31.5, 192.98, -30.3631, 193.674, -29.2034, 194.091, -28.0222, 194.238, -26.8207, 194.123, -25.6003, 193.753, -24.3623, 193.137, -23.1081, 192.281, -21.8389, 191.194, -20.556, 189.883, -19.2608, 186.621, -16.6388, 182.556, -13.9832, 177.75, -11.3047, 152.344, -0.571289, 120, 9.6875, 50.25, 26.0859, 20.7188, 30.8779, 0, 32.5, -3.27189, 32.3292, -6.44926, 31.8284, -9.516, 31.0152, -12.456, 29.9072, -15.2533, 28.5219, -17.8917, 26.8768, -20.3552, 24.9895, -22.6276, 22.8776, -24.6929, 20.5585, -26.535, 18.0499, -28.1379, 15.3693, -29.4853, 12.5342, -30.5614, 9.56214, -31.3499, 6.47074, -31.8348, 3.27751, -32, 0, -31.8348, -3.26628, -31.3499, -6.42777, -30.5614, -9.46986, -29.4853, -12.3779, -28.1379, -15.1374, -26.535, -17.7335, -24.6929, -20.1518, -22.6276, -22.3776, -20.3552, -24.3963, -17.8917, -26.1932, -15.2533, -27.7538, -12.456, -29.0635, -9.516, -30.1075, -6.44926, -30.8714, -3.27189, -31.3404, 0, -31.5) +metadata/_edit_lock_ = true diff --git a/addons/curved_lines_2d/examples/pinball/game.gd b/addons/curved_lines_2d/examples/pinball/game.gd new file mode 100644 index 0000000..6e0ab75 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/game.gd @@ -0,0 +1,18 @@ +extends Node2D + +var PinballScene : PackedScene = preload("res://addons/curved_lines_2d/examples/pinball/pinball.tscn") +@onready var pinball_spawn_point : Vector2 = $Pinball.position + +func _process(_delta: float) -> void: + $LeftFlipper.flipping_up = Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) + $RightFlipper.flipping_up = Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) + + +func _on_catch_ball_area_2d_body_entered(body: Node2D) -> void: + if body.is_in_group("pinballs"): + body.remove_from_group("pinballs") + await get_tree().create_timer(1).timeout + body.queue_free() + var new_ball : Node2D = PinballScene.instantiate() + new_ball.position = pinball_spawn_point + add_child.call_deferred(new_ball) diff --git a/addons/curved_lines_2d/examples/pinball/game.gd.uid b/addons/curved_lines_2d/examples/pinball/game.gd.uid new file mode 100644 index 0000000..198b221 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/game.gd.uid @@ -0,0 +1 @@ +uid://wyeymr4vku74 diff --git a/addons/curved_lines_2d/examples/pinball/game.tscn b/addons/curved_lines_2d/examples/pinball/game.tscn new file mode 100644 index 0000000..9f70240 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/game.tscn @@ -0,0 +1,188 @@ +[gd_scene load_steps=22 format=3 uid="uid://bpjhx0g61ptyq"] + +[ext_resource type="Script" uid="uid://wyeymr4vku74" path="res://addons/curved_lines_2d/examples/pinball/game.gd" id="1_eow3j"] +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="2_j5wjh"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="3_vef74"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="4_hve3p"] +[ext_resource type="PackedScene" uid="uid://c4qvvoxq5w28e" path="res://addons/curved_lines_2d/examples/pinball/flipper.tscn" id="5_mfdv2"] +[ext_resource type="PackedScene" uid="uid://bwxjc7a0mapl0" path="res://addons/curved_lines_2d/examples/pinball/pinball.tscn" id="6_iotsf"] +[ext_resource type="PackedScene" uid="uid://cisphek1rg6t6" path="res://addons/curved_lines_2d/examples/pinball/butterfly.scn" id="6_j6l5u"] +[ext_resource type="PackedScene" uid="uid://de7qp86gcbt0j" path="res://addons/curved_lines_2d/examples/pinball/chasing_light.tscn" id="7_lc2xo"] + +[sub_resource type="Curve2D" id="Curve2D_ipynf"] +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -576, -584, 0, 0, 0, 0, 576, -584, 0, 0, 0, 0, 576, 1440, 0, 0, 0, 0, -576, 1440, 0, 0, 0, 0, -576, -584) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_dpgl4"] +script = ExtResource("4_hve3p") +arcs = Array[ExtResource("3_vef74")]([]) + +[sub_resource type="Gradient" id="Gradient_8lkhd"] +colors = PackedColorArray(1, 0.613281, 0.613281, 1, 1, 0.421875, 0.421875, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_mpo7f"] +gradient = SubResource("Gradient_8lkhd") +width = 1152 +height = 2024 +fill_from = Vector2(0.552951, 0.153472) +fill_to = Vector2(0.510417, 0.762352) + +[sub_resource type="Curve2D" id="Curve2D_ara7v"] +_data = { +"points": PackedVector2Array(0, 0, -48, 21.3333, 235.143, -125.429, 0, 0, 91, 100.857, 201, -71.8571, 0, 0, 0, 0, 922, 262, 0, 0, 0, 0, 930, 206, 0, 0, 13.3333, -24, 678.333, -67.3333, 24, 13.3333, 16, -16, 652.667, -127, 53.3333, 625.333, 0, 0, 898, -1218, 0, 0, -22.6667, 726.667, 2, -1218, -16, -16, 0, 0, 235.143, -125.429) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_vbn2a"] +script = ExtResource("3_vef74") +start_point = 6 +radius = Vector2(448, 448) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_x3eih"] +script = ExtResource("3_vef74") +start_point = 2 +radius = Vector2(44, 44) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = true + +[sub_resource type="Resource" id="Resource_gdr51"] +script = ExtResource("3_vef74") +start_point = 0 +radius = Vector2(28, 28) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_1vgfy"] +script = ExtResource("3_vef74") +start_point = 4 +radius = Vector2(32, 32) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_8v3mp"] +script = ExtResource("4_hve3p") +arcs = Array[ExtResource("3_vef74")]([SubResource("Resource_vbn2a"), SubResource("Resource_x3eih"), SubResource("Resource_gdr51"), SubResource("Resource_1vgfy")]) + +[sub_resource type="Gradient" id="Gradient_x3eih"] +offsets = PackedFloat32Array(0.752276, 0.836019) +colors = PackedColorArray(0, 0, 0, 1, 0, 0, 0, 0) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_gdr51"] +gradient = SubResource("Gradient_x3eih") +width = 1001 +height = 1948 +fill = 1 +fill_from = Vector2(1.01428, 1.00321) +fill_to = Vector2(0.892115, 0.96797) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_1vgfy"] +size = Vector2(53, 18) + +[node name="Game" type="Node2D"] +script = ExtResource("1_eow3j") + +[node name="Rectangle" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "collision_object", "clip_paths")] +position = Vector2(0, -1144) +script = ExtResource("2_j5wjh") +polygon = NodePath("Fill") +collision_object = NodePath("StaticBody2D") +curve = SubResource("Curve2D_ipynf") +update_curve_at_runtime = true +arc_list = SubResource("Resource_dpgl4") +clip_paths = [NodePath("CutoutOfRectangle")] +metadata/_edit_lock_ = true + +[node name="StaticBody2D" type="StaticBody2D" parent="Rectangle"] +metadata/_edit_lock_ = true + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Rectangle/StaticBody2D"] +polygon = PackedVector2Array(576, 1440, 52.6829, 1440, 52.6829, 1236.91, 145.625, 1278.89, 472, 1408, 473.712, 1410.55, 475.597, 1412.97, 477.647, 1415.26, 479.852, 1417.4, 482.2, 1419.38, 484.68, 1421.19, 487.281, 1422.82, 489.99, 1424.27, 492.793, 1425.53, 495.676, 1426.58, 498.626, 1427.44, 501.629, 1428.08, 504.669, 1428.52, 507.733, 1428.74, 510.804, 1428.74, 513.868, 1428.54, 516.91, 1428.11, 519.915, 1427.48, 522.87, 1426.64, 525.758, 1425.6, 528.566, 1424.36, 531.281, 1422.92, 533.889, 1421.3, 536.378, 1419.5, 538.735, 1417.53, 540.949, 1415.4, 543.009, 1413.12, 544.905, 1410.71, 546.628, 1408.17, 548.17, 1405.51, 549.522, 1402.75, 550.679, 1399.91, 551.634, 1396.99, 552.384, 1394.01, 552.924, 1390.99, 553.252, 1387.93, 553.366, 1384.86, 553.265, 1381.79, 552.951, 1378.74, 552.425, 1375.71, 551.688, 1372.73, 550.746, 1369.81, 549.602, 1366.96, 548.261, 1364.2, 546.732, 1361.53, 545.02, 1358.98, 543.135, 1356.56, 541.085, 1354.27, 538.88, 1352.13, 536.532, 1350.15, 534.051, 1348.34, 531.451, 1346.71, 528.742, 1345.26, 525.939, 1344.01, 523.056, 1342.95, 520.105, 1342.1, 517.103, 1341.45, 514.062, 1341.02, 510.999, 1340.8, 507.928, 1340.79, 504.864, 1341, 501.822, 1341.42, 498.816, 1342.05, 495.862, 1342.89, 492.974, 1343.93, 490.165, 1345.18, 487.451, 1346.61, 484.842, 1348.23, 482.354, 1350.03, 480, 1352, 228.333, 1078.67, 230.383, 1077.7, 232.36, 1076.59, 234.255, 1075.35, 236.058, 1073.97, 237.762, 1072.48, 239.356, 1070.87, 240.835, 1069.15, 242.19, 1067.33, 243.415, 1065.42, 244.504, 1063.44, 245.452, 1061.38, 246.254, 1059.26, 246.906, 1057.08, 247.405, 1054.87, 247.748, 1052.63, 247.934, 1050.37, 247.963, 1048.11, 247.833, 1045.84, 247.545, 1043.6, 247.102, 1041.37, 246.504, 1039.19, 245.755, 1037.05, 244.859, 1034.96, 243.82, 1032.95, 242.643, 1031.01, 241.333, 1029.16, 239.898, 1027.41, 238.344, 1025.76, 236.678, 1024.22, 234.91, 1022.8, 233.046, 1021.51, 231.097, 1020.35, 229.073, 1019.33, 226.982, 1018.46, 224.835, 1017.73, 222.642, 1017.16, 220.415, 1016.73, 218.163, 1016.47, 215.899, 1016.36, 213.633, 1016.41, 211.376, 1016.62, 209.139, 1016.99, 206.932, 1017.51, 204.768, 1018.18, 202.667, 1019, 204.93, 1016.24, 208.645, 1010.98, 219.99, 993.176, 255.25, 929.719, 301.386, 831.652, 351.333, 702, 398.031, 543.785, 434.417, 360.031, 453.427, 153.762, 448, -72, 446.909, -103.251, 443.64, -134.35, 438.21, -165.144, 430.645, -195.486, 420.982, -225.225, 409.268, -254.218, 395.561, -282.323, 379.926, -309.404, 362.44, -335.328, 343.188, -359.969, 322.264, -383.207, 299.771, -404.929, 275.816, -425.029, 250.518, -443.409, 224, -459.979, 196.39, -474.66, 167.824, -487.378, 138.44, -498.073, 108.381, -506.693, 77.7944, -513.194, 52.6828, -516.723, 52.6828, -584, 576, -584) +metadata/_edit_lock_ = true + +[node name="CollisionPolygon2D2" type="CollisionPolygon2D" parent="Rectangle/StaticBody2D"] +polygon = PackedVector2Array(52.6828, -584, 52.6828, -516.723, 46.8288, -517.546, 15.635, -519.727, -15.635, -519.727, -46.8288, -517.546, -77.7944, -513.194, -108.381, -506.693, -138.44, -498.073, -167.824, -487.378, -196.39, -474.66, -224, -459.979, -250.518, -443.409, -275.816, -425.029, -299.771, -404.929, -322.264, -383.207, -343.188, -359.969, -362.44, -335.328, -379.926, -309.404, -395.561, -282.323, -409.268, -254.218, -420.982, -225.225, -430.645, -195.486, -438.21, -165.144, -443.64, -134.35, -446.909, -103.251, -448, -72, -445.146, 182.923, -423.384, 403.027, -388.412, 588.814, -345.929, 740.786, -301.633, 859.445, -261.223, 945.294, -230.398, 998.836, -220.361, 1013.65, -214.857, 1020.57, -216.767, 1019.45, -218.751, 1018.46, -220.8, 1017.61, -222.902, 1016.9, -225.049, 1016.35, -227.229, 1015.95, -229.431, 1015.69, -231.646, 1015.6, -233.863, 1015.66, -236.07, 1015.87, -238.256, 1016.23, -240.412, 1016.75, -242.526, 1017.42, -244.589, 1018.23, -246.59, 1019.19, -248.52, 1020.28, -250.369, 1021.5, -252.128, 1022.85, -253.788, 1024.32, -255.342, 1025.9, -256.782, 1027.59, -258.101, 1029.37, -259.292, 1031.24, -260.35, 1033.19, -261.269, 1035.2, -262.046, 1037.28, -262.675, 1039.41, -263.155, 1041.57, -263.483, 1043.76, -263.657, 1045.97, -263.676, 1048.19, -263.541, 1050.4, -263.252, 1052.6, -262.81, 1054.78, -262.217, 1056.91, -261.477, 1059, -260.593, 1061.03, -259.569, 1063, -258.411, 1064.89, -257.123, 1066.7, -255.713, 1068.41, -254.187, 1070.02, -252.552, 1071.51, -250.817, 1072.89, -249, 1074.14, -238.925, 1083.97, -225.906, 1094.51, -191.893, 1117.45, -97.9531, 1168.86, 52.6829, 1236.91, 52.6829, 1440, -576, 1440, -576, -584) +metadata/_edit_lock_ = true + +[node name="CollisionPolygon2D3" type="CollisionPolygon2D" parent="Rectangle/StaticBody2D"] +visible = false +polygon = PackedVector2Array(480.704, 1331.87, 248, 1200, 250.281, 1195.56, 252.125, 1191.25, 253.531, 1187.06, 254.5, 1183, 255.031, 1179.06, 255.125, 1175.25, 254.781, 1171.56, 254, 1168, 252.781, 1164.56, 251.125, 1161.25, 249.031, 1158.06, 246.5, 1155, 243.531, 1152.06, 240.125, 1149.25, 236.281, 1146.56, 232, 1144, 232.922, 1142.84, 234.179, 1140.88, 237.648, 1134.58, 248.063, 1112.8, 280, 1035.19, 366, 764.5, 407.313, 583.336, 439, 379.563, 454.688, 159.133, 448, -72, 446.909, -103.251, 443.64, -134.35, 438.21, -165.144, 430.645, -195.486, 420.982, -225.225, 409.268, -254.218, 395.561, -282.323, 379.926, -309.404, 362.44, -335.328, 343.188, -359.969, 322.264, -383.207, 299.771, -404.929, 275.816, -425.029, 250.518, -443.409, 224, -459.979, 196.39, -474.66, 167.824, -487.378, 138.44, -498.073, 108.381, -506.693, 77.7944, -513.194, 46.8288, -517.546, 20, -519.422, 20, -584, 480.704, -584) +disabled = true +metadata/_edit_lock_ = true + +[node name="CollisionPolygon2D4" type="CollisionPolygon2D" parent="Rectangle/StaticBody2D"] +visible = false +polygon = PackedVector2Array(20, -584, 20, -519.422, 15.635, -519.727, -15.635, -519.727, -46.8288, -517.546, -77.7944, -513.194, -108.381, -506.693, -138.44, -498.073, -167.824, -487.378, -196.39, -474.66, -224, -459.979, -250.518, -443.409, -275.816, -425.029, -299.771, -404.929, -322.264, -383.207, -343.188, -359.969, -362.44, -335.328, -379.926, -309.404, -395.561, -282.323, -409.268, -254.218, -420.982, -225.225, -430.645, -195.486, -438.21, -165.144, -443.64, -134.35, -446.909, -103.251, -448, -72, -445.883, 188.227, -426.063, 422.313, -354.5, 802.5, -275.688, 1049.44, -246.805, 1116.96, -237.312, 1135.69, -234.092, 1141.17, -232.9, 1142.92, -232, 1144, -240.09, 1148.14, -243.483, 1150.31, -246.469, 1152.53, -249.068, 1154.79, -251.301, 1157.09, -253.188, 1159.41, -254.75, 1161.75, -256.007, 1164.1, -256.98, 1166.44, -257.69, 1168.78, -258.156, 1171.09, -258.4, 1173.38, -258.441, 1175.64, -258.301, 1177.85, -258, 1180, -256.996, 1184.11, -255.594, 1187.91, -253.957, 1191.31, -252.25, 1194.25, -249.281, 1198.47, -248, 1200, -113.016, 1264.75, 18.875, 1316, 20, 1316.32, 20, 1440, -576, 1440, -576, -584) +disabled = true +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Rectangle"] +texture = SubResource("GradientTexture2D_mpo7f") +texture_offset = Vector2(576, 584) +polygon = PackedVector2Array(576, 1440, 52.6829, 1440, 52.6829, 1236.91, 145.625, 1278.89, 472, 1408, 473.712, 1410.55, 475.597, 1412.97, 477.647, 1415.26, 479.852, 1417.4, 482.2, 1419.38, 484.68, 1421.19, 487.281, 1422.82, 489.99, 1424.27, 492.793, 1425.53, 495.676, 1426.58, 498.626, 1427.44, 501.629, 1428.08, 504.669, 1428.52, 507.733, 1428.74, 510.804, 1428.74, 513.868, 1428.54, 516.91, 1428.11, 519.915, 1427.48, 522.87, 1426.64, 525.758, 1425.6, 528.566, 1424.36, 531.281, 1422.92, 533.889, 1421.3, 536.378, 1419.5, 538.735, 1417.53, 540.949, 1415.4, 543.009, 1413.12, 544.905, 1410.71, 546.628, 1408.17, 548.17, 1405.51, 549.522, 1402.75, 550.679, 1399.91, 551.634, 1396.99, 552.384, 1394.01, 552.924, 1390.99, 553.252, 1387.93, 553.366, 1384.86, 553.265, 1381.79, 552.951, 1378.74, 552.425, 1375.71, 551.688, 1372.73, 550.746, 1369.81, 549.602, 1366.96, 548.261, 1364.2, 546.732, 1361.53, 545.02, 1358.98, 543.135, 1356.56, 541.085, 1354.27, 538.88, 1352.13, 536.532, 1350.15, 534.051, 1348.34, 531.451, 1346.71, 528.742, 1345.26, 525.939, 1344.01, 523.056, 1342.95, 520.105, 1342.1, 517.103, 1341.45, 514.062, 1341.02, 510.999, 1340.8, 507.928, 1340.79, 504.864, 1341, 501.822, 1341.42, 498.816, 1342.05, 495.862, 1342.89, 492.974, 1343.93, 490.165, 1345.18, 487.451, 1346.61, 484.842, 1348.23, 482.354, 1350.03, 480, 1352, 228.333, 1078.67, 230.383, 1077.7, 232.36, 1076.59, 234.255, 1075.35, 236.058, 1073.97, 237.762, 1072.48, 239.356, 1070.87, 240.835, 1069.15, 242.19, 1067.33, 243.415, 1065.42, 244.504, 1063.44, 245.452, 1061.38, 246.254, 1059.26, 246.906, 1057.08, 247.405, 1054.87, 247.748, 1052.63, 247.934, 1050.37, 247.963, 1048.11, 247.833, 1045.84, 247.545, 1043.6, 247.102, 1041.37, 246.504, 1039.19, 245.755, 1037.05, 244.859, 1034.96, 243.82, 1032.95, 242.643, 1031.01, 241.333, 1029.16, 239.898, 1027.41, 238.344, 1025.76, 236.678, 1024.22, 234.91, 1022.8, 233.046, 1021.51, 231.097, 1020.35, 229.073, 1019.33, 226.982, 1018.46, 224.835, 1017.73, 222.642, 1017.16, 220.415, 1016.73, 218.163, 1016.47, 215.899, 1016.36, 213.633, 1016.41, 211.376, 1016.62, 209.139, 1016.99, 206.932, 1017.51, 204.768, 1018.18, 202.667, 1019, 204.93, 1016.24, 208.645, 1010.98, 219.99, 993.176, 255.25, 929.719, 301.386, 831.652, 351.333, 702, 398.031, 543.785, 434.417, 360.031, 453.427, 153.762, 448, -72, 446.909, -103.251, 443.64, -134.35, 438.21, -165.144, 430.645, -195.486, 420.982, -225.225, 409.268, -254.218, 395.561, -282.323, 379.926, -309.404, 362.44, -335.328, 343.188, -359.969, 322.264, -383.207, 299.771, -404.929, 275.816, -425.029, 250.518, -443.409, 224, -459.979, 196.39, -474.66, 167.824, -487.378, 138.44, -498.073, 108.381, -506.693, 77.7944, -513.194, 52.6828, -516.723, 52.6828, -584, 576, -584, 52.6828, -584, 52.6828, -516.723, 46.8288, -517.546, 15.635, -519.727, -15.635, -519.727, -46.8288, -517.546, -77.7944, -513.194, -108.381, -506.693, -138.44, -498.073, -167.824, -487.378, -196.39, -474.66, -224, -459.979, -250.518, -443.409, -275.816, -425.029, -299.771, -404.929, -322.264, -383.207, -343.188, -359.969, -362.44, -335.328, -379.926, -309.404, -395.561, -282.323, -409.268, -254.218, -420.982, -225.225, -430.645, -195.486, -438.21, -165.144, -443.64, -134.35, -446.909, -103.251, -448, -72, -445.146, 182.923, -423.384, 403.027, -388.412, 588.814, -345.929, 740.786, -301.633, 859.445, -261.223, 945.294, -230.398, 998.836, -220.361, 1013.65, -214.857, 1020.57, -216.767, 1019.45, -218.751, 1018.46, -220.8, 1017.61, -222.902, 1016.9, -225.049, 1016.35, -227.229, 1015.95, -229.431, 1015.69, -231.646, 1015.6, -233.863, 1015.66, -236.07, 1015.87, -238.256, 1016.23, -240.412, 1016.75, -242.526, 1017.42, -244.589, 1018.23, -246.59, 1019.19, -248.52, 1020.28, -250.369, 1021.5, -252.128, 1022.85, -253.788, 1024.32, -255.342, 1025.9, -256.782, 1027.59, -258.101, 1029.37, -259.292, 1031.24, -260.35, 1033.19, -261.269, 1035.2, -262.046, 1037.28, -262.675, 1039.41, -263.155, 1041.57, -263.483, 1043.76, -263.657, 1045.97, -263.676, 1048.19, -263.541, 1050.4, -263.252, 1052.6, -262.81, 1054.78, -262.217, 1056.91, -261.477, 1059, -260.593, 1061.03, -259.569, 1063, -258.411, 1064.89, -257.123, 1066.7, -255.713, 1068.41, -254.187, 1070.02, -252.552, 1071.51, -250.817, 1072.89, -249, 1074.14, -238.925, 1083.97, -225.906, 1094.51, -191.893, 1117.45, -97.9531, 1168.86, 52.6829, 1236.91, 52.6829, 1440, -576, 1440, -576, -584) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153], [154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242]] +metadata/_edit_lock_ = true + +[node name="CutoutOfRectangle" type="Node2D" parent="Rectangle" node_paths=PackedStringArray("polygon")] +position = Vector2(-450, 1146) +script = ExtResource("2_j5wjh") +polygon = NodePath("Polygon2D") +curve = SubResource("Curve2D_ara7v") +update_curve_at_runtime = true +arc_list = SubResource("Resource_8v3mp") + +[node name="Polygon2D" type="Polygon2D" parent="Rectangle/CutoutOfRectangle"] +texture = SubResource("GradientTexture2D_gdr51") +texture_offset = Vector2(-2, 1665.73) +polygon = PackedVector2Array(235.143, -125.429, 233.233, -126.554, 231.249, -127.543, 229.2, -128.392, 227.098, -129.095, 224.951, -129.651, 222.771, -130.055, 220.569, -130.306, 218.354, -130.402, 216.137, -130.344, 213.93, -130.132, 211.744, -129.766, 209.588, -129.248, 207.474, -128.582, 205.411, -127.769, 203.41, -126.815, 201.48, -125.723, 199.631, -124.499, 197.872, -123.149, 196.212, -121.68, 194.658, -120.099, 193.218, -118.413, 191.899, -116.631, 190.708, -114.761, 189.65, -112.813, 188.731, -110.795, 187.954, -108.719, 187.325, -106.593, 186.845, -104.428, 186.517, -102.236, 186.343, -100.025, 186.324, -97.8085, 186.459, -95.5955, 186.748, -93.3974, 187.191, -91.2249, 187.783, -89.0885, 188.523, -86.9986, 189.407, -84.9654, 190.431, -82.9988, 191.589, -81.1085, 192.877, -79.3035, 194.287, -77.5928, 195.813, -75.9846, 197.448, -74.4867, 199.183, -73.1066, 201, -71.8571, 211.075, -62.0258, 224.094, -51.487, 258.107, -28.5547, 352.047, 22.8571, 595.625, 132.893, 922, 262, 923.712, 264.55, 925.597, 266.974, 927.647, 269.261, 929.852, 271.399, 932.2, 273.379, 934.68, 275.189, 937.281, 276.823, 939.99, 278.271, 942.793, 279.526, 945.676, 280.583, 948.626, 281.436, 951.629, 282.081, 954.669, 282.515, 957.733, 282.736, 960.804, 282.743, 963.868, 282.536, 966.91, 282.115, 969.915, 281.483, 972.87, 280.643, 975.758, 279.599, 978.566, 278.356, 981.281, 276.92, 983.889, 275.299, 986.378, 273.499, 988.735, 271.53, 990.949, 269.402, 993.009, 267.124, 994.905, 264.708, 996.628, 262.166, 998.17, 259.51, 999.522, 256.752, 1000.68, 253.907, 1001.63, 250.989, 1002.38, 248.01, 1002.92, 244.987, 1003.25, 241.933, 1003.37, 238.864, 1003.27, 235.795, 1002.95, 232.74, 1002.42, 229.714, 1001.69, 226.733, 1000.75, 223.81, 999.602, 220.96, 998.261, 218.196, 996.732, 215.533, 995.02, 212.983, 993.135, 210.559, 991.085, 208.272, 988.88, 206.134, 986.532, 204.154, 984.051, 202.344, 981.451, 200.71, 978.742, 199.263, 975.939, 198.007, 973.056, 196.95, 970.105, 196.097, 967.103, 195.452, 964.062, 195.018, 960.999, 194.797, 957.928, 194.79, 954.864, 194.997, 951.822, 195.418, 948.816, 196.05, 945.862, 196.89, 942.974, 197.934, 940.165, 199.177, 937.451, 200.613, 934.842, 202.234, 932.354, 204.034, 930, 206, 678.333, -67.3333, 680.383, -68.3015, 682.36, -69.4104, 684.255, -70.6545, 686.058, -72.0277, 687.762, -73.5234, 689.356, -75.1342, 690.835, -76.8524, 692.19, -78.6696, 693.415, -80.5768, 694.504, -82.5649, 695.452, -84.6241, 696.254, -86.7444, 696.906, -88.9154, 697.405, -91.1266, 697.748, -93.3673, 697.934, -95.6264, 697.963, -97.8931, 697.833, -100.156, 697.545, -102.405, 697.102, -104.628, 696.504, -106.814, 695.755, -108.954, 694.859, -111.036, 693.82, -113.051, 692.643, -114.988, 691.333, -116.838, 689.898, -118.593, 688.344, -120.243, 686.678, -121.781, 684.91, -123.198, 683.046, -124.489, 681.097, -125.647, 679.073, -126.666, 676.982, -127.541, 674.835, -128.269, 672.642, -128.844, 670.415, -129.266, 668.163, -129.531, 665.899, -129.638, 663.633, -129.587, 661.376, -129.378, 659.139, -129.013, 656.932, -128.492, 654.768, -127.818, 652.667, -127, 654.93, -129.763, 658.645, -135.019, 669.99, -152.824, 705.25, -216.281, 751.386, -314.348, 801.333, -444, 848.031, -602.215, 884.417, -785.969, 903.427, -992.238, 898, -1218, 896.909, -1249.25, 893.64, -1280.35, 888.21, -1311.14, 880.645, -1341.49, 870.982, -1371.22, 859.268, -1400.22, 845.561, -1428.32, 829.926, -1455.4, 812.44, -1481.33, 793.188, -1505.97, 772.264, -1529.21, 749.771, -1550.93, 725.816, -1571.03, 700.518, -1589.41, 674, -1605.98, 646.39, -1620.66, 617.824, -1633.38, 588.44, -1644.07, 558.381, -1652.69, 527.794, -1659.19, 496.829, -1663.55, 465.635, -1665.73, 434.365, -1665.73, 403.171, -1663.55, 372.206, -1659.19, 341.619, -1652.69, 311.56, -1644.07, 282.176, -1633.38, 253.61, -1620.66, 226, -1605.98, 199.482, -1589.41, 174.184, -1571.03, 150.229, -1550.93, 127.736, -1529.21, 106.812, -1505.97, 87.5604, -1481.33, 70.0745, -1455.4, 54.4395, -1428.32, 40.7316, -1400.22, 29.0177, -1371.22, 19.3548, -1341.49, 11.7899, -1311.14, 6.35991, -1280.35, 3.09131, -1249.25, 2, -1218, 4.85379, -963.077, 26.6161, -742.973, 61.5882, -557.186, 104.071, -405.214, 148.367, -286.555, 188.777, -200.706, 219.602, -147.164, 229.639, -132.352) +metadata/_edit_lock_ = true + +[node name="LeftFlipper" parent="." instance=ExtResource("5_mfdv2")] +position = Vector2(-232, -96) + +[node name="RightFlipper" parent="." instance=ExtResource("5_mfdv2")] +position = Vector2(216, -96) +scale = Vector2(-1, 1) +flipping_up = true + +[node name="Butterfly" parent="." instance=ExtResource("6_j6l5u")] + +[node name="CatchBallArea2D" type="Area2D" parent="."] +position = Vector2(502, 286) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="CatchBallArea2D"] +position = Vector2(6.5, 1) +shape = SubResource("RectangleShape2D_1vgfy") + +[node name="Pinball" parent="." instance=ExtResource("6_iotsf")] +position = Vector2(376, -1000) + +[node name="ChasingLight" parent="." instance=ExtResource("7_lc2xo")] +position = Vector2(-140, -493) + +[node name="ChasingLight2" parent="." instance=ExtResource("7_lc2xo")] +position = Vector2(153, -492) + +[node name="ChasingLight3" parent="." instance=ExtResource("7_lc2xo")] +position = Vector2(-317, -1066) + +[node name="ChasingLight4" parent="." instance=ExtResource("7_lc2xo")] +position = Vector2(349, -1044) + +[node name="ChasingLight5" parent="." instance=ExtResource("7_lc2xo")] +position = Vector2(-113, -1094) + +[node name="ChasingLight6" parent="." instance=ExtResource("7_lc2xo")] +position = Vector2(131, -1102) + +[node name="ChasingLight7" parent="." instance=ExtResource("7_lc2xo")] +position = Vector2(12, -807) + +[connection signal="body_entered" from="CatchBallArea2D" to="." method="_on_catch_ball_area_2d_body_entered"] diff --git a/addons/curved_lines_2d/examples/pinball/pinball.gd b/addons/curved_lines_2d/examples/pinball/pinball.gd new file mode 100644 index 0000000..c738d32 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/pinball.gd @@ -0,0 +1,5 @@ +extends RigidBody2D + + +func _process(_delta: float) -> void: + $Gradient.rotation = -rotation diff --git a/addons/curved_lines_2d/examples/pinball/pinball.gd.uid b/addons/curved_lines_2d/examples/pinball/pinball.gd.uid new file mode 100644 index 0000000..ce6518a --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/pinball.gd.uid @@ -0,0 +1 @@ +uid://bsnpei7ltelnx diff --git a/addons/curved_lines_2d/examples/pinball/pinball.tscn b/addons/curved_lines_2d/examples/pinball/pinball.tscn new file mode 100644 index 0000000..36d5c24 --- /dev/null +++ b/addons/curved_lines_2d/examples/pinball/pinball.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=7 format=3 uid="uid://bwxjc7a0mapl0"] + +[ext_resource type="Script" uid="uid://bsnpei7ltelnx" path="res://addons/curved_lines_2d/examples/pinball/pinball.gd" id="1_t6ii5"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_ia8el"] +radius = 24.0 + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_48gu3"] + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_t6ii5"] +seamless = true +noise = SubResource("FastNoiseLite_48gu3") + +[sub_resource type="Gradient" id="Gradient_q2wd1"] +offsets = PackedFloat32Array(0.115583, 1) +colors = PackedColorArray(1, 1, 1, 1, 0.183594, 0.183594, 0.183594, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_qlygp"] +gradient = SubResource("Gradient_q2wd1") +width = 48 +height = 48 +fill = 1 +fill_from = Vector2(0.354167, 0.246528) +fill_to = Vector2(0.840278, 0.864583) + +[node name="Pinball" type="RigidBody2D" groups=["pinballs"]] +z_index = -1 +script = ExtResource("1_t6ii5") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("CircleShape2D_ia8el") + +[node name="Polygon2D" type="Polygon2D" parent="."] +texture_repeat = 2 +texture = SubResource("NoiseTexture2D_t6ii5") +polygon = PackedVector2Array(24, 0, 23.8761, 2.45392, 23.5124, 4.83694, 22.921, 7.137, 22.114, 9.34204, 21.1034, 11.44, 19.9013, 13.4188, 18.5197, 15.2664, 16.9707, 16.9707, 15.2664, 18.5197, 13.4188, 19.9013, 11.44, 21.1034, 9.34204, 22.114, 7.137, 22.921, 4.83694, 23.5124, 2.45392, 23.8761, 0, 24, -2.45392, 23.8761, -4.83694, 23.5124, -7.137, 22.921, -9.34204, 22.114, -11.44, 21.1034, -13.4188, 19.9013, -15.2664, 18.5197, -16.9707, 16.9707, -18.5197, 15.2664, -19.9013, 13.4188, -21.1034, 11.44, -22.114, 9.34204, -22.921, 7.137, -23.5124, 4.83694, -23.8761, 2.45392, -24, 0, -23.8761, -2.45392, -23.5124, -4.83694, -22.921, -7.137, -22.114, -9.34204, -21.1034, -11.44, -19.9013, -13.4188, -18.5197, -15.2664, -16.9707, -16.9707, -15.2664, -18.5197, -13.4188, -19.9013, -11.44, -21.1034, -9.34204, -22.114, -7.137, -22.921, -4.83694, -23.5124, -2.45392, -23.8761, 0, -24, 2.45392, -23.8761, 4.83694, -23.5124, 7.137, -22.921, 9.34204, -22.114, 11.44, -21.1034, 13.4188, -19.9013, 15.2664, -18.5197, 16.9707, -16.9707, 18.5197, -15.2664, 19.9013, -13.4188, 21.1034, -11.44, 22.114, -9.34204, 22.921, -7.137, 23.5124, -4.83694, 23.8761, -2.45392) +metadata/_edit_lock_ = true + +[node name="Gradient" type="Polygon2D" parent="."] +color = Color(1, 1, 1, 0.47451) +texture = SubResource("GradientTexture2D_qlygp") +texture_offset = Vector2(24, 24) +polygon = PackedVector2Array(24, 0, 23.8761, 2.45392, 23.5124, 4.83694, 22.921, 7.137, 22.114, 9.34204, 21.1034, 11.44, 19.9013, 13.4188, 18.5197, 15.2664, 16.9707, 16.9707, 15.2664, 18.5197, 13.4188, 19.9013, 11.44, 21.1034, 9.34204, 22.114, 7.137, 22.921, 4.83694, 23.5124, 2.45392, 23.8761, 0, 24, -2.45392, 23.8761, -4.83694, 23.5124, -7.137, 22.921, -9.34204, 22.114, -11.44, 21.1034, -13.4188, 19.9013, -15.2664, 18.5197, -16.9707, 16.9707, -18.5197, 15.2664, -19.9013, 13.4188, -21.1034, 11.44, -22.114, 9.34204, -22.921, 7.137, -23.5124, 4.83694, -23.8761, 2.45392, -24, 0, -23.8761, -2.45392, -23.5124, -4.83694, -22.921, -7.137, -22.114, -9.34204, -21.1034, -11.44, -19.9013, -13.4188, -18.5197, -15.2664, -16.9707, -16.9707, -15.2664, -18.5197, -13.4188, -19.9013, -11.44, -21.1034, -9.34204, -22.114, -7.137, -22.921, -4.83694, -23.5124, -2.45392, -23.8761, 0, -24, 2.45392, -23.8761, 4.83694, -23.5124, 7.137, -22.921, 9.34204, -22.114, 11.44, -21.1034, 13.4188, -19.9013, 15.2664, -18.5197, 16.9707, -16.9707, 18.5197, -15.2664, 19.9013, -13.4188, 21.1034, -11.44, 22.114, -9.34204, 22.921, -7.137, 23.5124, -4.83694, 23.8761, -2.45392) +metadata/_edit_lock_ = true + +[node name="Camera2D" type="Camera2D" parent="."] diff --git a/addons/curved_lines_2d/examples/pony.tscn b/addons/curved_lines_2d/examples/pony.tscn new file mode 100644 index 0000000..2573ac3 --- /dev/null +++ b/addons/curved_lines_2d/examples/pony.tscn @@ -0,0 +1,3560 @@ +[gd_scene load_steps=108 format=3 uid="uid://gmlmhdf0cxl8"] + +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="1_inuwg"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="2_trrx4"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="3_gghv2"] +[ext_resource type="Script" uid="uid://dn747ucen5o8b" path="res://addons/curved_lines_2d/svs_vertex_merge_2d.gd" id="4_p8hpb"] + +[sub_resource type="GDScript" id="GDScript_6k4l8"] +script/source = "extends Node2D + + +func _on_reset_pose_button_pressed() -> void: + $AnimationPlayer.play(\"RESET\") + + + +func _on_stagger_button_pressed() -> void: + $AnimationPlayer.play(\"stagger\") + + +func _on_close_mouth_button_pressed() -> void: + $AnimationPlayer.play(\"close_mouth\") + + +func _on_blink_button_pressed() -> void: + $AnimationPlayer.play(\"blink\") + + +func _on_open_mouth_button_pressed() -> void: + $AnimationPlayer.play(\"open_mouth\") +" + +[sub_resource type="Curve2D" id="Curve2D_gghv2"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 24.4414, -13.026, -52.9414, -33.224, 0, 0, 0, 0, 59.6188, -40.9053, 0, 0, -30.3618, 36.3833, 99.2969, -5.36705, 33.4447, 88.8218, 0, 0, -73.4447, 7.17824, -24.4414, 13.026, 0, 0, -52.9414, -33.224) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_p8hpb"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_nndv2"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 19.1353, 25.9584, 21.7024, -14.457, 5.16881, -20.5032, -15.8126, 8.11737, 27.3494, 78.1857, 7.29735, 6.45433, 2.21308, -23.9175, -6.96468, 83.7015, 9.24532, 35.92, 0, 0, -12.75, -3.25) +} +point_count = 4 + +[sub_resource type="Resource" id="Resource_nndv2"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve" id="Curve_d7gkk"] +_data = [Vector2(0, 0.123596), 0.0, 0.0, 0, 0, Vector2(0.28, 1), 0.0, 0.0, 0, 0, Vector2(0.725, 1), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_gy81n"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 25.3488, 3.06196, -5.87953, -24.608, -15.798, 8.43912, 27.1715, 73.4236, 16.202, 8.43912, -5.33333, -8, -20.8285, 73.4236, 0, 0, 0, 0, -8.5396, 10.7729) +} +point_count = 4 + +[sub_resource type="Resource" id="Resource_ipurh"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve" id="Curve_1ve1q"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0] +point_count = 1 + +[sub_resource type="Curve2D" id="Curve2D_inuwg"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 27.19, -1.95666, 0, 0, -18.1389, 15.7369, 22.9566, 90.574, 2.17223, 24.3741, 0, 0, -8.89595, 81.5466, 0, 0, 0, 0, -12.75, -3.25) +} +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_trrx4"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 24.5672, 10.8046, 0, 0, -15.798, 8.43912, 27.1715, 73.4236, 16.202, 8.43912, -5.33333, -8, -20.8285, 73.4236, 0, 0, 0, 0, -8.53989, 10.7727) +} +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_2jd1f"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -41.9709, -47.2013, 13.6271, -11.8026, 44.9163, -7.65238, 0, 0, -110.77, -73.1318, 0, 0, 0, 0, -101.872, -51.5176, 0, 0, 0, 0, -101.466, -27.786, 0, 0, 25.2829, -11.3116, -89.5158, -9.09912, -30.5652, -33.7253, 0, 0, -8, 27, 0, 0, 0, 0, -1.55304, 15.4331, 0, 0, 0, 0, 3.31161, 6.70516, 0, 0, 0, 0, 13.6271, -11.8026) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_gtrm0"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Gradient" id="Gradient_hytqm"] +colors = PackedColorArray(1, 0.0234375, 0, 1, 1, 0.961853, 0.0234375, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_d1cq6"] +gradient = SubResource("Gradient_hytqm") +width = 124 +height = 101 +fill_from = Vector2(0.181493, 0.51364) +fill_to = Vector2(0.703132, 0.375778) + +[sub_resource type="Curve2D" id="Curve2D_7tj20"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -25.2576, -26.2332, -1.55305, 15.4331, 34.2419, -12.5172, 0, 0, -101.466, -27.786) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_t2jyf"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_r5ynq"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -8.78005, -32.4297, 0.816067, 0.639946, 36.6793, -14.0018, 0, 0, -101.872, -51.5175) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_fwayd"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_1ve1q"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -5.10262, -46.7849, 0, 0, 0, 0, 40.5973, -22.6226, 0, 0, 0, 0, 25.2388, 3.93773, 0, 0, 0, 0, -17.3993, -27.9891, 0, 0, 0, 0, -5.10262, -46.7849) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_2jd1f"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_gtrm0"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -12.1017, 44.0403, 88.8385, -45.7059, 27.9212, 6.53257, -12.282, -3.06843, 30.681, 7.93027, 9.04167, 10.2389, 0, 0, -15.9463, -14.3899, 0, 33.138, 0, -33.138, -24.4827, -55.8203, -33.138, 0, 33.138, 0, 39.0523, -109.591, 7.91847, -34.4402, 0, 0, 88.8385, -45.7059) +} +point_count = 6 + +[sub_resource type="Resource" id="Resource_hytqm"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_hytqm"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -54.3072, -35.3798, 0, 0, 8.45951, 48.8759, -14.1477, -85.0489, 0, 0, 0, 0, 27.5123, -9.66228, 27.7082, -43.0843, -3.16883, -65.735, -42.9545, 80.1351, 24.1836, 24.5039, 0, 0, -54.3072, -35.3798) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_d1cq6"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Gradient" id="Gradient_7tj20"] +colors = PackedColorArray(1, 0.960784, 0.0235294, 1, 1, 0.027451, 0, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_t2jyf"] +gradient = SubResource("Gradient_7tj20") +width = 81 +height = 165 +fill_from = Vector2(0.129879, -0.242988) +fill_to = Vector2(1.01504, 1.18403) + +[sub_resource type="Curve2D" id="Curve2D_d1cq6"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 9.76573, 4.79903, 75.6559, 25.4058, -4.45378, -6.94, 0, 0, 96.6769, 41.2414, 13.3526, -21.6545, -13.3526, 21.6545, 112.022, 103.484, -6.08649, -23.5575, 6.08649, 23.5575, 69.1889, 189.13, -7.61893, 4.68524, 4.013, -2.19511, 114.557, 223.877, 2.3475, 4.97448, 0, 0, 119.302, 214.678, 0, 0, 0, 0, 114.691, 189.598, 0, 0, 5.03558, 11.6036, 130.665, 211.435, 15.9385, -1.40125, -15.9385, 1.40125, 105.657, 232.528, 6.30141, 2.28281, -6.30141, -2.28281, 64.0548, 222.042, 1.46579, 20.8485, -1.46579, -20.8485, 35.5347, 188.212, 2.78104, 21.8464, -2.78104, -21.8464, 85.5029, 87.3347, 17.4208, -8.62385, 0, 0, 54.5043, 60.459, 0, 0, -30.0897, -18.2423, 35.6321, 74.1644, 19.1169, -14.0631, -19.1169, 14.0631, -30.5683, 59.9526, -26.7269, -49.1511, 4.5521, 12.7226, -26.9482, 162.09, 0, 0, 0, 0, -39.7099, 193.86, 0, 0, -45.1943, -34.9456, -49.7804, 210.682, -14.9535, 28.0719, 0, 0, -88.2476, 84.1675, -18.2539, 15.6165, 12.4751, -11.6711, -64.859, 56.5772, -68.2705, -31.85, 0, 0, 75.6559, 25.4058) +} +point_count = 21 + +[sub_resource type="Resource" id="Resource_7tj20"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Gradient" id="Gradient_t2jyf"] +colors = PackedColorArray(1, 0.0235294, 0, 1, 1, 0.960784, 0.0235294, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_r5ynq"] +gradient = SubResource("Gradient_t2jyf") +width = 226 +height = 217 +fill_from = Vector2(0.868072, 1.00284) +fill_to = Vector2(0.366104, 0.0372316) + +[sub_resource type="Curve2D" id="Curve2D_fwayd"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 17.5101, -17.1831, -9.61644, -5.25069, -37.3112, -2.74139, 0, 0, 72.6156, -26.9133) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_rr8qp"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_t2jyf"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -19.9432, -8.15901, 0, 0, 0, 0, -25.0773, 24.753) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_r5ynq"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_rr8qp"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 26.0753, -19.4745, -1.11281, -0.872726, -36.8714, 0.142624, 0, 0, 93.3073, -30.2989) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_ej6pp"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve" id="Curve_r5ynq"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.39726, 1), 0.0, 0.0, 0, 0, Vector2(0.625571, 0.426966), 0.0, 0.0, 0, 0, Vector2(0.821918, 1), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_bjmri"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0.162262, 52.5931, 7.86132, -40.8235, -30.8461, -40.5656, 0, 0, 46.3285, 85.6911) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_w157y"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_ryeyi"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -14.8045, 47.4401, 7.65607, -7.64099, -37.951, -47.2524, 0, 0, 32.8052, 129.641) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_qpkqr"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_ej6pp"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 13.2965, 10.3081, 0, 5.69317, 0, -5.69317, 0, 0, 24.0747, 0, 13.2965, 0, -13.2965, -10.3081, 0, -5.69317, 0, 5.69317, 0, 0, -24.0747, 0, -13.2965, 0, 0, 10.3081, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_ayt5m"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_ayt5m"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0.99209, -0.0567052, -0.0906372, 0.273613, -1.68842, -1.73415, 0, 0, 4.57506, 2.69504, 0, 0, 0, 0, 18.9873, 11.8766) +} +point_count = 3 + +[sub_resource type="Resource" id="Resource_inuwg"] +script = ExtResource("2_trrx4") +start_point = 1 +radius = Vector2(20, 20) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_wlod0"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([SubResource("Resource_inuwg")]) + +[sub_resource type="Curve" id="Curve_ef0ch"] +_data = [Vector2(0.0349206, 0.700969), 0.0, 0.0, 0, 0, Vector2(1, 0.245536), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="Curve2D" id="Curve2D_wlod0"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 15.506, 12.4081, 0, 6.85302, 0, -6.85302, 0, 0, 28.0754, 0, 15.506, 0, -15.506, -12.4081, 0, -6.85302, 0, 6.85302, 0, 0, -28.0754, 0, -15.506, 0, 0, 12.4081, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_ef0ch"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Gradient" id="Gradient_ycisl"] +offsets = PackedFloat32Array(0.311863, 1) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_48nhp"] +gradient = SubResource("Gradient_ycisl") +width = 24 +height = 56 +fill = 1 +fill_from = Vector2(1.10846, 0.827872) +fill_to = Vector2(-0.0453812, -0.141333) + +[sub_resource type="Curve2D" id="Curve2D_p0i0j"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 13.8075, 12, 0, 6.6276, 0, -6.6276, 0, 0, 25, 0, 13.8075, 0, -13.8075, -12, 0, -6.6276, 0, 6.6276, 0, 0, -25, 0, -13.8075, 0, 0, 12, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_s3xq1"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_lkcyw"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 6.6276, 8, 0, 4.4184, 0, -4.4184, 0, 0, 12, 0, 6.6276, 0, -6.6276, -8, 0, -4.4184, 0, 4.4184, 0, 0, -12, 0, -6.6276, 0, 0, 8, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_ye2us"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_48nhp"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 1.14246, 0.89263, 0, 0.493, 0, -0.493, 0, 0, 2.06855, 0, 1.14246, 0, -1.14246, -0.89263, 0, -0.493, 0, 0.493, 0, 0, -2.06855, 0, -1.14246, 0, 0, 0.89263, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_13sh3"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve" id="Curve_inuwg"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.628571, 0.452806), 1.60714, 1.60714, 0, 0, Vector2(0.834921, 1), 0.0, 0.0, 0, 0, Vector2(0.92381, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_ycisl"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 2.54356, 0.664536, 0, 0, 0, 0, -8.80157, -18.014, 0, 0, 0, 0, -13.745, 9.15728) +} +point_count = 3 + +[sub_resource type="Resource" id="Resource_48nhp"] +script = ExtResource("2_trrx4") +start_point = 1 +radius = Vector2(20, 20) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_p0i0j"] +script = ExtResource("2_trrx4") +start_point = 0 +radius = Vector2(20, 20) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_lkcyw"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([SubResource("Resource_48nhp"), SubResource("Resource_p0i0j")]) + +[sub_resource type="Curve" id="Curve_ye2us"] +_data = [Vector2(0, 0.568878), 0.0, 0.0, 0, 0, Vector2(0.539683, 0.676658), 0.0, 0.0, 0, 0, Vector2(0.968254, 0.991709), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_ef0ch"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 6.13687, -3.51773, -15.597, -6.92982, 0.423523, 5.78717, 20.6588, 25.7082, 11.829, -1.05778, -11.829, 1.05778, 5.65263, 43.6499, 0, 0, 0, 0, -11.0152, 25.8978) +} +point_count = 4 + +[sub_resource type="Resource" id="Resource_ycisl"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve" id="Curve_48nhp"] +_data = [Vector2(0, 0.0216837), 0.0, 0.0, 0, 0, Vector2(0.52381, 1), 0.0, 0.0, 0, 0, Vector2(0.698413, 1), 0.0, -2.61161, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_s3xq1"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -0.977737, 18.8678, 21.446, 0.794495, 9.55051, -0.934471, -9.55051, 0.934471, 0, 28.4301, 2.13377, 16.4391, 0, 0, -19.412, 11.5617, -5.547, 7.10938, 5.547, -7.10938, -14.2871, -9.32756, -6.6368, 1.44151, 6.6368, -1.44151, 4.63549, -25.614, 0.977737, -18.8678, 0, 0, 21.446, 0.794495) +} +point_count = 6 + +[sub_resource type="Resource" id="Resource_ala13"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_ye2us"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -0.0906372, 0.273613, 0, 0, 0, 0, 14.1008, 9.53712) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_bjmri"] +script = ExtResource("2_trrx4") +start_point = 0 +radius = Vector2(20, 20) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_lno47"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([SubResource("Resource_bjmri")]) + +[sub_resource type="Curve2D" id="Curve2D_13sh3"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 13.3232, 17.774, 0, 9.81658, 0, -9.81658, 0, 0, 24.1231, 0, 13.3232, 0, -13.3232, -17.774, 0, -9.81658, 0, 9.81658, 0, 0, -24.1231, 0, -13.3232, 0, 0, 17.774, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_xhpvu"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Gradient" id="Gradient_bjmri"] +offsets = PackedFloat32Array(0.356469, 1) +colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_lno47"] +gradient = SubResource("Gradient_bjmri") +width = 35 +height = 48 +fill = 1 +fill_from = Vector2(0.79337, 0.735999) +fill_to = Vector2(-0.0216875, 0.0835365) + +[sub_resource type="Curve2D" id="Curve2D_78whv"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 12.4997, 15.6026, 0, 8.61732, 0, -8.61732, 0, 0, 22.6322, 0, 12.4997, 0, -12.4997, -15.6026, 0, -8.61732, 0, 8.61732, 0, 0, -22.6322, 0, -12.4997, 0, 0, 15.6026, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_y8bhp"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_w157y"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 6.6276, 8, 0, 4.4184, 0, -4.4184, 0, 0, 12, 0, 6.6276, 0, -6.6276, -8, 0, -4.4184, 0, 4.4184, 0, 0, -12, 0, -6.6276, 0, 0, 8, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_7717w"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_ala13"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 1.1046, 2, 0, 1.1046, 0, -1.1046, 0, 0, 2, 0, 1.1046, 0, -1.1046, -2, 0, -1.1046, 0, 1.1046, 0, 0, -2, 0, -1.1046, 0, 0, 2, 0) +} +point_count = 5 + +[sub_resource type="Curve" id="Curve_ryeyi"] +_data = [Vector2(0.403175, 0), 0.0, 0.0, 0, 0, Vector2(0.803175, 1), 0.0492753, 0.0492753, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 3 + +[sub_resource type="Curve2D" id="Curve2D_xhpvu"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -21.8442, -20.3022, -0.216156, 0.27977, -18.1455, 11.1495, 7.08963, 2.87126, -3.74375, -64.5483, -2.46992, -20.4351, 0, 0, 26.0354, -13.4283) +} +point_count = 3 + +[sub_resource type="Resource" id="Resource_78whv"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve" id="Curve_y8bhp"] +_data = [Vector2(0, 0.121174), 0.0, 0.0, 0, 0, Vector2(0.28254, 1), 0.0, 0.0, 0, 0, Vector2(0.75873, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.096301), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_7717w"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -7.8454, -7.75524, 0.0507202, -0.158768, -3.70908, 11.0626, 0, 0, -6.15376, -28.3856) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_ryeyi"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve" id="Curve_qpkqr"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.453968, 1), 0.0, 0.0, 0, 0, Vector2(0.669841, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_p8hpb"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -0.140676, 25.4729, 27.19, -1.95666, 0, 0, -11.0904, 3.76456, 21.3743, 73.1478, 7.12278, 15.1901, 0, 0, -10.7541, 70.2118, 9.24532, 35.92, 0, 0, -12.75, -3.25) +} +point_count = 4 + +[sub_resource type="Curve" id="Curve_p8hpb"] +_data = [Vector2(0, 0.123596), 0.0, 0.0, 0, 0, Vector2(0.28, 1), 0.0, 0.0, 0, 0, Vector2(0.725, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_6svqr"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 19.1051, 0.926422, -5.87953, -24.608, -15.798, 8.43912, 27.1715, 73.4236, 16.202, 8.43912, -5.33333, -8, -20.8285, 73.4236, 0, 0, 0, 0, -12.7553, -4.14976) +} +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_ipurh"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 24.5918, 4.49943, 14.2393, -32.027, -11.5791, 13.3461, 27.781, 73.18, 11.1599, 8.89924, -3.20073, -29.4281, -4.78858, 85.3084, 0, 0, 0, 0, -12.0539, 10.9409) +} +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_d7gkk"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 25.3487, 3.06203, -5.87953, -24.608, -15.798, 8.43912, 27.1715, 73.4236, 16.202, 8.43912, -5.33333, -8, -20.8285, 73.4236, 0, 0, 0, 0, -8.5396, 10.7729) +} +point_count = 4 + +[sub_resource type="Curve2D" id="Curve2D_lno47"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, -13.0486, -3.19907, -0.0625, 0.125, 0.259254, 2.81481, -0.259254, -2.81481, -14.963, -11.4444, -5.34492, -4.39352, 0.469902, -5.09722, -6.0625, -15.125, -2.76389, -3.3912, 2.76389, 3.3912, 3.22221, -18.5185, 6.39583, -10.4954, 0, 0, -0.0625, 0.125) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_hc35e"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Curve2D" id="Curve2D_y6oqb"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 1.03448, -0.310345, -3, -4, -0.758621, -0.275862, 0.758621, 0.275862, 0, -1.55172, -0.344833, -0.896553, 0.344833, 0.896553, 2.17242, -0.896551, 0.206902, -0.517242, -0.206902, 0.517242, 0.93103, 1.13793, 0.689659, -0.241379, -0.689659, 0.241379, 0.482758, 4.75862, 0.55172, 0.413794, -0.55172, -0.413794, -2.24138, 2.24138, 0.620689, 0.793104, -0.620689, -0.793104, -4.62069, 1.89655, -0.275856, 0.689655, 0.275856, -0.689655, -3.31035, -0.344828, -1.03448, 0.310345, 0, 0, -3, -4) +} +point_count = 9 + +[sub_resource type="Resource" id="Resource_g8ae8"] +resource_local_to_scene = true +script = ExtResource("3_gghv2") +arcs = Array[ExtResource("2_trrx4")]([]) + +[sub_resource type="Animation" id="Animation_mbs44"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Body/Neck/Head/Mouth:curve:point_2/position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-13.745, 9.15728)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Body/Neck/Head/EyeFront:curve:point_0/position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(21.446, 0.794495)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Body/Neck/Head/EyeFront:curve:point_0/out") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-0.977737, 18.8678)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Body/Neck/Head/EyeFront:curve:point_1/position") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 28.4301)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Body/Neck/Head/EyeFront:curve:point_1/in") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(9.55051, -0.934471)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Body/Neck/Head/EyeFront:curve:point_1/out") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-9.55051, 0.934471)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Body/Neck/Head/EyeFront:curve:point_2/position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-19.412, 11.5617)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Body/Neck/Head/EyeFront:curve:point_2/in") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.13377, 16.4391)] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Body/Neck/Head/EyeFront:curve:point_2/out") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 0)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Body/Neck/Head/EyeFront:curve:point_3/position") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-14.2871, -9.32756)] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Body/Neck/Head/EyeFront:curve:point_3/in") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-5.547, 7.10938)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Body/Neck/Head/EyeFront:curve:point_3/out") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(5.547, -7.10938)] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Body/Neck/Head/EyeFront:curve:point_4/position") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(4.63549, -25.614)] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("Body/Neck/Head/EyeFront:curve:point_4/in") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-6.6368, 1.44151)] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("Body/Neck/Head/EyeFront:curve:point_4/out") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(6.6368, -1.44151)] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("Body/Neck/Head/EyeFront:curve:point_5/position") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(21.446, 0.794495)] +} +tracks/16/type = "value" +tracks/16/imported = false +tracks/16/enabled = true +tracks/16/path = NodePath("Body/Neck/Head/EyeFront:curve:point_5/in") +tracks/16/interp = 1 +tracks/16/loop_wrap = true +tracks/16/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0.977737, -18.8678)] +} +tracks/17/type = "value" +tracks/17/imported = false +tracks/17/enabled = true +tracks/17/path = NodePath("Body/BackFrontLeg/LowerLeg:position") +tracks/17/interp = 1 +tracks/17/loop_wrap = true +tracks/17/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.25, 73.5)] +} +tracks/18/type = "value" +tracks/18/imported = false +tracks/18/enabled = true +tracks/18/path = NodePath("Body/BackFrontLeg/LowerLeg:rotation") +tracks/18/interp = 1 +tracks/18/loop_wrap = true +tracks/18/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.132747] +} +tracks/19/type = "value" +tracks/19/imported = false +tracks/19/enabled = true +tracks/19/path = NodePath("Body/BackFrontLeg:position") +tracks/19/interp = 1 +tracks/19/loop_wrap = true +tracks/19/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-60, -2)] +} +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath("Body/BackFrontLeg:rotation") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.138036] +} +tracks/21/type = "value" +tracks/21/imported = false +tracks/21/enabled = true +tracks/21/path = NodePath("Body/FrontFrontLeg/LowerLeg:position") +tracks/21/interp = 1 +tracks/21/loop_wrap = true +tracks/21/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.25, 73.5)] +} +tracks/22/type = "value" +tracks/22/imported = false +tracks/22/enabled = true +tracks/22/path = NodePath("Body/FrontFrontLeg/LowerLeg:rotation") +tracks/22/interp = 1 +tracks/22/loop_wrap = true +tracks/22/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.0668674] +} +tracks/23/type = "value" +tracks/23/imported = false +tracks/23/enabled = true +tracks/23/path = NodePath("Body/FrontFrontLeg:position") +tracks/23/interp = 1 +tracks/23/loop_wrap = true +tracks/23/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(40, -4)] +} +tracks/24/type = "value" +tracks/24/imported = false +tracks/24/enabled = true +tracks/24/path = NodePath("Body/FrontFrontLeg:rotation") +tracks/24/interp = 1 +tracks/24/loop_wrap = true +tracks/24/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.0792349] +} +tracks/25/type = "value" +tracks/25/imported = false +tracks/25/enabled = true +tracks/25/path = NodePath("Body/Neck/Head/Ear:position") +tracks/25/interp = 1 +tracks/25/loop_wrap = true +tracks/25/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(3.42202, -63.7032)] +} +tracks/26/type = "value" +tracks/26/imported = false +tracks/26/enabled = true +tracks/26/path = NodePath("Body/Neck/Head/Ear:rotation") +tracks/26/interp = 1 +tracks/26/loop_wrap = true +tracks/26/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.436805] +} +tracks/27/type = "value" +tracks/27/imported = false +tracks/27/enabled = true +tracks/27/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine2:position") +tracks/27/interp = 1 +tracks/27/loop_wrap = true +tracks/27/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(6.48325, 4.35518)] +} +tracks/28/type = "value" +tracks/28/imported = false +tracks/28/enabled = true +tracks/28/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine2:rotation") +tracks/28/interp = 1 +tracks/28/loop_wrap = true +tracks/28/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/29/type = "value" +tracks/29/imported = false +tracks/29/enabled = true +tracks/29/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine:position") +tracks/29/interp = 1 +tracks/29/loop_wrap = true +tracks/29/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1.03037, -9.94677)] +} +tracks/30/type = "value" +tracks/30/imported = false +tracks/30/enabled = true +tracks/30/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine:rotation") +tracks/30/interp = 1 +tracks/30/loop_wrap = true +tracks/30/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.236561] +} +tracks/31/type = "value" +tracks/31/imported = false +tracks/31/enabled = true +tracks/31/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil:position") +tracks/31/interp = 1 +tracks/31/loop_wrap = true +tracks/31/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-3.08707, -0.685577)] +} +tracks/32/type = "value" +tracks/32/imported = false +tracks/32/enabled = true +tracks/32/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil:rotation") +tracks/32/interp = 1 +tracks/32/loop_wrap = true +tracks/32/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/33/type = "value" +tracks/33/imported = false +tracks/33/enabled = true +tracks/33/path = NodePath("Body/Neck/Head/EyeFront/Iris:position") +tracks/33/interp = 1 +tracks/33/loop_wrap = true +tracks/33/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-5.45288, 5.5916)] +} +tracks/34/type = "value" +tracks/34/imported = false +tracks/34/enabled = true +tracks/34/path = NodePath("Body/Neck/Head/EyeFront/Iris:rotation") +tracks/34/interp = 1 +tracks/34/loop_wrap = true +tracks/34/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/35/type = "value" +tracks/35/imported = false +tracks/35/enabled = true +tracks/35/path = NodePath("Body/Neck/Head/EyeFront/Lash:position") +tracks/35/interp = 1 +tracks/35/loop_wrap = true +tracks/35/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-14.2871, -9.32756)] +} +tracks/36/type = "value" +tracks/36/imported = false +tracks/36/enabled = true +tracks/36/path = NodePath("Body/Neck/Head/EyeFront/Lash:rotation") +tracks/36/interp = 1 +tracks/36/loop_wrap = true +tracks/36/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [2.24227] +} +tracks/37/type = "value" +tracks/37/imported = false +tracks/37/enabled = true +tracks/37/path = NodePath("Body/Neck/Head/EyeFront:position") +tracks/37/interp = 1 +tracks/37/loop_wrap = true +tracks/37/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(32.107, -44.2939)] +} +tracks/38/type = "value" +tracks/38/imported = false +tracks/38/enabled = true +tracks/38/path = NodePath("Body/Neck/Head/EyeFront:rotation") +tracks/38/interp = 1 +tracks/38/loop_wrap = true +tracks/38/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/39/type = "value" +tracks/39/imported = false +tracks/39/enabled = true +tracks/39/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil/PupilShine2:position") +tracks/39/interp = 1 +tracks/39/loop_wrap = true +tracks/39/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(1.24684, 7.96526)] +} +tracks/40/type = "value" +tracks/40/imported = false +tracks/40/enabled = true +tracks/40/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil/PupilShine2:rotation") +tracks/40/interp = 1 +tracks/40/loop_wrap = true +tracks/40/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/41/type = "value" +tracks/41/imported = false +tracks/41/enabled = true +tracks/41/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil:position") +tracks/41/interp = 1 +tracks/41/loop_wrap = true +tracks/41/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1.09432, 3.43547)] +} +tracks/42/type = "value" +tracks/42/imported = false +tracks/42/enabled = true +tracks/42/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil:rotation") +tracks/42/interp = 1 +tracks/42/loop_wrap = true +tracks/42/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/43/type = "value" +tracks/43/imported = false +tracks/43/enabled = true +tracks/43/path = NodePath("Body/Neck/Head/Eye/Iris:position") +tracks/43/interp = 1 +tracks/43/loop_wrap = true +tracks/43/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-5.11155, -3.27573)] +} +tracks/44/type = "value" +tracks/44/imported = false +tracks/44/enabled = true +tracks/44/path = NodePath("Body/Neck/Head/Eye/Iris:rotation") +tracks/44/interp = 1 +tracks/44/loop_wrap = true +tracks/44/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/45/type = "value" +tracks/45/imported = false +tracks/45/enabled = true +tracks/45/path = NodePath("Body/Neck/Head/Eye/Lash:position") +tracks/45/interp = 1 +tracks/45/loop_wrap = true +tracks/45/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(1.52588e-05, -24.0747)] +} +tracks/46/type = "value" +tracks/46/imported = false +tracks/46/enabled = true +tracks/46/path = NodePath("Body/Neck/Head/Eye/Lash:rotation") +tracks/46/interp = 1 +tracks/46/loop_wrap = true +tracks/46/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.456177] +} +tracks/47/type = "value" +tracks/47/imported = false +tracks/47/enabled = true +tracks/47/path = NodePath("Body/Neck/Head/Eye:position") +tracks/47/interp = 1 +tracks/47/loop_wrap = true +tracks/47/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(86.1287, -46.8739)] +} +tracks/48/type = "value" +tracks/48/imported = false +tracks/48/enabled = true +tracks/48/path = NodePath("Body/Neck/Head/Eye:rotation") +tracks/48/interp = 1 +tracks/48/loop_wrap = true +tracks/48/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0577994] +} +tracks/49/type = "value" +tracks/49/imported = false +tracks/49/enabled = true +tracks/49/path = NodePath("Body/Neck/Head/Hair:position") +tracks/49/interp = 1 +tracks/49/loop_wrap = true +tracks/49/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(28.6955, -149.617)] +} +tracks/50/type = "value" +tracks/50/imported = false +tracks/50/enabled = true +tracks/50/path = NodePath("Body/Neck/Head/Hair:rotation") +tracks/50/interp = 1 +tracks/50/loop_wrap = true +tracks/50/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.068965] +} +tracks/51/type = "value" +tracks/51/imported = false +tracks/51/enabled = true +tracks/51/path = NodePath("Body/Neck/Head:position") +tracks/51/interp = 1 +tracks/51/loop_wrap = true +tracks/51/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(10.257, -31.7704)] +} +tracks/52/type = "value" +tracks/52/imported = false +tracks/52/enabled = true +tracks/52/path = NodePath("Body/Neck/Head:rotation") +tracks/52/interp = 1 +tracks/52/loop_wrap = true +tracks/52/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0398988] +} +tracks/53/type = "value" +tracks/53/imported = false +tracks/53/enabled = true +tracks/53/path = NodePath("Body/Neck:position") +tracks/53/interp = 1 +tracks/53/loop_wrap = true +tracks/53/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(74.5, -11.5)] +} +tracks/54/type = "value" +tracks/54/imported = false +tracks/54/enabled = true +tracks/54/path = NodePath("Body/Neck:rotation") +tracks/54/interp = 1 +tracks/54/loop_wrap = true +tracks/54/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0876902] +} +tracks/55/type = "value" +tracks/55/imported = false +tracks/55/enabled = true +tracks/55/path = NodePath("Body/Tail:position") +tracks/55/interp = 1 +tracks/55/loop_wrap = true +tracks/55/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-53, -16)] +} +tracks/56/type = "value" +tracks/56/imported = false +tracks/56/enabled = true +tracks/56/path = NodePath("Body/Tail:rotation") +tracks/56/interp = 1 +tracks/56/loop_wrap = true +tracks/56/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.951901] +} +tracks/57/type = "value" +tracks/57/imported = false +tracks/57/enabled = true +tracks/57/path = NodePath("Body/FrontBackLeg/LowerLeg:position") +tracks/57/interp = 1 +tracks/57/loop_wrap = true +tracks/57/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.25, 73.5)] +} +tracks/58/type = "value" +tracks/58/imported = false +tracks/58/enabled = true +tracks/58/path = NodePath("Body/FrontBackLeg/LowerLeg:rotation") +tracks/58/interp = 1 +tracks/58/loop_wrap = true +tracks/58/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.275205] +} +tracks/59/type = "value" +tracks/59/imported = false +tracks/59/enabled = true +tracks/59/path = NodePath("Body/FrontBackLeg:position") +tracks/59/interp = 1 +tracks/59/loop_wrap = true +tracks/59/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(40, -3.8147e-06)] +} +tracks/60/type = "value" +tracks/60/imported = false +tracks/60/enabled = true +tracks/60/path = NodePath("Body/FrontBackLeg:rotation") +tracks/60/interp = 1 +tracks/60/loop_wrap = true +tracks/60/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.469617] +} +tracks/61/type = "value" +tracks/61/imported = false +tracks/61/enabled = true +tracks/61/path = NodePath("Body/BackBackLeg/LowerLeg:position") +tracks/61/interp = 1 +tracks/61/loop_wrap = true +tracks/61/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.25, 73.5)] +} +tracks/62/type = "value" +tracks/62/imported = false +tracks/62/enabled = true +tracks/62/path = NodePath("Body/BackBackLeg/LowerLeg:rotation") +tracks/62/interp = 1 +tracks/62/loop_wrap = true +tracks/62/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0643497] +} +tracks/63/type = "value" +tracks/63/imported = false +tracks/63/enabled = true +tracks/63/path = NodePath("Body/BackBackLeg:position") +tracks/63/interp = 1 +tracks/63/loop_wrap = true +tracks/63/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-54, -4)] +} +tracks/64/type = "value" +tracks/64/imported = false +tracks/64/enabled = true +tracks/64/path = NodePath("Body/BackBackLeg:rotation") +tracks/64/interp = 1 +tracks/64/loop_wrap = true +tracks/64/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.0282668] +} +tracks/65/type = "value" +tracks/65/imported = false +tracks/65/enabled = true +tracks/65/path = NodePath("Body:position") +tracks/65/interp = 1 +tracks/65/loop_wrap = true +tracks/65/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 0)] +} +tracks/66/type = "value" +tracks/66/imported = false +tracks/66/enabled = true +tracks/66/path = NodePath("Body:rotation") +tracks/66/interp = 1 +tracks/66/loop_wrap = true +tracks/66/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} + +[sub_resource type="Animation" id="Animation_6k4l8"] +resource_name = "blink" +length = 0.4 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Body/Neck/Head/EyeFront:curve:point_0/position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(21.446, 0.794495), Vector2(20.4251, -2.68896), Vector2(20.4251, -2.68896), Vector2(21.446, 0.794495)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Body/Neck/Head/EyeFront:curve:point_0/out") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-0.977737, 18.8678), Vector2(0.057373, 1.75699), Vector2(0.057373, 1.75699), Vector2(-0.977737, 18.8678)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Body/Neck/Head/EyeFront:curve:point_1/position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(0, 28.4301), Vector2(3.85795, -6.97078), Vector2(3.85795, -6.97078), Vector2(0, 28.4301)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Body/Neck/Head/EyeFront:curve:point_1/in") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(9.55051, -0.934471), Vector2(8.95242, 0.363831), Vector2(8.95242, 0.363831), Vector2(9.55051, -0.934471)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Body/Neck/Head/EyeFront:curve:point_1/out") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-9.55051, 0.934471), Vector2(-8.95242, -0.363831), Vector2(-8.95242, -0.363831), Vector2(-9.55051, 0.934471)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Body/Neck/Head/EyeFront:curve:point_2/position") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-19.412, 11.5617), Vector2(-16.5947, -4.4091), Vector2(-16.5947, -4.4091), Vector2(-19.412, 11.5617)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Body/Neck/Head/EyeFront:curve:point_2/in") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(2.13377, 16.4391), Vector2(0, 0), Vector2(0, 0), Vector2(2.13377, 16.4391)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Body/Neck/Head/EyeFront:curve:point_2/out") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(0, 0), Vector2(0, 0), Vector2(0, 0)] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Body/Neck/Head/EyeFront:curve:point_3/position") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-14.2871, -9.32756), Vector2(-16.33, -4.42479), Vector2(-16.33, -4.42479), Vector2(-14.2871, -9.32756)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Body/Neck/Head/EyeFront:curve:point_3/in") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-5.547, 7.10938), Vector2(0, 0), Vector2(0, 0), Vector2(-5.547, 7.10938)] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Body/Neck/Head/EyeFront:curve:point_3/out") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(5.547, -7.10938), Vector2(1.11481, -1.14967), Vector2(1.11481, -1.14967), Vector2(5.547, -7.10938)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Body/Neck/Head/EyeFront:curve:point_4/position") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(4.63549, -25.614), Vector2(4.39856, -8.22367), Vector2(4.39856, -8.22367), Vector2(4.63549, -25.614)] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Body/Neck/Head/EyeFront:curve:point_4/in") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-6.6368, 1.44151), Vector2(-6.94746, -0.453003), Vector2(-6.94746, -0.453003), Vector2(-6.6368, 1.44151)] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("Body/Neck/Head/EyeFront:curve:point_4/out") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(6.6368, -1.44151), Vector2(6.94746, 0.453003), Vector2(6.94746, 0.453003), Vector2(6.6368, -1.44151)] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("Body/Neck/Head/EyeFront:curve:point_5/position") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(21.446, 0.794495), Vector2(20.4251, -2.68896), Vector2(20.4251, -2.68896), Vector2(21.446, 0.794495)] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("Body/Neck/Head/EyeFront:curve:point_5/in") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(0.977737, -18.8678), Vector2(-0.311813, -3.74073), Vector2(-0.311813, -3.74073), Vector2(0.977737, -18.8678)] +} + +[sub_resource type="Animation" id="Animation_fdul0"] +resource_name = "close_mouth" +length = 0.1 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Body/Neck/Head/Mouth:curve:point_2/position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-13.745, 9.15728), Vector2(2.44629, 0.755123)] +} + +[sub_resource type="Animation" id="Animation_7nlme"] +resource_name = "open_mouth" +length = 0.1 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Body/Neck/Head/Mouth:curve:point_2/position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(2.44629, 0.755123), Vector2(-13.745, 9.15728)] +} + +[sub_resource type="Animation" id="Animation_xtm0y"] +resource_name = "stagger" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Body/BackFrontLeg/LowerLeg:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.25, 73.5)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Body/BackFrontLeg/LowerLeg:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.132747] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Body/BackFrontLeg:position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-60, -2)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Body/BackFrontLeg:rotation") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.2, 0.4), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.138036, 0.604681, 0.806003] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Body/FrontFrontLeg/LowerLeg:position") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.25, 73.5)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Body/FrontFrontLeg/LowerLeg:rotation") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 0.4), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [-0.0668674, 0.612558] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Body/FrontFrontLeg:position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(40, -4)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Body/FrontFrontLeg:rotation") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 0.4), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [-0.0792349, -0.264371] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Body/Neck/Head/Ear:position") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(3.42202, -63.7032)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Body/Neck/Head/Ear:rotation") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.436805] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine2:position") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(6.48325, 4.35518)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine2:rotation") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine:position") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1.03037, -9.94677)] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine:rotation") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.236561] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil:position") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-3.08707, -0.685577)] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("Body/Neck/Head/EyeFront/Iris/Pupil:rotation") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/16/type = "value" +tracks/16/imported = false +tracks/16/enabled = true +tracks/16/path = NodePath("Body/Neck/Head/EyeFront/Iris:position") +tracks/16/interp = 1 +tracks/16/loop_wrap = true +tracks/16/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-5.45288, 5.5916)] +} +tracks/17/type = "value" +tracks/17/imported = false +tracks/17/enabled = true +tracks/17/path = NodePath("Body/Neck/Head/EyeFront/Iris:rotation") +tracks/17/interp = 1 +tracks/17/loop_wrap = true +tracks/17/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/18/type = "value" +tracks/18/imported = false +tracks/18/enabled = true +tracks/18/path = NodePath("Body/Neck/Head/EyeFront/Lash:position") +tracks/18/interp = 1 +tracks/18/loop_wrap = true +tracks/18/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-14.2871, -9.32756)] +} +tracks/19/type = "value" +tracks/19/imported = false +tracks/19/enabled = true +tracks/19/path = NodePath("Body/Neck/Head/EyeFront/Lash:rotation") +tracks/19/interp = 1 +tracks/19/loop_wrap = true +tracks/19/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [2.24227] +} +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath("Body/Neck/Head/EyeFront:position") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(32.107, -44.2939)] +} +tracks/21/type = "value" +tracks/21/imported = false +tracks/21/enabled = true +tracks/21/path = NodePath("Body/Neck/Head/EyeFront:rotation") +tracks/21/interp = 1 +tracks/21/loop_wrap = true +tracks/21/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/22/type = "value" +tracks/22/imported = false +tracks/22/enabled = true +tracks/22/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil/PupilShine2:position") +tracks/22/interp = 1 +tracks/22/loop_wrap = true +tracks/22/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(1.24684, 7.96526)] +} +tracks/23/type = "value" +tracks/23/imported = false +tracks/23/enabled = true +tracks/23/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil/PupilShine2:rotation") +tracks/23/interp = 1 +tracks/23/loop_wrap = true +tracks/23/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/24/type = "value" +tracks/24/imported = false +tracks/24/enabled = true +tracks/24/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil:position") +tracks/24/interp = 1 +tracks/24/loop_wrap = true +tracks/24/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1.09432, 3.43547)] +} +tracks/25/type = "value" +tracks/25/imported = false +tracks/25/enabled = true +tracks/25/path = NodePath("Body/Neck/Head/Eye/Iris/Pupil:rotation") +tracks/25/interp = 1 +tracks/25/loop_wrap = true +tracks/25/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/26/type = "value" +tracks/26/imported = false +tracks/26/enabled = true +tracks/26/path = NodePath("Body/Neck/Head/Eye/Iris:position") +tracks/26/interp = 1 +tracks/26/loop_wrap = true +tracks/26/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-5.11155, -3.27573)] +} +tracks/27/type = "value" +tracks/27/imported = false +tracks/27/enabled = true +tracks/27/path = NodePath("Body/Neck/Head/Eye/Iris:rotation") +tracks/27/interp = 1 +tracks/27/loop_wrap = true +tracks/27/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/28/type = "value" +tracks/28/imported = false +tracks/28/enabled = true +tracks/28/path = NodePath("Body/Neck/Head/Eye/Lash:position") +tracks/28/interp = 1 +tracks/28/loop_wrap = true +tracks/28/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(1.52588e-05, -24.0747)] +} +tracks/29/type = "value" +tracks/29/imported = false +tracks/29/enabled = true +tracks/29/path = NodePath("Body/Neck/Head/Eye/Lash:rotation") +tracks/29/interp = 1 +tracks/29/loop_wrap = true +tracks/29/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.456177] +} +tracks/30/type = "value" +tracks/30/imported = false +tracks/30/enabled = true +tracks/30/path = NodePath("Body/Neck/Head/Eye:position") +tracks/30/interp = 1 +tracks/30/loop_wrap = true +tracks/30/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(86.1287, -46.8739)] +} +tracks/31/type = "value" +tracks/31/imported = false +tracks/31/enabled = true +tracks/31/path = NodePath("Body/Neck/Head/Eye:rotation") +tracks/31/interp = 1 +tracks/31/loop_wrap = true +tracks/31/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0577994] +} +tracks/32/type = "value" +tracks/32/imported = false +tracks/32/enabled = true +tracks/32/path = NodePath("Body/Neck/Head/Hair:position") +tracks/32/interp = 1 +tracks/32/loop_wrap = true +tracks/32/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(28.6955, -149.617)] +} +tracks/33/type = "value" +tracks/33/imported = false +tracks/33/enabled = true +tracks/33/path = NodePath("Body/Neck/Head/Hair:rotation") +tracks/33/interp = 1 +tracks/33/loop_wrap = true +tracks/33/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.068965] +} +tracks/34/type = "value" +tracks/34/imported = false +tracks/34/enabled = true +tracks/34/path = NodePath("Body/Neck/Head:position") +tracks/34/interp = 1 +tracks/34/loop_wrap = true +tracks/34/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(10.257, -31.7704)] +} +tracks/35/type = "value" +tracks/35/imported = false +tracks/35/enabled = true +tracks/35/path = NodePath("Body/Neck/Head:rotation") +tracks/35/interp = 1 +tracks/35/loop_wrap = true +tracks/35/keys = { +"times": PackedFloat32Array(0, 0.2, 0.4), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0398988, 0.289577, 0.24501] +} +tracks/36/type = "value" +tracks/36/imported = false +tracks/36/enabled = true +tracks/36/path = NodePath("Body/Neck:position") +tracks/36/interp = 1 +tracks/36/loop_wrap = true +tracks/36/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(74.5, -11.5)] +} +tracks/37/type = "value" +tracks/37/imported = false +tracks/37/enabled = true +tracks/37/path = NodePath("Body/Neck:rotation") +tracks/37/interp = 1 +tracks/37/loop_wrap = true +tracks/37/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0876902] +} +tracks/38/type = "value" +tracks/38/imported = false +tracks/38/enabled = true +tracks/38/path = NodePath("Body/Tail:position") +tracks/38/interp = 1 +tracks/38/loop_wrap = true +tracks/38/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-53, -16)] +} +tracks/39/type = "value" +tracks/39/imported = false +tracks/39/enabled = true +tracks/39/path = NodePath("Body/Tail:rotation") +tracks/39/interp = 1 +tracks/39/loop_wrap = true +tracks/39/keys = { +"times": PackedFloat32Array(0, 0.4), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [-0.951901, -0.698623] +} +tracks/40/type = "value" +tracks/40/imported = false +tracks/40/enabled = true +tracks/40/path = NodePath("Body/FrontBackLeg/LowerLeg:position") +tracks/40/interp = 1 +tracks/40/loop_wrap = true +tracks/40/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(2.25, 73.5)] +} +tracks/41/type = "value" +tracks/41/imported = false +tracks/41/enabled = true +tracks/41/path = NodePath("Body/FrontBackLeg/LowerLeg:rotation") +tracks/41/interp = 1 +tracks/41/loop_wrap = true +tracks/41/keys = { +"times": PackedFloat32Array(0, 0.4), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.275205, 0.195533] +} +tracks/42/type = "value" +tracks/42/imported = false +tracks/42/enabled = true +tracks/42/path = NodePath("Body/FrontBackLeg:position") +tracks/42/interp = 1 +tracks/42/loop_wrap = true +tracks/42/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(40, -3.8147e-06)] +} +tracks/43/type = "value" +tracks/43/imported = false +tracks/43/enabled = true +tracks/43/path = NodePath("Body/FrontBackLeg:rotation") +tracks/43/interp = 1 +tracks/43/loop_wrap = true +tracks/43/keys = { +"times": PackedFloat32Array(0, 0.2, 0.4), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [-0.469617, -0.779233, -0.975267] +} +tracks/44/type = "value" +tracks/44/imported = false +tracks/44/enabled = true +tracks/44/path = NodePath("Body/BackBackLeg/LowerLeg:position") +tracks/44/interp = 1 +tracks/44/loop_wrap = true +tracks/44/keys = { +"times": PackedFloat32Array(0, 0.2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(2.25, 73.5), Vector2(2.20336, 74.2264)] +} +tracks/45/type = "value" +tracks/45/imported = false +tracks/45/enabled = true +tracks/45/path = NodePath("Body/BackBackLeg/LowerLeg:rotation") +tracks/45/interp = 1 +tracks/45/loop_wrap = true +tracks/45/keys = { +"times": PackedFloat32Array(0, 0.2, 0.4), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0643497, 0.452207, 0.295327] +} +tracks/46/type = "value" +tracks/46/imported = false +tracks/46/enabled = true +tracks/46/path = NodePath("Body/BackBackLeg:position") +tracks/46/interp = 1 +tracks/46/loop_wrap = true +tracks/46/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-54, -4)] +} +tracks/47/type = "value" +tracks/47/imported = false +tracks/47/enabled = true +tracks/47/path = NodePath("Body/BackBackLeg:rotation") +tracks/47/interp = 1 +tracks/47/loop_wrap = true +tracks/47/keys = { +"times": PackedFloat32Array(0, 0.2, 0.4), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [-0.0282668, 0.0831692, -0.0478] +} +tracks/48/type = "value" +tracks/48/imported = false +tracks/48/enabled = true +tracks/48/path = NodePath("Body:position") +tracks/48/interp = 1 +tracks/48/loop_wrap = true +tracks/48/keys = { +"times": PackedFloat32Array(0, 0.2, 0.4), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(-1, -28), Vector2(-1, -41)] +} +tracks/49/type = "value" +tracks/49/imported = false +tracks/49/enabled = true +tracks/49/path = NodePath("Body:rotation") +tracks/49/interp = 1 +tracks/49/loop_wrap = true +tracks/49/keys = { +"times": PackedFloat32Array(0, 0.2, 0.4), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0, -0.480274, -0.633399] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_xtm0y"] +_data = { +&"RESET": SubResource("Animation_mbs44"), +&"blink": SubResource("Animation_6k4l8"), +&"close_mouth": SubResource("Animation_fdul0"), +&"open_mouth": SubResource("Animation_7nlme"), +&"stagger": SubResource("Animation_xtm0y") +} + +[node name="Pony" type="Node2D"] +script = SubResource("GDScript_6k4l8") +metadata/_edit_horizontal_guides_ = [153.0] +metadata/_edit_lock_ = true + +[node name="Body" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "line")] +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line = NodePath("Stroke") +curve = SubResource("Curve2D_gghv2") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_p8hpb") + +[node name="BackBackLeg" type="Node2D" parent="Body" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(-54, -4) +rotation = -0.0282668 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_nndv2") +update_curve_at_runtime = true +arc_list = SubResource("Resource_nndv2") +offset = Vector2(-1, 43.3333) + +[node name="Stroke" type="Line2D" parent="Body/BackBackLeg"] +points = PackedVector2Array(21.7024, -14.457, 24.976, -9.36402, 27.651, -3.86431, 29.7721, 1.9749, 31.3843, 8.08636, 33.2611, 20.8571, 33.6399, 33.91, 31.3386, 58.7109, 27.3494, 78.1857, 16.3431, 83.3797, 11.4674, 85.2, 6.99914, 86.408, 4.9152, 86.7603, 2.93001, 86.933, 1.04256, 86.9172, -0.748183, 86.7041, -2.44325, 86.2848, -4.04367, 85.6505, -4.80871, 85.25, -5.55047, 84.7924, -6.96468, 83.7015, -5.56044, 44.7267, -7.63446, 22.1265, -12.75, -3.25) +width_curve = SubResource("Curve_d7gkk") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="LowerLeg" type="Node2D" parent="Body/BackBackLeg" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(2.25, 73.5) +rotation = 0.0643497 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_gy81n") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ipurh") + +[node name="Stroke" type="Line2D" parent="Body/BackBackLeg/LowerLeg"] +points = PackedVector2Array(25.3488, 3.06196, 24.0553, 29.0148, 24.4063, 52.0481, 25.4051, 63.3351, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0618, 73.0148, -21.2625, 72.54, -21.4314, 72.0015, -21.5694, 71.4016, -21.7567, 70.027, -21.8317, 68.4347, -21.6749, 64.6712, -21.1584, 60.2594, -16.684, 39.0982, -8.5396, 10.7729) +width_curve = SubResource("Curve_1ve1q") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/BackBackLeg/LowerLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(25.3488, 3.06196, 24.0553, 29.0148, 24.4063, 52.0481, 25.4051, 63.3351, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0618, 73.0148, -21.2625, 72.54, -21.4314, 72.0015, -21.5694, 71.4016, -21.7567, 70.027, -21.8317, 68.4347, -21.6749, 64.6712, -21.1584, 60.2594, -16.684, 39.0982, -8.5396, 10.7729) +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/BackBackLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(21.7024, -14.457, 24.976, -9.36402, 27.651, -3.86431, 29.7721, 1.9749, 31.3843, 8.08636, 33.2611, 20.8571, 33.6399, 33.91, 31.3386, 58.7109, 27.3494, 78.1857, 16.3431, 83.3797, 11.4674, 85.2, 6.99914, 86.408, 4.9152, 86.7603, 2.93001, 86.933, 1.04256, 86.9172, -0.748183, 86.7041, -2.44325, 86.2848, -4.04367, 85.6505, -4.80871, 85.25, -5.55047, 84.7924, -6.96468, 83.7015, -5.56044, 44.7267, -7.63446, 22.1265, -12.75, -3.25) +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/BackBackLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-6.96468, 83.7015) +rotation = -0.522935 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 2, +NodePath("../LowerLeg"): 3 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/BackBackLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(27.3494, 78.1857) +rotation = -0.522935 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 1, +NodePath("../LowerLeg"): 0 +} +metadata/_edit_lock_ = true + +[node name="FrontBackLeg" type="Node2D" parent="Body" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(40, -3.8147e-06) +rotation = -0.469617 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_inuwg") +update_curve_at_runtime = true +arc_list = SubResource("Resource_nndv2") +offset = Vector2(-1, 43.3333) + +[node name="Stroke" type="Line2D" parent="Body/FrontBackLeg"] +points = PackedVector2Array(27.19, -1.95666, 22.9566, 90.574, 16.4692, 95.704, 13.4676, 97.6733, 10.6328, 99.2301, 7.96882, 100.363, 6.7022, 100.767, 5.47981, 101.06, 4.30218, 101.242, 3.16979, 101.31, 2.08317, 101.264, 1.04282, 101.102, 0.0492504, 100.822, -0.897038, 100.424, -1.79553, 99.9045, -2.64573, 99.2636, -3.44712, 98.4994, -4.19919, 97.6106, -4.90144, 96.5956, -5.55336, 95.453, -6.70418, 92.7793, -7.6476, 89.578, -8.37954, 85.8376, -8.89595, 81.5466, -12.75, -3.25) +width_curve = SubResource("Curve_d7gkk") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="LowerLeg" type="Node2D" parent="Body/FrontBackLeg" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(2.25, 73.5) +rotation = 0.275205 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_trrx4") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ipurh") + +[node name="Stroke" type="Line2D" parent="Body/FrontBackLeg/LowerLeg"] +points = PackedVector2Array(24.5672, 10.8046, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0618, 73.0148, -21.2625, 72.54, -21.4314, 72.0015, -21.5694, 71.4016, -21.7567, 70.027, -21.8317, 68.4347, -21.6749, 64.6712, -21.1584, 60.2594, -16.6842, 39.0982, -8.53989, 10.7727) +width_curve = SubResource("Curve_1ve1q") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/FrontBackLeg/LowerLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(24.5672, 10.8046, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0618, 73.0148, -21.2625, 72.54, -21.4314, 72.0015, -21.5694, 71.4016, -21.7567, 70.027, -21.8317, 68.4347, -21.6749, 64.6712, -21.1584, 60.2594, -16.6842, 39.0982, -8.53989, 10.7727) +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/FrontBackLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(27.19, -1.95666, 22.9566, 90.574, 16.4692, 95.704, 13.4676, 97.6733, 10.6328, 99.2301, 7.96882, 100.363, 6.7022, 100.767, 5.47981, 101.06, 4.30218, 101.242, 3.16979, 101.31, 2.08317, 101.264, 1.04282, 101.102, 0.0492504, 100.822, -0.897038, 100.424, -1.79553, 99.9045, -2.64573, 99.2636, -3.44712, 98.4994, -4.19919, 97.6106, -4.90144, 96.5956, -5.55336, 95.453, -6.70418, 92.7793, -7.6476, 89.578, -8.37954, 85.8376, -8.89595, 81.5466, -12.75, -3.25) +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/FrontBackLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(22.9566, 90.574) +rotation = 0.665231 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 1, +NodePath("../LowerLeg"): 0 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/FrontBackLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-8.89595, 81.5466) +rotation = 0.665231 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 2, +NodePath("../LowerLeg"): 3 +} +metadata/_edit_lock_ = true + +[node name="Tail" type="Node2D" parent="Body" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(-53, -16) +rotation = -0.951901 +scale = Vector2(1.03201, 0.842576) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.58, 0, 0.212667, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_2jd1f") +update_curve_at_runtime = true +arc_list = SubResource("Resource_gtrm0") +metadata/_hover_point_idx_ = 4 +metadata/_hover_closest_point_on_curve_ = Object(Object,"script":Resource("res://addons/curved_lines_2d/closest_point_on_curve_meta.gd"),"before_segment":5,"point_position":Vector2(-60.43, 67.1905),"local_point_position":Vector2(-86.8231, -10.1369)) + + +[node name="Stroke" type="Line2D" parent="Body/Tail"] +points = PackedVector2Array(13.6271, -11.8026, -1.92606, -28.3036, -17.2001, -42.3745, -32.334, -53.968, -47.4669, -63.0373, -55.0765, -66.6107, -62.7379, -69.5354, -70.4686, -71.8055, -78.286, -73.4151, -86.2075, -74.3585, -94.2504, -74.6296, -102.432, -74.2227, -110.77, -73.1318, -101.872, -51.5176, -101.466, -27.786, -89.5158, -9.09912, -84.7696, -10.9283, -80.0079, -12.1789, -75.2238, -12.8582, -70.411, -12.9733, -65.5626, -12.5317, -60.6722, -11.5405, -55.7331, -10.0069, -50.7388, -7.9384, -45.6825, -5.34207, -40.5577, -2.22523, -30.0761, 5.54096, -19.2412, 15.3021, -8, 27, -1.55304, 15.4331, 3.31161, 6.70516) +closed = true +default_color = Color(0.58, 0, 0.212667, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Tail"] +texture = SubResource("GradientTexture2D_d1cq6") +texture_offset = Vector2(110.77, 74.6296) +polygon = PackedVector2Array(13.6271, -11.8026, -1.92606, -28.3036, -17.2001, -42.3745, -32.334, -53.968, -47.4669, -63.0373, -55.0765, -66.6107, -62.7379, -69.5354, -70.4686, -71.8055, -78.286, -73.4151, -86.2075, -74.3585, -94.2504, -74.6296, -102.432, -74.2227, -110.77, -73.1318, -101.872, -51.5176, -101.466, -27.786, -89.5158, -9.09912, -84.7696, -10.9283, -80.0079, -12.1789, -75.2238, -12.8582, -70.411, -12.9733, -65.5626, -12.5317, -60.6722, -11.5405, -55.7331, -10.0069, -50.7388, -7.9384, -45.6825, -5.34207, -40.5577, -2.22523, -30.0761, 5.54096, -19.2412, 15.3021, -8, 27, -1.55304, 15.4331, 3.31161, 6.70516) +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/Tail" node_paths=PackedStringArray("vertex_map")] +position = Vector2(13.6271, -11.8025) +rotation = 0.901859 +scale = Vector2(1.08689, 1.0799) +skew = -0.201318 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../.."): 0, +NodePath(".."): 0 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/Tail" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-101.872, -51.5176) +rotation = 1.14354 +scale = Vector2(1.13894, 1.02486) +skew = -0.171998 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 2, +NodePath("../Path"): 1 +} +metadata/_edit_lock_ = true + +[node name="Path2" type="Node2D" parent="Body/Tail" node_paths=PackedStringArray("line")] +script = ExtResource("1_inuwg") +stroke_color = Color(0.58, 0, 0.212667, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_7tj20") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_t2jyf") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Tail/Path2"] +points = PackedVector2Array(-1.55305, 15.4331, -11.6934, 5.53083, -17.2183, 0.630596, -23.0047, -4.14725, -29.0214, -8.73636, -35.237, -13.0704, -41.6205, -17.083, -48.1404, -20.7078, -54.7657, -23.8786, -58.108, -25.2729, -61.4649, -26.5289, -64.8326, -27.6381, -68.207, -28.5924, -71.5843, -29.3834, -74.9607, -30.0028, -78.332, -30.4423, -81.6946, -30.6936, -85.0445, -30.7485, -88.3777, -30.5987, -91.6903, -30.2358, -94.9785, -29.6516, -98.2384, -28.8378, -99.8565, -28.3421, -101.466, -27.786) +width = 2.0 +default_color = Color(0.58, 0, 0.212667, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Path" type="Node2D" parent="Body/Tail" node_paths=PackedStringArray("line")] +script = ExtResource("1_inuwg") +stroke_color = Color(0.58, 0, 0.212667, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_r5ynq") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_fwayd") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Tail/Path"] +points = PackedVector2Array(0.816067, 0.639946, 0.36928, -0.880961, -0.146897, -2.40265, -0.730885, -3.924, -1.3811, -5.44388, -2.87392, -8.47478, -4.61272, -11.4864, -6.58486, -14.4696, -8.77771, -17.4156, -11.1786, -20.3154, -13.775, -23.1599, -16.5542, -25.9403, -19.5035, -28.6474, -22.6104, -31.2724, -25.8622, -33.8062, -29.2463, -36.2399, -32.75, -38.5645, -36.3607, -40.7711, -40.0658, -42.8506, -43.8526, -44.7941, -47.7085, -46.5925, -51.6209, -48.237, -55.5771, -49.7185, -59.5645, -51.0281, -63.5705, -52.1567, -67.5824, -53.0955, -71.5876, -53.8353, -75.5735, -54.3674, -79.5274, -54.6826, -83.4367, -54.7719, -87.2888, -54.6265, -91.071, -54.2374, -92.9319, -53.9486, -94.7707, -53.5955, -96.5856, -53.1769, -98.3752, -52.6918, -100.138, -52.1391, -101.872, -51.5175) +width = 2.0 +default_color = Color(0.58, 0, 0.212667, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D3" type="Node2D" parent="Body/Tail" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-101.466, -27.786) +rotation = 1.00185 +scale = Vector2(1.10906, 1.05712) +skew = -0.195706 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 3, +NodePath("../Path2"): 1 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D4" type="Node2D" parent="Body/Tail" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-1.55304, 15.4331) +rotation = 1.00185 +scale = Vector2(1.10906, 1.05712) +skew = -0.195706 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 6, +NodePath("../Path2"): 0 +} +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body"] +points = PackedVector2Array(-52.9414, -33.224, -51.7496, -33.8212, -50.4681, -34.3921, -49.1002, -34.9371, -47.6495, -35.4569, -44.5133, -36.4227, -41.0875, -37.2939, -33.4777, -38.7699, -25.0426, -39.9195, -6.5858, -41.3787, 12.5042, -41.9494, 59.6188, -40.9053, 99.2969, -5.36705, 96.225, -1.87789, 92.7209, 1.74545, 88.8128, 5.46957, 84.529, 9.26107, 74.9469, 16.9126, 64.2003, 24.4329, 52.5148, 31.5548, 46.3906, 34.8827, 40.1162, 38.0109, 33.72, 40.9059, 27.2301, 43.5342, 20.6748, 45.8626, 14.0822, 47.8575, 7.48057, 49.4856, 0.89814, 50.7135, -5.63691, 51.5078, -8.87785, 51.7319, -12.0964, 51.8351, -15.2889, 51.8132, -18.452, 51.662, -21.5821, 51.3773, -24.6756, 50.955, -27.7291, 50.3909, -30.739, 49.6809, -33.7018, 48.8207, -36.614, 47.8061, -39.472, 46.6331, -42.2723, 45.2974, -45.0114, 43.7948, -47.6857, 42.1212, -50.2918, 40.2724, -52.8261, 38.2442, -55.2851, 36.0325, -57.6652, 33.633, -59.963, 31.0417, -62.1749, 28.2542, -64.2973, 25.2666, -66.3268, 22.0745, -68.2598, 18.6737, -70.0928, 15.0602, -71.8223, 11.2298, -73.4447, 7.17824, -73.5662, 5.97648, -73.647, 4.56595, -73.6781, 2.69717, -73.6122, 0.431249, -73.4018, -2.17069, -72.9997, -5.04752, -72.3586, -8.13813, -71.9335, -9.7445, -71.431, -11.3814, -70.845, -13.0412, -70.1696, -14.7162, -69.399, -16.3988, -68.5272, -18.0813, -67.5482, -19.7562, -66.4563, -21.4158, -65.2453, -23.0524, -63.9096, -24.6584, -62.443, -26.2262, -60.8398, -27.7481, -59.0939, -29.2164, -57.1995, -30.6236, -55.1506, -31.962) +closed = true +default_color = Color(0.427548, 0.209066, 0.760482, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Neck" type="Node2D" parent="Body" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(74.5, -11.5) +rotation = 0.0876902 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_1ve1q") +update_curve_at_runtime = true +arc_list = SubResource("Resource_2jd1f") + +[node name="Stroke" type="Line2D" parent="Body/Neck"] +points = PackedVector2Array(-5.10262, -46.7849, 40.5973, -22.6226, 25.2388, 3.93773, -17.3993, -27.9891) +closed = true +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Neck"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(-5.10262, -46.7849, 40.5973, -22.6226, 25.2388, 3.93773, -17.3993, -27.9891) +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/Neck" node_paths=PackedStringArray("vertex_map")] +visible = false +position = Vector2(-17.3993, -27.989) +rotation = -0.210176 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../.."): 1, +NodePath(".."): 3 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/Neck" node_paths=PackedStringArray("vertex_map")] +position = Vector2(25.2387, 3.93773) +rotation = -0.210176 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../.."): 2, +NodePath(".."): 2 +} +metadata/_edit_lock_ = true + +[node name="Head" type="Node2D" parent="Body/Neck" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(10.257, -31.7704) +rotation = 0.0398988 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427451, 0.207843, 0.760784, 1) +line = NodePath("BackHair/Stroke2") +curve = SubResource("Curve2D_gtrm0") +update_curve_at_runtime = true +arc_list = SubResource("Resource_hytqm") +rx = 60.0 +ry = 60.0 + +[node name="BackHair" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(120.07, -44.4362) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.580392, 0, 0.211765, 1) +stroke_width = 4.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_hytqm") +update_curve_at_runtime = true +arc_list = SubResource("Resource_d1cq6") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/BackHair"] +points = PackedVector2Array(-54.3072, -35.3798, -14.1477, -85.0489, -9.92882, -67.7769, -4.06947, -52.6502, 2.75134, -39.7174, 9.85462, -29.0271, 16.5614, -20.6279, 22.1925, -14.5683, 27.5123, -9.66228, 2.66948, 19.0798, -42.9545, 80.1351, -40.7503, 6.91599, -40.9231, -5.39432, -41.5963, -10.97, -42.7765, -16.237, -44.5508, -21.2533, -47.006, -26.0771, -50.2292, -30.7666) +closed = true +width = 4.0 +default_color = Color(0.580392, 0, 0.211765, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/BackHair"] +texture = SubResource("GradientTexture2D_t2jyf") +texture_offset = Vector2(54.3072, 85.0489) +polygon = PackedVector2Array(-54.3072, -35.3798, -14.1477, -85.0489, -9.92882, -67.7769, -4.06947, -52.6502, 2.75134, -39.7174, 9.85462, -29.0271, 16.5614, -20.6279, 22.1925, -14.5683, 27.5123, -9.66228, 2.66948, 19.0798, -42.9545, 80.1351, -40.7503, 6.91599, -40.9231, -5.39432, -41.5963, -10.97, -42.7765, -16.237, -44.5508, -21.2533, -47.006, -26.0771, -50.2292, -30.7666) +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/Neck/Head/BackHair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-42.9545, 80.1351) +rotation = -0.0876902 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 3, +NodePath("../../Hair"): 10 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/Neck/Head/BackHair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-14.1477, -85.0489) +rotation = -0.0876902 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 1, +NodePath("../../Hair"): 0 +} +metadata/_edit_lock_ = true + +[node name="Stroke2" type="Line2D" parent="Body/Neck/Head/BackHair"] +position = Vector2(-120.07, 44.4362) +points = PackedVector2Array(88.8385, -45.7059, 84.0102, -30.4889, 78.5724, -17.8271, 75.6112, -12.4352, 72.481, -7.65898, 69.1765, -3.49081, 65.6921, 0.0770115, 62.0223, 3.05218, 58.1616, 5.4424, 54.1045, 7.25534, 49.8456, 8.49871, 45.3792, 9.1802, 40.7, 9.30749, 35.8025, 8.88829, 30.681, 7.93027, 19.4855, 4.58809, 6.15223, -0.540889, -6.57349, -7.01434, -11.8506, -10.617, -14.0676, -12.4856, -15.9463, -14.3899, -16.3131, -14.8109, -17.2801, -16.2034, -18.6473, -18.7612, -20.2145, -22.6784, -21.7817, -28.1489, -23.1489, -35.3667, -24.1159, -44.5259, -24.4827, -55.8203, -24.1332, -61.8851, -23.1119, -67.645, -21.4591, -73.0879, -19.2154, -78.2021, -16.4213, -82.9755, -13.1174, -87.3963, -9.34409, -91.4526, -5.14195, -95.1324, -0.551472, -98.4239, 4.38683, -101.315, 9.63245, -103.794, 15.1449, -105.849, 20.8836, -107.468, 26.808, -108.64, 32.8778, -109.351, 39.0523, -109.591, 45.1594, -109.252, 51.0306, -108.259, 56.6308, -106.647, 61.925, -104.452, 66.8783, -101.711, 71.4554, -98.4583, 75.6216, -94.7306, 79.3416, -90.5635, 82.5805, -85.9929, 85.3032, -81.0544, 87.4747, -75.784, 89.06, -70.2174, 90.0241, -64.3905, 90.3319, -58.3391, 89.9484, -52.0989) +closed = true +default_color = Color(0.427451, 0.207843, 0.760784, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head"] +color = Color(0.556863, 0.603922, 1, 1) +polygon = PackedVector2Array(88.8385, -45.7059, 84.0102, -30.4889, 78.5724, -17.8271, 75.6112, -12.4352, 72.481, -7.65898, 69.1765, -3.49081, 65.6921, 0.0770115, 62.0223, 3.05218, 58.1616, 5.4424, 54.1045, 7.25534, 49.8456, 8.49871, 45.3792, 9.1802, 40.7, 9.30749, 35.8025, 8.88829, 30.681, 7.93027, 19.4855, 4.58809, 6.15223, -0.540889, -6.57349, -7.01434, -11.8506, -10.617, -14.0676, -12.4856, -15.9463, -14.3899, -16.3131, -14.8109, -17.2801, -16.2034, -18.6473, -18.7612, -20.2145, -22.6784, -21.7817, -28.1489, -23.1489, -35.3667, -24.1159, -44.5259, -24.4827, -55.8203, -24.1332, -61.8851, -23.1119, -67.645, -21.4591, -73.0879, -19.2154, -78.2021, -16.4213, -82.9755, -13.1174, -87.3963, -9.34409, -91.4526, -5.14195, -95.1324, -0.551472, -98.4239, 4.38683, -101.315, 9.63245, -103.794, 15.1449, -105.849, 20.8836, -107.468, 26.808, -108.64, 32.8778, -109.351, 39.0523, -109.591, 45.1594, -109.252, 51.0306, -108.259, 56.6308, -106.647, 61.925, -104.452, 66.8783, -101.711, 71.4554, -98.4583, 75.6216, -94.7306, 79.3416, -90.5635, 82.5805, -85.9929, 85.3032, -81.0544, 87.4747, -75.784, 89.06, -70.2174, 90.0241, -64.3905, 90.3319, -58.3391, 89.9484, -52.0989) +metadata/_edit_lock_ = true + +[node name="Hair" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("polygon", "line")] +z_index = 1 +position = Vector2(28.6955, -149.617) +rotation = -0.068965 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.580392, 0, 0.211765, 1) +stroke_width = 5.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_d1cq6") +update_curve_at_runtime = true +tolerance_degrees = 1.0 +arc_list = SubResource("Resource_7tj20") + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Hair"] +texture = SubResource("GradientTexture2D_r5ynq") +texture_offset = Vector2(95.0759, -15.1402) +polygon = PackedVector2Array(75.6559, 25.4058, 79.1803, 27.1794, 82.434, 28.9288, 83.9617, 29.8073, 85.4243, 30.6954, 86.8229, 31.5981, 88.1584, 32.5207, 88.8027, 32.9911, 89.4316, 33.4685, 90.0451, 33.9534, 90.6434, 34.4465, 91.2267, 34.9485, 91.7949, 35.46, 92.3482, 35.9817, 92.8867, 36.5141, 93.4106, 37.0581, 93.92, 37.6142, 94.4149, 38.183, 94.8955, 38.7653, 95.3619, 39.3616, 95.8142, 39.9726, 96.2525, 40.599, 96.6769, 41.2414, 97.8839, 43.0277, 99.2373, 45.1298, 100.952, 47.9216, 102.925, 51.316, 105.053, 55.2257, 106.142, 57.3465, 107.231, 59.5635, 108.307, 61.8657, 109.357, 64.2423, 110.367, 66.6823, 111.326, 69.1748, 112.219, 71.709, 113.035, 74.2739, 113.409, 75.5645, 113.759, 76.8587, 114.083, 78.1551, 114.38, 79.4524, 114.647, 80.7492, 114.883, 82.0442, 115.088, 83.3359, 115.257, 84.6231, 115.392, 85.9043, 115.489, 87.1783, 115.547, 88.4435, 115.564, 89.6988, 115.54, 90.9427, 115.471, 92.1738, 115.357, 93.3908, 115.196, 94.5923, 114.987, 95.777, 114.727, 96.9435, 114.415, 98.0904, 114.05, 99.2164, 113.63, 100.32, 113.153, 101.4, 112.617, 102.455, 112.022, 103.484, 109.274, 107.756, 106.098, 112.415, 90.9967, 133.888, 87.0891, 139.703, 83.3158, 145.593, 79.7703, 151.506, 78.1122, 154.454, 76.5461, 157.388, 75.0838, 160.302, 73.7369, 163.189, 72.5171, 166.042, 71.9585, 167.454, 71.4361, 168.855, 70.9513, 170.244, 70.5057, 171.621, 70.1005, 172.985, 69.7374, 174.334, 69.4177, 175.669, 69.143, 176.987, 68.9147, 178.29, 68.7342, 179.574, 68.6031, 180.841, 68.5227, 182.089, 68.4946, 183.317, 68.5202, 184.524, 68.601, 185.71, 68.7384, 186.873, 68.9339, 188.014, 69.1889, 189.13, 69.4928, 190.229, 69.8329, 191.316, 70.2083, 192.391, 70.6177, 193.454, 71.0601, 194.504, 71.5342, 195.542, 72.039, 196.567, 72.5733, 197.579, 73.136, 198.577, 73.7259, 199.561, 74.342, 200.531, 74.9829, 201.486, 75.6478, 202.426, 76.3353, 203.352, 77.0445, 204.262, 77.774, 205.156, 78.5228, 206.035, 79.2898, 206.897, 80.0738, 207.743, 80.8737, 208.571, 81.6884, 209.383, 82.5166, 210.177, 83.3574, 210.954, 84.2095, 211.712, 85.0718, 212.452, 85.9432, 213.173, 87.7086, 214.559, 89.4966, 215.867, 91.2983, 217.095, 93.1044, 218.239, 94.906, 219.299, 96.6938, 220.271, 97.5798, 220.723, 98.4589, 221.153, 99.3301, 221.56, 100.192, 221.943, 101.044, 222.303, 101.884, 222.639, 102.712, 222.951, 103.527, 223.238, 104.326, 223.5, 105.11, 223.737, 105.876, 223.949, 106.625, 224.135, 107.354, 224.295, 108.063, 224.429, 108.75, 224.536, 109.414, 224.616, 110.054, 224.67, 110.67, 224.695, 111.259, 224.693, 111.821, 224.663, 112.355, 224.605, 112.859, 224.518, 113.332, 224.402, 113.774, 224.256, 114.182, 224.082, 114.557, 223.877, 115.297, 223.467, 116.009, 223.056, 116.686, 222.639, 117.009, 222.428, 117.322, 222.213, 117.621, 221.995, 117.909, 221.773, 118.047, 221.66, 118.182, 221.546, 118.313, 221.43, 118.441, 221.313, 118.565, 221.195, 118.684, 221.075, 118.8, 220.954, 118.912, 220.831, 119.019, 220.706, 119.122, 220.579, 119.221, 220.45, 119.315, 220.32, 119.404, 220.187, 119.489, 220.052, 119.568, 219.916, 119.643, 219.776, 119.713, 219.635, 119.777, 219.491, 119.837, 219.345, 119.89, 219.196, 119.939, 219.044, 119.982, 218.89, 120.019, 218.733, 120.05, 218.574, 120.075, 218.411, 120.095, 218.246, 120.108, 218.077, 120.115, 217.905, 120.116, 217.73, 120.111, 217.552, 120.098, 217.371, 120.08, 217.186, 120.054, 216.998, 120.022, 216.806, 119.983, 216.611, 119.937, 216.411, 119.883, 216.209, 119.823, 216.002, 119.755, 215.791, 119.68, 215.577, 119.597, 215.358, 119.506, 215.136, 119.408, 214.909, 119.302, 214.678, 114.691, 189.598, 130.665, 211.435, 130.887, 211.976, 131.082, 212.512, 131.249, 213.043, 131.389, 213.569, 131.503, 214.089, 131.591, 214.603, 131.653, 215.112, 131.69, 215.615, 131.702, 216.113, 131.69, 216.605, 131.653, 217.09, 131.593, 217.57, 131.509, 218.044, 131.403, 218.512, 131.274, 218.974, 131.123, 219.429, 130.951, 219.878, 130.757, 220.321, 130.542, 220.757, 130.306, 221.187, 130.051, 221.61, 129.776, 222.026, 129.481, 222.436, 129.168, 222.839, 128.836, 223.235, 128.486, 223.624, 128.118, 224.006, 127.733, 224.381, 127.33, 224.748, 126.912, 225.109, 126.477, 225.462, 126.026, 225.807, 125.56, 226.146, 125.079, 226.476, 124.584, 226.799, 124.074, 227.115, 123.551, 227.422, 123.014, 227.722, 122.464, 228.014, 121.902, 228.298, 121.327, 228.574, 120.741, 228.841, 120.143, 229.101, 119.534, 229.352, 118.285, 229.829, 116.997, 230.273, 115.672, 230.682, 114.315, 231.055, 112.928, 231.393, 111.514, 231.695, 110.077, 231.96, 108.62, 232.188, 107.145, 232.377, 105.657, 232.528, 104.907, 232.586, 104.153, 232.628, 103.395, 232.654, 102.632, 232.666, 101.867, 232.664, 101.098, 232.647, 99.5518, 232.573, 97.9979, 232.449, 96.4391, 232.276, 94.8784, 232.059, 93.3187, 231.802, 91.7631, 231.506, 90.2147, 231.177, 88.6763, 230.816, 87.1511, 230.428, 84.1521, 229.582, 81.242, 228.667, 78.4448, 227.708, 75.7846, 226.732, 70.9722, 224.841, 65.3853, 222.551, 64.0548, 222.042, 63.4227, 221.803, 62.7122, 221.515, 61.9293, 221.177, 61.0803, 220.788, 60.1713, 220.349, 59.2085, 219.859, 58.1981, 219.318, 57.1463, 218.725, 56.0592, 218.08, 54.943, 217.383, 53.804, 216.634, 52.6482, 215.832, 51.4819, 214.977, 50.3112, 214.068, 49.1423, 213.106, 47.9814, 212.089, 46.8347, 211.018, 45.7083, 209.893, 45.1547, 209.309, 44.6084, 208.712, 44.0704, 208.101, 43.5413, 207.476, 43.0219, 206.837, 42.513, 206.184, 42.0154, 205.518, 41.5298, 204.837, 41.057, 204.142, 40.5978, 203.433, 40.1529, 202.71, 39.7232, 201.972, 39.3094, 201.221, 38.9122, 200.455, 38.5325, 199.675, 38.171, 198.88, 37.8285, 198.071, 37.5057, 197.248, 37.2035, 196.41, 36.9226, 195.558, 36.6637, 194.691, 36.4277, 193.809, 36.2153, 192.913, 36.0273, 192.003, 35.8645, 191.077, 35.7276, 190.137, 35.6174, 189.182, 35.5347, 188.212, 35.5063, 187.208, 35.557, 186.15, 35.684, 185.042, 35.8849, 183.883, 36.157, 182.677, 36.4978, 181.425, 36.9046, 180.128, 37.375, 178.788, 37.9063, 177.407, 38.496, 175.986, 39.1414, 174.527, 39.84, 173.033, 41.3866, 169.942, 43.1149, 166.727, 45.0045, 163.401, 47.0346, 159.977, 51.4341, 152.892, 61.012, 138.148, 70.5283, 123.356, 74.8507, 116.213, 76.8307, 112.751, 78.6625, 109.381, 80.3253, 106.116, 81.087, 104.528, 81.7987, 102.97, 82.4578, 101.445, 83.0618, 99.9555, 83.6081, 98.502, 84.0942, 97.0865, 84.5173, 95.7107, 84.8751, 94.3764, 85.1648, 93.0852, 85.3839, 91.8387, 85.5299, 90.6388, 85.6001, 89.487, 85.5919, 88.3851, 85.5029, 87.3347, 85.2187, 85.311, 84.8879, 83.338, 84.5105, 81.418, 84.087, 79.5539, 83.6175, 77.748, 83.1023, 76.0031, 82.8277, 75.1542, 82.5417, 74.3216, 82.2444, 73.5055, 81.9359, 72.7062, 81.6162, 71.9241, 81.2852, 71.1594, 80.9431, 70.4126, 80.5898, 69.6839, 80.2254, 68.9736, 79.85, 68.2821, 79.4635, 67.6097, 79.066, 66.9567, 78.6575, 66.3235, 78.2381, 65.7103, 77.8078, 65.1175, 77.3665, 64.5454, 76.9145, 63.9943, 76.4516, 63.4646, 75.9779, 62.9566, 75.4935, 62.4705, 74.9984, 62.0068, 74.4925, 61.5657, 73.976, 61.1475, 73.4489, 60.7527, 72.9112, 60.3815, 72.3629, 60.0341, 71.8041, 59.7111, 71.2348, 59.4126, 70.655, 59.139, 70.0648, 58.8906, 69.4642, 58.6678, 68.8532, 58.4708, 68.2319, 58.3, 67.6002, 58.1557, 66.9583, 58.0383, 66.3061, 57.948, 65.6438, 57.8852, 64.9712, 57.8501, 64.2885, 57.8432, 63.5957, 57.8648, 62.8928, 57.9151, 62.1798, 57.9945, 61.4568, 58.1033, 60.7239, 58.2418, 59.9809, 58.4104, 59.2281, 58.6093, 58.4653, 58.839, 57.6927, 59.0996, 56.9103, 59.3917, 56.118, 59.7153, 55.316, 60.071, 54.5043, 60.459, 35.6321, 74.1644, 24.9326, 67.7394, 19.9875, 64.8737, 15.2825, 62.2702, 10.7952, 59.9522, 8.62631, 58.9076, 6.50345, 57.943, 4.42389, 57.0615, 2.38484, 56.2658, 0.383501, 55.559, -0.603893, 55.2399, -1.5829, 54.944, -2.55387, 54.6717, -3.51716, 54.4235, -4.4731, 54.1997, -5.42205, 54.0007, -6.36436, 53.8267, -7.30037, 53.6783, -8.23044, 53.5557, -9.15491, 53.4592, -10.0741, 53.3894, -10.9884, 53.3465, -11.8982, 53.3309, -12.8038, 53.3429, -13.7055, 53.383, -14.6037, 53.4515, -15.4987, 53.5487, -16.3909, 53.675, -17.2807, 53.8308, -18.1683, 54.0165, -19.0542, 54.2323, -19.9386, 54.4787, -20.822, 54.7561, -21.7047, 55.0647, -22.587, 55.4051, -23.4693, 55.7774, -24.3518, 56.1821, -25.2351, 56.6196, -26.1194, 57.0902, -27.005, 57.5943, -27.8924, 58.1322, -28.7818, 58.7043, -29.6737, 59.311, -30.5683, 59.9526, -31.4533, 60.63, -32.3157, 61.3434, -33.1553, 62.0926, -33.9716, 62.8772, -34.7644, 63.6969, -35.5332, 64.5513, -36.2777, 65.4401, -36.9976, 66.363, -37.6925, 67.3196, -38.3619, 68.3097, -39.0057, 69.3328, -39.6234, 70.3886, -40.2146, 71.4768, -40.779, 72.5971, -41.3163, 73.7492, -41.8261, 74.9326, -42.308, 76.147, -42.7616, 77.3922, -43.1867, 78.6678, -43.5829, 79.9734, -43.9498, 81.3088, -44.287, 82.6735, -44.5942, 84.0673, -44.871, 85.4898, -45.1171, 86.9407, -45.3321, 88.4196, -45.5157, 89.9262, -45.6675, 91.4603, -45.7872, 93.0213, -45.8743, 94.609, -45.9286, 96.2232, -45.9497, 97.8633, -45.9372, 99.5291, -45.8907, 101.22, -45.81, 102.937, -45.6946, 104.678, -45.5442, 106.443, -45.3584, 108.232, -45.137, 110.045, -44.8794, 111.882, -44.2547, 115.623, -43.4814, 119.454, -42.5566, 123.371, -41.4776, 127.373, -40.2414, 131.456, -38.8452, 135.618, -37.2861, 139.855, -35.5614, 144.166, -33.6681, 148.548, -31.6033, 152.998, -29.3643, 157.512, -26.9482, 162.09, -26.7507, 162.691, -26.5843, 163.3, -26.4482, 163.918, -26.3414, 164.543, -26.263, 165.176, -26.2122, 165.814, -26.188, 166.458, -26.1896, 167.108, -26.216, 167.762, -26.2665, 168.42, -26.3399, 169.082, -26.4355, 169.746, -26.5525, 170.413, -26.6897, 171.082, -26.8465, 171.751, -27.0218, 172.421, -27.2148, 173.092, -27.4246, 173.761, -27.6503, 174.43, -27.891, 175.096, -28.1457, 175.76, -28.4137, 176.422, -28.9856, 177.733, -29.5996, 179.026, -30.2485, 180.296, -30.925, 181.537, -31.622, 182.746, -32.3324, 183.918, -33.0489, 185.047, -34.4718, 187.162, -35.8332, 189.054, -37.0757, 190.685, -38.1421, 192.018, -38.9748, 193.017, -39.7099, 193.86, -49.7804, 210.682, -51.8719, 209.023, -53.9095, 207.324, -55.8936, 205.586, -57.8245, 203.811, -59.7025, 201.999, -61.5279, 200.153, -63.3011, 198.275, -65.0223, 196.364, -66.6919, 194.423, -68.3102, 192.454, -69.8775, 190.458, -71.3941, 188.436, -72.8604, 186.389, -74.2766, 184.32, -75.643, 182.229, -76.9601, 180.119, -78.228, 177.99, -79.4472, 175.845, -80.6179, 173.683, -81.7404, 171.508, -82.8151, 169.321, -83.8422, 167.122, -84.8222, 164.913, -85.7553, 162.697, -86.6417, 160.474, -87.482, 158.245, -88.2762, 156.013, -89.0249, 153.779, -89.7282, 151.543, -90.3865, 149.309, -91.0002, 147.076, -91.5694, 144.847, -92.0946, 142.623, -92.5761, 140.406, -93.0142, 138.196, -93.4091, 135.996, -93.7613, 133.807, -94.071, 131.63, -94.3385, 129.467, -94.5642, 127.32, -94.7483, 125.189, -94.8912, 123.076, -94.9933, 120.983, -95.0547, 118.911, -95.0759, 116.862, -95.0572, 114.836, -94.9988, 112.837, -94.9011, 110.864, -94.7643, 108.92, -94.5889, 107.005, -94.3751, 105.123, -94.1233, 103.272, -93.8337, 101.457, -93.5067, 99.6768, -93.1426, 97.9341, -92.7417, 96.2301, -92.3043, 94.5662, -91.8307, 92.9441, -91.3213, 91.365, -90.7764, 89.8305, -90.1962, 88.342, -89.5812, 86.9011, -88.9315, 85.5091, -88.2476, 84.1675, -88.1855, 84.0292, -87.9913, 83.6225, -87.6534, 82.9596, -87.1601, 82.0526, -86.4996, 80.9138, -85.6603, 79.5554, -84.6305, 77.9896, -83.3985, 76.2285, -81.9526, 74.2845, -80.281, 72.1697, -78.3722, 69.8962, -76.2143, 67.4764, -73.7958, 64.9224, -71.1048, 62.2464, -68.1298, 59.4606, -64.859, 56.5772, -61.9752, 53.9539, -58.0397, 50.5806, -55.6954, 48.6689, -53.1094, 46.6373, -50.289, 44.5081, -47.2412, 42.304, -43.973, 40.0474, -40.4917, 37.7608, -36.8044, 35.4666, -32.918, 33.1875, -28.8398, 30.9459, -24.5768, 28.7643, -20.1361, 26.6652, -15.5248, 24.6711, -13.1575, 23.7204, -10.7501, 22.8045, -8.30369, 21.926, -5.81905, 21.0879, -3.2971, 20.2929, -0.738726, 19.5438, 1.85519, 18.8435, 4.48375, 18.1947, 7.14608, 17.6003, 9.84128, 17.0631, 12.5685, 16.5859, 15.3268, 16.1715, 18.1153, 15.8228, 20.9331, 15.5424, 23.7793, 15.3334, 26.6531, 15.1984, 29.5536, 15.1402, 32.4798, 15.1618, 35.431, 15.2658, 38.4061, 15.4552, 41.4043, 15.7327, 44.4247, 16.1011, 47.4665, 16.5633, 50.5287, 17.1221, 53.6105, 17.7802, 56.7109, 18.5405, 59.8292, 19.4058, 62.9643, 20.3789, 66.1154, 21.4627, 69.2816, 22.6599, 72.4621, 23.9733) +metadata/_edit_lock_ = true + +[node name="Path" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("line")] +position = Vector2(24.0613, 68.1546) +script = ExtResource("1_inuwg") +stroke_color = Color(0.580392, 0, 0.211765, 1) +stroke_width = 2.0 +end_cap_mode = 1 +line = NodePath("Stroke") +curve = SubResource("Curve2D_fwayd") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_rr8qp") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Hair/Path"] +points = PackedVector2Array(-9.61644, -5.25069, -7.94586, -6.83242, -6.21727, -8.35578, -4.43067, -9.82076, -2.58606, -11.2274, 1.2772, -13.8655, 5.3725, -16.2701, 9.69985, -18.4412, 14.2592, -20.3789, 19.0507, -22.083, 24.0742, -23.5537, 29.3297, -24.7908, 34.8173, -25.7945, 40.5369, -26.5647, 46.4885, -27.1014, 52.6722, -27.4046, 59.088, -27.4743, 72.6156, -26.9133) +width = 2.0 +default_color = Color(0.580392, 0, 0.211765, 1) +end_cap_mode = 1 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/Neck/Head/Hair/Path" node_paths=PackedStringArray("vertex_map")] +position = Vector2(45.1276, 120.975) +rotation = -0.130073 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../.."): 3, +NodePath("../../Path2"): 0 +} +metadata/_edit_lock_ = true + +[node name="Path2" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("line")] +position = Vector2(89.1321, 197.289) +script = ExtResource("1_inuwg") +stroke_color = Color(0.580392, 0, 0.211765, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_t2jyf") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_r5ynq") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Hair/Path2"] +points = PackedVector2Array(-19.9432, -8.15901, -25.0773, 24.753) +width = 2.0 +default_color = Color(0.580392, 0, 0.211765, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Path3" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("line")] +position = Vector2(-17.6514, 55.7047) +script = ExtResource("1_inuwg") +stroke_color = Color(0.580392, 0, 0.211765, 1) +stroke_width = 2.0 +end_cap_mode = 1 +line = NodePath("Stroke") +curve = SubResource("Curve2D_rr8qp") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_ej6pp") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Hair/Path3"] +points = PackedVector2Array(-1.11281, -0.872726, 3.83957, -4.41093, 8.91846, -7.72259, 14.1239, -10.8077, 19.4558, -13.6663, 24.9143, -16.2984, 30.4992, -18.7039, 36.2107, -20.8828, 42.0487, -22.8353, 48.0132, -24.5611, 54.1043, -26.0605, 60.3218, -27.3333, 66.6659, -28.3795, 73.1365, -29.1992, 79.7336, -29.7923, 93.3073, -30.2989) +width = 2.0 +default_color = Color(0.580392, 0, 0.211765, 1) +end_cap_mode = 1 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(112.022, 103.484) +rotation = -0.192857 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../../BackHair"): 2, +NodePath(".."): 2 +} +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Hair"] +points = PackedVector2Array(75.6559, 25.4058, 79.1803, 27.1794, 82.434, 28.9288, 83.9617, 29.8073, 85.4243, 30.6954, 86.8229, 31.5981, 88.1584, 32.5207, 88.8027, 32.9911, 89.4316, 33.4685, 90.0451, 33.9534, 90.6434, 34.4465, 91.2267, 34.9485, 91.7949, 35.46, 92.3482, 35.9817, 92.8867, 36.5141, 93.4106, 37.0581, 93.92, 37.6142, 94.4149, 38.183, 94.8955, 38.7653, 95.3619, 39.3616, 95.8142, 39.9726, 96.2525, 40.599, 96.6769, 41.2414, 97.8839, 43.0277, 99.2373, 45.1298, 100.952, 47.9216, 102.925, 51.316, 105.053, 55.2257, 106.142, 57.3465, 107.231, 59.5635, 108.307, 61.8657, 109.357, 64.2423, 110.367, 66.6823, 111.326, 69.1748, 112.219, 71.709, 113.035, 74.2739, 113.409, 75.5645, 113.759, 76.8587, 114.083, 78.1551, 114.38, 79.4524, 114.647, 80.7492, 114.883, 82.0442, 115.088, 83.3359, 115.257, 84.6231, 115.392, 85.9043, 115.489, 87.1783, 115.547, 88.4435, 115.564, 89.6988, 115.54, 90.9427, 115.471, 92.1738, 115.357, 93.3908, 115.196, 94.5923, 114.987, 95.777, 114.727, 96.9435, 114.415, 98.0904, 114.05, 99.2164, 113.63, 100.32, 113.153, 101.4, 112.617, 102.455, 112.022, 103.484, 109.274, 107.756, 106.098, 112.415, 90.9967, 133.888, 87.0891, 139.703, 83.3158, 145.593, 79.7703, 151.506, 78.1122, 154.454, 76.5461, 157.388, 75.0838, 160.302, 73.7369, 163.189, 72.5171, 166.042, 71.9585, 167.454, 71.4361, 168.855, 70.9513, 170.244, 70.5057, 171.621, 70.1005, 172.985, 69.7374, 174.334, 69.4177, 175.669, 69.143, 176.987, 68.9147, 178.29, 68.7342, 179.574, 68.6031, 180.841, 68.5227, 182.089, 68.4946, 183.317, 68.5202, 184.524, 68.601, 185.71, 68.7384, 186.873, 68.9339, 188.014, 69.1889, 189.13, 69.4928, 190.229, 69.8329, 191.316, 70.2083, 192.391, 70.6177, 193.454, 71.0601, 194.504, 71.5342, 195.542, 72.039, 196.567, 72.5733, 197.579, 73.136, 198.577, 73.7259, 199.561, 74.342, 200.531, 74.9829, 201.486, 75.6478, 202.426, 76.3353, 203.352, 77.0445, 204.262, 77.774, 205.156, 78.5228, 206.035, 79.2898, 206.897, 80.0738, 207.743, 80.8737, 208.571, 81.6884, 209.383, 82.5166, 210.177, 83.3574, 210.954, 84.2095, 211.712, 85.0718, 212.452, 85.9432, 213.173, 87.7086, 214.559, 89.4966, 215.867, 91.2983, 217.095, 93.1044, 218.239, 94.906, 219.299, 96.6938, 220.271, 97.5798, 220.723, 98.4589, 221.153, 99.3301, 221.56, 100.192, 221.943, 101.044, 222.303, 101.884, 222.639, 102.712, 222.951, 103.527, 223.238, 104.326, 223.5, 105.11, 223.737, 105.876, 223.949, 106.625, 224.135, 107.354, 224.295, 108.063, 224.429, 108.75, 224.536, 109.414, 224.616, 110.054, 224.67, 110.67, 224.695, 111.259, 224.693, 111.821, 224.663, 112.355, 224.605, 112.859, 224.518, 113.332, 224.402, 113.774, 224.256, 114.182, 224.082, 114.557, 223.877, 115.297, 223.467, 116.009, 223.056, 116.686, 222.639, 117.009, 222.428, 117.322, 222.213, 117.621, 221.995, 117.909, 221.773, 118.047, 221.66, 118.182, 221.546, 118.313, 221.43, 118.441, 221.313, 118.565, 221.195, 118.684, 221.075, 118.8, 220.954, 118.912, 220.831, 119.019, 220.706, 119.122, 220.579, 119.221, 220.45, 119.315, 220.32, 119.404, 220.187, 119.489, 220.052, 119.568, 219.916, 119.643, 219.776, 119.713, 219.635, 119.777, 219.491, 119.837, 219.345, 119.89, 219.196, 119.939, 219.044, 119.982, 218.89, 120.019, 218.733, 120.05, 218.574, 120.075, 218.411, 120.095, 218.246, 120.108, 218.077, 120.115, 217.905, 120.116, 217.73, 120.111, 217.552, 120.098, 217.371, 120.08, 217.186, 120.054, 216.998, 120.022, 216.806, 119.983, 216.611, 119.937, 216.411, 119.883, 216.209, 119.823, 216.002, 119.755, 215.791, 119.68, 215.577, 119.597, 215.358, 119.506, 215.136, 119.408, 214.909, 119.302, 214.678, 114.691, 189.598, 130.665, 211.435, 130.887, 211.976, 131.082, 212.512, 131.249, 213.043, 131.389, 213.569, 131.503, 214.089, 131.591, 214.603, 131.653, 215.112, 131.69, 215.615, 131.702, 216.113, 131.69, 216.605, 131.653, 217.09, 131.593, 217.57, 131.509, 218.044, 131.403, 218.512, 131.274, 218.974, 131.123, 219.429, 130.951, 219.878, 130.757, 220.321, 130.542, 220.757, 130.306, 221.187, 130.051, 221.61, 129.776, 222.026, 129.481, 222.436, 129.168, 222.839, 128.836, 223.235, 128.486, 223.624, 128.118, 224.006, 127.733, 224.381, 127.33, 224.748, 126.912, 225.109, 126.477, 225.462, 126.026, 225.807, 125.56, 226.146, 125.079, 226.476, 124.584, 226.799, 124.074, 227.115, 123.551, 227.422, 123.014, 227.722, 122.464, 228.014, 121.902, 228.298, 121.327, 228.574, 120.741, 228.841, 120.143, 229.101, 119.534, 229.352, 118.285, 229.829, 116.997, 230.273, 115.672, 230.682, 114.315, 231.055, 112.928, 231.393, 111.514, 231.695, 110.077, 231.96, 108.62, 232.188, 107.145, 232.377, 105.657, 232.528, 104.907, 232.586, 104.153, 232.628, 103.395, 232.654, 102.632, 232.666, 101.867, 232.664, 101.098, 232.647, 99.5518, 232.573, 97.9979, 232.449, 96.4391, 232.276, 94.8784, 232.059, 93.3187, 231.802, 91.7631, 231.506, 90.2147, 231.177, 88.6763, 230.816, 87.1511, 230.428, 84.1521, 229.582, 81.242, 228.667, 78.4448, 227.708, 75.7846, 226.732, 70.9722, 224.841, 65.3853, 222.551, 64.0548, 222.042, 63.4227, 221.803, 62.7122, 221.515, 61.9293, 221.177, 61.0803, 220.788, 60.1713, 220.349, 59.2085, 219.859, 58.1981, 219.318, 57.1463, 218.725, 56.0592, 218.08, 54.943, 217.383, 53.804, 216.634, 52.6482, 215.832, 51.4819, 214.977, 50.3112, 214.068, 49.1423, 213.106, 47.9814, 212.089, 46.8347, 211.018, 45.7083, 209.893, 45.1547, 209.309, 44.6084, 208.712, 44.0704, 208.101, 43.5413, 207.476, 43.0219, 206.837, 42.513, 206.184, 42.0154, 205.518, 41.5298, 204.837, 41.057, 204.142, 40.5978, 203.433, 40.1529, 202.71, 39.7232, 201.972, 39.3094, 201.221, 38.9122, 200.455, 38.5325, 199.675, 38.171, 198.88, 37.8285, 198.071, 37.5057, 197.248, 37.2035, 196.41, 36.9226, 195.558, 36.6637, 194.691, 36.4277, 193.809, 36.2153, 192.913, 36.0273, 192.003, 35.8645, 191.077, 35.7276, 190.137, 35.6174, 189.182, 35.5347, 188.212, 35.5063, 187.208, 35.557, 186.15, 35.684, 185.042, 35.8849, 183.883, 36.157, 182.677, 36.4978, 181.425, 36.9046, 180.128, 37.375, 178.788, 37.9063, 177.407, 38.496, 175.986, 39.1414, 174.527, 39.84, 173.033, 41.3866, 169.942, 43.1149, 166.727, 45.0045, 163.401, 47.0346, 159.977, 51.4341, 152.892, 61.012, 138.148, 70.5283, 123.356, 74.8507, 116.213, 76.8307, 112.751, 78.6625, 109.381, 80.3253, 106.116, 81.087, 104.528, 81.7987, 102.97, 82.4578, 101.445, 83.0618, 99.9555, 83.6081, 98.502, 84.0942, 97.0865, 84.5173, 95.7107, 84.8751, 94.3764, 85.1648, 93.0852, 85.3839, 91.8387, 85.5299, 90.6388, 85.6001, 89.487, 85.5919, 88.3851, 85.5029, 87.3347, 85.2187, 85.311, 84.8879, 83.338, 84.5105, 81.418, 84.087, 79.5539, 83.6175, 77.748, 83.1023, 76.0031, 82.8277, 75.1542, 82.5417, 74.3216, 82.2444, 73.5055, 81.9359, 72.7062, 81.6162, 71.9241, 81.2852, 71.1594, 80.9431, 70.4126, 80.5898, 69.6839, 80.2254, 68.9736, 79.85, 68.2821, 79.4635, 67.6097, 79.066, 66.9567, 78.6575, 66.3235, 78.2381, 65.7103, 77.8078, 65.1175, 77.3665, 64.5454, 76.9145, 63.9943, 76.4516, 63.4646, 75.9779, 62.9566, 75.4935, 62.4705, 74.9984, 62.0068, 74.4925, 61.5657, 73.976, 61.1475, 73.4489, 60.7527, 72.9112, 60.3815, 72.3629, 60.0341, 71.8041, 59.7111, 71.2348, 59.4126, 70.655, 59.139, 70.0648, 58.8906, 69.4642, 58.6678, 68.8532, 58.4708, 68.2319, 58.3, 67.6002, 58.1557, 66.9583, 58.0383, 66.3061, 57.948, 65.6438, 57.8852, 64.9712, 57.8501, 64.2885, 57.8432, 63.5957, 57.8648, 62.8928, 57.9151, 62.1798, 57.9945, 61.4568, 58.1033, 60.7239, 58.2418, 59.9809, 58.4104, 59.2281, 58.6093, 58.4653, 58.839, 57.6927, 59.0996, 56.9103, 59.3917, 56.118, 59.7153, 55.316, 60.071, 54.5043, 60.459, 35.6321, 74.1644, 24.9326, 67.7394, 19.9875, 64.8737, 15.2825, 62.2702, 10.7952, 59.9522, 8.62631, 58.9076, 6.50345, 57.943, 4.42389, 57.0615, 2.38484, 56.2658, 0.383501, 55.559, -0.603893, 55.2399, -1.5829, 54.944, -2.55387, 54.6717, -3.51716, 54.4235, -4.4731, 54.1997, -5.42205, 54.0007, -6.36436, 53.8267, -7.30037, 53.6783, -8.23044, 53.5557, -9.15491, 53.4592, -10.0741, 53.3894, -10.9884, 53.3465, -11.8982, 53.3309, -12.8038, 53.3429, -13.7055, 53.383, -14.6037, 53.4515, -15.4987, 53.5487, -16.3909, 53.675, -17.2807, 53.8308, -18.1683, 54.0165, -19.0542, 54.2323, -19.9386, 54.4787, -20.822, 54.7561, -21.7047, 55.0647, -22.587, 55.4051, -23.4693, 55.7774, -24.3518, 56.1821, -25.2351, 56.6196, -26.1194, 57.0902, -27.005, 57.5943, -27.8924, 58.1322, -28.7818, 58.7043, -29.6737, 59.311, -30.5683, 59.9526, -31.4533, 60.63, -32.3157, 61.3434, -33.1553, 62.0926, -33.9716, 62.8772, -34.7644, 63.6969, -35.5332, 64.5513, -36.2777, 65.4401, -36.9976, 66.363, -37.6925, 67.3196, -38.3619, 68.3097, -39.0057, 69.3328, -39.6234, 70.3886, -40.2146, 71.4768, -40.779, 72.5971, -41.3163, 73.7492, -41.8261, 74.9326, -42.308, 76.147, -42.7616, 77.3922, -43.1867, 78.6678, -43.5829, 79.9734, -43.9498, 81.3088, -44.287, 82.6735, -44.5942, 84.0673, -44.871, 85.4898, -45.1171, 86.9407, -45.3321, 88.4196, -45.5157, 89.9262, -45.6675, 91.4603, -45.7872, 93.0213, -45.8743, 94.609, -45.9286, 96.2232, -45.9497, 97.8633, -45.9372, 99.5291, -45.8907, 101.22, -45.81, 102.937, -45.6946, 104.678, -45.5442, 106.443, -45.3584, 108.232, -45.137, 110.045, -44.8794, 111.882, -44.2547, 115.623, -43.4814, 119.454, -42.5566, 123.371, -41.4776, 127.373, -40.2414, 131.456, -38.8452, 135.618, -37.2861, 139.855, -35.5614, 144.166, -33.6681, 148.548, -31.6033, 152.998, -29.3643, 157.512, -26.9482, 162.09, -26.7507, 162.691, -26.5843, 163.3, -26.4482, 163.918, -26.3414, 164.543, -26.263, 165.176, -26.2122, 165.814, -26.188, 166.458, -26.1896, 167.108, -26.216, 167.762, -26.2665, 168.42, -26.3399, 169.082, -26.4355, 169.746, -26.5525, 170.413, -26.6897, 171.082, -26.8465, 171.751, -27.0218, 172.421, -27.2148, 173.092, -27.4246, 173.761, -27.6503, 174.43, -27.891, 175.096, -28.1457, 175.76, -28.4137, 176.422, -28.9856, 177.733, -29.5996, 179.026, -30.2485, 180.296, -30.925, 181.537, -31.622, 182.746, -32.3324, 183.918, -33.0489, 185.047, -34.4718, 187.162, -35.8332, 189.054, -37.0757, 190.685, -38.1421, 192.018, -38.9748, 193.017, -39.7099, 193.86, -49.7804, 210.682, -51.8719, 209.023, -53.9095, 207.324, -55.8936, 205.586, -57.8245, 203.811, -59.7025, 201.999, -61.5279, 200.153, -63.3011, 198.275, -65.0223, 196.364, -66.6919, 194.423, -68.3102, 192.454, -69.8775, 190.458, -71.3941, 188.436, -72.8604, 186.389, -74.2766, 184.32, -75.643, 182.229, -76.9601, 180.119, -78.228, 177.99, -79.4472, 175.845, -80.6179, 173.683, -81.7404, 171.508, -82.8151, 169.321, -83.8422, 167.122, -84.8222, 164.913, -85.7553, 162.697, -86.6417, 160.474, -87.482, 158.245, -88.2762, 156.013, -89.0249, 153.779, -89.7282, 151.543, -90.3865, 149.309, -91.0002, 147.076, -91.5694, 144.847, -92.0946, 142.623, -92.5761, 140.406, -93.0142, 138.196, -93.4091, 135.996, -93.7613, 133.807, -94.071, 131.63, -94.3385, 129.467, -94.5642, 127.32, -94.7483, 125.189, -94.8912, 123.076, -94.9933, 120.983, -95.0547, 118.911, -95.0759, 116.862, -95.0572, 114.836, -94.9988, 112.837, -94.9011, 110.864, -94.7643, 108.92, -94.5889, 107.005, -94.3751, 105.123, -94.1233, 103.272, -93.8337, 101.457, -93.5067, 99.6768, -93.1426, 97.9341, -92.7417, 96.2301, -92.3043, 94.5662, -91.8307, 92.9441, -91.3213, 91.365, -90.7764, 89.8305, -90.1962, 88.342, -89.5812, 86.9011, -88.9315, 85.5091, -88.2476, 84.1675, -88.1855, 84.0292, -87.9913, 83.6225, -87.6534, 82.9596, -87.1601, 82.0526, -86.4996, 80.9138, -85.6603, 79.5554, -84.6305, 77.9896, -83.3985, 76.2285, -81.9526, 74.2845, -80.281, 72.1697, -78.3722, 69.8962, -76.2143, 67.4764, -73.7958, 64.9224, -71.1048, 62.2464, -68.1298, 59.4606, -64.859, 56.5772, -61.9752, 53.9539, -58.0397, 50.5806, -55.6954, 48.6689, -53.1094, 46.6373, -50.289, 44.5081, -47.2412, 42.304, -43.973, 40.0474, -40.4917, 37.7608, -36.8044, 35.4666, -32.918, 33.1875, -28.8398, 30.9459, -24.5768, 28.7643, -20.1361, 26.6652, -15.5248, 24.6711, -13.1575, 23.7204, -10.7501, 22.8045, -8.30369, 21.926, -5.81905, 21.0879, -3.2971, 20.2929, -0.738726, 19.5438, 1.85519, 18.8435, 4.48375, 18.1947, 7.14608, 17.6003, 9.84128, 17.0631, 12.5685, 16.5859, 15.3268, 16.1715, 18.1153, 15.8228, 20.9331, 15.5424, 23.7793, 15.3334, 26.6531, 15.1984, 29.5536, 15.1402, 32.4798, 15.1618, 35.431, 15.2658, 38.4061, 15.4552, 41.4043, 15.7327, 44.4247, 16.1011, 47.4665, 16.5633, 50.5287, 17.1221, 53.6105, 17.7802, 56.7109, 18.5405, 59.8292, 19.4058, 62.9643, 20.3789, 66.1154, 21.4627, 69.2816, 22.6599, 72.4621, 23.9733) +closed = true +width = 5.0 +width_curve = SubResource("Curve_r5ynq") +default_color = Color(0.580392, 0, 0.211765, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(96.6769, 41.2414) +rotation = -0.196411 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 1, +NodePath("../Path"): 1 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D3" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(75.6559, 25.4058) +rotation = -0.196411 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../../BackHair"): 1, +NodePath(".."): 0, +NodePath("../Path3"): 1 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D4" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(64.0548, 222.042) +rotation = -0.196411 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 9, +NodePath("../Path2"): 1 +} +metadata/_edit_lock_ = true + +[node name="Path4" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("line")] +position = Vector2(-96.1089, 124.991) +script = ExtResource("1_inuwg") +stroke_color = Color(0.580392, 0, 0.211765, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_bjmri") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_w157y") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Hair/Path4"] +points = PackedVector2Array(7.86132, -40.8235, 8.29562, -21.9512, 9.60254, -4.57242, 10.6422, 3.65373, 11.9706, 11.6227, 13.6115, 19.3733, 15.5885, 26.9441, 17.925, 34.374, 20.6446, 41.7017, 23.771, 48.966, 27.3276, 56.2055, 31.3381, 63.459, 35.8261, 70.7653, 40.815, 78.1631, 46.3285, 85.6911) +width = 2.0 +default_color = Color(0.580392, 0, 0.211765, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D5" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-88.2476, 84.1675) +rotation = -0.196411 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 18, +NodePath("../Path4"): 0 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D6" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-49.7804, 210.682) +rotation = -0.196411 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 17, +NodePath("../Path4"): 1 +} +metadata/_edit_lock_ = true + +[node name="Path5" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("line")] +position = Vector2(-72.5151, 64.2182) +script = ExtResource("1_inuwg") +stroke_color = Color(0.580392, 0, 0.211765, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ryeyi") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_qpkqr") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Hair/Path5"] +points = PackedVector2Array(7.65607, -7.64099, 5.08186, 1.19951, 2.9296, 9.94026, 1.22734, 18.5952, 0.00311404, 27.1782, -0.715041, 35.7034, -0.899083, 44.1845, -0.520975, 52.6355, -0.112353, 56.8541, 0.447322, 61.0704, 1.16155, 65.2861, 2.03385, 69.5031, 3.06771, 73.723, 4.26664, 77.9475, 5.63415, 82.1785, 7.17374, 86.4176, 10.7832, 94.9274, 15.123, 103.491, 20.2213, 112.121, 26.106, 120.834, 32.8052, 129.641) +width = 2.0 +default_color = Color(0.580392, 0, 0.211765, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D7" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-64.859, 56.5772) +rotation = -0.196411 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 19, +NodePath("../Path5"): 0 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D8" type="Node2D" parent="Body/Neck/Head/Hair" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-39.7099, 193.86) +rotation = -0.196411 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 16, +NodePath("../Path5"): 1 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-15.9463, -14.3899) +rotation = -0.0876902 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../.."): 0, +NodePath(".."): 2 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("vertex_map")] +position = Vector2(30.6811, 7.9303) +rotation = -0.0876902 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath("../.."): 1, +NodePath(".."): 1 +} +metadata/_edit_lock_ = true + +[node name="Eye" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("polygon", "line", "glue_map")] +position = Vector2(86.1287, -46.8739) +rotation = 0.0577994 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ej6pp") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ayt5m") +glue_map = { +3: NodePath("Lash") +} +use_interect_when_clipping = true +rx = 10.3081 +ry = 24.0747 + +[node name="Lash" type="Node2D" parent="Body/Neck/Head/Eye" node_paths=PackedStringArray("line")] +position = Vector2(1.52588e-05, -24.0747) +rotation = -0.456177 +script = ExtResource("1_inuwg") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ayt5m") +update_curve_at_runtime = true +arc_list = SubResource("Resource_wlod0") + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Eye/Lash"] +points = PackedVector2Array(-0.0906372, 0.273613, 0.106703, 0.27241, 0.325429, 0.290251, 0.819482, 0.384174, 1.37641, 0.557602, 1.98109, 0.812756, 2.61841, 1.15186, 3.27326, 1.57712, 3.93051, 2.09078, 4.57506, 2.69504, 5.35991, 3.8495, 6.22338, 4.9464, 7.16126, 5.98039, 8.16898, 6.94644, 9.24164, 7.83984, 10.374, 8.65624, 11.5606, 9.39167, 12.7955, 10.0425, 14.0729, 10.6057, 15.3864, 11.0783, 16.7297, 11.4582, 18.0962, 11.7434, 18.9873, 11.8766) +width = 2.0 +width_curve = SubResource("Curve_ef0ch") +default_color = Color(0, 0, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Eye"] +color = Color(1, 0.960784, 1, 1) +polygon = PackedVector2Array(10.3081, 0, 10.0987, 4.85201, 9.49806, 9.37113, 8.54768, 13.4606, 7.28899, 17.0235, 6.55698, 18.5773, 5.76343, 19.9632, 4.91352, 21.1691, 4.01245, 22.1828, 3.54434, 22.6139, 3.06537, 22.9924, 2.57621, 23.3168, 2.07749, 23.5856, 1.56986, 23.7973, 1.05397, 23.9504, 0.530468, 24.0434, 0, 24.0747, -0.530468, 24.0434, -1.05397, 23.9504, -1.56986, 23.7973, -2.07749, 23.5856, -2.57621, 23.3168, -3.06537, 22.9924, -3.54434, 22.6139, -4.01245, 22.1828, -4.91352, 21.1691, -5.76343, 19.9632, -6.55698, 18.5773, -7.28899, 17.0235, -8.54768, 13.4606, -9.49806, 9.37113, -10.0987, 4.85201, -10.3081, 0, -10.0987, -4.85201, -9.49806, -9.37113, -8.54768, -13.4606, -7.28899, -17.0235, -6.55698, -18.5773, -5.76343, -19.9632, -4.91352, -21.1691, -4.01245, -22.1828, -3.54434, -22.6139, -3.06537, -22.9924, -2.57621, -23.3168, -2.07749, -23.5856, -1.56986, -23.7973, -1.05397, -23.9504, -0.530468, -24.0434, 0, -24.0747, 0.530468, -24.0434, 1.05397, -23.9504, 1.56986, -23.7973, 2.07749, -23.5856, 2.57621, -23.3168, 3.06537, -22.9924, 3.54434, -22.6139, 4.01245, -22.1828, 4.91352, -21.1691, 5.76343, -19.9632, 6.55698, -18.5773, 7.28899, -17.0235, 8.54768, -13.4606, 9.49806, -9.37113, 10.0987, -4.85201) +metadata/_edit_lock_ = true + +[node name="Iris" type="Node2D" parent="Body/Neck/Head/Eye" node_paths=PackedStringArray("polygon", "clip_paths")] +position = Vector2(-5.11155, -3.27573) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.588235, 0, 0.505882, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_wlod0") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ef0ch") +clip_paths = [NodePath("..")] +shape_type = 2 +size = Vector2(24.8163, 56.1508) +rx = 12.4082 +ry = 28.0754 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Eye/Iris"] +color = Color(0, 0.87298, 0.698602, 1) +texture = SubResource("GradientTexture2D_48nhp") +texture_offset = Vector2(12.4081, 28.0754) +polygon = PackedVector2Array(5.64201, -20.7676, 6.16551, -20.6747, 6.68141, -20.5216, 7.18904, -20.3099, 7.68774, -20.0411, 8.17693, -19.7167, 8.65587, -19.3382, 9.11598, -18.9145, 10.2891, -15.6974, 11.4331, -10.9284, 12.1561, -5.65829, 12.4081, 0, 12.1561, 5.65829, 11.4331, 10.9284, 10.2891, 15.6974, 8.77396, 19.8525, 7.89281, 21.6645, 6.9376, 23.2807, 5.91454, 24.6869, 4.8299, 25.8692, 4.26641, 26.3718, 3.68987, 26.8132, 3.38631, 27.0082, 3.03406, 26.8613, 2.53534, 26.5925, 2.04617, 26.2681, 1.56721, 25.8896, 1.09909, 25.4586, 0.198013, 24.4448, -0.651871, 23.239, -1.44542, 21.8531, -2.17744, 20.2993, -3.43614, 16.7363, -4.38651, 12.6469, -4.98714, 8.12775, -5.19655, 3.27573, -4.98715, -1.57627, -4.38652, -6.0954, -3.43614, -10.1848, -2.17744, -13.7478, -1.44543, -15.3016, -0.651886, -16.6875, 0.198029, -17.8934, 1.09909, -18.9071, 1.56721, -19.3382, 2.04616, -19.7166, 2.53534, -20.0411, 3.03404, -20.3099, 3.54167, -20.5216, 4.05757, -20.6747, 4.58107, -20.7676, 5.11156, -20.799) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]] +metadata/_edit_lock_ = true + +[node name="Pupil" type="Node2D" parent="Body/Neck/Head/Eye/Iris" node_paths=PackedStringArray("polygon", "clip_paths")] +position = Vector2(-1.09432, 3.43547) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.588235, 0, 0.505882, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_p0i0j") +update_curve_at_runtime = true +arc_list = SubResource("Resource_s3xq1") +clip_paths = [NodePath("../..")] +shape_type = 2 +size = Vector2(24, 50) +rx = 12.0 +ry = 25.0 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Eye/Iris/Pupil"] +color = Color(0, 0, 0, 1) +polygon = PackedVector2Array(4.12608, -23.483, 4.67102, -23.0354, 5.71999, -21.9827, 6.7094, -20.7305, 7.63319, -19.2913, 8.48535, -17.6778, 9.95064, -13.9779, 11.057, -9.73129, 11.7562, -5.03848, 12, 0, 11.7562, 5.03848, 11.057, 9.73129, 9.95064, 13.9779, 8.48535, 17.6778, 7.63319, 19.2913, 6.7094, 20.7305, 5.71999, 21.9827, 4.67102, 23.0354, 4.17301, 23.4445, 4.12837, 23.4259, 3.62965, 23.1571, 3.14049, 22.8326, 2.66153, 22.4542, 2.19341, 22.0231, 1.29233, 21.0094, 0.442444, 19.8035, -0.351105, 18.4176, -1.08313, 16.8638, -2.34183, 13.3008, -3.29219, 9.2114, -3.89282, 4.69228, -4.10223, -0.159744, -3.89284, -5.01174, -3.29221, -9.53087, -2.34183, -13.6203, -1.08313, -17.1833, -0.35112, -18.7371, 0.442429, -20.123, 1.29234, -21.3288, 2.19341, -22.3426, 2.66153, -22.7736, 3.14047, -23.1521, 3.62965, -23.4765, 3.9162, -23.631) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]] +metadata/_edit_lock_ = true + +[node name="PupilShine" type="Node2D" parent="Body/Neck/Head/Eye/Iris/Pupil" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(-4.82516, -13.1802) +rotation = 0.0993998 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(1, 1, 1, 0.439216) +stroke_width = 0.5 +line = NodePath("Stroke") +curve = SubResource("Curve2D_lkcyw") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ye2us") +clip_paths = [NodePath("../../..")] +shape_type = 2 +size = Vector2(16, 24) +rx = 8.0 +ry = 12.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Eye/Iris/Pupil/PupilShine"] +polygon = PackedVector2Array(5.6569, -8.48535, 6.17323, -7.63319, 6.63376, -6.7094, 7.03447, -5.71999, 7.37134, -4.67102, 7.83747, -2.41847, 8, 0, 7.83747, 2.41847, 7.37134, 4.67102, 7.03447, 5.71999, 6.63376, 6.7094, 6.17323, 7.63319, 5.6569, 8.48535, 5.08879, 9.25984, 4.47293, 9.95064, 3.81333, 10.5517, 3.11401, 11.057, 2.379, 11.4605, 1.94076, 11.6295, 1.73834, 8.03561, 1.88754, 3.47919, 2.42743, -0.684387, 3.32631, -4.35466, 3.90053, -5.97343, 4.55263, -7.43123, 5.27867, -8.71548, 5.38275, -8.85908) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]] +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Eye/Iris/Pupil/PupilShine"] +points = PackedVector2Array(5.6569, -8.48535, 6.17323, -7.63319, 6.63376, -6.7094, 7.03447, -5.71999, 7.37134, -4.67102, 7.83747, -2.41847, 8, 0, 7.83747, 2.41847, 7.37134, 4.67102, 7.03447, 5.71999, 6.63376, 6.7094, 6.17323, 7.63319, 5.6569, 8.48535, 5.08879, 9.25984, 4.47293, 9.95064, 3.81333, 10.5517, 3.11401, 11.057, 2.379, 11.4605, 1.94076, 11.6295, 1.73834, 8.03561, 1.88754, 3.47919, 2.42743, -0.684387, 3.32631, -4.35466, 3.90053, -5.97343, 4.55263, -7.43123, 5.27867, -8.71548, 5.38275, -8.85908) +closed = true +width = 0.5 +default_color = Color(1, 1, 1, 0.439216) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="PupilShine2" type="Node2D" parent="Body/Neck/Head/Eye/Iris/Pupil" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(1.24684, 7.96526) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(1, 1, 1, 0.662745) +stroke_width = 0.5 +line = NodePath("Stroke") +curve = SubResource("Curve2D_48nhp") +update_curve_at_runtime = true +arc_list = SubResource("Resource_13sh3") +clip_paths = [NodePath("../../..")] +shape_type = 2 +size = Vector2(1.78526, 4.13709) +rx = 0.89263 +ry = 2.06855 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Eye/Iris/Pupil/PupilShine2"] +polygon = PackedVector2Array(0.0459366, -2.06586, 0.0912704, -2.05787, 0.135941, -2.04471, 0.179901, -2.02652, 0.223083, -2.00343, 0.26545, -1.97555, 0.306923, -1.94303, 0.347458, -1.90599, 0.425484, -1.81889, 0.499084, -1.71528, 0.567802, -1.5962, 0.631187, -1.46269, 0.740189, -1.15656, 0.822487, -0.805183, 0.874496, -0.416893, 0.892632, 0, 0.874496, 0.416893, 0.822487, 0.805183, 0.740189, 1.15656, 0.631187, 1.46269, 0.567802, 1.5962, 0.499084, 1.71528, 0.425484, 1.81889, 0.347458, 1.90599, 0.306923, 1.94303, 0.26545, 1.97555, 0.223083, 2.00343, 0.179901, 2.02652, 0.135941, 2.04471, 0.0912704, 2.05787, 0.0459366, 2.06586, 0, 2.06854, -0.0459366, 2.06586, -0.0912704, 2.05787, -0.135941, 2.04471, -0.179901, 2.02652, -0.223083, 2.00343, -0.26545, 1.97555, -0.306923, 1.94303, -0.347458, 1.90599, -0.425484, 1.81889, -0.499084, 1.71528, -0.567802, 1.5962, -0.631187, 1.46269, -0.740189, 1.15656, -0.822487, 0.805183, -0.874496, 0.416893, -0.892632, 0, -0.874496, -0.416893, -0.822487, -0.805183, -0.740189, -1.15656, -0.631187, -1.46269, -0.567802, -1.5962, -0.499084, -1.71528, -0.425484, -1.81889, -0.347458, -1.90599, -0.306923, -1.94303, -0.26545, -1.97555, -0.223083, -2.00343, -0.179901, -2.02652, -0.135941, -2.04471, -0.0912704, -2.05787, -0.0459366, -2.06586, 0, -2.06854) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]] +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Eye/Iris/Pupil/PupilShine2"] +points = PackedVector2Array(0.0459366, -2.06586, 0.0912704, -2.05787, 0.135941, -2.04471, 0.179901, -2.02652, 0.223083, -2.00343, 0.26545, -1.97555, 0.306923, -1.94303, 0.347458, -1.90599, 0.425484, -1.81889, 0.499084, -1.71528, 0.567802, -1.5962, 0.631187, -1.46269, 0.740189, -1.15656, 0.822487, -0.805183, 0.874496, -0.416893, 0.892632, 0, 0.874496, 0.416893, 0.822487, 0.805183, 0.740189, 1.15656, 0.631187, 1.46269, 0.567802, 1.5962, 0.499084, 1.71528, 0.425484, 1.81889, 0.347458, 1.90599, 0.306923, 1.94303, 0.26545, 1.97555, 0.223083, 2.00343, 0.179901, 2.02652, 0.135941, 2.04471, 0.0912704, 2.05787, 0.0459366, 2.06586, 0, 2.06854, -0.0459366, 2.06586, -0.0912704, 2.05787, -0.135941, 2.04471, -0.179901, 2.02652, -0.223083, 2.00343, -0.26545, 1.97555, -0.306923, 1.94303, -0.347458, 1.90599, -0.425484, 1.81889, -0.499084, 1.71528, -0.567802, 1.5962, -0.631187, 1.46269, -0.740189, 1.15656, -0.822487, 0.805183, -0.874496, 0.416893, -0.892632, 0, -0.874496, -0.416893, -0.822487, -0.805183, -0.740189, -1.15656, -0.631187, -1.46269, -0.567802, -1.5962, -0.499084, -1.71528, -0.425484, -1.81889, -0.347458, -1.90599, -0.306923, -1.94303, -0.26545, -1.97555, -0.223083, -2.00343, -0.179901, -2.02652, -0.135941, -2.04471, -0.0912704, -2.05787, -0.0459366, -2.06586, 0, -2.06854) +closed = true +width = 0.5 +default_color = Color(1, 1, 1, 0.662745) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Eye"] +points = PackedVector2Array(10.3081, 0, 10.0987, 4.85201, 9.49806, 9.37113, 8.54768, 13.4606, 7.28899, 17.0235, 6.55698, 18.5773, 5.76343, 19.9632, 4.91352, 21.1691, 4.01245, 22.1828, 3.54434, 22.6139, 3.06537, 22.9924, 2.57621, 23.3168, 2.07749, 23.5856, 1.56986, 23.7973, 1.05397, 23.9504, 0.530468, 24.0434, 0, 24.0747, -0.530468, 24.0434, -1.05397, 23.9504, -1.56986, 23.7973, -2.07749, 23.5856, -2.57621, 23.3168, -3.06537, 22.9924, -3.54434, 22.6139, -4.01245, 22.1828, -4.91352, 21.1691, -5.76343, 19.9632, -6.55698, 18.5773, -7.28899, 17.0235, -8.54768, 13.4606, -9.49806, 9.37113, -10.0987, 4.85201, -10.3081, 0, -10.0987, -4.85201, -9.49806, -9.37113, -8.54768, -13.4606, -7.28899, -17.0235, -6.55698, -18.5773, -5.76343, -19.9632, -4.91352, -21.1691, -4.01245, -22.1828, -3.54434, -22.6139, -3.06537, -22.9924, -2.57621, -23.3168, -2.07749, -23.5856, -1.56986, -23.7973, -1.05397, -23.9504, -0.530468, -24.0434, 0, -24.0747, 0.530468, -24.0434, 1.05397, -23.9504, 1.56986, -23.7973, 2.07749, -23.5856, 2.57621, -23.3168, 3.06537, -22.9924, 3.54434, -22.6139, 4.01245, -22.1828, 4.91352, -21.1691, 5.76343, -19.9632, 6.55698, -18.5773, 7.28899, -17.0235, 8.54768, -13.4606, 9.49806, -9.37113, 10.0987, -4.85201) +closed = true +width = 2.0 +width_curve = SubResource("Curve_inuwg") +default_color = Color(0, 0, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Mouth" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(70.7687, -1.04735) +rotation = -0.144918 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427451, 0.207843, 0.760784, 1) +stroke_width = 3.0 +begin_cap_mode = 2 +end_cap_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ycisl") +update_curve_at_runtime = true +arc_list = SubResource("Resource_lkcyw") +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Mouth"] +polygon = PackedVector2Array(2.54356, 0.664536, 1.30654, 0.0175916, 0.117661, -0.714067, -1.01729, -1.52688, -2.09277, -2.41687, -3.10355, -3.37973, -4.0447, -4.41074, -4.91164, -5.5049, -5.70014, -6.65686, -6.40637, -7.86102, -7.02688, -9.11152, -7.55864, -10.4022, -7.99907, -11.7269, -8.34603, -13.0791, -8.59782, -14.4522, -8.75321, -15.8395, -8.81145, -17.2343, -8.80157, -18.014, -9.90125, -17.1541, -10.9383, -16.2196, -11.9076, -15.215, -12.8044, -14.1452, -13.6245, -13.0155, -14.3638, -11.8313, -15.0186, -10.5985, -15.5859, -9.32292, -16.0628, -8.01093, -16.447, -6.66886, -16.7366, -5.30327, -16.9303, -3.92079, -17.0271, -2.52817, -17.0265, -1.13219, -16.9286, 0.260349, -16.7337, 1.64266, -16.4429, 3.00801, -16.0575, 4.34975, -15.5795, 5.66134, -15.0112, 6.93639, -14.3553, 8.16869, -13.745, 9.15728) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Mouth"] +points = PackedVector2Array(2.54356, 0.664536, 1.30654, 0.0175916, 0.117661, -0.714067, -1.01729, -1.52688, -2.09277, -2.41687, -3.10355, -3.37973, -4.0447, -4.41074, -4.91164, -5.5049, -5.70014, -6.65686, -6.40637, -7.86102, -7.02688, -9.11152, -7.55864, -10.4022, -7.99907, -11.7269, -8.34603, -13.0791, -8.59782, -14.4522, -8.75321, -15.8395, -8.81145, -17.2343, -8.80157, -18.014, -9.90125, -17.1541, -10.9383, -16.2196, -11.9076, -15.215, -12.8044, -14.1452, -13.6245, -13.0155, -14.3638, -11.8313, -15.0186, -10.5985, -15.5859, -9.32292, -16.0628, -8.01093, -16.447, -6.66886, -16.7366, -5.30327, -16.9303, -3.92079, -17.0271, -2.52817, -17.0265, -1.13219, -16.9286, 0.260349, -16.7337, 1.64266, -16.4429, 3.00801, -16.0575, 4.34975, -15.5795, 5.66134, -15.0112, 6.93639, -14.3553, 8.16869, -13.745, 9.15728) +width = 3.0 +width_curve = SubResource("Curve_ye2us") +default_color = Color(0.427451, 0.207843, 0.760784, 1) +begin_cap_mode = 2 +end_cap_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Nose" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(69.3222, -44.1276) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427451, 0.207843, 0.760784, 1) +stroke_width = 4.0 +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ef0ch") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ycisl") +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Nose"] +color = Color(0.556863, 0.603922, 1, 1) +polygon = PackedVector2Array(6.13687, -3.51773, 6.21259, 0.0743157, 6.61921, 3.90234, 7.54896, 8.49655, 8.275, 10.9431, 9.20982, 13.4156, 10.3794, 15.859, 11.8098, 18.2181, 13.5269, 20.4378, 15.5568, 22.4628, 16.6971, 23.3851, 17.9254, 24.238, 19.2449, 25.0147, 20.6588, 25.7082, 20.69, 26.8518, 20.6208, 28.0973, 20.4449, 29.4223, 20.1562, 30.8043, 19.7486, 32.2208, 19.2158, 33.6493, 18.5518, 35.0674, 17.7504, 36.4526, 16.8054, 37.7823, 15.7106, 39.0341, 14.46, 40.1855, 13.0473, 41.2141, 11.4663, 42.0973, 9.71101, 42.8126, 7.77517, 43.3377, 5.65263, 43.6499, 4.56407, 43.692, 3.51608, 43.6249, 2.50826, 43.4554, 1.54022, 43.1908, 0.611555, 42.8381, -0.27812, 42.4044, -1.1292, 41.8968, -1.94208, 41.3224, -3.45481, 40.0013, -4.81947, 38.4979, -6.0392, 36.8687, -7.11716, 35.1705, -8.86037, 31.7936, -10.0743, 28.8203, -11.0152, 25.8978) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Nose"] +points = PackedVector2Array(6.13687, -3.51773, 6.21259, 0.0743157, 6.61921, 3.90234, 7.54896, 8.49655, 8.275, 10.9431, 9.20982, 13.4156, 10.3794, 15.859, 11.8098, 18.2181, 13.5269, 20.4378, 15.5568, 22.4628, 16.6971, 23.3851, 17.9254, 24.238, 19.2449, 25.0147, 20.6588, 25.7082, 20.69, 26.8518, 20.6208, 28.0973, 20.4449, 29.4223, 20.1562, 30.8043, 19.7486, 32.2208, 19.2158, 33.6493, 18.5518, 35.0674, 17.7504, 36.4526, 16.8054, 37.7823, 15.7106, 39.0341, 14.46, 40.1855, 13.0473, 41.2141, 11.4663, 42.0973, 9.71101, 42.8126, 7.77517, 43.3377, 5.65263, 43.6499, 4.56407, 43.692, 3.51608, 43.6249, 2.50826, 43.4554, 1.54022, 43.1908, 0.611555, 42.8381, -0.27812, 42.4044, -1.1292, 41.8968, -1.94208, 41.3224, -3.45481, 40.0013, -4.81947, 38.4979, -6.0392, 36.8687, -7.11716, 35.1705, -8.86037, 31.7936, -10.0743, 28.8203, -11.0152, 25.8978) +width = 4.0 +width_curve = SubResource("Curve_48nhp") +default_color = Color(0.427451, 0.207843, 0.760784, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="EyeFront" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("polygon", "line", "glue_map")] +position = Vector2(32.107, -44.2939) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 4.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_s3xq1") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ala13") +glue_map = { +3: NodePath("Lash") +} +use_interect_when_clipping = true +rx = 22.3641 +ry = 28.4301 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/EyeFront"] +polygon = PackedVector2Array(21.446, 0.794495, 21.149, 4.20391, 20.6355, 7.36076, 19.9222, 10.2711, 19.0256, 12.941, 17.9623, 15.3765, 16.7489, 17.5837, 15.4018, 19.5686, 13.9378, 21.3373, 12.3733, 22.8958, 10.7248, 24.2503, 9.00909, 25.4067, 7.24256, 26.3711, 5.44183, 27.1496, 3.62345, 27.7482, 1.80398, 28.173, 0, 28.4301, -3.48863, 28.6478, -6.76219, 28.5004, -8.3045, 28.2429, -9.77646, 27.838, -11.1726, 27.2669, -12.4873, 26.511, -13.1124, 26.0578, -13.7151, 25.5514, -14.2947, 24.9895, -14.8504, 24.3696, -15.8878, 22.9467, -16.8217, 21.264, -17.6466, 19.3029, -18.357, 17.0447, -19.412, 11.5617, -19.3913, 9.29751, -18.9297, 3.78309, -18.3463, 0.406171, -17.428, -3.06434, -16.8199, -4.75981, -16.0999, -6.38881, -15.2588, -7.92137, -14.2871, -9.32756, -9.9236, -14.6689, -5.23448, -19.5962, -2.80571, -21.7019, -0.341018, -23.4609, 0.900062, -24.1849, 2.14444, -24.7919, 3.39021, -25.2716, 4.63549, -25.614, 5.27041, -25.7186, 5.92873, -25.7623, 6.60741, -25.745, 7.30341, -25.667, 8.01366, -25.5283, 8.73513, -25.329, 10.1995, -24.7491, 11.6722, -23.928, 13.1288, -22.8666, 14.5449, -21.5655, 15.8962, -20.0257, 17.1582, -18.2479, 18.3067, -16.2329, 19.3171, -13.9815, 20.1651, -11.4944, 20.8264, -8.77248, 21.2766, -5.81649, 21.4913, -2.62724) +metadata/_edit_lock_ = true + +[node name="Lash" type="Node2D" parent="Body/Neck/Head/EyeFront" node_paths=PackedStringArray("line")] +position = Vector2(-14.2871, -9.32756) +rotation = 2.24227 +script = ExtResource("1_inuwg") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ye2us") +update_curve_at_runtime = true +arc_list = SubResource("Resource_lno47") + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/EyeFront/Lash"] +points = PackedVector2Array(-0.0906369, 0.273612, 1.28385, 0.517639, 2.63796, 0.85695, 3.96511, 1.28989, 5.25883, 1.81436, 6.5128, 2.42779, 7.72093, 3.1272, 8.87734, 3.90919, 9.97637, 4.76993, 11.0127, 5.70524, 11.9812, 6.71057, 12.8773, 7.781, 13.6965, 8.91134, 14.1008, 9.53712) +width = 2.0 +width_curve = SubResource("Curve_ef0ch") +default_color = Color(0, 0, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Iris" type="Node2D" parent="Body/Neck/Head/EyeFront" node_paths=PackedStringArray("polygon", "clip_paths")] +position = Vector2(-5.45288, 5.5916) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_13sh3") +update_curve_at_runtime = true +arc_list = SubResource("Resource_xhpvu") +clip_paths = [NodePath("..")] +use_interect_when_clipping = true +shape_type = 2 +size = Vector2(35.548, 48.2463) +rx = 17.774 +ry = 24.1232 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/EyeFront/Iris"] +color = Color(0, 0.87451, 0.698039, 1) +texture = SubResource("GradientTexture2D_lno47") +texture_offset = Vector2(17.774, 24.1231) +polygon = PackedVector2Array(1.81733, -23.9986, 3.58216, -23.6331, 5.28555, -23.0387, 6.91856, -22.2275, 8.47227, -21.2117, 9.93773, -20.0034, 11.306, -18.6147, 12.5682, -17.0578, 13.7154, -15.3447, 14.7385, -13.4876, 15.6288, -11.4987, 16.3773, -9.38998, 16.9749, -7.17362, 17.4129, -4.86176, 17.6822, -2.46651, 17.774, 0, 17.6822, 2.46651, 17.4129, 4.86176, 16.9749, 7.17362, 16.3773, 9.38998, 15.6288, 11.4987, 14.7386, 13.4876, 13.7154, 15.3447, 12.5682, 17.0578, 11.306, 18.6147, 9.93773, 20.0034, 8.47227, 21.2117, 6.91856, 22.2275, 5.78327, 22.7914, 5.45288, 22.8385, 1.96425, 23.0562, -1.3093, 22.9088, -2.85162, 22.6513, -4.32359, 22.2464, -5.7197, 21.6753, -7.0344, 20.9194, -7.65952, 20.4662, -8.26219, 19.9598, -8.84178, 19.3979, -9.39755, 18.778, -10.435, 17.3551, -11.3689, 15.6724, -12.1938, 13.7113, -12.9041, 11.4531, -13.9591, 5.97009, -13.9384, 3.70591, -13.4768, -1.80852, -12.8934, -5.18544, -11.9751, -8.65595, -11.367, -10.3514, -10.647, -11.9804, -9.80589, -13.513, -8.83422, -14.9192, -4.47073, -20.2605, -0.850266, -24.0649, 0, -24.1232) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]] +metadata/_edit_lock_ = true + +[node name="Pupil" type="Node2D" parent="Body/Neck/Head/EyeFront/Iris" node_paths=PackedStringArray("polygon", "clip_paths")] +position = Vector2(-3.08707, -0.685577) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0, 0, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_78whv") +update_curve_at_runtime = true +arc_list = SubResource("Resource_y8bhp") +clip_paths = [NodePath("../.."), NodePath("..")] +use_interect_when_clipping = true +shape_type = 2 +size = Vector2(31.2052, 45.2643) +rx = 15.6026 +ry = 22.6321 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil"] +color = Color(0, 0, 0, 1) +polygon = PackedVector2Array(1.59531, -22.5153, 2.37617, -22.3714, 3.14454, -22.1724, 4.63982, -21.6147, 6.07333, -20.8537, 7.43723, -19.9006, 8.72366, -18.767, 9.9248, -17.4642, 11.0328, -16.0035, 12.0398, -14.3963, 12.938, -12.654, 13.7195, -10.788, 14.3765, -8.8096, 14.9012, -6.73024, 15.2856, -4.56126, 15.522, -2.31406, 15.6026, 0, 15.522, 2.31406, 15.2856, 4.56126, 14.9012, 6.73024, 14.3765, 8.8096, 13.7195, 10.788, 12.938, 12.654, 12.0398, 14.3963, 11.0328, 16.0035, 9.9248, 17.4642, 8.72367, 18.767, 7.43723, 19.9006, 6.07333, 20.8537, 4.63982, 21.6147, 3.14454, 22.1724, 2.37617, 22.3714, 1.59531, 22.5153, 0.802925, 22.6027, 0, 22.6321, -0.802925, 22.6027, -1.59531, 22.5153, -2.37617, 22.3714, -2.80972, 22.2591, -3.94733, 21.605, -4.57245, 21.1518, -5.17513, 20.6454, -5.75471, 20.0834, -6.31049, 19.4636, -7.34789, 18.0407, -8.28179, 16.358, -9.10669, 14.3969, -9.81704, 12.1386, -10.8721, 6.65568, -10.8513, 4.39149, -10.3897, -1.12293, -9.80635, -4.49986, -8.88806, -7.97037, -8.27992, -9.66583, -7.55996, -11.2948, -6.71883, -12.8274, -5.74715, -14.2336, -1.38366, -19.5749, 1.43175, -22.5333) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58]] +metadata/_edit_lock_ = true + +[node name="PupilShine" type="Node2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(-1.03037, -9.94677) +rotation = 0.236561 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(1, 1, 1, 0.560784) +stroke_width = 0.5 +line = NodePath("Stroke") +curve = SubResource("Curve2D_w157y") +update_curve_at_runtime = true +arc_list = SubResource("Resource_7717w") +clip_paths = [NodePath("../../.."), NodePath("..")] +shape_type = 2 +size = Vector2(16, 24) +rx = 8.0 +ry = 12.0 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine"] +polygon = PackedVector2Array(0.41169, -11.9844, 0.81797, -11.938, 1.21835, -11.8617, 1.61231, -11.7562, 2.379, -11.4605, 3.11401, -11.057, 3.81333, -10.5517, 4.47293, -9.95064, 5.08879, -9.25984, 5.6569, -8.48535, 6.17323, -7.63319, 6.63376, -6.7094, 7.03447, -5.71999, 7.37134, -4.67102, 7.83747, -2.41847, 8, 0, 7.83747, 2.41847, 7.37134, 4.67102, 7.03447, 5.71999, 6.63376, 6.7094, 6.17323, 7.63319, 5.6569, 8.48535, 5.08879, 9.25984, 4.47293, 9.95064, 3.81333, 10.5517, 3.11401, 11.057, 2.379, 11.4605, 1.61231, 11.7562, 1.21835, 11.8617, 0.81797, 11.938, 0.41169, 11.9844, 0, 12, -0.41169, 11.9844, -0.81797, 11.938, -1.21835, 11.8617, -1.61231, 11.7562, -2.379, 11.4605, -3.11401, 11.057, -3.81333, 10.5517, -4.47293, 9.95064, -5.08879, 9.25984, -5.6569, 8.48535, -6.17323, 7.63319, -6.63376, 6.7094, -7.03447, 5.71999, -7.20705, 5.18258, -7.17566, 3.7629, -6.98181, 1.97212, -6.66367, 0.219765, -6.20514, -1.46725, -5.59009, -3.062, -2.5999, -9.27718, -1.09219, -11.8858, -0.81797, -11.938, -0.41169, -11.9844, 0, -12) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]] +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine"] +points = PackedVector2Array(0.41169, -11.9844, 0.81797, -11.938, 1.21835, -11.8617, 1.61231, -11.7562, 2.379, -11.4605, 3.11401, -11.057, 3.81333, -10.5517, 4.47293, -9.95064, 5.08879, -9.25984, 5.6569, -8.48535, 6.17323, -7.63319, 6.63376, -6.7094, 7.03447, -5.71999, 7.37134, -4.67102, 7.83747, -2.41847, 8, 0, 7.83747, 2.41847, 7.37134, 4.67102, 7.03447, 5.71999, 6.63376, 6.7094, 6.17323, 7.63319, 5.6569, 8.48535, 5.08879, 9.25984, 4.47293, 9.95064, 3.81333, 10.5517, 3.11401, 11.057, 2.379, 11.4605, 1.61231, 11.7562, 1.21835, 11.8617, 0.81797, 11.938, 0.41169, 11.9844, 0, 12, -0.41169, 11.9844, -0.81797, 11.938, -1.21835, 11.8617, -1.61231, 11.7562, -2.379, 11.4605, -3.11401, 11.057, -3.81333, 10.5517, -4.47293, 9.95064, -5.08879, 9.25984, -5.6569, 8.48535, -6.17323, 7.63319, -6.63376, 6.7094, -7.03447, 5.71999, -7.20705, 5.18258, -7.17566, 3.7629, -6.98181, 1.97212, -6.66367, 0.219765, -6.20514, -1.46725, -5.59009, -3.062, -2.5999, -9.27718, -1.09219, -11.8858, -0.81797, -11.938, -0.41169, -11.9844, 0, -12) +closed = true +width = 0.5 +default_color = Color(1, 1, 1, 0.560784) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="ExtraStroke" type="Line2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine/Stroke"] +visible = false +points = PackedVector2Array(7.37134, -4.67102, 7.58776, -3.62515, 5.88145, -3.14936, -0.334999, -0.727379, -6.38522, 2.12116, -6.38108, 2.11504, -6.31966, 2.04053, -6.15194, 1.87279, -5.64703, 1.4684, -4.03872, 0.432213, 0.936218, -2.16418, 7.04475, -4.72474, 7.32463, -4.81645) +closed = true +width = 0.5 +default_color = Color(1, 1, 1, 0.560784) +metadata/_edit_lock_ = true + +[node name="PupilShine2" type="Node2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(6.48325, 4.35518) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(1, 1, 1, 0.662745) +stroke_width = 0.5 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ala13") +update_curve_at_runtime = true +arc_list = SubResource("Resource_13sh3") +clip_paths = [NodePath("../../..")] +shape_type = 2 +size = Vector2(4, 4) +rx = 2.0 +ry = 2.0 + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine2"] +polygon = PackedVector2Array(0.204491, -1.98968, 0.403076, -1.95937, 0.594749, -1.91009, 0.778503, -1.84283, 0.953331, -1.75861, 1.11823, -1.65844, 1.2722, -1.5433, 1.41422, -1.41422, 1.5433, -1.2722, 1.65844, -1.11823, 1.75861, -0.953331, 1.84283, -0.778503, 1.91009, -0.594749, 1.95937, -0.403076, 1.98968, -0.204491, 2, 0, 1.98968, 0.204491, 1.95937, 0.403076, 1.91009, 0.594749, 1.84283, 0.778503, 1.75861, 0.953331, 1.65844, 1.11823, 1.5433, 1.2722, 1.41422, 1.41422, 1.2722, 1.5433, 1.11823, 1.65844, 0.953331, 1.75861, 0.778503, 1.84283, 0.594749, 1.91009, 0.403076, 1.95937, 0.204491, 1.98968, 0, 2, -0.204491, 1.98968, -0.403076, 1.95937, -0.594749, 1.91009, -0.778503, 1.84283, -0.953331, 1.75861, -1.11823, 1.65844, -1.2722, 1.5433, -1.41422, 1.41422, -1.5433, 1.2722, -1.65844, 1.11823, -1.75861, 0.953331, -1.84283, 0.778503, -1.91009, 0.594749, -1.95937, 0.403076, -1.98968, 0.204491, -2, 0, -1.98968, -0.204491, -1.95937, -0.403076, -1.91009, -0.594749, -1.84283, -0.778503, -1.75861, -0.953331, -1.65844, -1.11823, -1.5433, -1.2722, -1.41422, -1.41422, -1.2722, -1.5433, -1.11823, -1.65844, -0.953331, -1.75861, -0.778503, -1.84283, -0.594749, -1.91009, -0.403076, -1.95937, -0.204491, -1.98968, 0, -2) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]] +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/EyeFront/Iris/Pupil/PupilShine2"] +points = PackedVector2Array(0.204491, -1.98968, 0.403076, -1.95937, 0.594749, -1.91009, 0.778503, -1.84283, 0.953331, -1.75861, 1.11823, -1.65844, 1.2722, -1.5433, 1.41422, -1.41422, 1.5433, -1.2722, 1.65844, -1.11823, 1.75861, -0.953331, 1.84283, -0.778503, 1.91009, -0.594749, 1.95937, -0.403076, 1.98968, -0.204491, 2, 0, 1.98968, 0.204491, 1.95937, 0.403076, 1.91009, 0.594749, 1.84283, 0.778503, 1.75861, 0.953331, 1.65844, 1.11823, 1.5433, 1.2722, 1.41422, 1.41422, 1.2722, 1.5433, 1.11823, 1.65844, 0.953331, 1.75861, 0.778503, 1.84283, 0.594749, 1.91009, 0.403076, 1.95937, 0.204491, 1.98968, 0, 2, -0.204491, 1.98968, -0.403076, 1.95937, -0.594749, 1.91009, -0.778503, 1.84283, -0.953331, 1.75861, -1.11823, 1.65844, -1.2722, 1.5433, -1.41422, 1.41422, -1.5433, 1.2722, -1.65844, 1.11823, -1.75861, 0.953331, -1.84283, 0.778503, -1.91009, 0.594749, -1.95937, 0.403076, -1.98968, 0.204491, -2, 0, -1.98968, -0.204491, -1.95937, -0.403076, -1.91009, -0.594749, -1.84283, -0.778503, -1.75861, -0.953331, -1.65844, -1.11823, -1.5433, -1.2722, -1.41422, -1.41422, -1.2722, -1.5433, -1.11823, -1.65844, -0.953331, -1.75861, -0.778503, -1.84283, -0.594749, -1.91009, -0.403076, -1.95937, -0.204491, -1.98968, 0, -2) +closed = true +width = 0.5 +default_color = Color(1, 1, 1, 0.662745) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/EyeFront"] +points = PackedVector2Array(21.446, 0.794495, 21.149, 4.20391, 20.6355, 7.36076, 19.9222, 10.2711, 19.0256, 12.941, 17.9623, 15.3765, 16.7489, 17.5837, 15.4018, 19.5686, 13.9378, 21.3373, 12.3733, 22.8958, 10.7248, 24.2503, 9.00909, 25.4067, 7.24256, 26.3711, 5.44183, 27.1496, 3.62345, 27.7482, 1.80398, 28.173, 0, 28.4301, -3.48863, 28.6478, -6.76219, 28.5004, -8.3045, 28.2429, -9.77646, 27.838, -11.1726, 27.2669, -12.4873, 26.511, -13.1124, 26.0578, -13.7151, 25.5514, -14.2947, 24.9895, -14.8504, 24.3696, -15.8878, 22.9467, -16.8217, 21.264, -17.6466, 19.3029, -18.357, 17.0447, -19.412, 11.5617, -19.3913, 9.29751, -18.9297, 3.78309, -18.3463, 0.406171, -17.428, -3.06434, -16.8199, -4.75981, -16.0999, -6.38881, -15.2588, -7.92137, -14.2871, -9.32756, -9.9236, -14.6689, -5.23448, -19.5962, -2.80571, -21.7019, -0.341018, -23.4609, 0.900062, -24.1849, 2.14444, -24.7919, 3.39021, -25.2716, 4.63549, -25.614, 5.27041, -25.7186, 5.92873, -25.7623, 6.60741, -25.745, 7.30341, -25.667, 8.01366, -25.5283, 8.73513, -25.329, 10.1995, -24.7491, 11.6722, -23.928, 13.1288, -22.8666, 14.5449, -21.5655, 15.8962, -20.0257, 17.1582, -18.2479, 18.3067, -16.2329, 19.3171, -13.9815, 20.1651, -11.4944, 20.8264, -8.77248, 21.2766, -5.81649, 21.4913, -2.62724) +closed = true +width = 4.0 +width_curve = SubResource("Curve_ryeyi") +default_color = Color(0, 0, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Ear" type="Node2D" parent="Body/Neck/Head" node_paths=PackedStringArray("polygon", "line")] +z_index = 1 +position = Vector2(3.42202, -63.7032) +rotation = -0.436805 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427451, 0.207843, 0.760784, 1) +stroke_width = 4.0 +begin_cap_mode = 2 +end_cap_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_xhpvu") +update_curve_at_runtime = true +arc_list = SubResource("Resource_78whv") + +[node name="Fill" type="Polygon2D" parent="Body/Neck/Head/Ear"] +color = Color(0.556863, 0.603922, 1, 1) +polygon = PackedVector2Array(-0.216156, 0.27977, -4.05494, -3.67149, -7.38366, -7.87746, -10.2082, -12.2864, -12.5346, -16.8467, -14.3686, -21.5066, -15.7163, -26.2143, -16.5835, -30.9182, -16.9761, -35.5665, -16.9001, -40.1076, -16.3614, -44.4897, -15.3659, -48.6612, -13.9195, -52.5702, -12.0282, -56.1652, -10.9176, -57.8287, -9.69787, -59.3943, -8.36991, -60.8555, -6.93441, -62.2059, -5.39211, -63.439, -3.74375, -64.5483, -3.04157, -64.207, -2.26812, -63.7255, -0.529983, -62.3655, 3.55285, -58.2232, 8.14287, -52.5, 12.8782, -45.5747, 17.397, -37.8262, 21.3374, -29.6331, 24.3375, -21.3742, 25.3718, -17.3385, 26.0354, -13.4283) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Ear"] +points = PackedVector2Array(-0.216156, 0.27977, -4.05494, -3.67149, -7.38366, -7.87746, -10.2082, -12.2864, -12.5346, -16.8467, -14.3686, -21.5066, -15.7163, -26.2143, -16.5835, -30.9182, -16.9761, -35.5665, -16.9001, -40.1076, -16.3614, -44.4897, -15.3659, -48.6612, -13.9195, -52.5702, -12.0282, -56.1652, -10.9176, -57.8287, -9.69787, -59.3943, -8.36991, -60.8555, -6.93441, -62.2059, -5.39211, -63.439, -3.74375, -64.5483, -3.04157, -64.207, -2.26812, -63.7255, -0.529983, -62.3655, 3.55285, -58.2232, 8.14287, -52.5, 12.8782, -45.5747, 17.397, -37.8262, 21.3374, -29.6331, 24.3375, -21.3742, 25.3718, -17.3385, 26.0354, -13.4283) +width = 4.0 +width_curve = SubResource("Curve_y8bhp") +default_color = Color(0.427451, 0.207843, 0.760784, 1) +begin_cap_mode = 2 +end_cap_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Path" type="Node2D" parent="Body/Neck/Head/Ear" node_paths=PackedStringArray("line")] +position = Vector2(-0.198175, -15.8101) +script = ExtResource("1_inuwg") +stroke_color = Color(0.427451, 0.207843, 0.760784, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_7717w") +update_curve_at_runtime = true +tolerance_degrees = 2.0 +arc_list = SubResource("Resource_ryeyi") +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Body/Neck/Head/Ear/Path"] +points = PackedVector2Array(0.0507202, -0.158768, -1.35259, -1.63226, -2.6205, -3.1445, -3.753, -4.69551, -4.26847, -5.48555, -4.7501, -6.28527, -5.19787, -7.09469, -5.61179, -7.9138, -5.99186, -8.7426, -6.33808, -9.58108, -6.65045, -10.4293, -6.92897, -11.2871, -7.17363, -12.1547, -7.38445, -13.0319, -7.56141, -13.9189, -7.70453, -14.8155, -7.81379, -15.7218, -7.8892, -16.6378, -7.93076, -17.5635, -7.93847, -18.4989, -7.91233, -19.4439, -7.85234, -20.3987, -7.6308, -22.3373, -7.27386, -24.3146, -6.78151, -26.3307, -6.15376, -28.3856) +width = 2.0 +width_curve = SubResource("Curve_qpkqr") +default_color = Color(0.427451, 0.207843, 0.760784, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(-52.9414, -33.224, -51.7496, -33.8212, -50.4681, -34.3921, -49.1002, -34.9371, -47.6495, -35.4569, -44.5133, -36.4227, -41.0875, -37.2939, -33.4777, -38.7699, -25.0426, -39.9195, -6.5858, -41.3787, 12.5042, -41.9494, 59.6188, -40.9053, 99.2969, -5.36705, 96.225, -1.87789, 92.7209, 1.74545, 88.8128, 5.46957, 84.529, 9.26107, 74.9469, 16.9126, 64.2003, 24.4329, 52.5148, 31.5548, 46.3906, 34.8827, 40.1162, 38.0109, 33.72, 40.9059, 27.2301, 43.5342, 20.6748, 45.8626, 14.0822, 47.8575, 7.48057, 49.4856, 0.89814, 50.7135, -5.63691, 51.5078, -8.87785, 51.7319, -12.0964, 51.8351, -15.2889, 51.8132, -18.452, 51.662, -21.5821, 51.3773, -24.6756, 50.955, -27.7291, 50.3909, -30.739, 49.6809, -33.7018, 48.8207, -36.614, 47.8061, -39.472, 46.6331, -42.2723, 45.2974, -45.0114, 43.7948, -47.6857, 42.1212, -50.2918, 40.2724, -52.8261, 38.2442, -55.2851, 36.0325, -57.6652, 33.633, -59.963, 31.0417, -62.1749, 28.2542, -64.2973, 25.2666, -66.3268, 22.0745, -68.2598, 18.6737, -70.0928, 15.0602, -71.8223, 11.2298, -73.4447, 7.17824, -73.5662, 5.97648, -73.647, 4.56595, -73.6781, 2.69717, -73.6122, 0.431249, -73.4018, -2.17069, -72.9997, -5.04752, -72.3586, -8.13813, -71.9335, -9.7445, -71.431, -11.3814, -70.845, -13.0412, -70.1696, -14.7162, -69.399, -16.3988, -68.5272, -18.0813, -67.5482, -19.7562, -66.4563, -21.4158, -65.2453, -23.0524, -63.9096, -24.6584, -62.443, -26.2262, -60.8398, -27.7481, -59.0939, -29.2164, -57.1995, -30.6236, -55.1506, -31.962) +metadata/_edit_lock_ = true + +[node name="FrontFrontLeg" type="Node2D" parent="Body" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(40, -4) +rotation = -0.0792349 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_p8hpb") +update_curve_at_runtime = true +arc_list = SubResource("Resource_nndv2") +offset = Vector2(-1, 43.3333) + +[node name="Stroke" type="Line2D" parent="Body/FrontFrontLeg"] +points = PackedVector2Array(27.19, -1.95666, 21.3743, 73.1478, 12.6771, 76.4133, 8.21304, 77.8784, 6.00144, 78.4233, 3.82224, 78.7878, 1.68954, 78.9301, -0.382572, 78.8087, -1.39151, 78.6361, -2.38002, 78.382, -3.34633, 78.0411, -4.2887, 77.6083, -5.20536, 77.0783, -6.09454, 76.446, -6.95449, 75.7062, -7.78345, 74.8536, -8.57965, 73.8831, -9.34133, 72.7894, -10.7541, 70.2118, -8.28506, 46.9509, -8.53777, 23.3822, -10.0098, 10.2195, -12.75, -3.25) +width_curve = SubResource("Curve_p8hpb") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="LowerLeg" type="Node2D" parent="Body/FrontFrontLeg" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(2.25, 73.5) +rotation = -0.0668674 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_6svqr") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ipurh") + +[node name="Stroke" type="Line2D" parent="Body/FrontFrontLeg/LowerLeg"] +points = PackedVector2Array(19.1051, 0.926422, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0649, 73.004, -21.2746, 72.4972, -21.4583, 71.9062, -21.6167, 71.234, -21.8609, 69.6581, -22.0129, 67.7935, -21.8171, 57.9278, -18.7919, 31.6369, -12.7553, -4.14976) +width_curve = SubResource("Curve_1ve1q") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/FrontFrontLeg/LowerLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(19.1051, 0.926422, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0649, 73.004, -21.2746, 72.4972, -21.4583, 71.9062, -21.6167, 71.234, -21.8609, 69.6581, -22.0129, 67.7935, -21.8171, 57.9278, -18.7919, 31.6369, -12.7553, -4.14976) +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/FrontFrontLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(27.19, -1.95666, 21.3743, 73.1478, 12.6771, 76.4133, 8.21304, 77.8784, 6.00144, 78.4233, 3.82224, 78.7878, 1.68954, 78.9301, -0.382572, 78.8087, -1.39151, 78.6361, -2.38002, 78.382, -3.34633, 78.0411, -4.2887, 77.6083, -5.20536, 77.0783, -6.09454, 76.446, -6.95449, 75.7062, -7.78345, 74.8536, -8.57965, 73.8831, -9.34133, 72.7894, -10.7541, 70.2118, -8.28506, 46.9509, -8.53777, 23.3822, -10.0098, 10.2195, -12.75, -3.25) +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/FrontFrontLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-10.7541, 70.2118) +rotation = -0.0993543 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 2, +NodePath("../LowerLeg"): 3 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/FrontFrontLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(21.3743, 73.1478) +rotation = -0.0993543 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 1, +NodePath("../LowerLeg"): 0 +} +metadata/_edit_lock_ = true + +[node name="BackFrontLeg" type="Node2D" parent="Body" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(-60, -2) +rotation = 0.138036 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ipurh") +update_curve_at_runtime = true +arc_list = SubResource("Resource_nndv2") +offset = Vector2(-1, 43.3333) + +[node name="Stroke" type="Line2D" parent="Body/BackFrontLeg"] +points = PackedVector2Array(24.5918, 4.49943, 27.0925, 10.727, 29.3554, 17.7858, 31.5261, 26.8296, 33.0294, 37.3747, 33.2899, 48.9373, 32.7743, 54.949, 31.7322, 61.0336, 30.0917, 67.1308, 27.781, 73.18, 19.3764, 81.9569, 15.3299, 85.229, 13.3297, 86.5299, 11.339, 87.5862, 9.35321, 88.3818, 7.36781, 88.9007, 6.37385, 89.0514, 5.3783, 89.1269, 4.38061, 89.1253, 3.38019, 89.0445, 2.37649, 88.8825, 1.36895, 88.6374, 0.357002, 88.3071, -0.659918, 87.8897, -2.71093, 86.7854, -4.78858, 85.3084, -12.0539, 10.9409) +width_curve = SubResource("Curve_d7gkk") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="LowerLeg" type="Node2D" parent="Body/BackFrontLeg" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(2.25, 73.5) +rotation = -0.132747 +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.427548, 0.209066, 0.760482, 1) +line_joint_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_d7gkk") +update_curve_at_runtime = true +arc_list = SubResource("Resource_ipurh") + +[node name="Stroke" type="Line2D" parent="Body/BackFrontLeg/LowerLeg"] +points = PackedVector2Array(25.3487, 3.06203, 24.0553, 29.0148, 24.4063, 52.0481, 25.4051, 63.3351, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0618, 73.0148, -21.2625, 72.54, -21.4314, 72.0015, -21.5694, 71.4016, -21.7567, 70.027, -21.8317, 68.4347, -21.6749, 64.6712, -21.1584, 60.2594, -16.684, 39.0982, -8.5396, 10.7729) +width_curve = SubResource("Curve_1ve1q") +default_color = Color(0.427548, 0.209066, 0.760482, 1) +joint_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/BackFrontLeg/LowerLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(25.3487, 3.06203, 24.0553, 29.0148, 24.4063, 52.0481, 25.4051, 63.3351, 27.1715, 73.4236, 21.2378, 76.1927, 15.2851, 78.1706, 9.31353, 79.3574, 3.323, 79.7529, -2.68647, 79.3574, -8.71488, 78.1706, -14.7622, 76.1927, -20.8285, 73.4236, -21.0618, 73.0148, -21.2625, 72.54, -21.4314, 72.0015, -21.5694, 71.4016, -21.7567, 70.027, -21.8317, 68.4347, -21.6749, 64.6712, -21.1584, 60.2594, -16.684, 39.0982, -8.5396, 10.7729) +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/BackFrontLeg"] +color = Color(0.558594, 0.606873, 1, 1) +polygon = PackedVector2Array(24.5918, 4.49943, 27.0925, 10.727, 29.3554, 17.7858, 31.5261, 26.8296, 33.0294, 37.3747, 33.2899, 48.9373, 32.7743, 54.949, 31.7322, 61.0336, 30.0917, 67.1308, 27.781, 73.18, 19.3764, 81.9569, 15.3299, 85.229, 13.3297, 86.5299, 11.339, 87.5862, 9.35321, 88.3818, 7.36781, 88.9007, 6.37385, 89.0514, 5.3783, 89.1269, 4.38061, 89.1253, 3.38019, 89.0445, 2.37649, 88.8825, 1.36895, 88.6374, 0.357002, 88.3071, -0.659918, 87.8897, -2.71093, 86.7854, -4.78858, 85.3084, -12.0539, 10.9409) +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D" type="Node2D" parent="Body/BackFrontLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-4.78859, 85.3084) +rotation = -0.510873 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 2, +NodePath("../LowerLeg"): 3 +} +metadata/_edit_lock_ = true + +[node name="SVSVertexMerge2D2" type="Node2D" parent="Body/BackFrontLeg" node_paths=PackedStringArray("vertex_map")] +position = Vector2(27.781, 73.18) +rotation = -0.510873 +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 1, +NodePath("../LowerLeg"): 0 +} +metadata/_edit_lock_ = true + +[node name="MergeBumVertices" type="Node2D" parent="Body" node_paths=PackedStringArray("vertex_map")] +position = Vector2(-73.4447, 7.17824) +script = ExtResource("4_p8hpb") +vertex_map = { +NodePath(".."): 3, +NodePath("../BackFrontLeg"): 3 +} +metadata/_edit_lock_ = true + +[node name="CutieMark" type="Node2D" parent="Body" node_paths=PackedStringArray("polygon")] +position = Vector2(-38, -8) +rotation = -0.292342 +scale = Vector2(1.10382, 1.10382) +script = ExtResource("1_inuwg") +polygon = NodePath("Polygon2D") +stroke_color = Color(0.588235, 0, 0.505882, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_lno47") +update_curve_at_runtime = true +arc_list = SubResource("Resource_hc35e") +metadata/_edit_lock_ = true + +[node name="Polygon2D" type="Polygon2D" parent="Body/CutieMark"] +color = Color(0.976471, 0.184314, 0.376471, 1) +polygon = PackedVector2Array(-0.0625, 0.125, -4.4385, -1.17515, -7.85912, -2.63649, -9.24824, -3.40894, -10.443, -4.19929, -11.4582, -5.00006, -12.3088, -5.8038, -13.0094, -6.60303, -13.575, -7.3903, -14.0204, -8.15813, -14.3604, -8.89905, -14.6098, -9.60561, -14.7835, -10.2703, -14.963, -11.4444, -14.9754, -11.7151, -14.9645, -11.9979, -14.9306, -12.2906, -14.8742, -12.5909, -14.6959, -13.2058, -14.4333, -13.8248, -14.0901, -14.4303, -13.6701, -15.0044, -13.1769, -15.5295, -12.6143, -15.9878, -12.3082, -16.1864, -11.9861, -16.3617, -11.6485, -16.5114, -11.2959, -16.6334, -10.9287, -16.7253, -10.5475, -16.7851, -10.1526, -16.8105, -9.74455, -16.7993, -9.32382, -16.7492, -8.89087, -16.658, -8.44616, -16.5236, -7.99015, -16.3437, -7.52332, -16.1161, -7.04612, -15.8386, -6.0625, -15.125, -6.00237, -15.5928, -5.91116, -16.0404, -5.79049, -16.4673, -5.642, -16.8734, -5.4673, -17.2582, -5.26801, -17.6216, -5.04577, -17.9631, -4.8022, -18.2825, -4.53891, -18.5795, -4.25754, -18.8538, -3.9597, -19.105, -3.64702, -19.3329, -2.98364, -19.7174, -2.28039, -20.0049, -1.55026, -20.1929, -0.806231, -20.279, -0.433067, -20.2831, -0.0613022, -20.2608, 0.307441, -20.2118, 0.671538, -20.1357, 1.02937, -20.0324, 1.3793, -19.9014, 1.71972, -19.7425, 2.04899, -19.5554, 2.3655, -19.3397, 2.66763, -19.0952, 2.95374, -18.8216, 3.22221, -18.5185, 3.71106, -17.8656, 4.13694, -17.1742, 4.4935, -16.4381, 4.7744, -15.6507, 4.97332, -14.8057, 5.08391, -13.8966, 5.09983, -12.9172, 5.01475, -11.8608, 4.82233, -10.7212, 4.51623, -9.49199, 3.53765, -6.73891, 2.02831, -3.55032) +metadata/_edit_lock_ = true + +[node name="Rectangle" type="Node2D" parent="Body/CutieMark" node_paths=PackedStringArray("polygon")] +position = Vector2(-6, -3) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.588235, 0, 0.505882, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_y6oqb") +update_curve_at_runtime = true +arc_list = SubResource("Resource_g8ae8") +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/CutieMark/Rectangle"] +color = Color(0.988235, 0.835294, 0.247059, 1) +polygon = PackedVector2Array(-3, -4, -2.95138, -4.01252, -2.90253, -4.02106, -2.85345, -4.02575, -2.80417, -4.02668, -2.75468, -4.02398, -2.70502, -4.01776, -2.6052, -3.99522, -2.50483, -3.95997, -2.40401, -3.91294, -2.30287, -3.85504, -2.20151, -3.78718, -1.9986, -3.62524, -1.7962, -3.43447, -1.39655, -2.99569, -0.643319, -2.09429, -0.304284, -1.74885, -0.147343, -1.62809, -0.0724151, -1.5839, 0, -1.55172, 0.145626, -1.50875, 0.29701, -1.48114, 0.610992, -1.45905, 1.24138, -1.45689, 1.39064, -1.44625, 1.53354, -1.42511, 1.66856, -1.39022, 1.73264, -1.36661, 1.79418, -1.33836, 1.853, -1.30506, 1.9089, -1.2663, 1.96169, -1.22168, 2.01118, -1.1708, 2.05719, -1.11325, 2.09953, -1.04863, 2.138, -0.976528, 2.17242, -0.896551, 2.19979, -0.813302, 2.21758, -0.731638, 2.22633, -0.651527, 2.22657, -0.572938, 2.21883, -0.495839, 2.20364, -0.420199, 2.18153, -0.345985, 2.15302, -0.273167, 2.07897, -0.131591, 1.98573, 0.00478233, 1.75863, 0.262931, 1.26078, 0.727909, 1.05792, 0.938779, 0.982856, 1.03969, 0.953773, 1.08913, 0.93103, 1.13793, 0.913498, 1.19314, 0.899476, 1.26118, 0.880652, 1.43211, 0.870684, 1.88793, 0.887928, 3.05172, 0.873113, 3.64332, 0.814655, 4.16379, 0.762493, 4.37918, 0.72953, 4.47247, 0.691541, 4.55496, 0.648198, 4.62572, 0.624415, 4.65643, 0.599172, 4.68386, 0.572425, 4.70791, 0.544134, 4.72846, 0.514259, 4.7454, 0.482758, 4.75862, 0.449856, 4.76806, 0.415832, 4.77381, 0.380724, 4.77598, 0.344574, 4.77467, 0.307419, 4.76999, 0.2693, 4.76204, 0.190327, 4.73673, 0.107969, 4.69958, 0.0225427, 4.65141, -0.156253, 4.52532, -0.536776, 4.17733, -0.931038, 3.74569, -1.99421, 2.47825, -2.12744, 2.34049, -2.24138, 2.24138, -2.29499, 2.20624, -2.3522, 2.17803, -2.4128, 2.15623, -2.47656, 2.14029, -2.54325, 2.12968, -2.61264, 2.12386, -2.75862, 2.12446, -3.40517, 2.21121, -3.74057, 2.24508, -3.90494, 2.24462, -4.06466, 2.22683, -4.1422, 2.2101, -4.21791, 2.18742, -4.29154, 2.15827, -4.36288, 2.1221, -4.43169, 2.07838, -4.49774, 2.02658, -4.56082, 1.96614, -4.62069, 1.89655, -4.67232, 1.8223, -4.71129, 1.74826, -4.73826, 1.67443, -4.74746, 1.6376, -4.75391, 1.60082, -4.75769, 1.5641, -4.75889, 1.52744, -4.75389, 1.45429, -4.73957, 1.38139, -4.71659, 1.30873, -4.68564, 1.23632, -4.64738, 1.16417, -4.55159, 1.02067, -4.30172, 0.737068, -3.71875, 0.184805, -3.47131, -0.083042, -3.37734, -0.214718, -3.34014, -0.279972, -3.31035, -0.344828, -3.28813, -0.41511, -3.27277, -0.496119, -3.26024, -0.687164, -3.29095, -1.16325, -3.43966, -2.31466, -3.48007, -2.88894, -3.47481, -3.15363, -3.44612, -3.39494, -3.42147, -3.50484, -3.38914, -3.60654, -3.34853, -3.69923, -3.29903, -3.78213, -3.27076, -3.81966, -3.24003, -3.85444, -3.20678, -3.88638, -3.17093, -3.91538, -3.1324, -3.94134, -3.09112, -3.96417, -3.04701, -3.98375) +metadata/_edit_lock_ = true + +[node name="Rectangle2" type="Node2D" parent="Body/CutieMark" node_paths=PackedStringArray("polygon")] +position = Vector2(1, -14) +scale = Vector2(0.644827, 0.644827) +script = ExtResource("1_inuwg") +polygon = NodePath("Fill") +stroke_color = Color(0.588235, 0, 0.505882, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_y6oqb") +update_curve_at_runtime = true +arc_list = SubResource("Resource_g8ae8") +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Body/CutieMark/Rectangle2"] +color = Color(0.988235, 0.835294, 0.247059, 1) +polygon = PackedVector2Array(-3, -4, -2.95138, -4.01252, -2.90253, -4.02106, -2.85345, -4.02575, -2.80417, -4.02668, -2.75468, -4.02398, -2.70502, -4.01776, -2.6052, -3.99522, -2.50483, -3.95997, -2.40401, -3.91294, -2.30287, -3.85504, -2.20151, -3.78718, -1.9986, -3.62524, -1.7962, -3.43447, -1.39655, -2.99569, -0.643319, -2.09429, -0.304284, -1.74885, -0.147343, -1.62809, -0.0724151, -1.5839, 0, -1.55172, 0.145626, -1.50875, 0.29701, -1.48114, 0.610992, -1.45905, 1.24138, -1.45689, 1.39064, -1.44625, 1.53354, -1.42511, 1.66856, -1.39022, 1.73264, -1.36661, 1.79418, -1.33836, 1.853, -1.30506, 1.9089, -1.2663, 1.96169, -1.22168, 2.01118, -1.1708, 2.05719, -1.11325, 2.09953, -1.04863, 2.138, -0.976528, 2.17242, -0.896551, 2.19979, -0.813302, 2.21758, -0.731638, 2.22633, -0.651527, 2.22657, -0.572938, 2.21883, -0.495839, 2.20364, -0.420199, 2.18153, -0.345985, 2.15302, -0.273167, 2.07897, -0.131591, 1.98573, 0.00478233, 1.75863, 0.262931, 1.26078, 0.727909, 1.05792, 0.938779, 0.982856, 1.03969, 0.953773, 1.08913, 0.93103, 1.13793, 0.913498, 1.19314, 0.899476, 1.26118, 0.880652, 1.43211, 0.870684, 1.88793, 0.887928, 3.05172, 0.873113, 3.64332, 0.814655, 4.16379, 0.762493, 4.37918, 0.72953, 4.47247, 0.691541, 4.55496, 0.648198, 4.62572, 0.624415, 4.65643, 0.599172, 4.68386, 0.572425, 4.70791, 0.544134, 4.72846, 0.514259, 4.7454, 0.482758, 4.75862, 0.449856, 4.76806, 0.415832, 4.77381, 0.380724, 4.77598, 0.344574, 4.77467, 0.307419, 4.76999, 0.2693, 4.76204, 0.190327, 4.73673, 0.107969, 4.69958, 0.0225427, 4.65141, -0.156253, 4.52532, -0.536776, 4.17733, -0.931038, 3.74569, -1.99421, 2.47825, -2.12744, 2.34049, -2.24138, 2.24138, -2.29499, 2.20624, -2.3522, 2.17803, -2.4128, 2.15623, -2.47656, 2.14029, -2.54325, 2.12968, -2.61264, 2.12386, -2.75862, 2.12446, -3.40517, 2.21121, -3.74057, 2.24508, -3.90494, 2.24462, -4.06466, 2.22683, -4.1422, 2.2101, -4.21791, 2.18742, -4.29154, 2.15827, -4.36288, 2.1221, -4.43169, 2.07838, -4.49774, 2.02658, -4.56082, 1.96614, -4.62069, 1.89655, -4.67232, 1.8223, -4.71129, 1.74826, -4.73826, 1.67443, -4.74746, 1.6376, -4.75391, 1.60082, -4.75769, 1.5641, -4.75889, 1.52744, -4.75389, 1.45429, -4.73957, 1.38139, -4.71659, 1.30873, -4.68564, 1.23632, -4.64738, 1.16417, -4.55159, 1.02067, -4.30172, 0.737068, -3.71875, 0.184805, -3.47131, -0.083042, -3.37734, -0.214718, -3.34014, -0.279972, -3.31035, -0.344828, -3.28813, -0.41511, -3.27277, -0.496119, -3.26024, -0.687164, -3.29095, -1.16325, -3.43966, -2.31466, -3.48007, -2.88894, -3.47481, -3.15363, -3.44612, -3.39494, -3.42147, -3.50484, -3.38914, -3.60654, -3.34853, -3.69923, -3.29903, -3.78213, -3.27076, -3.81966, -3.24003, -3.85444, -3.20678, -3.88638, -3.17093, -3.91538, -3.1324, -3.94134, -3.09112, -3.96417, -3.04701, -3.98375) +metadata/_edit_lock_ = true + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +&"": SubResource("AnimationLibrary_xtm0y") +} + +[node name="Camera2D" type="Camera2D" parent="."] +position = Vector2(50, -80) +zoom = Vector2(1.4, 1.4) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +custom_minimum_size = Vector2(150, 0) +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 283.0 +offset_top = -283.0 +offset_right = 433.0 +offset_bottom = -147.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 10 +size_flags_vertical = 3 + +[node name="ResetPoseButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "reset pose" + +[node name="BlinkButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "blink" + +[node name="CloseMouthButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "close mouth" + +[node name="OpenMouthButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "open mouth" + +[node name="StaggerButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "stagger" + +[connection signal="pressed" from="VBoxContainer/ResetPoseButton" to="." method="_on_reset_pose_button_pressed"] +[connection signal="pressed" from="VBoxContainer/BlinkButton" to="." method="_on_blink_button_pressed"] +[connection signal="pressed" from="VBoxContainer/CloseMouthButton" to="." method="_on_close_mouth_button_pressed"] +[connection signal="pressed" from="VBoxContainer/OpenMouthButton" to="." method="_on_open_mouth_button_pressed"] +[connection signal="pressed" from="VBoxContainer/StaggerButton" to="." method="_on_stagger_button_pressed"] diff --git a/addons/curved_lines_2d/examples/rat/checkers.png b/addons/curved_lines_2d/examples/rat/checkers.png new file mode 100644 index 0000000..e2debb2 Binary files /dev/null and b/addons/curved_lines_2d/examples/rat/checkers.png differ diff --git a/addons/curved_lines_2d/examples/rat/checkers.png.import b/addons/curved_lines_2d/examples/rat/checkers.png.import new file mode 100644 index 0000000..a580998 --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/checkers.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cl0eabp7mc2k1" +path="res://.godot/imported/checkers.png-3ed970dd1a9bb4e755715165fe8f2a07.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/examples/rat/checkers.png" +dest_files=["res://.godot/imported/checkers.png-3ed970dd1a9bb4e755715165fe8f2a07.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/examples/rat/rat.gd b/addons/curved_lines_2d/examples/rat/rat.gd new file mode 100644 index 0000000..11f9b79 --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/rat.gd @@ -0,0 +1,93 @@ +extends CharacterBody2D + +signal place_shape(global_pos : Vector2, curve : Curve2D) +signal cut_shapes(global_pos : Vector2, curve : Curve2D) +signal has_won() + +const SPEED := 500.0 +const JUMP_VELOCITY = -300.0 + +var dead := false +var won := false +var bumped_into_wall := false +var finish : VisibleOnScreenNotifier2D = null +@onready var orig_pos := position + +func _ready() -> void: + $AnimationPlayer.play("run") + $ShapeHintEllipse.visible = false + $ShapeHintRectangle.visible = true + +func _process(delta: float) -> void: + var global_mouse_pos := get_global_mouse_position() + $ShapeHintEllipse.global_position = global_mouse_pos + $ShapeHintRectangle.global_position = global_mouse_pos + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + if event.button_index in [MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN] and not event.pressed: + $ShapeHintEllipse.visible = not $ShapeHintEllipse.visible + $ShapeHintRectangle.visible = not $ShapeHintRectangle.visible + + if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + var cur_shape : ScalableVectorShape2D = $ShapeHintEllipse if $ShapeHintEllipse.visible else $ShapeHintRectangle + place_shape.emit(get_global_mouse_position(), cur_shape.curve) + + if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: + var cur_shape : ScalableVectorShape2D = $ShapeHintEllipse if $ShapeHintEllipse.visible else $ShapeHintRectangle + cut_shapes.emit(get_global_mouse_position(), cur_shape.curve) + + +func _physics_process(delta: float) -> void: + if dead or won: + return + if not is_on_floor(): + velocity += get_gravity() * delta * 3 + velocity.x = move_toward(velocity.x, 0.0, SPEED * delta) + else: + velocity.x = SPEED if $Pivot.scale.x > 0 else -SPEED + move_and_slide() + if bumped_into_wall: + bumped_into_wall = false + $Pivot.scale.x = -$Pivot.scale.x + elif is_on_wall() and is_on_floor(): + velocity.y = JUMP_VELOCITY + + if is_instance_valid(finish): + if not finish.is_on_screen(): + $TargetArrow.show() + $TargetArrow.look_at(finish.global_position) + $TargetArrow/CutoutOfTargetArrow/TheCheese.rotation = -$TargetArrow.rotation + else: + $TargetArrow.hide() + if position.distance_to(finish.global_position) < 150.0: + win() + +func _on_wall_detector_body_entered(body: Node2D) -> void: + if body is StaticBody2D: + bumped_into_wall = true + + +func die() -> void: + dead = true + $AnimationPlayer.play("disappear") + + +func win() -> void: + won = true + $AnimationPlayer.play("win") + + +func _on_animation_player_animation_finished(anim_name: StringName) -> void: + if anim_name == "disappear" or anim_name == "win": + position = orig_pos + modulate = Color(1.0, 1.0, 1.0, 1.0) + $AnimationPlayer.play("run") + dead = false + won = false + velocity = Vector2.ZERO + if anim_name == "win" and is_instance_valid(finish): + finish.queue_free() + has_won.emit() + diff --git a/addons/curved_lines_2d/examples/rat/rat.gd.uid b/addons/curved_lines_2d/examples/rat/rat.gd.uid new file mode 100644 index 0000000..ad933af --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/rat.gd.uid @@ -0,0 +1 @@ +uid://xhridu7hgcrc diff --git a/addons/curved_lines_2d/examples/rat/rat.tscn b/addons/curved_lines_2d/examples/rat/rat.tscn new file mode 100644 index 0000000..bcc55b5 --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/rat.tscn @@ -0,0 +1,2833 @@ +[gd_scene load_steps=45 format=3 uid="uid://kbkwi2nx8ith"] + +[ext_resource type="Script" uid="uid://xhridu7hgcrc" path="res://addons/curved_lines_2d/examples/rat/rat.gd" id="1_7hgga"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="3_4sn87"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="4_jqihn"] +[ext_resource type="PackedScene" uid="uid://c0m21g8gf1lro" path="res://addons/curved_lines_2d/examples/rat/the_cheese.tscn" id="5_jqihn"] +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="18_xsi10"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_4sn87"] +radius = 5.7795 + +[sub_resource type="CircleShape2D" id="CircleShape2D_jqihn"] +radius = 1.26088 + +[sub_resource type="Gradient" id="Gradient_ggbq8"] +colors = PackedColorArray(0.462745, 0.462745, 0.364706, 1, 0.180392, 0.180392, 0.137255, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_ycbh5"] +gradient = SubResource("Gradient_ggbq8") +width = 21 +height = 10 +fill_from = Vector2(0.955745, 0.375904) +fill_to = Vector2(0.150987, 0.875987) + +[sub_resource type="Gradient" id="Gradient_ne4dc"] +colors = PackedColorArray(0.478431, 0.478431, 0.431373, 1, 0.4, 0.4, 0.341176, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_vheyn"] +gradient = SubResource("Gradient_ne4dc") +width = 4 +height = 6 +fill = 1 +fill_from = Vector2(0.442296, 0.503586) +fill_to = Vector2(0.846897, 0.426704) + +[sub_resource type="Gradient" id="Gradient_y345n"] +offsets = PackedFloat32Array(0.494424, 1) +colors = PackedColorArray(0.478431, 0.478431, 0.431373, 1, 0.301961, 0.301961, 0.235294, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_yvsbv"] +gradient = SubResource("Gradient_y345n") +width = 13 +height = 9 +fill = 1 +fill_from = Vector2(0.267746, 0.140616) +fill_to = Vector2(-0.137976, 0.979422) + +[sub_resource type="SegmentShape2D" id="SegmentShape2D_4sn87"] +a = Vector2(-0.263762, 0.0208244) +b = Vector2(6.06653, -0.478956) + +[sub_resource type="Gradient" id="Gradient_i65be"] +colors = PackedColorArray(1, 0.564706, 0.564706, 1, 0.423529, 0.239216, 0.239216, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_c0nxa"] +gradient = SubResource("Gradient_i65be") +width = 6 +height = 7 +fill_from = Vector2(0.829235, 0.95743) +fill_to = Vector2(0.331858, 0.0881278) + +[sub_resource type="Curve" id="Curve_jqihn"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.406522), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="Curve" id="Curve_bxi6m"] +_data = [Vector2(0.033241, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.273861), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="Gradient" id="Gradient_d4tj5"] +colors = PackedColorArray(1, 0.564706, 0.564706, 1, 0.75283, 0.334624, 0.342916, 1) + +[sub_resource type="Curve2D" id="Curve2D_d4tj5"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(8.87613, 7.12121, -7.20475, -5.93393, -1.28417, -2.88979, -4.59851, 12.7017, 4.59851, -12.7017, -6.45195, -35.544, -14.8595, -1.9786, 14.8595, 1.9786, 30.5377, -58.2104, -16.317, -6.66003, 10.8842, 8.67538, 67.2043, -42.6683) +} +point_count = 4 + +[sub_resource type="Resource" id="Resource_syjnd"] +script = ExtResource("4_jqihn") +arcs = Array[ExtResource("3_4sn87")]([]) + +[sub_resource type="Resource" id="Resource_6gv5h"] +script = ExtResource("4_jqihn") +arcs = Array[ExtResource("3_4sn87")]([]) + +[sub_resource type="Gradient" id="Gradient_7pevi"] +colors = PackedColorArray(0.345098, 0.345098, 0.290196, 1, 0.462745, 0.462745, 0.384314, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_y0lfb"] +gradient = SubResource("Gradient_7pevi") +width = 10 +height = 7 +fill_from = Vector2(-0.000118592, 0.500395) +fill_to = Vector2(1.00001, 0.500395) + +[sub_resource type="Gradient" id="Gradient_78idp"] +colors = PackedColorArray(0.262745, 0.262745, 0.207843, 1, 0.356863, 0.356863, 0.294118, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_3b0nw"] +gradient = SubResource("Gradient_78idp") +width = 12 +height = 10 +fill_from = Vector2(0.107913, 0.426326) +fill_to = Vector2(0.624601, 0.15084) + +[sub_resource type="Animation" id="Animation_c1gwa"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Pivot/Body_fill:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Pivot/Body_fill:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0964239] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Pivot/Body_fill/Head_stroke:position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(29, 12)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Pivot/Body_fill/Head_stroke:rotation") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Pivot/Body_fill/Head_fill:position") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(29, 12)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Pivot/Body_fill/Head_fill:rotation") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Pivot/Body_fill/Head_fill/Ear_back:position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(9, -23)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Pivot/Body_fill/Head_fill/Ear_back:rotation") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_fill:position") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1, -21)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_fill:rotation") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_stroke:position") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1, -20)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_stroke:rotation") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Pivot/Body_fill/Leg_front_far_fill:position") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(15, 12)] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("Pivot/Body_fill/Leg_front_far_fill:rotation") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_stroke:position") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(28, 14)] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_stroke:rotation") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/16/type = "value" +tracks/16/imported = false +tracks/16/enabled = true +tracks/16/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_fill:position") +tracks/16/interp = 1 +tracks/16/loop_wrap = true +tracks/16/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(28, 14)] +} +tracks/17/type = "value" +tracks/17/imported = false +tracks/17/enabled = true +tracks/17/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_fill:rotation") +tracks/17/interp = 1 +tracks/17/loop_wrap = true +tracks/17/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/18/type = "value" +tracks/18/imported = false +tracks/18/enabled = true +tracks/18/path = NodePath("Pivot/Body_fill/Leg_back_far_fill:position") +tracks/18/interp = 1 +tracks/18/loop_wrap = true +tracks/18/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-14, 4)] +} +tracks/19/type = "value" +tracks/19/imported = false +tracks/19/enabled = true +tracks/19/path = NodePath("Pivot/Body_fill/Leg_back_far_fill:rotation") +tracks/19/interp = 1 +tracks/19/loop_wrap = true +tracks/19/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Leg_back_far_stroke:position") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(5, 10)] +} +tracks/21/type = "value" +tracks/21/imported = false +tracks/21/enabled = true +tracks/21/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Leg_back_far_stroke:rotation") +tracks/21/interp = 1 +tracks/21/loop_wrap = true +tracks/21/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/22/type = "value" +tracks/22/imported = false +tracks/22/enabled = true +tracks/22/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_stroke:position") +tracks/22/interp = 1 +tracks/22/loop_wrap = true +tracks/22/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(23, 25.5)] +} +tracks/23/type = "value" +tracks/23/imported = false +tracks/23/enabled = true +tracks/23/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_stroke:rotation") +tracks/23/interp = 1 +tracks/23/loop_wrap = true +tracks/23/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/24/type = "value" +tracks/24/imported = false +tracks/24/enabled = true +tracks/24/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_fill:position") +tracks/24/interp = 1 +tracks/24/loop_wrap = true +tracks/24/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(23, 25.5)] +} +tracks/25/type = "value" +tracks/25/imported = false +tracks/25/enabled = true +tracks/25/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_fill:rotation") +tracks/25/interp = 1 +tracks/25/loop_wrap = true +tracks/25/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/26/type = "value" +tracks/26/imported = false +tracks/26/enabled = true +tracks/26/path = NodePath("Pivot/Body_fill/Leg_front_near_stroke:position") +tracks/26/interp = 1 +tracks/26/loop_wrap = true +tracks/26/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(10, 11)] +} +tracks/27/type = "value" +tracks/27/imported = false +tracks/27/enabled = true +tracks/27/path = NodePath("Pivot/Body_fill/Leg_front_near_stroke:rotation") +tracks/27/interp = 1 +tracks/27/loop_wrap = true +tracks/27/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/28/type = "value" +tracks/28/imported = false +tracks/28/enabled = true +tracks/28/path = NodePath("Pivot/Body_fill/Leg_front_near_fill:position") +tracks/28/interp = 1 +tracks/28/loop_wrap = true +tracks/28/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(10, 11)] +} +tracks/29/type = "value" +tracks/29/imported = false +tracks/29/enabled = true +tracks/29/path = NodePath("Pivot/Body_fill/Leg_front_near_fill:rotation") +tracks/29/interp = 1 +tracks/29/loop_wrap = true +tracks/29/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/30/type = "value" +tracks/30/imported = false +tracks/30/enabled = true +tracks/30/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_stroke:position") +tracks/30/interp = 1 +tracks/30/loop_wrap = true +tracks/30/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(22, 15.5)] +} +tracks/31/type = "value" +tracks/31/imported = false +tracks/31/enabled = true +tracks/31/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_stroke:rotation") +tracks/31/interp = 1 +tracks/31/loop_wrap = true +tracks/31/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/32/type = "value" +tracks/32/imported = false +tracks/32/enabled = true +tracks/32/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_fill:position") +tracks/32/interp = 1 +tracks/32/loop_wrap = true +tracks/32/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(22, 15.5)] +} +tracks/33/type = "value" +tracks/33/imported = false +tracks/33/enabled = true +tracks/33/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_fill:rotation") +tracks/33/interp = 1 +tracks/33/loop_wrap = true +tracks/33/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/34/type = "value" +tracks/34/imported = false +tracks/34/enabled = true +tracks/34/path = NodePath("Pivot/Body_fill/Leg_back_near_stroke:position") +tracks/34/interp = 1 +tracks/34/loop_wrap = true +tracks/34/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-23, 8)] +} +tracks/35/type = "value" +tracks/35/imported = false +tracks/35/enabled = true +tracks/35/path = NodePath("Pivot/Body_fill/Leg_back_near_stroke:rotation") +tracks/35/interp = 1 +tracks/35/loop_wrap = true +tracks/35/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/36/type = "value" +tracks/36/imported = false +tracks/36/enabled = true +tracks/36/path = NodePath("Pivot/Body_fill/Leg_back_near_fill:position") +tracks/36/interp = 1 +tracks/36/loop_wrap = true +tracks/36/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-23, 8)] +} +tracks/37/type = "value" +tracks/37/imported = false +tracks/37/enabled = true +tracks/37/path = NodePath("Pivot/Body_fill/Leg_back_near_fill:rotation") +tracks/37/interp = 1 +tracks/37/loop_wrap = true +tracks/37/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/38/type = "value" +tracks/38/imported = false +tracks/38/enabled = true +tracks/38/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_stroke:position") +tracks/38/interp = 1 +tracks/38/loop_wrap = true +tracks/38/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(25, 22.5)] +} +tracks/39/type = "value" +tracks/39/imported = false +tracks/39/enabled = true +tracks/39/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_stroke:rotation") +tracks/39/interp = 1 +tracks/39/loop_wrap = true +tracks/39/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/40/type = "value" +tracks/40/imported = false +tracks/40/enabled = true +tracks/40/path = NodePath("Pivot:modulate") +tracks/40/interp = 1 +tracks/40/loop_wrap = true +tracks/40/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/41/type = "value" +tracks/41/imported = false +tracks/41/enabled = true +tracks/41/path = NodePath("Pivot/Body_fill/Tail:curve:point_0/position") +tracks/41/interp = 1 +tracks/41/loop_wrap = true +tracks/41/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1.28417, -2.88979)] +} +tracks/42/type = "value" +tracks/42/imported = false +tracks/42/enabled = true +tracks/42/path = NodePath("Pivot/Body_fill/Tail:curve:point_0/out") +tracks/42/interp = 1 +tracks/42/loop_wrap = true +tracks/42/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-7.20475, -5.93393)] +} +tracks/43/type = "value" +tracks/43/imported = false +tracks/43/enabled = true +tracks/43/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/position") +tracks/43/interp = 1 +tracks/43/loop_wrap = true +tracks/43/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-6.45195, -35.544)] +} +tracks/44/type = "value" +tracks/44/imported = false +tracks/44/enabled = true +tracks/44/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/in") +tracks/44/interp = 1 +tracks/44/loop_wrap = true +tracks/44/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-4.59851, 12.7017)] +} +tracks/45/type = "value" +tracks/45/imported = false +tracks/45/enabled = true +tracks/45/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/out") +tracks/45/interp = 1 +tracks/45/loop_wrap = true +tracks/45/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(4.59851, -12.7017)] +} +tracks/46/type = "value" +tracks/46/imported = false +tracks/46/enabled = true +tracks/46/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/position") +tracks/46/interp = 1 +tracks/46/loop_wrap = true +tracks/46/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(30.5377, -58.2104)] +} +tracks/47/type = "value" +tracks/47/imported = false +tracks/47/enabled = true +tracks/47/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/in") +tracks/47/interp = 1 +tracks/47/loop_wrap = true +tracks/47/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-14.8595, -1.9786)] +} +tracks/48/type = "value" +tracks/48/imported = false +tracks/48/enabled = true +tracks/48/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/out") +tracks/48/interp = 1 +tracks/48/loop_wrap = true +tracks/48/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(14.8595, 1.9786)] +} +tracks/49/type = "value" +tracks/49/imported = false +tracks/49/enabled = true +tracks/49/path = NodePath("Pivot/Body_fill/Tail:curve:point_3/position") +tracks/49/interp = 1 +tracks/49/loop_wrap = true +tracks/49/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(67.2043, -42.6683)] +} +tracks/50/type = "value" +tracks/50/imported = false +tracks/50/enabled = true +tracks/50/path = NodePath("Pivot/Body_fill/Tail:curve:point_3/in") +tracks/50/interp = 1 +tracks/50/loop_wrap = true +tracks/50/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-16.317, -6.66003)] +} +tracks/51/type = "value" +tracks/51/imported = false +tracks/51/enabled = true +tracks/51/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_fill:position") +tracks/51/interp = 1 +tracks/51/loop_wrap = true +tracks/51/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(26.9855, 22.367)] +} +tracks/52/type = "value" +tracks/52/imported = false +tracks/52/enabled = true +tracks/52/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_fill:rotation") +tracks/52/interp = 1 +tracks/52/loop_wrap = true +tracks/52/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.080757] +} +tracks/53/type = "value" +tracks/53/imported = false +tracks/53/enabled = true +tracks/53/path = NodePath("Heart:modulate") +tracks/53/interp = 1 +tracks/53/loop_wrap = true +tracks/53/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} + +[sub_resource type="Animation" id="Animation_axc4l"] +resource_name = "disappear" +length = 3.0 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Pivot:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(0, 0, 0, 0)] +} + +[sub_resource type="Animation" id="Animation_10vlp"] +resource_name = "run" +length = 0.4 +loop_mode = 1 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Pivot/Body_fill:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(5, -19), Vector2(5, -21), Vector2(6, -15), Vector2(4, -8)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Pivot/Body_fill:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.446922, -0.241509, 0.297453, 0.110711] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Pivot/Body_fill/Head_stroke:position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(29, 12), Vector2(29, 12), Vector2(34.6122, 8.99839), Vector2(33.6155, 8.72849)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Pivot/Body_fill/Head_stroke:rotation") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [0.622133, 0.3882, -0.200947, 0.0483851] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Pivot/Body_fill/Head_fill:position") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(29, 12), Vector2(29, 12), Vector2(34.6122, 8.99839), Vector2(33.6155, 8.72849)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Pivot/Body_fill/Head_fill:rotation") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [0.622133, 0.3882, -0.200947, 0.0483851] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Pivot/Body_fill/Head_fill/Ear_back:position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(9, -23), Vector2(9, -23), Vector2(9, -23), Vector2(9, -23)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Pivot/Body_fill/Head_fill/Ear_back:rotation") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.435407, -0.212468, -0.754257, -0.231413] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_fill:position") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-1, -21), Vector2(-1, -21), Vector2(-1, -21), Vector2(-1, -21)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_fill:rotation") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.232181, -0.00924213, -0.262543, -0.00222224] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_stroke:position") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-1, -20), Vector2(-1, -20), Vector2(-1, -20), Vector2(-1, -20)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_stroke:rotation") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.232181, -0.00924213, -0.262543, -0.00222224] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Pivot/Body_fill/Leg_front_far_fill:position") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(15.9813, 5.17803), Vector2(16.4936, 8.35554), Vector2(16.4936, 8.35554), Vector2(16.4936, 8.35554)] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("Pivot/Body_fill/Leg_front_far_fill:rotation") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [0.562217, 0.209577, 0.75204, 1.9024] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_stroke:position") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(28, 14), Vector2(28, 14), Vector2(28, 14)] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_stroke:rotation") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0, -0.769276, 0.17667] +} +tracks/16/type = "value" +tracks/16/imported = false +tracks/16/enabled = true +tracks/16/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_fill:position") +tracks/16/interp = 1 +tracks/16/loop_wrap = true +tracks/16/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(28, 14), Vector2(28, 14), Vector2(28, 14)] +} +tracks/17/type = "value" +tracks/17/imported = false +tracks/17/enabled = true +tracks/17/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_fill:rotation") +tracks/17/interp = 1 +tracks/17/loop_wrap = true +tracks/17/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0, -0.769276, 0.17667] +} +tracks/18/type = "value" +tracks/18/imported = false +tracks/18/enabled = true +tracks/18/path = NodePath("Pivot/Body_fill/Leg_back_far_fill:position") +tracks/18/interp = 1 +tracks/18/loop_wrap = true +tracks/18/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-8.18641, 3.32624), Vector2(-11.8384, 6.19634), Vector2(-14.3553, 2.4958), Vector2(-14.3553, 2.4958)] +} +tracks/19/type = "value" +tracks/19/imported = false +tracks/19/enabled = true +tracks/19/path = NodePath("Pivot/Body_fill/Leg_back_far_fill:rotation") +tracks/19/interp = 1 +tracks/19/loop_wrap = true +tracks/19/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [1.29112, 1.9999, 0.160818, 0.536679] +} +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Leg_back_far_stroke:position") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(5, 10)] +} +tracks/21/type = "value" +tracks/21/imported = false +tracks/21/enabled = true +tracks/21/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Leg_back_far_stroke:rotation") +tracks/21/interp = 1 +tracks/21/loop_wrap = true +tracks/21/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/22/type = "value" +tracks/22/imported = false +tracks/22/enabled = true +tracks/22/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_stroke:position") +tracks/22/interp = 1 +tracks/22/loop_wrap = true +tracks/22/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(24.2295, 26.2205), Vector2(24.2295, 26.2205), Vector2(24.2295, 26.2205), Vector2(24.2853, 25.0235)] +} +tracks/23/type = "value" +tracks/23/imported = false +tracks/23/enabled = true +tracks/23/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_stroke:rotation") +tracks/23/interp = 1 +tracks/23/loop_wrap = true +tracks/23/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.625832, 0.89782, -0.153269, -0.526496] +} +tracks/24/type = "value" +tracks/24/imported = false +tracks/24/enabled = true +tracks/24/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_fill:position") +tracks/24/interp = 1 +tracks/24/loop_wrap = true +tracks/24/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(24.2295, 26.2205), Vector2(24.2295, 26.2205), Vector2(24.2295, 26.2205), Vector2(24.2853, 25.0235)] +} +tracks/25/type = "value" +tracks/25/imported = false +tracks/25/enabled = true +tracks/25/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_fill:rotation") +tracks/25/interp = 1 +tracks/25/loop_wrap = true +tracks/25/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.625832, 0.89782, -0.153269, -0.526496] +} +tracks/26/type = "value" +tracks/26/imported = false +tracks/26/enabled = true +tracks/26/path = NodePath("Pivot/Body_fill/Leg_front_near_stroke:position") +tracks/26/interp = 1 +tracks/26/loop_wrap = true +tracks/26/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(14.0844, 8.41868), Vector2(14.3406, 10.0074), Vector2(14.5967, 11.5962), Vector2(14.5967, 11.5962)] +} +tracks/27/type = "value" +tracks/27/imported = false +tracks/27/enabled = true +tracks/27/path = NodePath("Pivot/Body_fill/Leg_front_near_stroke:rotation") +tracks/27/interp = 1 +tracks/27/loop_wrap = true +tracks/27/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [0.498674, 0.157202, 0.55977, 1.71013] +} +tracks/28/type = "value" +tracks/28/imported = false +tracks/28/enabled = true +tracks/28/path = NodePath("Pivot/Body_fill/Leg_front_near_fill:position") +tracks/28/interp = 1 +tracks/28/loop_wrap = true +tracks/28/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(14.0844, 8.41868), Vector2(14.3406, 10.0074), Vector2(14.5967, 11.5962), Vector2(14.5967, 11.5962)] +} +tracks/29/type = "value" +tracks/29/imported = false +tracks/29/enabled = true +tracks/29/path = NodePath("Pivot/Body_fill/Leg_front_near_fill:rotation") +tracks/29/interp = 1 +tracks/29/loop_wrap = true +tracks/29/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [0.498674, 0.157202, 0.55977, 1.71013] +} +tracks/30/type = "value" +tracks/30/imported = false +tracks/30/enabled = true +tracks/30/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_stroke:position") +tracks/30/interp = 1 +tracks/30/loop_wrap = true +tracks/30/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(22, 15.5), Vector2(22, 15.5), Vector2(22, 15.5)] +} +tracks/31/type = "value" +tracks/31/imported = false +tracks/31/enabled = true +tracks/31/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_stroke:rotation") +tracks/31/interp = 1 +tracks/31/loop_wrap = true +tracks/31/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0, -0.549254, 0.215607] +} +tracks/32/type = "value" +tracks/32/imported = false +tracks/32/enabled = true +tracks/32/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_fill:position") +tracks/32/interp = 1 +tracks/32/loop_wrap = true +tracks/32/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Vector2(22, 15.5), Vector2(22, 15.5), Vector2(22, 15.5)] +} +tracks/33/type = "value" +tracks/33/imported = false +tracks/33/enabled = true +tracks/33/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_fill:rotation") +tracks/33/interp = 1 +tracks/33/loop_wrap = true +tracks/33/keys = { +"times": PackedFloat32Array(0, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0, -0.549254, 0.215607] +} +tracks/34/type = "value" +tracks/34/imported = false +tracks/34/enabled = true +tracks/34/path = NodePath("Pivot/Body_fill/Leg_back_near_stroke:position") +tracks/34/interp = 1 +tracks/34/loop_wrap = true +tracks/34/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-18.3, 3.91398), Vector2(-21.952, 6.78408), Vector2(-24.4689, 3.08354), Vector2(-24.4689, 3.08354)] +} +tracks/35/type = "value" +tracks/35/imported = false +tracks/35/enabled = true +tracks/35/path = NodePath("Pivot/Body_fill/Leg_back_near_stroke:rotation") +tracks/35/interp = 1 +tracks/35/loop_wrap = true +tracks/35/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [1.29112, 1.9999, 0.160818, 0.536679] +} +tracks/36/type = "value" +tracks/36/imported = false +tracks/36/enabled = true +tracks/36/path = NodePath("Pivot/Body_fill/Leg_back_near_fill:position") +tracks/36/interp = 1 +tracks/36/loop_wrap = true +tracks/36/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-18.3, 3.91398), Vector2(-21.952, 6.78408), Vector2(-24.4689, 3.08354), Vector2(-24.4689, 3.08354)] +} +tracks/37/type = "value" +tracks/37/imported = false +tracks/37/enabled = true +tracks/37/path = NodePath("Pivot/Body_fill/Leg_back_near_fill:rotation") +tracks/37/interp = 1 +tracks/37/loop_wrap = true +tracks/37/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [1.29112, 1.9999, 0.160818, 0.536679] +} +tracks/38/type = "value" +tracks/38/imported = false +tracks/38/enabled = true +tracks/38/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_stroke:position") +tracks/38/interp = 1 +tracks/38/loop_wrap = true +tracks/38/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(26.9855, 22.367), Vector2(26.9855, 22.367), Vector2(26.9855, 22.367), Vector2(27.0413, 21.17)] +} +tracks/39/type = "value" +tracks/39/imported = false +tracks/39/enabled = true +tracks/39/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_stroke:rotation") +tracks/39/interp = 1 +tracks/39/loop_wrap = true +tracks/39/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.727685, 0.795966, -0.255122, -0.628349] +} +tracks/40/type = "value" +tracks/40/imported = false +tracks/40/enabled = true +tracks/40/path = NodePath("Pivot:modulate") +tracks/40/interp = 1 +tracks/40/loop_wrap = true +tracks/40/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/41/type = "value" +tracks/41/imported = false +tracks/41/enabled = true +tracks/41/path = NodePath("Pivot/Body_fill/Tail:curve:point_0/position") +tracks/41/interp = 1 +tracks/41/loop_wrap = true +tracks/41/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(0.412685, -11.2885), Vector2(3.91448, -6.74484), Vector2(0.727715, -10.0255), Vector2(0.5702, -10.657)] +} +tracks/42/type = "value" +tracks/42/imported = false +tracks/42/enabled = true +tracks/42/path = NodePath("Pivot/Body_fill/Tail:curve:point_0/out") +tracks/42/interp = 1 +tracks/42/loop_wrap = true +tracks/42/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-7.20475, -5.93393), Vector2(-7.20475, -5.93393), Vector2(-8.87613, -7.12121), Vector2(-8.04044, -6.52757)] +} +tracks/43/type = "value" +tracks/43/imported = false +tracks/43/enabled = true +tracks/43/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/position") +tracks/43/interp = 1 +tracks/43/loop_wrap = true +tracks/43/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(0.321308, -43.4908), Vector2(-4.43182, -35.5778), Vector2(-16.0066, -37.3195), Vector2(-2.01613, -45.5128)] +} +tracks/44/type = "value" +tracks/44/imported = false +tracks/44/enabled = true +tracks/44/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/in") +tracks/44/interp = 1 +tracks/44/loop_wrap = true +tracks/44/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-4.59851, 12.7017), Vector2(-4.59851, 12.7017), Vector2(-3.81849, 5.01035), Vector2(-4.2085, 8.85604)] +} +tracks/45/type = "value" +tracks/45/imported = false +tracks/45/enabled = true +tracks/45/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/out") +tracks/45/interp = 1 +tracks/45/loop_wrap = true +tracks/45/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(4.59851, -12.7017), Vector2(4.59851, -12.7017), Vector2(3.81849, -5.01035), Vector2(4.2085, -8.85604)] +} +tracks/46/type = "value" +tracks/46/imported = false +tracks/46/enabled = true +tracks/46/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/position") +tracks/46/interp = 1 +tracks/46/loop_wrap = true +tracks/46/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(39.8335, -61.1482), Vector2(30.5377, -58.2104), Vector2(25.4608, -38.526), Vector2(32.1062, -64.3984)] +} +tracks/47/type = "value" +tracks/47/imported = false +tracks/47/enabled = true +tracks/47/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/in") +tracks/47/interp = 1 +tracks/47/loop_wrap = true +tracks/47/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-14.8595, -1.9786), Vector2(-16.2352, 6.95154), Vector2(-18.4322, 12.3719), Vector2(-16.591, -2.22988)] +} +tracks/48/type = "value" +tracks/48/imported = false +tracks/48/enabled = true +tracks/48/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/out") +tracks/48/interp = 1 +tracks/48/loop_wrap = true +tracks/48/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(14.8595, 1.9786), Vector2(16.2352, -6.95154), Vector2(17.2371, -12.0055), Vector2(16.591, 2.22988)] +} +tracks/49/type = "value" +tracks/49/imported = false +tracks/49/enabled = true +tracks/49/path = NodePath("Pivot/Body_fill/Tail:curve:point_3/position") +tracks/49/interp = 1 +tracks/49/loop_wrap = true +tracks/49/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(75.5474, -38.4873), Vector2(65.7853, -69.7766), Vector2(56.5165, -66.8728), Vector2(73.5191, -44.8543)] +} +tracks/50/type = "value" +tracks/50/imported = false +tracks/50/enabled = true +tracks/50/path = NodePath("Pivot/Body_fill/Tail:curve:point_3/in") +tracks/50/interp = 1 +tracks/50/loop_wrap = true +tracks/50/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(-12.4389, -10.1242), Vector2(-16.9073, 4.93529), Vector2(-9.1905, 12.1265), Vector2(-10.8842, -8.67538)] +} +tracks/51/type = "value" +tracks/51/imported = false +tracks/51/enabled = true +tracks/51/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_fill:position") +tracks/51/interp = 1 +tracks/51/loop_wrap = true +tracks/51/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Vector2(26.9855, 22.367), Vector2(26.9855, 22.367), Vector2(26.9855, 22.367), Vector2(27.0413, 21.17)] +} +tracks/52/type = "value" +tracks/52/imported = false +tracks/52/enabled = true +tracks/52/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_fill:rotation") +tracks/52/interp = 1 +tracks/52/loop_wrap = true +tracks/52/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [-0.727685, 0.795966, -0.255122, -0.628349] +} +tracks/53/type = "value" +tracks/53/imported = false +tracks/53/enabled = true +tracks/53/path = NodePath("Heart:modulate") +tracks/53/interp = 1 +tracks/53/loop_wrap = true +tracks/53/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} + +[sub_resource type="Animation" id="Animation_jqihn"] +resource_name = "win" +length = 3.0 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Heart:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Pivot/Body_fill/Head_stroke:position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(31.6262, 4.97833)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Pivot/Body_fill/Head_stroke:rotation") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.243507] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Pivot/Body_fill/Head_fill:position") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(31.6262, 4.97833)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Pivot/Body_fill/Head_fill:rotation") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.243507] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Pivot/Body_fill:position") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 0)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Pivot/Body_fill:rotation") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0964239] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Pivot/Body_fill/Head_fill:position") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(29, 12)] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Pivot/Body_fill/Head_fill:rotation") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Pivot/Body_fill/Head_fill/Ear_back:position") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(9, -23)] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Pivot/Body_fill/Head_fill/Ear_back:rotation") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_fill:position") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1, -21)] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_fill:rotation") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_stroke:position") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1, -20)] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("Pivot/Body_fill/Head_fill/Ear_front_stroke:rotation") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("Pivot/Body_fill/Leg_front_far_fill:position") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(15, 12)] +} +tracks/16/type = "value" +tracks/16/imported = false +tracks/16/enabled = true +tracks/16/path = NodePath("Pivot/Body_fill/Leg_front_far_fill:rotation") +tracks/16/interp = 1 +tracks/16/loop_wrap = true +tracks/16/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/17/type = "value" +tracks/17/imported = false +tracks/17/enabled = true +tracks/17/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_stroke:position") +tracks/17/interp = 1 +tracks/17/loop_wrap = true +tracks/17/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(28, 14)] +} +tracks/18/type = "value" +tracks/18/imported = false +tracks/18/enabled = true +tracks/18/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_stroke:rotation") +tracks/18/interp = 1 +tracks/18/loop_wrap = true +tracks/18/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/19/type = "value" +tracks/19/imported = false +tracks/19/enabled = true +tracks/19/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_fill:position") +tracks/19/interp = 1 +tracks/19/loop_wrap = true +tracks/19/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(28, 14)] +} +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath("Pivot/Body_fill/Leg_front_far_fill/Paw_fill:rotation") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/21/type = "value" +tracks/21/imported = false +tracks/21/enabled = true +tracks/21/path = NodePath("Pivot/Body_fill/Leg_back_far_fill:position") +tracks/21/interp = 1 +tracks/21/loop_wrap = true +tracks/21/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-14, 4)] +} +tracks/22/type = "value" +tracks/22/imported = false +tracks/22/enabled = true +tracks/22/path = NodePath("Pivot/Body_fill/Leg_back_far_fill:rotation") +tracks/22/interp = 1 +tracks/22/loop_wrap = true +tracks/22/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/23/type = "value" +tracks/23/imported = false +tracks/23/enabled = true +tracks/23/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Leg_back_far_stroke:position") +tracks/23/interp = 1 +tracks/23/loop_wrap = true +tracks/23/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(5, 10)] +} +tracks/24/type = "value" +tracks/24/imported = false +tracks/24/enabled = true +tracks/24/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Leg_back_far_stroke:rotation") +tracks/24/interp = 1 +tracks/24/loop_wrap = true +tracks/24/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/25/type = "value" +tracks/25/imported = false +tracks/25/enabled = true +tracks/25/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_stroke:position") +tracks/25/interp = 1 +tracks/25/loop_wrap = true +tracks/25/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(23, 25.5)] +} +tracks/26/type = "value" +tracks/26/imported = false +tracks/26/enabled = true +tracks/26/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_stroke:rotation") +tracks/26/interp = 1 +tracks/26/loop_wrap = true +tracks/26/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/27/type = "value" +tracks/27/imported = false +tracks/27/enabled = true +tracks/27/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_fill:position") +tracks/27/interp = 1 +tracks/27/loop_wrap = true +tracks/27/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(23, 25.5)] +} +tracks/28/type = "value" +tracks/28/imported = false +tracks/28/enabled = true +tracks/28/path = NodePath("Pivot/Body_fill/Leg_back_far_fill/Paw_fill:rotation") +tracks/28/interp = 1 +tracks/28/loop_wrap = true +tracks/28/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/29/type = "value" +tracks/29/imported = false +tracks/29/enabled = true +tracks/29/path = NodePath("Pivot/Body_fill/Leg_front_near_stroke:position") +tracks/29/interp = 1 +tracks/29/loop_wrap = true +tracks/29/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(10, 11)] +} +tracks/30/type = "value" +tracks/30/imported = false +tracks/30/enabled = true +tracks/30/path = NodePath("Pivot/Body_fill/Leg_front_near_stroke:rotation") +tracks/30/interp = 1 +tracks/30/loop_wrap = true +tracks/30/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/31/type = "value" +tracks/31/imported = false +tracks/31/enabled = true +tracks/31/path = NodePath("Pivot/Body_fill/Leg_front_near_fill:position") +tracks/31/interp = 1 +tracks/31/loop_wrap = true +tracks/31/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(10, 11)] +} +tracks/32/type = "value" +tracks/32/imported = false +tracks/32/enabled = true +tracks/32/path = NodePath("Pivot/Body_fill/Leg_front_near_fill:rotation") +tracks/32/interp = 1 +tracks/32/loop_wrap = true +tracks/32/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/33/type = "value" +tracks/33/imported = false +tracks/33/enabled = true +tracks/33/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_stroke:position") +tracks/33/interp = 1 +tracks/33/loop_wrap = true +tracks/33/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(22, 15.5)] +} +tracks/34/type = "value" +tracks/34/imported = false +tracks/34/enabled = true +tracks/34/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_stroke:rotation") +tracks/34/interp = 1 +tracks/34/loop_wrap = true +tracks/34/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/35/type = "value" +tracks/35/imported = false +tracks/35/enabled = true +tracks/35/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_fill:position") +tracks/35/interp = 1 +tracks/35/loop_wrap = true +tracks/35/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(22, 15.5)] +} +tracks/36/type = "value" +tracks/36/imported = false +tracks/36/enabled = true +tracks/36/path = NodePath("Pivot/Body_fill/Leg_front_near_fill/Paw_fill:rotation") +tracks/36/interp = 1 +tracks/36/loop_wrap = true +tracks/36/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/37/type = "value" +tracks/37/imported = false +tracks/37/enabled = true +tracks/37/path = NodePath("Pivot/Body_fill/Leg_back_near_stroke:position") +tracks/37/interp = 1 +tracks/37/loop_wrap = true +tracks/37/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-23, 8)] +} +tracks/38/type = "value" +tracks/38/imported = false +tracks/38/enabled = true +tracks/38/path = NodePath("Pivot/Body_fill/Leg_back_near_stroke:rotation") +tracks/38/interp = 1 +tracks/38/loop_wrap = true +tracks/38/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/39/type = "value" +tracks/39/imported = false +tracks/39/enabled = true +tracks/39/path = NodePath("Pivot/Body_fill/Leg_back_near_fill:position") +tracks/39/interp = 1 +tracks/39/loop_wrap = true +tracks/39/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-23, 8)] +} +tracks/40/type = "value" +tracks/40/imported = false +tracks/40/enabled = true +tracks/40/path = NodePath("Pivot/Body_fill/Leg_back_near_fill:rotation") +tracks/40/interp = 1 +tracks/40/loop_wrap = true +tracks/40/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/41/type = "value" +tracks/41/imported = false +tracks/41/enabled = true +tracks/41/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_stroke:position") +tracks/41/interp = 1 +tracks/41/loop_wrap = true +tracks/41/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(25, 22.5)] +} +tracks/42/type = "value" +tracks/42/imported = false +tracks/42/enabled = true +tracks/42/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_stroke:rotation") +tracks/42/interp = 1 +tracks/42/loop_wrap = true +tracks/42/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/43/type = "value" +tracks/43/imported = false +tracks/43/enabled = true +tracks/43/path = NodePath("Pivot:modulate") +tracks/43/interp = 1 +tracks/43/loop_wrap = true +tracks/43/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/44/type = "value" +tracks/44/imported = false +tracks/44/enabled = true +tracks/44/path = NodePath("Pivot/Body_fill/Tail:curve:point_0/position") +tracks/44/interp = 1 +tracks/44/loop_wrap = true +tracks/44/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-1.28417, -2.88979)] +} +tracks/45/type = "value" +tracks/45/imported = false +tracks/45/enabled = true +tracks/45/path = NodePath("Pivot/Body_fill/Tail:curve:point_0/out") +tracks/45/interp = 1 +tracks/45/loop_wrap = true +tracks/45/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-7.20475, -5.93393)] +} +tracks/46/type = "value" +tracks/46/imported = false +tracks/46/enabled = true +tracks/46/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/position") +tracks/46/interp = 1 +tracks/46/loop_wrap = true +tracks/46/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-6.45195, -35.544)] +} +tracks/47/type = "value" +tracks/47/imported = false +tracks/47/enabled = true +tracks/47/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/in") +tracks/47/interp = 1 +tracks/47/loop_wrap = true +tracks/47/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-4.59851, 12.7017)] +} +tracks/48/type = "value" +tracks/48/imported = false +tracks/48/enabled = true +tracks/48/path = NodePath("Pivot/Body_fill/Tail:curve:point_1/out") +tracks/48/interp = 1 +tracks/48/loop_wrap = true +tracks/48/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(4.59851, -12.7017)] +} +tracks/49/type = "value" +tracks/49/imported = false +tracks/49/enabled = true +tracks/49/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/position") +tracks/49/interp = 1 +tracks/49/loop_wrap = true +tracks/49/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(30.5377, -58.2104)] +} +tracks/50/type = "value" +tracks/50/imported = false +tracks/50/enabled = true +tracks/50/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/in") +tracks/50/interp = 1 +tracks/50/loop_wrap = true +tracks/50/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-14.8595, -1.9786)] +} +tracks/51/type = "value" +tracks/51/imported = false +tracks/51/enabled = true +tracks/51/path = NodePath("Pivot/Body_fill/Tail:curve:point_2/out") +tracks/51/interp = 1 +tracks/51/loop_wrap = true +tracks/51/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(14.8595, 1.9786)] +} +tracks/52/type = "value" +tracks/52/imported = false +tracks/52/enabled = true +tracks/52/path = NodePath("Pivot/Body_fill/Tail:curve:point_3/position") +tracks/52/interp = 1 +tracks/52/loop_wrap = true +tracks/52/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(67.2043, -42.6683)] +} +tracks/53/type = "value" +tracks/53/imported = false +tracks/53/enabled = true +tracks/53/path = NodePath("Pivot/Body_fill/Tail:curve:point_3/in") +tracks/53/interp = 1 +tracks/53/loop_wrap = true +tracks/53/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(-16.317, -6.66003)] +} +tracks/54/type = "value" +tracks/54/imported = false +tracks/54/enabled = true +tracks/54/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_fill:position") +tracks/54/interp = 1 +tracks/54/loop_wrap = true +tracks/54/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(26.9855, 22.367)] +} +tracks/55/type = "value" +tracks/55/imported = false +tracks/55/enabled = true +tracks/55/path = NodePath("Pivot/Body_fill/Leg_back_near_fill/Paw_fill:rotation") +tracks/55/interp = 1 +tracks/55/loop_wrap = true +tracks/55/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.080757] +} +tracks/56/type = "value" +tracks/56/imported = false +tracks/56/enabled = true +tracks/56/path = NodePath("Heart:modulate") +tracks/56/interp = 1 +tracks/56/loop_wrap = true +tracks/56/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_k146a"] +_data = { +&"RESET": SubResource("Animation_c1gwa"), +&"disappear": SubResource("Animation_axc4l"), +&"run": SubResource("Animation_10vlp"), +&"win": SubResource("Animation_jqihn") +} + +[sub_resource type="LabelSettings" id="LabelSettings_4sn87"] +font_color = Color(0.0156863, 1, 0, 1) +outline_size = 3 +outline_color = Color(0, 0.313726, 0, 1) + +[sub_resource type="Curve2D" id="Curve2D_4sn87"] +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -113, -75, 0, 0, 0, 0, 113, -75, 0, 0, 0, 0, 113, 75, 0, 0, 0, 0, -113, 75, 0, 0, 0, 0, -113, -75) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_jqihn"] +script = ExtResource("4_jqihn") +arcs = Array[ExtResource("3_4sn87")]([]) + +[sub_resource type="Curve2D" id="Curve2D_syjnd"] +_data = { +"points": PackedVector2Array(0, 0, 0, 27.615, 113, 0, 62.4099, 0, -62.4099, 0, 0, 50, 0, 27.615, 0, -27.615, -113, 0, -62.4099, 0, 62.4099, 0, 0, -50, 0, -27.615, 0, 0, 113, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_1ynft"] +script = ExtResource("4_jqihn") +arcs = Array[ExtResource("3_4sn87")]([]) + +[sub_resource type="Curve2D" id="Curve2D_6gv5h"] +_data = { +"points": PackedVector2Array(0, 0, 31.9968, 8.0128, 160.006, -15.936, -40, -0.0159945, 2.66667, -8, 264.003, -7.89443, 8, 18.6667, 7.97763, -0.102371, 256.022, -55.8976, 0, 0, 0, 0, 320, 0.127959, 8.02242, -0.102364, 8, -18.6667, 255.978, 56.1024, 2.66667, 8, -40, -0.015995, 263.997, 8.10557, 32.0032, -7.9872, 0, 0, 159.994, 16.064, 0, 0, 0, 0, 160.006, -15.936) +} +point_count = 8 + +[sub_resource type="Resource" id="Resource_lefxx"] +script = ExtResource("4_jqihn") +arcs = Array[ExtResource("3_4sn87")]([]) + +[sub_resource type="Curve2D" id="Curve2D_ekw72"] +_data = { +"points": PackedVector2Array(0, 0, 0, 13.2546, 24.9394, 0, 13.7741, 0, -13.7741, 0, 0, 23.999, 0, 13.2546, 0, -13.2546, -24.9394, 0, -13.7741, 0, 13.7741, 0, 0, -23.999, 0, -13.2546, 0, 0, 24.9394, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_vryrk"] +script = ExtResource("4_jqihn") +arcs = Array[ExtResource("3_4sn87")]([]) + +[sub_resource type="Curve2D" id="Curve2D_1ynft"] +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 0.47074, 13.6515, 0, 7.53184, 0, -7.53184, -14.5929, -8.94406, 0, 0, 0, 0, 0.47074, -8.94406, 0, -7.53184, 0, 7.53184, 15.5344, -8.94406, 0, 0, 0, 0, 0.47074, 13.6515) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_ekw72"] +script = ExtResource("3_4sn87") +start_point = 1 +radius = Vector2(7.53184, 7.53184) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_j7fu7"] +script = ExtResource("3_4sn87") +start_point = 2 +radius = Vector2(7.53184, 7.53184) +rotation_deg = 0.0 +sweep_flag = true +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_6j8tw"] +script = ExtResource("4_jqihn") +arcs = Array[ExtResource("3_4sn87")]([SubResource("Resource_ekw72"), SubResource("Resource_j7fu7")]) + +[node name="Rat" type="CharacterBody2D"] +script = ExtResource("1_7hgga") +metadata/_edit_horizontal_guides_ = [24.0] +metadata/movie_file = "test.avi" +metadata/_edit_vertical_guides_ = [384.0, 376.0] + +[node name="BackPaws" type="CollisionShape2D" parent="."] +position = Vector2(7.11809, 17.2294) +rotation = 0.0964239 +shape = SubResource("CircleShape2D_4sn87") + +[node name="FrontPaws" type="CollisionShape2D" parent="."] +position = Vector2(36, 18) +rotation = 0.0964239 +scale = Vector2(3.77953, 3.77953) +shape = SubResource("CircleShape2D_jqihn") + +[node name="Pivot" type="Node2D" parent="."] +position = Vector2(1, -13) + +[node name="Body_fill" type="Node2D" parent="Pivot"] +light_mask = 2 +rotation = 0.0964239 + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill"] +show_behind_parent = true +position = Vector2(0, 9.53674e-07) +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(10.4944, 1.07936, 10.208, 2.3083, 10.0081, 2.90882, 9.882, 3.19542, 9.73392, 3.46904, 9.56045, 3.72676, 9.35819, 3.96568, 9.12371, 4.18289, 8.85362, 4.37548, 8.54449, 4.54055, 8.19291, 4.67519, 7.79548, 4.77649, 7.34878, 4.84154, -8.20749, 4.94481, -8.80283, 4.60462, -9.10348, 4.40066, -9.39502, 4.17073, -9.66916, 3.91228, -9.91758, 3.62279, -10.132, 3.29971, -10.2238, 3.12477, -10.304, 2.94049, -10.3716, 2.74653, -10.4254, 2.54259, -10.4645, 2.32835, -10.4879, 2.10348, -10.4944, 1.86767, -10.483, 1.62061, -10.4026, 1.09144, -10.2383, 0.513434, -9.98184, -0.115956, -9.62484, -0.79927, -9.15901, -1.53905, -8.43804, -2.36002, -7.63898, -3.05574, -6.75898, -3.63237, -5.79518, -4.09608, -4.74472, -4.45302, -3.60474, -4.70935, -2.37239, -4.87123, -1.04482, -4.94482, -0.190294, -4.84434, 0.670796, -4.67918, 2.39181, -4.17875, 4.07651, -3.49129, 5.68314, -2.66459, 7.16997, -1.7464, 8.49528, -0.784502, 9.61733, 0.173342) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Leg_front_far_fill" type="Node2D" parent="Pivot/Body_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(15, 12) + +[node name="Paw_stroke" type="Node2D" parent="Pivot/Body_fill/Leg_front_far_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(28, 14) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_front_far_fill/Paw_stroke"] +show_behind_parent = true +position = Vector2(5.58428, 0.835604) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(-0.968994, 0.921921, -0.989042, 0.89513, -1.01283, 0.870654, -1.04013, 0.848435, -1.07069, 0.828416, -1.10428, 0.810537, -1.14067, 0.79474, -1.22085, 0.76916, -1.30934, 0.75121, -1.40423, 0.740424, -1.60559, 0.738474, -1.8097, 0.75958, -2.00131, 0.80001, -2.08767, 0.826306, -2.16519, 0.856034, -2.23197, 0.888727, -2.26074, 0.90604, -2.2861, 0.92392, -2.30577, 0.90402, -2.32327, 0.881134, -2.3387, 0.855457, -2.35216, 0.82719, -2.36374, 0.796529, -2.37356, 0.763673, -2.38825, 0.692168, -2.40065, 0.531536, -2.39563, 0.357972, -2.3269, -0.21199, -2.14641, -0.387708, -1.86397, -0.620299, -1.69092, -0.732911, -1.50005, -0.829725, -1.39873, -0.869082, -1.29393, -0.900738, -1.18595, -0.923442, -1.07511, -0.935944, -0.781714, -0.751844, -0.495804, -0.599254, -0.218185, -0.475738, 0.0503362, -0.378863, 0.308955, -0.306192, 0.556867, -0.255291, 1.01735, -0.209061, 1.29172, -0.134452, 1.52339, -0.0491136, 1.71923, 0.0428488, 1.88608, 0.137329, 2.28123, 0.39482, 2.40065, 0.458313, 1.99294, 0.547023, 1.82534, 0.59382, 1.69313, 0.645036, 1.64292, 0.672955, 1.62225, 0.687607, 1.60472, 0.702765, 1.59045, 0.71846, 1.58457, 0.726519, 1.57957, 0.734725, 1.57544, 0.743082, 1.57222, 0.751594, 1.56991, 0.760265, 1.56853, 0.769099, 1.56809, 0.7781, 1.56862, 0.787273, 1.57014, 0.796621, 1.57264, 0.806148, 1.57617, 0.815859, 1.58072, 0.825757, 1.59297, 0.846133, 1.60954, 0.867308, 1.63056, 0.889316, 1.68647, 0.935959, 0.598272, 0.70844, 0.191094, 0.670996, -0.141249, 0.673563, -0.411093, 0.707992, -0.630773, 0.766133, -0.812623, 0.839839) +closed = true +width = 0.534647 +default_color = Color(0.403922, 0.2, 0.192157, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_front_far_fill"] +show_behind_parent = true +position = Vector2(10.6215, 3.6058) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(4.58061, 2.74669, 2.75771, 3.06064, 1.10918, 3.20542, -0.354013, 3.18672, -1.01268, 3.11784, -1.62089, 3.01022, -2.17728, 2.86457, -2.68047, 2.68161, -3.1291, 2.46204, -3.5218, 2.20658, -3.69674, 2.06561, -3.85718, 1.91593, -4.00295, 1.75764, -4.13388, 1.59081, -4.24979, 1.41555, -4.35052, 1.23193, -4.4359, 1.04005, -4.50574, 0.839996, -4.60819, 0.446954, -4.6715, 0.0756004, -4.69792, -0.274331, -4.68972, -0.603104, -4.64913, -0.910985, -4.57842, -1.19824, -4.47984, -1.46513, -4.35564, -1.71193, -4.20807, -1.93889, -4.03939, -2.14629, -3.85185, -2.33439, -3.64771, -2.50345, -3.4292, -2.65374, -3.1986, -2.78552, -2.95815, -2.89907, -2.7101, -2.99464, -2.20023, -3.13292, -1.68701, -3.20248, -1.18847, -3.20545, -0.95034, -3.18262, -0.722636, -3.14394, -0.507613, -3.08967, -0.307524, -3.02008, -0.124622, -2.93544, 0.0388396, -2.836, 0.112576, -2.78081, 0.180608, -2.72203, 0.242653, -2.65968, 0.29843, -2.5938, 0.347657, -2.52442, 0.390053, -2.45158, 0.425336, -2.3753, 0.453224, -2.29562, 0.694987, -1.61372, 0.989236, -0.996931, 1.32519, -0.441774, 1.69205, 0.0552211, 2.07906, 0.497527, 2.47541, 0.888616, 3.25302, 1.53104, 4.44593, 2.3541, 4.60577, 2.48392, 4.63413, 2.51258, 4.65752, 2.53983, 4.67576, 2.56572, 4.68869, 2.59031, 4.69613, 2.61366, 4.69793, 2.63581, 4.69391, 2.65682, 4.6839, 2.67674, 4.66773, 2.69564, 4.64524, 2.71356, 4.61626, 2.73056) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Leg_front_far_fill"] +show_behind_parent = true +position = Vector2(9.6261, 3.70207) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +color = Color(0.298039, 0.298039, 0.247059, 1) +polygon = PackedVector2Array(4.58061, 2.74669, 2.75771, 3.06064, 1.10918, 3.20542, -0.354013, 3.18672, -1.01268, 3.11784, -1.62089, 3.01022, -2.17728, 2.86457, -2.68047, 2.68161, -3.1291, 2.46204, -3.5218, 2.20658, -3.69674, 2.06561, -3.85718, 1.91593, -4.00295, 1.75764, -4.13388, 1.59081, -4.24979, 1.41555, -4.35052, 1.23193, -4.4359, 1.04005, -4.50574, 0.839996, -4.60819, 0.446954, -4.6715, 0.0756004, -4.69792, -0.274331, -4.68972, -0.603104, -4.64913, -0.910985, -4.57842, -1.19824, -4.47984, -1.46513, -4.35564, -1.71193, -4.20807, -1.93889, -4.03939, -2.14629, -3.85185, -2.33439, -3.64771, -2.50345, -3.4292, -2.65374, -3.1986, -2.78552, -2.95815, -2.89907, -2.7101, -2.99464, -2.20023, -3.13292, -1.68701, -3.20248, -1.18847, -3.20545, -0.95034, -3.18262, -0.722636, -3.14394, -0.507613, -3.08967, -0.307524, -3.02008, -0.124622, -2.93544, 0.0388396, -2.836, 0.112576, -2.78081, 0.180608, -2.72203, 0.242653, -2.65968, 0.29843, -2.5938, 0.347657, -2.52442, 0.390053, -2.45158, 0.425336, -2.3753, 0.453224, -2.29562, 0.694987, -1.61372, 0.989236, -0.996931, 1.32519, -0.441774, 1.69205, 0.0552211, 2.07906, 0.497527, 2.47541, 0.888616, 3.25302, 1.53104, 4.44593, 2.3541, 4.60577, 2.48392, 4.63413, 2.51258, 4.65752, 2.53983, 4.67576, 2.56572, 4.68869, 2.59031, 4.69613, 2.61366, 4.69793, 2.63581, 4.69391, 2.65682, 4.6839, 2.67674, 4.66773, 2.69564, 4.64524, 2.71356, 4.61626, 2.73056) + +[node name="Paw_fill" type="Node2D" parent="Pivot/Body_fill/Leg_front_far_fill"] +light_mask = 2 +position = Vector2(28, 14) + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Leg_front_far_fill/Paw_fill"] +show_behind_parent = true +position = Vector2(5.5843, 0.835602) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +color = Color(0.960784, 0.545098, 0.545098, 1) +polygon = PackedVector2Array(-0.968994, 0.921921, -0.989042, 0.89513, -1.01283, 0.870654, -1.04013, 0.848435, -1.07069, 0.828416, -1.10428, 0.810537, -1.14067, 0.79474, -1.22085, 0.76916, -1.30934, 0.75121, -1.40423, 0.740424, -1.60559, 0.738474, -1.8097, 0.75958, -2.00131, 0.80001, -2.08767, 0.826306, -2.16519, 0.856034, -2.23197, 0.888727, -2.26074, 0.90604, -2.2861, 0.92392, -2.30577, 0.90402, -2.32327, 0.881134, -2.3387, 0.855457, -2.35216, 0.82719, -2.36374, 0.796529, -2.37356, 0.763673, -2.38825, 0.692168, -2.40065, 0.531536, -2.39563, 0.357972, -2.3269, -0.21199, -2.14641, -0.387708, -1.86397, -0.620299, -1.69092, -0.732911, -1.50005, -0.829725, -1.39873, -0.869082, -1.29393, -0.900738, -1.18595, -0.923442, -1.07511, -0.935944, -0.781714, -0.751844, -0.495804, -0.599254, -0.218185, -0.475738, 0.0503362, -0.378863, 0.308955, -0.306192, 0.556867, -0.255291, 1.01735, -0.209061, 1.29172, -0.134452, 1.52339, -0.0491136, 1.71923, 0.0428488, 1.88608, 0.137329, 2.28123, 0.39482, 2.40065, 0.458313, 1.99294, 0.547023, 1.82534, 0.59382, 1.69313, 0.645036, 1.64292, 0.672955, 1.62225, 0.687607, 1.60472, 0.702765, 1.59045, 0.71846, 1.58457, 0.726519, 1.57957, 0.734725, 1.57544, 0.743082, 1.57222, 0.751594, 1.56991, 0.760265, 1.56853, 0.769099, 1.56809, 0.7781, 1.56862, 0.787273, 1.57014, 0.796621, 1.57264, 0.806148, 1.57617, 0.815859, 1.58072, 0.825757, 1.59297, 0.846133, 1.60954, 0.867308, 1.63056, 0.889316, 1.68647, 0.935959, 0.598272, 0.70844, 0.191094, 0.670996, -0.141249, 0.673563, -0.411093, 0.707992, -0.630773, 0.766133, -0.812623, 0.839839) + +[node name="Leg_back_far_fill" type="Node2D" parent="Pivot/Body_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(-14, 4) + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Leg_back_far_fill"] +show_behind_parent = true +position = Vector2(4.5255, 11.8962) +rotation = -0.0201065 +scale = Vector2(3.77953, 3.77953) +color = Color(0.219608, 0.219608, 0.168627, 1) +polygon = PackedVector2Array(5.51884, 4.18761, 4.36447, 4.45093, 3.25842, 4.61613, 2.20359, 4.68872, 1.20285, 4.67421, 0.259085, 4.57811, -0.624818, 4.40593, -1.44598, 4.16317, -2.20151, 3.85535, -2.88853, 3.48798, -3.50416, 3.06656, -4.0455, 2.59661, -4.50969, 2.08363, -4.89384, 1.53314, -5.19505, 0.950638, -5.41045, 0.34164, -5.48507, 0.0289267, -5.53716, -0.288345, -5.53881, -0.533293, -5.52077, -0.77763, -5.48394, -1.02067, -5.42922, -1.26174, -5.26976, -1.73521, -5.04961, -2.19256, -4.77599, -2.62834, -4.45613, -3.03708, -4.09727, -3.41331, -3.70663, -3.75155, -3.29143, -4.04636, -2.8589, -4.29224, -2.41628, -4.48375, -1.97079, -4.61542, -1.74922, -4.6571, -1.52965, -4.68176, -1.31298, -4.68874, -1.1001, -4.67733, -0.891929, -4.64686, -0.689363, -4.59665, -0.493307, -4.526, -0.304665, -4.43425, 0.163506, -4.07557, 0.621729, -3.67012, 1.05178, -3.20192, 1.25055, -2.93931, 1.43545, -2.65503, 1.60419, -2.34708, 1.7545, -2.01348, 1.8841, -1.65221, 1.99071, -1.2613, 2.07206, -0.83875, 2.12586, -0.382555, 2.14174, 0.638733, 2.6023, 1.24995, 3.15488, 1.84813, 5.25537, 3.76194, 5.39938, 3.91135, 5.45386, 3.97599, 5.49558, 4.03355, 5.51141, 4.0596, 5.52375, 4.08377, 5.53249, 4.10603, 5.53755, 4.12636, 5.53881, 4.14471, 5.53618, 4.16106, 5.52955, 4.17536) + +[node name="Leg_back_far_stroke" type="Node2D" parent="Pivot/Body_fill/Leg_back_far_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(5, 10) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_back_far_fill/Leg_back_far_stroke"] +show_behind_parent = true +position = Vector2(-2.49551, 2.18189) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(5.51884, 4.18761, 4.36447, 4.45093, 3.25842, 4.61613, 2.20359, 4.68872, 1.20285, 4.67421, 0.259085, 4.57811, -0.624818, 4.40593, -1.44598, 4.16317, -2.20151, 3.85535, -2.88853, 3.48798, -3.50416, 3.06656, -4.0455, 2.59661, -4.50969, 2.08363, -4.89384, 1.53314, -5.19505, 0.950638, -5.41045, 0.34164, -5.48507, 0.0289267, -5.53716, -0.288345, -5.53881, -0.533293, -5.52077, -0.77763, -5.48394, -1.02067, -5.42922, -1.26174, -5.26976, -1.73521, -5.04961, -2.19256, -4.77599, -2.62834, -4.45613, -3.03708, -4.09727, -3.41331, -3.70663, -3.75155, -3.29143, -4.04636, -2.8589, -4.29224, -2.41628, -4.48375, -1.97079, -4.61542, -1.74922, -4.6571, -1.52965, -4.68176, -1.31298, -4.68874, -1.1001, -4.67733, -0.891929, -4.64686, -0.689363, -4.59665, -0.493307, -4.526, -0.304665, -4.43425, 0.163506, -4.07557, 0.621729, -3.67012, 1.05178, -3.20192, 1.25055, -2.93931, 1.43545, -2.65503, 1.60419, -2.34708, 1.7545, -2.01348, 1.8841, -1.65221, 1.99071, -1.2613, 2.07206, -0.83875, 2.12586, -0.382555, 2.14174, 0.638733, 2.6023, 1.24995, 3.15488, 1.84813, 5.25537, 3.76194, 5.39938, 3.91135, 5.45386, 3.97599, 5.49558, 4.03355, 5.51141, 4.0596, 5.52375, 4.08377, 5.53249, 4.10603, 5.53755, 4.12636, 5.53881, 4.14471, 5.53618, 4.16106, 5.52955, 4.17536) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Paw_stroke" type="Node2D" parent="Pivot/Body_fill/Leg_back_far_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(23, 25.5) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_back_far_fill/Paw_stroke"] +show_behind_parent = true +position = Vector2(7.21295, 3.09049) +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(-0.879219, 0.814774, -0.902945, 0.791176, -0.930038, 0.770413, -0.960271, 0.752393, -0.993416, 0.737022, -1.02925, 0.724209, -1.06754, 0.713862, -1.15059, 0.700194, -1.24074, 0.695282, -1.33619, 0.698386, -1.5357, 0.725693, -1.73458, 0.776212, -1.91829, 0.844038, -1.99992, 0.882596, -2.0723, 0.923267, -2.13363, 0.965313, -2.15957, 0.986621, -2.18208, 1.008, -2.20442, 0.991163, -2.22506, 0.971059, -2.24405, 0.947895, -2.26147, 0.921881, -2.27739, 0.893227, -2.29187, 0.862144, -2.31679, 0.79353, -2.35238, 0.636398, -2.37261, 0.463944, -2.38738, -0.109955, -2.23432, -0.310011, -1.98864, -0.581144, -1.83377, -0.717688, -1.65898, -0.841189, -1.56446, -0.894838, -1.46536, -0.941376, -1.36182, -0.979518, -1.25397, -1.00798, -0.936955, -0.868431, -0.631919, -0.758969, -0.339309, -0.677068, -0.0595682, -0.620203, 0.206861, -0.585849, 0.459536, -0.571482, 0.921852, -0.592606, 1.20414, -0.558625, 1.44575, -0.507829, 1.65287, -0.445276, 1.83167, -0.376022, 2.26002, -0.178631, 2.38739, -0.133148, 1.99688, 0.013819, 1.83784, 0.0844559, 1.71446, 0.154326, 1.66884, 0.189239, 1.65052, 0.206737, 1.63537, 0.224279, 1.62353, 0.241879, 1.61889, 0.250706, 1.61513, 0.259551, 1.61226, 0.268418, 1.6103, 0.277308, 1.60928, 0.286222, 1.60919, 0.295162, 1.61007, 0.30413, 1.61193, 0.313128, 1.61478, 0.322157, 1.61864, 0.331218, 1.62354, 0.340314, 1.62948, 0.349446, 1.64456, 0.367825, 1.66403, 0.386368, 1.68802, 0.405089, 1.75011, 0.443115, 0.64041, 0.376006, 0.232112, 0.398079, -0.0963352, 0.448873, -0.35832, 0.522115, -0.567229, 0.611531, -0.736451, 0.71085) +closed = true +width = 0.534647 +default_color = Color(0.403922, 0.2, 0.192157, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Paw_fill" type="Node2D" parent="Pivot/Body_fill/Leg_back_far_fill"] +light_mask = 2 +position = Vector2(23, 25.5) + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Leg_back_far_fill/Paw_fill"] +show_behind_parent = true +position = Vector2(6.84759, 3.24232) +rotation = -0.0164752 +scale = Vector2(3.77953, 3.77953) +color = Color(1, 0.564706, 0.564706, 1) +polygon = PackedVector2Array(-0.879219, 0.814774, -0.902945, 0.791176, -0.930038, 0.770413, -0.960271, 0.752393, -0.993416, 0.737022, -1.02925, 0.724209, -1.06754, 0.713862, -1.15059, 0.700194, -1.24074, 0.695282, -1.33619, 0.698386, -1.5357, 0.725693, -1.73458, 0.776212, -1.91829, 0.844038, -1.99992, 0.882596, -2.0723, 0.923267, -2.13363, 0.965313, -2.15957, 0.986621, -2.18208, 1.008, -2.20442, 0.991163, -2.22506, 0.971059, -2.24405, 0.947895, -2.26147, 0.921881, -2.27739, 0.893227, -2.29187, 0.862144, -2.31679, 0.79353, -2.35238, 0.636398, -2.37261, 0.463944, -2.38738, -0.109955, -2.23432, -0.310011, -1.98864, -0.581144, -1.83377, -0.717688, -1.65898, -0.841189, -1.56446, -0.894838, -1.46536, -0.941376, -1.36182, -0.979518, -1.25397, -1.00798, -0.936955, -0.868431, -0.631919, -0.758969, -0.339309, -0.677068, -0.0595682, -0.620203, 0.206861, -0.585849, 0.459536, -0.571482, 0.921852, -0.592606, 1.20414, -0.558625, 1.44575, -0.507829, 1.65287, -0.445276, 1.83167, -0.376022, 2.26001, -0.178631, 2.38738, -0.133148, 1.99688, 0.013819, 1.83784, 0.0844559, 1.71447, 0.154326, 1.66884, 0.189239, 1.65052, 0.206737, 1.63537, 0.224279, 1.62353, 0.241879, 1.61889, 0.250706, 1.61513, 0.259551, 1.61226, 0.268418, 1.61031, 0.277308, 1.60928, 0.286222, 1.6092, 0.295162, 1.61007, 0.30413, 1.61193, 0.313128, 1.61478, 0.322157, 1.61865, 0.331218, 1.62354, 0.340314, 1.62948, 0.349446, 1.64457, 0.367825, 1.66404, 0.386368, 1.68803, 0.405089, 1.75011, 0.443115, 0.640417, 0.376006, 0.232119, 0.398079, -0.0963295, 0.448873, -0.358316, 0.522115, -0.567228, 0.611531, -0.736453, 0.71085) + +[node name="RemoteTransform2D" type="RemoteTransform2D" parent="Pivot/Body_fill/Leg_back_far_fill/Paw_fill"] +remote_path = NodePath("../../../../../BackPaws") + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill"] +show_behind_parent = true +scale = Vector2(3.77953, 3.77953) +texture = SubResource("GradientTexture2D_ycbh5") +texture_offset = Vector2(10.4944, 4.94482) +polygon = PackedVector2Array(10.4944, 1.07936, 10.208, 2.3083, 10.0081, 2.90882, 9.882, 3.19542, 9.73392, 3.46904, 9.56045, 3.72676, 9.35819, 3.96568, 9.12371, 4.18289, 8.85362, 4.37548, 8.54449, 4.54055, 8.19291, 4.67519, 7.79548, 4.77649, 7.34878, 4.84154, -8.20749, 4.94481, -8.80283, 4.60462, -9.10348, 4.40066, -9.39502, 4.17073, -9.66916, 3.91228, -9.91758, 3.62279, -10.132, 3.29971, -10.2238, 3.12477, -10.304, 2.94049, -10.3716, 2.74653, -10.4254, 2.54259, -10.4645, 2.32835, -10.4879, 2.10348, -10.4944, 1.86767, -10.483, 1.62061, -10.4026, 1.09144, -10.2383, 0.513434, -9.98184, -0.115956, -9.62484, -0.79927, -9.15901, -1.53905, -8.43804, -2.36002, -7.63898, -3.05574, -6.75898, -3.63237, -5.79518, -4.09608, -4.74472, -4.45302, -3.60474, -4.70935, -2.37239, -4.87123, -1.04482, -4.94482, -0.190294, -4.84434, 0.670796, -4.67918, 2.39181, -4.17875, 4.07651, -3.49129, 5.68314, -2.66459, 7.16997, -1.7464, 8.49528, -0.784502, 9.61733, 0.173342) + +[node name="Head_stroke" type="Node2D" parent="Pivot/Body_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(29, 12) + +[node name="Stroke2" type="Line2D" parent="Pivot/Body_fill/Head_stroke"] +show_behind_parent = true +position = Vector2(16.5612, -8.36952) +rotation = -0.031361 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(-5.1235, 3.5421, -5.32184, 3.22654, -5.51257, 2.86892, -5.86152, 2.05666, -6.15101, 1.16372, -6.36169, 0.24848, -6.47421, -0.630679, -6.48761, -1.03848, -6.46922, -1.41537, -6.4166, -1.75405, -6.37671, -1.90678, -6.32736, -2.04721, -6.26824, -2.17445, -6.19906, -2.28757, -6.16059, -2.33855, -6.1195, -2.38566, -6.07575, -2.42879, -6.02928, -2.46782, -5.82858, -2.68304, -5.58203, -2.89492, -4.97444, -3.30111, -4.25261, -3.67122, -3.46265, -3.9901, -2.65068, -4.24258, -1.86282, -4.41352, -1.14516, -4.48774, -0.827069, -4.48384, -0.543823, -4.45009, 0.400548, -3.90231, 1.24231, -3.31108, 3.26865, -1.53729, 3.99883, -0.620914, 4.34269, -0.265416, 4.69365, 0.0479463, 6.48762, 1.2749, 6.33494, 1.59174, 6.13961, 1.89128, 5.90455, 2.17366, 5.63265, 2.43903, 5.32684, 2.68753, 4.99001, 2.9193, 4.23495, 3.33324, 3.39074, 3.68198, 2.48067, 3.96666, 0.555983, 4.34845, -1.35294, 4.48775, -2.24332, 4.46932, -3.05995, 4.39369, -3.77955, 4.26201, -4.09569, 4.17551, -4.37885, 4.07543, -4.62613, 3.9619, -4.8346, 3.83507, -4.92337, 3.76672, -5.00136, 3.69509, -5.06819, 3.62021) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Head_fill" type="Node2D" parent="Pivot/Body_fill"] +light_mask = 2 +position = Vector2(29, 12) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +position = Vector2(19.2836, -12.5163) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(-1.51561, -0.200943, -1.47976, -0.346925, -1.43196, -0.48815, -1.37294, -0.623806, -1.3034, -0.753083, -1.22404, -0.875172, -1.1356, -0.989261, -1.03877, -1.09454, -0.934273, -1.1902, -0.822818, -1.27543, -0.705116, -1.34941, -0.581881, -1.41135, -0.453825, -1.46043, -0.32166, -1.49583, -0.186097, -1.51675, -0.0478504, -1.52238, 0.0923691, -1.5119, 0.126495, -1.50584, 0.16381, -1.49638, 0.246996, -1.46752, 0.339898, -1.42584, 0.440491, -1.37189, 0.656638, -1.22925, 0.879221, -1.04381, 1.09202, -0.81979, 1.18969, -0.69463, 1.27883, -0.561406, 1.35742, -0.420645, 1.42343, -0.272876, 1.47483, -0.118625, 1.5096, 0.0415802, 1.5156, 0.106706, 1.51332, 0.171676, 1.50328, 0.236386, 1.48596, 0.300728, 1.46187, 0.364597, 1.43151, 0.427886, 1.35402, 0.552303, 1.25748, 0.673128, 1.14593, 0.789514, 0.893849, 1.00557, 0.0885696, 1.52238, -0.0841791, 1.51028, -0.240996, 1.4881, -0.383223, 1.45527, -0.512204, 1.41122, -0.629282, 1.35538, -0.7358, 1.28717, -0.8331, 1.20603, -0.922526, 1.11137, -1.00542, 1.00263, -1.08313, 0.879237, -1.22834, 0.586192) +closed = true +width = 0.365313 +default_color = Color(0.262745, 0.262745, 0.262745, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Ear_front_stroke" type="Node2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(-1, -20) + +[node name="Stroke2" type="Line2D" parent="Pivot/Body_fill/Head_fill/Ear_front_stroke"] +show_behind_parent = true +position = Vector2(-5.5556, -9.24091) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(2.82073, 0.00202942, 2.90208, 0.508293, 2.93115, 1.00263, 2.90697, 1.47407, 2.82858, 1.91168, 2.76875, 2.11436, 2.695, 2.30448, 2.60722, 2.48065, 2.50528, 2.64152, 2.38906, 2.78571, 2.25844, 2.91184, 2.11331, 3.01856, 2.03526, 3.06421, 1.95353, 3.10449, 1.93581, 3.11295, 1.91696, 3.12001, 1.89701, 3.12569, 1.87598, 3.13003, 1.83079, 3.13484, 1.78159, 3.13474, 1.7286, 3.13, 1.67201, 3.12093, 1.54889, 3.09093, 0.95401, 2.85518, 0.274572, 2.54524, -0.0638338, 2.4087, -0.383751, 2.30913, -0.982054, 2.00755, -1.31448, 1.78923, -1.65359, 1.51561, -1.98773, 1.17898, -2.30528, 0.771642, -2.59462, 0.285885, -2.84409, -0.285995, -2.90337, -0.601486, -2.93116, -0.893266, -2.92912, -1.1624, -2.8989, -1.40997, -2.84216, -1.63702, -2.76058, -1.84463, -2.65579, -2.03387, -2.52948, -2.20579, -2.38328, -2.36148, -2.21887, -2.502, -2.03791, -2.62841, -1.84205, -2.74177, -1.41228, -2.93366, -0.942841, -3.0862, -0.819604, -3.11409, -0.692594, -3.13019, -0.562225, -3.13485, -0.42891, -3.12847, -0.293062, -3.11142, -0.155096, -3.08407, 0.125538, -3, 0.409683, -2.8793, 0.694032, -2.72498, 0.975274, -2.54007, 1.2501, -2.32759, 1.76728, -1.832, 2.21909, -1.26242, 2.41221, -0.957426, 2.57906, -0.643004, 2.71634, -0.322173) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Ear_back" type="Node2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(9, -23) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Head_fill/Ear_back"] +show_behind_parent = true +position = Vector2(-0.819748, -9.27491) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(1.56583, 2.4758, 1.14945, 2.39586, 0.741913, 2.28367, -0.0500554, 1.97516, -0.816994, 1.57546, -1.56583, 1.10976, -1.47698, 0.246929, -1.32348, -0.575294, -1.21022, -0.975357, -1.06608, -1.37028, -0.886146, -1.76175, -0.66552, -2.15141, -0.508435, -2.2898, -0.432738, -2.34398, -0.358905, -2.38851, -0.286913, -2.42366, -0.216737, -2.4497, -0.148354, -2.46689, -0.0817398, -2.4755, -0.0168702, -2.4758, 0.0462788, -2.46806, 0.107731, -2.45254, 0.16751, -2.42951, 0.225641, -2.39924, 0.282147, -2.362, 0.337052, -2.31805, 0.390381, -2.26767, 0.492403, -2.14866, 0.588405, -2.0071, 0.763119, -1.66495, 0.916058, -1.25832, 1.04875, -0.804368) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Head_fill/Ear_back"] +show_behind_parent = true +position = Vector2(-0.803364, -9.10554) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +texture = SubResource("GradientTexture2D_vheyn") +texture_offset = Vector2(1.56583, 2.52082) +polygon = PackedVector2Array(1.56583, 2.43079, 1.48967, 2.46543, 1.41044, 2.49139, 1.32831, 2.50902, 1.24345, 2.5187, 1.15603, 2.5208, 1.06621, 2.51569, 0.880039, 2.48531, 0.686276, 2.43052, 0.486249, 2.3543, 0.0727233, 2.14939, -1.56583, 1.06474, -1.47698, 0.201915, -1.32348, -0.620307, -1.21022, -1.02037, -1.06608, -1.4153, -0.886146, -1.80676, -0.66552, -2.19643, -0.508435, -2.33481, -0.432738, -2.38899, -0.358905, -2.43353, -0.286913, -2.46868, -0.216737, -2.49471, -0.148354, -2.5119, -0.0817398, -2.52052, -0.0168702, -2.52082, 0.0462788, -2.51307, 0.107731, -2.49755, 0.16751, -2.47453, 0.225641, -2.44426, 0.282147, -2.40701, 0.337052, -2.36307, 0.390381, -2.31268, 0.492403, -2.19367, 0.588405, -2.05212, 0.763119, -1.70996, 0.916058, -1.30334, 1.04875, -0.849382) + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +position = Vector2(15.5658, -8.27324) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +texture = SubResource("GradientTexture2D_yvsbv") +texture_offset = Vector2(6.48761, 4.48774) +polygon = PackedVector2Array(-5.1235, 3.5421, -5.32184, 3.22654, -5.51257, 2.86892, -5.86152, 2.05666, -6.15101, 1.16372, -6.36169, 0.24848, -6.47421, -0.630679, -6.48761, -1.03848, -6.46922, -1.41537, -6.4166, -1.75405, -6.37671, -1.90678, -6.32736, -2.04721, -6.26824, -2.17445, -6.19906, -2.28757, -6.16059, -2.33855, -6.1195, -2.38566, -6.07575, -2.42879, -6.02928, -2.46782, -5.82858, -2.68304, -5.58203, -2.89492, -4.97444, -3.30111, -4.25261, -3.67122, -3.46265, -3.9901, -2.65068, -4.24258, -1.86282, -4.41352, -1.14516, -4.48774, -0.827069, -4.48384, -0.543823, -4.45009, 0.400548, -3.90231, 1.24231, -3.31108, 3.26865, -1.53729, 3.99883, -0.620914, 4.34269, -0.265416, 4.69365, 0.0479463, 6.48762, 1.2749, 6.33494, 1.59174, 6.13961, 1.89128, 5.90455, 2.17366, 5.63265, 2.43903, 5.32684, 2.68753, 4.99001, 2.9193, 4.23495, 3.33324, 3.39074, 3.68198, 2.48067, 3.96666, 0.555983, 4.34845, -1.35294, 4.48775, -2.24332, 4.46932, -3.05995, 4.39369, -3.77955, 4.26201, -4.09569, 4.17551, -4.37885, 4.07543, -4.62613, 3.9619, -4.8346, 3.83507, -4.92337, 3.76672, -5.00136, 3.69509, -5.06819, 3.62021) + +[node name="WallDetector" type="Area2D" parent="Pivot/Body_fill/Head_fill/Fill"] +position = Vector2(2.28603, -0.938115) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Pivot/Body_fill/Head_fill/Fill/WallDetector"] +shape = SubResource("SegmentShape2D_4sn87") + +[node name="Fill2" type="Polygon2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +position = Vector2(19.626, -12.8988) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +polygon = PackedVector2Array(-1.4198, -0.188248, -1.38622, -0.325005, -1.34145, -0.457304, -1.28615, -0.584385, -1.22101, -0.705491, -1.14667, -0.819861, -1.06382, -0.926738, -0.973108, -1.02536, -0.875214, -1.11497, -0.770802, -1.19481, -0.660539, -1.26412, -0.545092, -1.32214, -0.425128, -1.36811, -0.301315, -1.40128, -0.17432, -1.42087, -0.0448098, -1.42615, 0.0865479, -1.41634, 0.118518, -1.41067, 0.153476, -1.40182, 0.231405, -1.3748, 0.318436, -1.33578, 0.41267, -1.28525, 0.615152, -1.15162, 0.823662, -0.977893, 1.02301, -0.768011, 1.1145, -0.65075, 1.19801, -0.525937, 1.27163, -0.394064, 1.33346, -0.255628, 1.38161, -0.111124, 1.41418, 0.0389557, 1.41981, 0.0999653, 1.41768, 0.16083, 1.40826, 0.221449, 1.39204, 0.281725, 1.36947, 0.341557, 1.34104, 0.400846, 1.26844, 0.517398, 1.17801, 0.630586, 1.07351, 0.739615, 0.837361, 0.942011, 0.0829926, 1.42616, -0.284311, 1.40156, -0.437856, 1.3734, -0.573561, 1.33402, -0.693101, 1.28295, -0.747332, 1.25288, -0.798149, 1.21971, -0.845761, 1.18337, -0.890378, 1.14381, -0.971464, 1.05477, -1.04308, 0.952112, -1.1069, 0.835353, -1.21784, 0.557611) + +[node name="Fill3" type="Polygon2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +position = Vector2(20.1843, -13.5357) +rotation = -0.881423 +scale = Vector2(3.77953, 3.77953) +color = Color(0, 0, 0, 1) +polygon = PackedVector2Array(0.909013, 0, 0.90432, 0.0996011, 0.890546, 0.196325, 0.868147, 0.289681, 0.837581, 0.37918, 0.799303, 0.464333, 0.753772, 0.544649, 0.701443, 0.61964, 0.642775, 0.688816, 0.578223, 0.751687, 0.508244, 0.807764, 0.433296, 0.856557, 0.353835, 0.897576, 0.270318, 0.930332, 0.183202, 0.954335, 0.0929436, 0.969096, 0, 0.974125, -0.0929436, 0.969096, -0.183202, 0.954335, -0.270318, 0.930332, -0.353835, 0.897576, -0.433296, 0.856557, -0.508244, 0.807764, -0.578223, 0.751687, -0.642775, 0.688816, -0.701443, 0.61964, -0.753772, 0.544649, -0.799303, 0.464333, -0.837581, 0.37918, -0.868147, 0.289681, -0.890546, 0.196324, -0.90432, 0.0996011, -0.909013, 0, -0.90432, -0.0996011, -0.890546, -0.196325, -0.868147, -0.289681, -0.837581, -0.37918, -0.799303, -0.464333, -0.753772, -0.544649, -0.701443, -0.61964, -0.642775, -0.688816, -0.578223, -0.751687, -0.508244, -0.807764, -0.433296, -0.856557, -0.353835, -0.897576, -0.270318, -0.930332, -0.183202, -0.954335, -0.0929436, -0.969096, 0, -0.974125, 0.0929436, -0.969096, 0.183202, -0.954335, 0.270318, -0.930332, 0.353835, -0.897576, 0.433296, -0.856557, 0.508244, -0.807764, 0.578223, -0.751687, 0.642775, -0.688816, 0.701443, -0.61964, 0.753772, -0.544649, 0.799303, -0.464333, 0.837581, -0.37918, 0.868147, -0.289681, 0.890546, -0.196324, 0.90432, -0.0996011) + +[node name="Fill4" type="Polygon2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +position = Vector2(20.4732, -15.3746) +rotation = -0.211078 +scale = Vector2(3.77953, 3.77953) +color = Color(0.952941, 0.952941, 0.952941, 1) +polygon = PackedVector2Array(0.432679, 0, 0.432116, 0.00865906, 0.430445, 0.0172044, 0.427693, 0.0256255, 0.423888, 0.0339118, 0.419057, 0.0420526, 0.413227, 0.0500375, 0.406425, 0.0578558, 0.398678, 0.065497, 0.380458, 0.0802057, 0.358786, 0.0940791, 0.333878, 0.107033, 0.305952, 0.118982, 0.241918, 0.139528, 0.168421, 0.155041, 0.0872017, 0.164845, 0, 0.168264, -0.0872017, 0.164845, -0.168421, 0.155041, -0.241918, 0.139528, -0.305952, 0.118982, -0.333878, 0.107033, -0.358786, 0.0940791, -0.380458, 0.0802057, -0.398678, 0.065497, -0.406425, 0.0578558, -0.413227, 0.0500375, -0.419057, 0.0420526, -0.423888, 0.0339118, -0.427693, 0.0256255, -0.430445, 0.0172044, -0.432116, 0.00865906, -0.432679, 0, -0.432116, -0.00865906, -0.430445, -0.0172044, -0.427693, -0.0256255, -0.423888, -0.0339118, -0.419057, -0.0420526, -0.413227, -0.0500375, -0.406425, -0.0578558, -0.398678, -0.065497, -0.380458, -0.0802057, -0.358786, -0.0940791, -0.333878, -0.107033, -0.305952, -0.118982, -0.241918, -0.139528, -0.168421, -0.155041, -0.0872017, -0.164845, 0, -0.168264, 0.0872017, -0.164845, 0.168421, -0.155041, 0.241918, -0.139528, 0.305952, -0.118982, 0.333878, -0.107033, 0.358786, -0.0940791, 0.380458, -0.0802057, 0.398678, -0.065497, 0.406425, -0.0578558, 0.413227, -0.0500375, 0.419057, -0.0420526, 0.423888, -0.0339118, 0.427693, -0.0256255, 0.430445, -0.0172044, 0.432116, -0.00865906) + +[node name="Fill5" type="Polygon2D" parent="Pivot/Body_fill/Head_fill"] +show_behind_parent = true +position = Vector2(38.2338, -2.42844) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +color = Color(0.960784, 0.545098, 0.545098, 1) +polygon = PackedVector2Array(0.671211, -0.780273, 0.723983, -0.783259, 0.771582, -0.780634, 0.814159, -0.772684, 0.833612, -0.766802, 0.851867, -0.759697, 0.868942, -0.751404, 0.884857, -0.741961, 0.89963, -0.731402, 0.913281, -0.719763, 0.925829, -0.707081, 0.937292, -0.693391, 0.947689, -0.678729, 0.95704, -0.663131, 0.972679, -0.629273, 0.984359, -0.592102, 0.992233, -0.551907, 0.996452, -0.508974, 0.997169, -0.463592, 0.994535, -0.416048, 0.979823, -0.315622, 0.95353, -0.209997, 0.916872, -0.101472, 0.81732, 0.115079, 0.690888, 0.315634, 0.620629, 0.404164, 0.547295, 0.481796, 0.470694, 0.549357, 0.390271, 0.609162, 0.306686, 0.661152, 0.220601, 0.70527, 0.132675, 0.741454, 0.0435687, 0.769648, -0.0460562, 0.789791, -0.13554, 0.801825, -0.224221, 0.80569, -0.311439, 0.801329, -0.396534, 0.788681, -0.478845, 0.767689, -0.557712, 0.738293, -0.632473, 0.700433, -0.702468, 0.654052, -0.767036, 0.599091, -0.824713, 0.536361, -0.874376, 0.46732, -0.915874, 0.392859, -0.949054, 0.313867, -0.973764, 0.231237, -0.989852, 0.14586, -0.997167, 0.0586261, -0.995557, -0.0295728, -0.984869, -0.117846, -0.964952, -0.205302, -0.935653, -0.29105, -0.896821, -0.374198, -0.848303, -0.453857, -0.789949, -0.529134, -0.721605, -0.599138, -0.64312, -0.662979, -0.572089, -0.707878, -0.497941, -0.742958, -0.421025, -0.769248, -0.341692, -0.787781, -0.260293, -0.799586, -0.177178, -0.805696, -0.00720246, -0.804948, 0.337911, -0.780455, 0.50744, -0.773202) + +[node name="Fill6" type="Polygon2D" parent="Pivot/Body_fill/Head_fill"] +self_modulate = Color(1, 1, 1, 0.688525) +show_behind_parent = true +position = Vector2(40.2245, -2.62099) +rotation = -0.0838128 +scale = Vector2(3.77953, 3.77953) +color = Color(0, 0, 0, 1) +polygon = PackedVector2Array(0.173072, 0, 0.172179, 0.0235948, 0.169556, 0.0465078, 0.165292, 0.0686232, 0.159472, 0.0898249, 0.152184, 0.109997, 0.143515, 0.129023, 0.133552, 0.146788, 0.122382, 0.163175, 0.110091, 0.178069, 0.0967675, 0.191353, 0.0824977, 0.202912, 0.0673686, 0.212629, 0.0514674, 0.220389, 0.0348809, 0.226075, 0.0176961, 0.229572, 0, 0.230763, -0.0176961, 0.229572, -0.0348809, 0.226075, -0.0514674, 0.220389, -0.0673686, 0.212629, -0.0824977, 0.202912, -0.0967675, 0.191353, -0.110091, 0.178069, -0.122382, 0.163175, -0.133552, 0.146788, -0.143515, 0.129023, -0.152184, 0.109997, -0.159472, 0.0898249, -0.165291, 0.0686232, -0.169556, 0.0465078, -0.172179, 0.0235948, -0.173072, 0, -0.172179, -0.0235948, -0.169556, -0.0465078, -0.165292, -0.0686232, -0.159472, -0.0898249, -0.152184, -0.109997, -0.143515, -0.129023, -0.133552, -0.146788, -0.122382, -0.163175, -0.110091, -0.178069, -0.0967675, -0.191353, -0.0824977, -0.202912, -0.0673686, -0.212629, -0.0514674, -0.220389, -0.0348809, -0.226075, -0.0176961, -0.229572, 0, -0.230763, 0.0176961, -0.229572, 0.0348809, -0.226075, 0.0514674, -0.220389, 0.0673686, -0.212629, 0.0824977, -0.202912, 0.0967675, -0.191353, 0.110091, -0.178069, 0.122382, -0.163175, 0.133552, -0.146788, 0.143515, -0.129023, 0.152184, -0.109997, 0.159472, -0.0898249, 0.165291, -0.0686232, 0.169556, -0.0465078, 0.172179, -0.0235948) + +[node name="Ear_front_fill" type="Node2D" parent="Pivot/Body_fill/Head_fill"] +light_mask = 2 +position = Vector2(-1, -21) + +[node name="Fill7" type="Polygon2D" parent="Pivot/Body_fill/Head_fill/Ear_front_fill"] +show_behind_parent = true +position = Vector2(-5.37235, -8.30081) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +texture = SubResource("GradientTexture2D_c0nxa") +texture_offset = Vector2(2.93116, 3.13485) +polygon = PackedVector2Array(2.82073, 0.00202942, 2.90208, 0.508293, 2.93115, 1.00263, 2.90697, 1.47407, 2.82858, 1.91168, 2.76875, 2.11436, 2.695, 2.30448, 2.60722, 2.48065, 2.50528, 2.64152, 2.38906, 2.78571, 2.25844, 2.91184, 2.11331, 3.01856, 2.03526, 3.06421, 1.95353, 3.10449, 1.93581, 3.11295, 1.91696, 3.12001, 1.89701, 3.12569, 1.87598, 3.13003, 1.83079, 3.13484, 1.78159, 3.13474, 1.7286, 3.13, 1.67201, 3.12093, 1.54889, 3.09093, 0.95401, 2.85518, 0.274572, 2.54524, -0.0638338, 2.4087, -0.383751, 2.30913, -0.982054, 2.00755, -1.31448, 1.78923, -1.65359, 1.51561, -1.98773, 1.17898, -2.30528, 0.771642, -2.59462, 0.285885, -2.84409, -0.285995, -2.90337, -0.601486, -2.93116, -0.893266, -2.92912, -1.1624, -2.8989, -1.40997, -2.84216, -1.63702, -2.76058, -1.84463, -2.65579, -2.03387, -2.52948, -2.20579, -2.38328, -2.36148, -2.21887, -2.502, -2.03791, -2.62841, -1.84205, -2.74177, -1.41228, -2.93366, -0.942841, -3.0862, -0.819604, -3.11409, -0.692594, -3.13019, -0.562225, -3.13485, -0.42891, -3.12847, -0.293062, -3.11142, -0.155096, -3.08407, 0.125538, -3, 0.409683, -2.8793, 0.694032, -2.72498, 0.975274, -2.54007, 1.2501, -2.32759, 1.76728, -1.832, 2.21909, -1.26242, 2.41221, -0.957426, 2.57906, -0.643004, 2.71634, -0.322173) + +[node name="Stroke3" type="Line2D" parent="Pivot/Body_fill/Head_fill/Ear_front_fill"] +show_behind_parent = true +position = Vector2(-5.37235, -8.30081) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(2.82073, 0.00202942, 2.90208, 0.508293, 2.93115, 1.00263, 2.90697, 1.47407, 2.82858, 1.91168, 2.76875, 2.11436, 2.695, 2.30448, 2.60722, 2.48065, 2.50528, 2.64152, 2.38906, 2.78571, 2.25844, 2.91184, 2.11331, 3.01856, 2.03526, 3.06421, 1.95353, 3.10449, 1.93581, 3.11295, 1.91696, 3.12001, 1.89701, 3.12569, 1.87598, 3.13003, 1.83079, 3.13484, 1.78159, 3.13474, 1.7286, 3.13, 1.67201, 3.12093, 1.54889, 3.09093, 0.95401, 2.85518, 0.274572, 2.54524, -0.0638338, 2.4087, -0.383751, 2.30913, -0.982054, 2.00755, -1.31448, 1.78923, -1.65359, 1.51561, -1.98773, 1.17898, -2.30528, 0.771642, -2.59462, 0.285885, -2.84409, -0.285995, -2.90337, -0.601486, -2.93116, -0.893266, -2.92912, -1.1624, -2.8989, -1.40997, -2.84216, -1.63702, -2.76058, -1.84463, -2.65579, -2.03387, -2.52948, -2.20579, -2.38328, -2.36148, -2.21887, -2.502, -2.03791, -2.62841, -1.84205, -2.74177, -1.41228, -2.93366, -0.942841, -3.0862, -0.819604, -3.11409, -0.692594, -3.13019, -0.562225, -3.13485, -0.42891, -3.12847, -0.293062, -3.11142, -0.155096, -3.08407, 0.125538, -3, 0.409683, -2.8793, 0.694032, -2.72498, 0.975274, -2.54007, 1.2501, -2.32759, 1.76728, -1.832, 2.21909, -1.26242, 2.41221, -0.957426, 2.57906, -0.643004, 2.71634, -0.322173) +closed = true +width = 0.293621 +default_color = Color(0.462745, 0.462745, 0.396078, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Line2D2" type="Line2D" parent="Pivot/Body_fill"] +show_behind_parent = true +position = Vector2(-37.6309, 5.64914) +points = PackedVector2Array(-1.28417, -2.88979, -2.58003, -4.09485, -3.76339, -5.47562, -4.83054, -7.01833, -5.77781, -8.70921, -6.6015, -10.5345, -7.29794, -12.4804, -7.86343, -14.5331, -8.29428, -16.679, -8.73735, -21.1948, -8.59765, -25.9177, -7.84568, -30.7375, -6.45195, -35.544, -5.44198, -37.9135, -4.15175, -40.2459, -2.60411, -42.5219, -0.821938, -44.7224, 1.17192, -46.8279, 3.3546, -48.8193, 8.195, -52.3823, 10.807, -53.9154, 13.5164, -55.2572, 16.3003, -56.3884, 19.1359, -57.2897, 22.0003, -57.9418, 24.8706, -58.3255, 27.724, -58.4215, 30.5377, -58.2104, 35.7103, -57.2477, 40.2411, -55.8838, 44.367, -54.1793, 48.3244, -52.1949, 67.2043, -42.6683) +width_curve = SubResource("Curve_jqihn") +default_color = Color(0.403922, 0.2, 0.192157, 1) +metadata/_edit_lock_ = true + +[node name="Line2D" type="Line2D" parent="Pivot/Body_fill"] +show_behind_parent = true +texture_repeat = 2 +position = Vector2(-37.6309, 5.64914) +points = PackedVector2Array(-1.28417, -2.88979, -2.58003, -4.09485, -3.76339, -5.47562, -4.83054, -7.01833, -5.77781, -8.70921, -6.6015, -10.5345, -7.29794, -12.4804, -7.86343, -14.5331, -8.29428, -16.679, -8.73735, -21.1948, -8.59765, -25.9177, -7.84568, -30.7375, -6.45195, -35.544, -5.44198, -37.9135, -4.15175, -40.2459, -2.60411, -42.5219, -0.821938, -44.7224, 1.17192, -46.8279, 3.3546, -48.8193, 8.195, -52.3823, 10.807, -53.9154, 13.5164, -55.2572, 16.3003, -56.3884, 19.1359, -57.2897, 22.0003, -57.9418, 24.8706, -58.3255, 27.724, -58.4215, 30.5377, -58.2104, 35.7103, -57.2477, 40.2411, -55.8838, 44.367, -54.1793, 48.3244, -52.1949, 67.2043, -42.6683) +width = 8.0 +width_curve = SubResource("Curve_bxi6m") +gradient = SubResource("Gradient_d4tj5") +texture_mode = 1 +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 +antialiased = true +metadata/_edit_lock_ = true + +[node name="Tail" type="Node2D" parent="Pivot/Body_fill" node_paths=PackedStringArray("line")] +position = Vector2(-37.6309, 5.64914) +script = ExtResource("18_xsi10") +stroke_width = 8.0 +begin_cap_mode = 2 +end_cap_mode = 2 +line_joint_mode = 2 +line = NodePath("../Line2D") +curve = SubResource("Curve2D_d4tj5") +update_curve_at_runtime = true +arc_list = SubResource("Resource_syjnd") + +[node name="Tail2" type="Node2D" parent="Pivot/Body_fill" node_paths=PackedStringArray("line")] +position = Vector2(-37.6309, 5.64914) +script = ExtResource("18_xsi10") +stroke_color = Color(0.403922, 0.2, 0.192157, 1) +line = NodePath("../Line2D2") +curve = SubResource("Curve2D_d4tj5") +update_curve_at_runtime = true +arc_list = SubResource("Resource_6gv5h") + +[node name="Leg_front_near_stroke" type="Node2D" parent="Pivot/Body_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(10, 11) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_front_near_stroke"] +show_behind_parent = true +position = Vector2(5.66791, 5.56854) +rotation = -0.0964239 +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(4.58061, 2.74669, 2.75771, 3.06064, 1.10918, 3.20543, -0.354013, 3.18673, -1.01268, 3.11785, -1.62089, 3.01023, -2.17728, 2.86458, -2.68047, 2.68162, -3.1291, 2.46205, -3.5218, 2.20659, -3.69674, 2.06562, -3.85718, 1.91594, -4.00295, 1.75764, -4.13388, 1.59082, -4.24979, 1.41555, -4.35052, 1.23193, -4.4359, 1.04005, -4.50574, 0.839996, -4.60819, 0.446953, -4.6715, 0.0755987, -4.69792, -0.274333, -4.68972, -0.603107, -4.64913, -0.910989, -4.57842, -1.19824, -4.47984, -1.46514, -4.35564, -1.71193, -4.20807, -1.9389, -4.03939, -2.14629, -3.85185, -2.33439, -3.6477, -2.50345, -3.4292, -2.65374, -3.1986, -2.78553, -2.95814, -2.89907, -2.7101, -2.99464, -2.20023, -3.13292, -1.68701, -3.20248, -1.18847, -3.20545, -0.950339, -3.18262, -0.722635, -3.14394, -0.507612, -3.08967, -0.307523, -3.02008, -0.124622, -2.93544, 0.0388398, -2.836, 0.112576, -2.78081, 0.180608, -2.72203, 0.242653, -2.65968, 0.29843, -2.5938, 0.347657, -2.52442, 0.390053, -2.45158, 0.425336, -2.3753, 0.453224, -2.29562, 0.694989, -1.61372, 0.989239, -0.996931, 1.32519, -0.441774, 1.69206, 0.0552211, 2.07906, 0.497527, 2.47541, 0.888616, 3.25302, 1.53104, 4.44593, 2.3541, 4.60577, 2.48392, 4.63413, 2.51258, 4.65752, 2.53983, 4.67576, 2.56572, 4.68869, 2.59031, 4.69613, 2.61366, 4.69793, 2.63581, 4.69391, 2.65682, 4.6839, 2.67674, 4.66773, 2.69564, 4.64524, 2.71356, 4.61626, 2.73056) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Leg_front_near_fill" type="Node2D" parent="Pivot/Body_fill"] +light_mask = 2 +position = Vector2(10, 11) + +[node name="Paw_stroke" type="Node2D" parent="Pivot/Body_fill/Leg_front_near_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(22, 15.5) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_front_near_fill/Paw_stroke"] +show_behind_parent = true +position = Vector2(5.82193, 0.986391) +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(-0.968987, 0.921936, -0.989036, 0.895144, -1.01283, 0.870667, -1.04012, 0.848448, -1.07069, 0.828428, -1.10428, 0.810548, -1.14066, 0.79475, -1.22085, 0.769169, -1.30934, 0.751218, -1.40423, 0.74043, -1.60559, 0.73848, -1.8097, 0.759586, -2.00131, 0.800018, -2.08767, 0.826315, -2.1652, 0.856045, -2.23198, 0.88874, -2.26074, 0.906054, -2.28611, 0.923935, -2.30578, 0.904035, -2.32328, 0.881147, -2.33871, 0.85547, -2.35217, 0.827201, -2.36375, 0.79654, -2.37356, 0.763683, -2.38826, 0.692177, -2.40066, 0.531542, -2.39564, 0.357976, -2.32691, -0.21199, -2.14642, -0.387704, -1.86398, -0.620296, -1.69092, -0.732908, -1.50005, -0.829724, -1.39874, -0.869081, -1.29393, -0.900737, -1.18595, -0.923442, -1.07512, -0.935944, -0.781719, -0.751847, -0.495807, -0.599258, -0.218188, -0.475743, 0.0503333, -0.378868, 0.308952, -0.306198, 0.556864, -0.255299, 1.01735, -0.209076, 1.29171, -0.134464, 1.52339, -0.0491247, 1.71923, 0.0428379, 1.88608, 0.137318, 2.28123, 0.394805, 2.40065, 0.458298, 1.99294, 0.547014, 1.82533, 0.593813, 1.69312, 0.64503, 1.64291, 0.67295, 1.62224, 0.687602, 1.60471, 0.702759, 1.59043, 0.718454, 1.58456, 0.726513, 1.57956, 0.734719, 1.57543, 0.743076, 1.57221, 0.751587, 1.5699, 0.760258, 1.56852, 0.769092, 1.56808, 0.778093, 1.56861, 0.787265, 1.57013, 0.796612, 1.57263, 0.806139, 1.57615, 0.815849, 1.58071, 0.825747, 1.59296, 0.846122, 1.60954, 0.867297, 1.63055, 0.889303, 1.68646, 0.935944, 0.598265, 0.708425, 0.191089, 0.670981, -0.141254, 0.673548, -0.411097, 0.707976, -0.630777, 0.766118, -0.812628, 0.839824) +closed = true +width = 0.534647 +default_color = Color(0.403922, 0.2, 0.192157, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Leg_front_near_fill"] +show_behind_parent = true +position = Vector2(5.66791, 5.56854) +scale = Vector2(3.77953, 3.77953) +texture = SubResource("GradientTexture2D_y0lfb") +texture_offset = Vector2(4.69792, 3.20545) +polygon = PackedVector2Array(4.58061, 2.74669, 2.75771, 3.06064, 1.10918, 3.20543, -0.354013, 3.18673, -1.01268, 3.11785, -1.62089, 3.01023, -2.17728, 2.86458, -2.68047, 2.68162, -3.1291, 2.46205, -3.5218, 2.20659, -3.69674, 2.06562, -3.85718, 1.91594, -4.00295, 1.75764, -4.13388, 1.59082, -4.24979, 1.41555, -4.35052, 1.23193, -4.4359, 1.04005, -4.50574, 0.839996, -4.60819, 0.446953, -4.6715, 0.0755987, -4.69792, -0.274333, -4.68972, -0.603107, -4.64913, -0.910989, -4.57842, -1.19824, -4.47984, -1.46514, -4.35564, -1.71193, -4.20807, -1.9389, -4.03939, -2.14629, -3.85185, -2.33439, -3.6477, -2.50345, -3.4292, -2.65374, -3.1986, -2.78553, -2.95814, -2.89907, -2.7101, -2.99464, -2.20023, -3.13292, -1.68701, -3.20248, -1.18847, -3.20545, -0.950339, -3.18262, -0.722635, -3.14394, -0.507612, -3.08967, -0.307523, -3.02008, -0.124622, -2.93544, 0.0388398, -2.836, 0.112576, -2.78081, 0.180608, -2.72203, 0.242653, -2.65968, 0.29843, -2.5938, 0.347657, -2.52442, 0.390053, -2.45158, 0.425336, -2.3753, 0.453224, -2.29562, 0.694989, -1.61372, 0.989239, -0.996931, 1.32519, -0.441774, 1.69206, 0.0552211, 2.07906, 0.497527, 2.47541, 0.888616, 3.25302, 1.53104, 4.44593, 2.3541, 4.60577, 2.48392, 4.63413, 2.51258, 4.65752, 2.53983, 4.67576, 2.56572, 4.68869, 2.59031, 4.69613, 2.61366, 4.69793, 2.63581, 4.69391, 2.65682, 4.6839, 2.67674, 4.66773, 2.69564, 4.64524, 2.71356, 4.61626, 2.73056) + +[node name="Paw_fill" type="Node2D" parent="Pivot/Body_fill/Leg_front_near_fill"] +light_mask = 2 +position = Vector2(22, 15.5) + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Leg_front_near_fill/Paw_fill"] +show_behind_parent = true +position = Vector2(5.82191, 0.986394) +scale = Vector2(3.77953, 3.77953) +color = Color(1, 0.564706, 0.564706, 1) +polygon = PackedVector2Array(-0.968987, 0.921936, -0.989036, 0.895144, -1.01283, 0.870667, -1.04012, 0.848448, -1.07069, 0.828428, -1.10428, 0.810548, -1.14066, 0.79475, -1.22085, 0.769169, -1.30934, 0.751218, -1.40423, 0.74043, -1.60559, 0.73848, -1.8097, 0.759586, -2.00131, 0.800018, -2.08767, 0.826315, -2.1652, 0.856045, -2.23198, 0.88874, -2.26074, 0.906054, -2.28611, 0.923935, -2.30578, 0.904035, -2.32328, 0.881147, -2.33871, 0.85547, -2.35217, 0.827201, -2.36375, 0.79654, -2.37356, 0.763683, -2.38826, 0.692177, -2.40066, 0.531542, -2.39564, 0.357976, -2.32691, -0.21199, -2.14642, -0.387704, -1.86398, -0.620296, -1.69092, -0.732908, -1.50005, -0.829724, -1.39874, -0.869081, -1.29393, -0.900737, -1.18595, -0.923442, -1.07512, -0.935944, -0.781719, -0.751847, -0.495807, -0.599258, -0.218188, -0.475743, 0.0503333, -0.378868, 0.308952, -0.306198, 0.556864, -0.255299, 1.01735, -0.209076, 1.29171, -0.134464, 1.52339, -0.0491247, 1.71923, 0.0428379, 1.88608, 0.137318, 2.28123, 0.394805, 2.40065, 0.458298, 1.99294, 0.547014, 1.82533, 0.593813, 1.69312, 0.64503, 1.64291, 0.67295, 1.62224, 0.687602, 1.60471, 0.702759, 1.59043, 0.718454, 1.58456, 0.726513, 1.57956, 0.734719, 1.57543, 0.743076, 1.57221, 0.751587, 1.5699, 0.760258, 1.56852, 0.769092, 1.56808, 0.778093, 1.56861, 0.787265, 1.57013, 0.796612, 1.57263, 0.806139, 1.57615, 0.815849, 1.58071, 0.825747, 1.59296, 0.846122, 1.60954, 0.867297, 1.63055, 0.889303, 1.68646, 0.935944, 0.598265, 0.708425, 0.191089, 0.670981, -0.141254, 0.673548, -0.411097, 0.707976, -0.630777, 0.766118, -0.812628, 0.839824) + +[node name="RemoteTransform2D" type="RemoteTransform2D" parent="Pivot/Body_fill/Leg_front_near_fill/Paw_fill/Fill"] +remote_path = NodePath("../../../../../../FrontPaws") + +[node name="Leg_back_near_stroke" type="Node2D" parent="Pivot/Body_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(-23, 8) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_back_near_stroke"] +show_behind_parent = true +position = Vector2(8.42217, 7.47536) +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(5.51884, 4.18761, 4.36447, 4.45093, 3.25843, 4.61613, 2.20359, 4.68872, 1.20285, 4.67421, 0.259092, 4.57811, -0.624809, 4.40593, -1.44597, 4.16317, -2.2015, 3.85535, -2.88852, 3.48798, -3.50414, 3.06656, -4.04549, 2.59661, -4.50968, 2.08363, -4.89382, 1.53313, -5.19503, 0.950628, -5.41044, 0.341628, -5.48506, 0.0289128, -5.53715, -0.288361, -5.53879, -0.533307, -5.52075, -0.777644, -5.48392, -1.02069, -5.42921, -1.26175, -5.26975, -1.73522, -5.04959, -2.19257, -4.77597, -2.62836, -4.45612, -3.03709, -4.09725, -3.41332, -3.70661, -3.75157, -3.29141, -4.04637, -2.85889, -4.29226, -2.41627, -4.48377, -1.97078, -4.61543, -1.74921, -4.65711, -1.52964, -4.68178, -1.31297, -4.68875, -1.10009, -4.67734, -0.89192, -4.64688, -0.689354, -4.59666, -0.493299, -4.52602, -0.304657, -4.43427, 0.163514, -4.07558, 0.621738, -3.67012, 1.05179, -3.20193, 1.25056, -2.93931, 1.43546, -2.65503, 1.6042, -2.34709, 1.75451, -2.01348, 1.88411, -1.65222, 1.99072, -1.26131, 2.07207, -0.838758, 2.12587, -0.382566, 2.14175, 0.638718, 2.60231, 1.24994, 3.15488, 1.84811, 5.25538, 3.76193, 5.39938, 3.91135, 5.45386, 3.97599, 5.49558, 4.03355, 5.51141, 4.05959, 5.52375, 4.08377, 5.53249, 4.10603, 5.53755, 4.12636, 5.53881, 4.14471, 5.53618, 4.16106, 5.52955, 4.17536) +closed = true +width = 1.06929 +default_color = Color(0.341176, 0.341176, 0.305882, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Leg_back_near_fill" type="Node2D" parent="Pivot/Body_fill"] +light_mask = 2 +position = Vector2(-23, 8) + +[node name="Fill" type="Polygon2D" parent="Pivot/Body_fill/Leg_back_near_fill"] +show_behind_parent = true +position = Vector2(8.42217, 7.47536) +scale = Vector2(3.77953, 3.77953) +texture = SubResource("GradientTexture2D_3b0nw") +texture_offset = Vector2(5.53879, 4.68875) +polygon = PackedVector2Array(5.51884, 4.18761, 4.36447, 4.45093, 3.25843, 4.61613, 2.20359, 4.68872, 1.20285, 4.67421, 0.259092, 4.57811, -0.624809, 4.40593, -1.44597, 4.16317, -2.2015, 3.85535, -2.88852, 3.48798, -3.50414, 3.06656, -4.04549, 2.59661, -4.50968, 2.08363, -4.89382, 1.53313, -5.19503, 0.950628, -5.41044, 0.341628, -5.48506, 0.0289128, -5.53715, -0.288361, -5.53879, -0.533307, -5.52075, -0.777644, -5.48392, -1.02069, -5.42921, -1.26175, -5.26975, -1.73522, -5.04959, -2.19257, -4.77597, -2.62836, -4.45612, -3.03709, -4.09725, -3.41332, -3.70661, -3.75157, -3.29141, -4.04637, -2.85889, -4.29226, -2.41627, -4.48377, -1.97078, -4.61543, -1.74921, -4.65711, -1.52964, -4.68178, -1.31297, -4.68875, -1.10009, -4.67734, -0.89192, -4.64688, -0.689354, -4.59666, -0.493299, -4.52602, -0.304657, -4.43427, 0.163514, -4.07558, 0.621738, -3.67012, 1.05179, -3.20193, 1.25056, -2.93931, 1.43546, -2.65503, 1.6042, -2.34709, 1.75451, -2.01348, 1.88411, -1.65222, 1.99072, -1.26131, 2.07207, -0.838758, 2.12587, -0.382566, 2.14175, 0.638718, 2.60231, 1.24994, 3.15488, 1.84811, 5.25538, 3.76193, 5.39938, 3.91135, 5.45386, 3.97599, 5.49558, 4.03355, 5.51141, 4.05959, 5.52375, 4.08377, 5.53249, 4.10603, 5.53755, 4.12636, 5.53881, 4.14471, 5.53618, 4.16106, 5.52955, 4.17536) + +[node name="Paw_stroke" type="Node2D" parent="Pivot/Body_fill/Leg_back_near_fill"] +show_behind_parent = true +light_mask = 2 +position = Vector2(25, 22.5) + +[node name="Stroke" type="Line2D" parent="Pivot/Body_fill/Leg_back_near_fill/Paw_stroke"] +show_behind_parent = true +position = Vector2(7.14919, 1.76906) +scale = Vector2(3.77953, 3.77953) +points = PackedVector2Array(-0.879219, 0.814774, -0.902945, 0.791176, -0.930038, 0.770413, -0.960271, 0.752393, -0.993416, 0.737022, -1.02925, 0.724209, -1.06754, 0.713862, -1.15059, 0.700194, -1.24074, 0.695282, -1.33619, 0.698386, -1.5357, 0.725693, -1.73458, 0.776212, -1.91829, 0.844038, -1.99992, 0.882596, -2.0723, 0.923267, -2.13363, 0.965313, -2.15957, 0.986621, -2.18208, 1.008, -2.20442, 0.991163, -2.22506, 0.971059, -2.24405, 0.947895, -2.26147, 0.921881, -2.27739, 0.893227, -2.29187, 0.862144, -2.31679, 0.79353, -2.35238, 0.636398, -2.37261, 0.463944, -2.38738, -0.109955, -2.23432, -0.310011, -1.98864, -0.581144, -1.83377, -0.717688, -1.65898, -0.841189, -1.56446, -0.894838, -1.46536, -0.941376, -1.36182, -0.979518, -1.25397, -1.00798, -0.936955, -0.868429, -0.631919, -0.758965, -0.339309, -0.677063, -0.0595682, -0.620199, 0.206861, -0.585847, 0.459536, -0.571481, 0.921852, -0.592606, 1.20414, -0.558625, 1.44575, -0.507829, 1.65287, -0.445276, 1.83167, -0.376022, 2.26001, -0.178631, 2.38738, -0.133148, 1.99688, 0.013819, 1.83784, 0.0844559, 1.71447, 0.154326, 1.66884, 0.189239, 1.65052, 0.206737, 1.63537, 0.224279, 1.62353, 0.241879, 1.61889, 0.250706, 1.61513, 0.259551, 1.61226, 0.268418, 1.61031, 0.277308, 1.60928, 0.286222, 1.6092, 0.295162, 1.61007, 0.30413, 1.61193, 0.313128, 1.61478, 0.322157, 1.61865, 0.331218, 1.62354, 0.340314, 1.62948, 0.349446, 1.64457, 0.367825, 1.66404, 0.386368, 1.68803, 0.405089, 1.75011, 0.443115, 0.640418, 0.376006, 0.232119, 0.398079, -0.0963285, 0.448873, -0.358314, 0.522115, -0.567225, 0.611531, -0.736448, 0.71085) +closed = true +width = 0.534647 +default_color = Color(0.423529, 0.207843, 0.207843, 1) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Paw_fill" type="Node2D" parent="Pivot/Body_fill/Leg_back_near_fill"] +light_mask = 2 +position = Vector2(26.9855, 22.367) +rotation = 0.080757 + +[node name="Fill2" type="Polygon2D" parent="Pivot/Body_fill/Leg_back_near_fill/Paw_fill"] +show_behind_parent = true +position = Vector2(5.3003, 1.47931) +rotation = -0.080757 +scale = Vector2(3.77953, 3.77953) +color = Color(1, 0.564706, 0.564706, 1) +polygon = PackedVector2Array(-0.879219, 0.814774, -0.902945, 0.791176, -0.930038, 0.770413, -0.960271, 0.752393, -0.993416, 0.737022, -1.02925, 0.724209, -1.06754, 0.713862, -1.15059, 0.700194, -1.24074, 0.695282, -1.33619, 0.698386, -1.5357, 0.725693, -1.73458, 0.776212, -1.91829, 0.844038, -1.99992, 0.882596, -2.0723, 0.923267, -2.13363, 0.965313, -2.15957, 0.986621, -2.18208, 1.008, -2.20442, 0.991163, -2.22506, 0.971059, -2.24405, 0.947895, -2.26147, 0.921881, -2.27739, 0.893227, -2.29187, 0.862144, -2.31679, 0.79353, -2.35238, 0.636398, -2.37261, 0.463944, -2.38738, -0.109955, -2.23432, -0.310011, -1.98864, -0.581144, -1.83377, -0.717688, -1.65898, -0.841189, -1.56446, -0.894838, -1.46536, -0.941376, -1.36182, -0.979518, -1.25397, -1.00798, -0.936955, -0.868429, -0.631919, -0.758965, -0.339309, -0.677063, -0.0595682, -0.620199, 0.206861, -0.585847, 0.459536, -0.571481, 0.921852, -0.592606, 1.20414, -0.558625, 1.44575, -0.507829, 1.65287, -0.445276, 1.83167, -0.376022, 2.26001, -0.178631, 2.38738, -0.133148, 1.99688, 0.013819, 1.83784, 0.0844559, 1.71447, 0.154326, 1.66884, 0.189239, 1.65052, 0.206737, 1.63537, 0.224279, 1.62353, 0.241879, 1.61889, 0.250706, 1.61513, 0.259551, 1.61226, 0.268418, 1.61031, 0.277308, 1.60928, 0.286222, 1.6092, 0.295162, 1.61007, 0.30413, 1.61193, 0.313128, 1.61478, 0.322157, 1.61865, 0.331218, 1.62354, 0.340314, 1.62948, 0.349446, 1.64457, 0.367825, 1.66404, 0.386368, 1.68803, 0.405089, 1.75011, 0.443115, 0.640418, 0.376006, 0.232119, 0.398079, -0.0963285, 0.448873, -0.358314, 0.522115, -0.567225, 0.611531, -0.736448, 0.71085) + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +&"": SubResource("AnimationLibrary_k146a") +} + +[node name="Camera2D2" type="Camera2D" parent="."] + +[node name="Label" type="Label" parent="."] +z_index = 1 +offset_left = 101.0 +offset_top = -39.0 +offset_right = 141.0 +offset_bottom = -16.0 +text = "Right click on block: cut hole" +label_settings = SubResource("LabelSettings_4sn87") + +[node name="Label2" type="Label" parent="."] +z_index = 1 +offset_left = -240.0 +offset_top = -35.0 +offset_right = -63.0 +offset_bottom = -12.0 +text = "Left click: place block" +label_settings = SubResource("LabelSettings_4sn87") + +[node name="Label3" type="Label" parent="."] +z_index = 1 +offset_left = -69.0 +offset_top = -148.0 +offset_right = 120.0 +offset_bottom = -125.0 +text = "Mousewheel: pick shape" +label_settings = SubResource("LabelSettings_4sn87") + +[node name="ShapeHintRectangle" type="Node2D" parent="." node_paths=PackedStringArray("line")] +z_index = 1 +position = Vector2(-8, 104) +script = ExtResource("18_xsi10") +stroke_color = Color(0.382813, 1, 0, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_4sn87") +arc_list = SubResource("Resource_jqihn") +shape_type = 1 +size = Vector2(226, 150) + +[node name="Stroke" type="Line2D" parent="ShapeHintRectangle"] +points = PackedVector2Array(-113, -75, 113, -75, 113, 75, -113, 75) +closed = true +width = 2.0 +default_color = Color(0.382813, 1, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="ShapeHintEllipse" type="Node2D" parent="." node_paths=PackedStringArray("line")] +z_index = 1 +position = Vector2(-8, 104) +script = ExtResource("18_xsi10") +stroke_color = Color(0.382813, 1, 0, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_syjnd") +arc_list = SubResource("Resource_1ynft") +shape_type = 2 +size = Vector2(226, 100) +rx = 113.0 +ry = 50.0 + +[node name="Stroke" type="Line2D" parent="ShapeHintEllipse"] +points = PackedVector2Array(113, 0, 112.853, 2.57306, 112.417, 5.11234, 111.698, 7.61468, 110.704, 10.077, 109.443, 12.496, 107.92, 14.8688, 106.143, 17.192, 104.12, 19.4626, 99.3619, 23.8333, 93.7018, 27.9558, 87.1969, 31.805, 79.9037, 35.3556, 63.1801, 41.461, 43.9854, 46.0709, 22.7739, 48.9842, 0, 50, -22.7739, 48.9842, -43.9854, 46.0709, -63.1801, 41.461, -79.9037, 35.3556, -87.1969, 31.805, -93.7018, 27.9558, -99.3619, 23.8333, -104.12, 19.4626, -106.143, 17.192, -107.92, 14.8688, -109.443, 12.496, -110.704, 10.077, -111.698, 7.61468, -112.417, 5.11234, -112.853, 2.57306, -113, 0, -112.853, -2.57306, -112.417, -5.11234, -111.698, -7.61468, -110.704, -10.077, -109.443, -12.496, -107.92, -14.8688, -106.143, -17.192, -104.12, -19.4626, -99.3619, -23.8333, -93.7018, -27.9558, -87.1969, -31.805, -79.9037, -35.3556, -63.1801, -41.461, -43.9854, -46.0709, -22.7739, -48.9842, 0, -50, 22.7739, -48.9842, 43.9854, -46.0709, 63.1801, -41.461, 79.9037, -35.3556, 87.1969, -31.805, 93.7018, -27.9558, 99.3619, -23.8333, 104.12, -19.4626, 106.143, -17.192, 107.92, -14.8688, 109.443, -12.496, 110.704, -10.077, 111.698, -7.61468, 112.417, -5.11234, 112.853, -2.57306) +closed = true +width = 2.0 +default_color = Color(0.382813, 1, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="TargetArrow" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "poly_stroke", "clip_paths")] +script = ExtResource("18_xsi10") +polygon = NodePath("Polygon2D") +stroke_width = 6.0 +poly_stroke = NodePath("Stroke") +curve = SubResource("Curve2D_6gv5h") +tolerance_degrees = 1.0 +arc_list = SubResource("Resource_lefxx") +clip_paths = [NodePath("CutoutOfTargetArrow")] +offset = Vector2(319.857, -0.14286) + +[node name="Stroke" type="Polygon2D" parent="TargetArrow"] +polygon = PackedVector2Array(256.919, -58.8303, 257.767, -58.6244, 258.561, -58.3419, 259.344, -57.9956, 260.141, -57.5892, 260.965, -57.1239, 261.824, -56.6003, 262.721, -56.0193, 263.658, -55.3823, 264.643, -54.6846, 266.706, -53.1523, 268.93, -51.4167, 271.297, -49.4977, 276.356, -45.2201, 281.776, -40.4476, 288.705, -34.0981, 288.705, -25.9598, 277.766, -35.984, 272.436, -40.6771, 267.471, -44.8758, 265.194, -46.7211, 263.071, -48.3783, 261.746, -49.3622, 262.82, -46.1203, 263.908, -42.4574, 264.867, -38.8268, 265.698, -35.2508, 266.402, -31.7514, 266.978, -28.3501, 267.189, -26.8135, 269.606, -26.4585, 272.277, -25.7976, 274.839, -24.8951, 277.279, -23.7644, 279.581, -22.4186, 281.732, -20.8708, 283.718, -19.134, 285.525, -17.2206, 287.139, -15.1435, 288.546, -12.9153, 288.705, -12.5975, 288.705, 12.5975, 288.546, 12.9153, 287.139, 15.1435, 285.525, 17.2206, 283.718, 19.134, 281.732, 20.8708, 279.581, 22.4186, 277.279, 23.7644, 274.839, 24.8951, 272.277, 25.7976, 269.606, 26.4585, 267.194, 26.8127, 266.953, 28.5613, 266.373, 31.9618, 265.666, 35.4604, 264.831, 39.0355, 263.869, 42.6652, 262.779, 46.3274, 261.728, 49.4946, 263.045, 48.5139, 265.174, 46.8503, 267.453, 45.0022, 272.423, 40.8022, 277.758, 36.1128, 288.705, 26.108, 288.705, 34.2364, 281.763, 40.5808, 276.34, 45.3472, 271.279, 49.6243, 268.91, 51.545, 266.685, 53.2839, 264.621, 54.8215, 263.635, 55.5221, 262.699, 56.1626, 261.802, 56.7474, 260.945, 57.2753, 260.123, 57.7454, 259.329, 58.1569, 258.551, 58.509, 257.766, 58.7989, 256.933, 59.0154, 251.248, 59.6413, 253.934, 53.2129, 254.614, 51.5025, 255.897, 48.0179, 257.055, 44.5266, 258.093, 41.0404, 259.009, 37.5849, 259.802, 34.1839, 260.474, 30.8625, 261.022, 27.6467, 261.45, 24.548, 261.837, 21.1005, 266.259, 20.8857, 268.447, 20.5644, 270.556, 20.0425, 272.576, 19.3311, 274.497, 18.4407, 276.307, 17.3822, 277.996, 16.167, 279.552, 14.806, 280.964, 13.3109, 282.222, 11.693, 283.313, 9.96374, 284.229, 8.13384, 284.96, 6.21391, 285.494, 4.21291, 285.823, 2.13936, 285.935, 0, 285.823, -2.13944, 285.494, -4.21284, 284.96, -6.21384, 284.229, -8.1339, 283.313, -9.96374, 282.222, -11.693, 280.964, -13.3109, 279.552, -14.806, 277.996, -16.167, 276.307, -17.3822, 274.497, -18.4407, 272.576, -19.331, 270.556, -20.0425, 268.447, -20.5644, 266.259, -20.8857, 261.831, -21.1008, 261.471, -24.3428, 261.047, -27.4418, 260.502, -30.6586, 259.834, -33.9799, 259.043, -37.3808, 258.13, -40.837, 257.095, -44.3225, 255.939, -47.8142, 254.657, -51.2985, 253.978, -53.0078, 251.34, -59.321, 293.059, -30.1076, 324.319, 0.132103, 293.051, 30.2645, 288.705, 34.2364, 288.705, 26.108, 288.944, 25.889, 315.681, 0.123817, 288.946, -25.7388, 288.705, -25.9598, 288.705, -34.0981, 289.73, -10.5494, 290.677, -8.05956, 291.371, -5.46059, 291.798, -2.76822, 291.944, 0, 291.798, 2.76824, 291.371, 5.46057, 290.677, 8.05954, 289.73, 10.5494, 288.705, 12.5975, 288.705, -12.5975, 166.652, -17.4556, 172.585, -16.2374, 178.544, -15.1804, 184.543, -14.2729, 190.594, -13.5037, 196.709, -12.8612, 199.792, -12.5988, 199.792, -6.57713, 196.142, -6.88789, 189.902, -7.54335, 183.716, -8.32978, 177.571, -9.25925, 171.457, -10.3438, 165.362, -11.5953, 163.005, -12.1494, 162.995, 12.2799, 165.354, 11.7275, 171.449, 10.4809, 177.564, 9.4013, 183.71, 8.47675, 189.897, 7.69526, 196.137, 7.04478, 199.792, 6.73654, 199.792, 12.7578, 196.7, 13.0186, 190.584, 13.6561, 184.532, 14.4205, 178.532, 15.3232, 172.572, 16.3754, 166.639, 17.5889, 156.993, 19.8481, 157.007, -19.7226, 202.901, -12.3342, 209.172, -11.9118, 222.057, -11.3316, 235.419, -11.0307, 244.855, -10.9857, 243.04, -6.2138, 242.506, -4.21291, 242.177, -2.13942, 242.065, 0, 242.177, 2.13942, 242.506, 4.21291, 243.04, 6.21385, 244.93, 11.1812, 235.41, 11.219, 222.049, 11.5092, 209.163, 12.0792, 202.892, 12.4965, 199.792, 12.7578, 199.792, 6.73654, 202.441, 6.51326, 208.831, 6.088, 221.851, 5.51208, 235.333, 5.21925, 236.59, 5.21426, 236.202, 2.76823, 236.056, 0, 236.202, -2.76823, 236.56, -5.02521, 235.337, -5.03104, 221.855, -5.33463, 208.835, -5.92095, 202.445, -6.35133, 199.792, -6.57713, 199.792, -12.5988) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136], [137, 138, 139, 140, 141, 142, 143, 144, 145, 146], [147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157], [158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189], [190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223]] +metadata/_edit_lock_ = true + +[node name="Polygon2D" type="Polygon2D" parent="TargetArrow"] +color = Color(0, 1, 0.15625, 1) +polygon = PackedVector2Array(256.431, -55.8616, 256.907, -55.7459, 257.45, -55.5529, 258.055, -55.2853, 258.721, -54.9456, 259.446, -54.5363, 260.227, -54.0602, 261.062, -53.5196, 261.947, -52.9173, 262.882, -52.2558, 264.889, -50.7653, 267.062, -49.0688, 269.384, -47.1868, 274.396, -42.9488, 279.771, -38.2158, 291.003, -27.9232, 320, 0.12796, 290.997, 28.0768, 279.76, 38.3468, 274.382, 43.0747, 269.366, 47.3132, 267.042, 49.1978, 264.865, 50.8988, 262.856, 52.3956, 261.92, 53.0611, 261.032, 53.6679, 260.196, 54.2134, 259.414, 54.6951, 258.687, 55.1105, 258.019, 55.4569, 257.412, 55.7319, 256.867, 55.9328, 256.389, 56.0572, 255.978, 56.1024, 256.712, 54.3451, 257.416, 52.5751, 258.729, 49.0088, 259.917, 45.4269, 260.981, 41.8529, 261.92, 38.3102, 262.734, 34.8221, 263.423, 31.4123, 263.987, 28.104, 264.427, 24.9207, 264.533, 23.9731, 266.55, 23.8751, 269.026, 23.5114, 271.416, 22.9201, 273.708, 22.1131, 275.888, 21.1025, 277.944, 19.9004, 279.864, 18.5189, 281.635, 16.97, 283.245, 15.2657, 284.68, 13.4182, 285.929, 11.4395, 286.98, 9.34165, 287.818, 7.1367, 288.433, 4.83674, 288.811, 2.45382, 288.939, 0, 288.811, -2.45382, 288.433, -4.83674, 287.818, -7.1367, 286.98, -9.34165, 285.929, -11.4395, 284.68, -13.4182, 283.245, -15.2657, 281.635, -16.97, 279.864, -18.5189, 277.944, -19.9004, 275.888, -21.1025, 273.708, -22.1131, 271.416, -22.9201, 269.026, -23.5114, 266.55, -23.8751, 264.53, -23.9732, 264.448, -24.7121, 264.013, -27.896, 263.452, -31.2049, 262.766, -34.6153, 261.955, -38.1039, 261.019, -41.6471, 259.958, -45.2215, 258.771, -48.8037, 257.459, -52.3702, 256.756, -54.1403, 256.022, -55.8976, 166.007, -14.5254, 172.021, -13.2906, 178.057, -12.2198, 184.129, -11.3014, 190.248, -10.5235, 196.426, -9.87457, 202.673, -9.34277, 209.003, -8.91641, 221.956, -8.33311, 235.378, -8.03088, 240.513, -8.0064, 240.182, -7.1367, 239.567, -4.83674, 239.189, -2.45382, 239.061, 0, 239.189, 2.45382, 239.567, 4.83674, 240.182, 7.1367, 240.586, 8.19844, 235.372, 8.21912, 221.95, 8.51064, 208.997, 9.08359, 202.666, 9.50488, 196.418, 10.0317, 190.24, 10.6757, 184.121, 11.4486, 178.048, 12.3622, 172.011, 13.4282, 165.997, 14.6582, 159.994, 16.064, 160.006, -15.936) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87], [88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118]] +metadata/_edit_lock_ = true + +[node name="CutoutOfTargetArrow" type="Node2D" parent="TargetArrow" node_paths=PackedStringArray("polygon", "line")] +position = Vector2(264, 0) +script = ExtResource("18_xsi10") +polygon = NodePath("Polygon2D") +stroke_width = 6.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_ekw72") +arc_list = SubResource("Resource_vryrk") +shape_type = 2 +size = Vector2(49.8789, 47.998) +rx = 24.9395 +ry = 23.999 + +[node name="Polygon2D" type="Polygon2D" parent="TargetArrow/CutoutOfTargetArrow"] +color = Color(0.0166667, 1, 0, 0.4) +polygon = PackedVector2Array(24.9394, 0, 24.8107, 2.45382, 24.4328, 4.83674, 23.8183, 7.1367, 22.9796, 9.34165, 21.9295, 11.4395, 20.6803, 13.4182, 19.2446, 15.2657, 17.635, 16.97, 15.864, 18.5189, 13.9441, 19.9004, 11.8878, 21.1025, 9.70772, 22.1131, 7.41637, 22.9201, 5.02628, 23.5114, 2.54998, 23.8751, 0, 23.999, -2.54998, 23.8751, -5.02628, 23.5114, -7.41637, 22.9201, -9.70772, 22.1131, -11.8878, 21.1025, -13.9441, 19.9004, -15.864, 18.5189, -17.635, 16.97, -19.2446, 15.2657, -20.6803, 13.4182, -21.9295, 11.4395, -22.9796, 9.34165, -23.8183, 7.1367, -24.4328, 4.83674, -24.8107, 2.45382, -24.9394, 0, -24.8107, -2.45382, -24.4328, -4.83674, -23.8183, -7.1367, -22.9796, -9.34165, -21.9295, -11.4395, -20.6803, -13.4182, -19.2446, -15.2657, -17.635, -16.97, -15.864, -18.5189, -13.9441, -19.9004, -11.8878, -21.1025, -9.70772, -22.1131, -7.41637, -22.9201, -5.02628, -23.5114, -2.54998, -23.8751, 0, -23.999, 2.54998, -23.8751, 5.02628, -23.5114, 7.41637, -22.9201, 9.70772, -22.1131, 11.8878, -21.1025, 13.9441, -19.9004, 15.864, -18.5189, 17.635, -16.97, 19.2446, -15.2657, 20.6803, -13.4182, 21.9295, -11.4395, 22.9796, -9.34165, 23.8183, -7.1367, 24.4328, -4.83674, 24.8107, -2.45382) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="TargetArrow/CutoutOfTargetArrow"] +points = PackedVector2Array(24.9394, 0, 24.8107, 2.45382, 24.4328, 4.83674, 23.8183, 7.1367, 22.9796, 9.34165, 21.9295, 11.4395, 20.6803, 13.4182, 19.2446, 15.2657, 17.635, 16.97, 15.864, 18.5189, 13.9441, 19.9004, 11.8878, 21.1025, 9.70772, 22.1131, 7.41637, 22.9201, 5.02628, 23.5114, 2.54998, 23.8751, 0, 23.999, -2.54998, 23.8751, -5.02628, 23.5114, -7.41637, 22.9201, -9.70772, 22.1131, -11.8878, 21.1025, -13.9441, 19.9004, -15.864, 18.5189, -17.635, 16.97, -19.2446, 15.2657, -20.6803, 13.4182, -21.9295, 11.4395, -22.9796, 9.34165, -23.8183, 7.1367, -24.4328, 4.83674, -24.8107, 2.45382, -24.9394, 0, -24.8107, -2.45382, -24.4328, -4.83674, -23.8183, -7.1367, -22.9796, -9.34165, -21.9295, -11.4395, -20.6803, -13.4182, -19.2446, -15.2657, -17.635, -16.97, -15.864, -18.5189, -13.9441, -19.9004, -11.8878, -21.1025, -9.70772, -22.1131, -7.41637, -22.9201, -5.02628, -23.5114, -2.54998, -23.8751, 0, -23.999, 2.54998, -23.8751, 5.02628, -23.5114, 7.41637, -22.9201, 9.70772, -22.1131, 11.8878, -21.1025, 13.9441, -19.9004, 15.864, -18.5189, 17.635, -16.97, 19.2446, -15.2657, 20.6803, -13.4182, 21.9295, -11.4395, 22.9796, -9.34165, 23.8183, -7.1367, 24.4328, -4.83674, 24.8107, -2.45382) +closed = true +width = 6.0 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="TheCheese" parent="TargetArrow/CutoutOfTargetArrow" instance=ExtResource("5_jqihn")] +rotation = 0.0463905 +scale = Vector2(0.333096, 0.333096) + +[node name="Heart" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "poly_stroke")] +modulate = Color(1, 1, 1, 0) +position = Vector2(61, -48) +rotation = 0.372315 +script = ExtResource("18_xsi10") +polygon = NodePath("Fill") +stroke_width = 2.0 +poly_stroke = NodePath("Stroke") +curve = SubResource("Curve2D_1ynft") +arc_list = SubResource("Resource_6j8tw") + +[node name="Stroke" type="Polygon2D" parent="Heart"] +polygon = PackedVector2Array(-6.7439, -17.4535, -6.14988, -17.4106, -5.56032, -17.3263, -4.97805, -17.2012, -4.40594, -17.0357, -3.84676, -16.8308, -3.30326, -16.5873, -2.77805, -16.3065, -2.27369, -15.9898, -1.79268, -15.6386, -1.33734, -15.2547, -0.909866, -14.8401, -0.512383, -14.3966, -0.146782, -13.9264, 0.18512, -13.4319, 0.469231, -12.9372, 0.470787, -12.9404, 0.470787, -7.94405, -0.49498, -7.94484, -0.544609, -9.36649, -0.591362, -9.82121, -0.669502, -10.2703, -0.77874, -10.7128, -0.918671, -11.1468, -1.08846, -11.5698, -1.28737, -11.98, -1.51443, -12.3753, -1.76845, -12.7538, -2.0483, -13.1137, -2.35263, -13.4532, -2.67978, -13.7706, -3.02833, -14.0644, -3.39663, -14.3333, -3.78255, -14.5757, -4.18454, -14.7906, -4.60073, -14.977, -5.02867, -15.1339, -5.46665, -15.2605, -5.91223, -15.3563, -6.36365, -15.4208, -6.81822, -15.4536, -7.27421, -15.4547, -7.72901, -15.4239, -8.18046, -15.3615, -8.62675, -15.2677, -9.06519, -15.1431, -9.49396, -14.9881, -9.91084, -14.8036, -10.3137, -14.5906, -10.701, -14.3498, -11.0704, -14.0827, -11.4202, -13.7905, -11.7489, -13.4745, -12.0547, -13.1365, -12.3362, -12.7779, -12.5919, -12.4006, -12.8208, -12.0062, -13.0216, -11.5969, -13.1933, -11.1748, -13.3352, -10.7415, -13.4465, -10.2993, -13.5266, -9.85066, -13.5753, -9.39734, -13.5918, -8.95512, -13.5545, -8.3275, -13.4438, -7.65302, -13.2597, -6.92502, -13.0089, -6.16313, -12.2988, -4.49165, -11.3748, -2.74068, -9.00594, 0.94265, -6.28711, 4.54367, 0.470741, 12.1463, 0.470787, 12.1462, 0.470787, 15.1566, 0.470741, 15.1567, -7.83506, 5.81263, -10.6474, 2.08776, -13.1036, -1.73127, -14.1067, -3.63237, -14.8824, -5.45823, -15.1814, -6.36645, -15.4036, -7.24514, -15.5449, -8.10565, -15.594, -8.93297, -15.5714, -9.54149, -15.5078, -10.1336, -15.403, -10.7199, -15.2576, -11.2974, -15.0723, -11.8634, -14.8479, -12.4151, -14.5856, -12.9498, -14.2867, -13.4649, -13.9525, -13.9579, -13.5848, -14.4263, -13.1853, -14.868, -12.756, -15.2807, -12.2989, -15.6625, -11.8163, -16.0115, -11.3105, -16.3259, -10.784, -16.6043, -10.2394, -16.8453, -9.67926, -17.0477, -9.10642, -17.2106, -8.5236, -17.3331, -7.93364, -17.4146, -7.33944, -17.4548, 8.31423, -17.4585, 8.90827, -17.4161, 9.4979, -17.3322, 10.0802, -17.2074, 10.6525, -17.0423, 11.2118, -16.8377, 11.7554, -16.5946, 12.2808, -16.3141, 12.7854, -15.9977, 13.2666, -15.6469, 13.7222, -15.2633, 14.1499, -14.8489, 14.5477, -14.4057, 14.9136, -13.9358, 15.2458, -13.4415, 15.5428, -12.9253, 15.803, -12.3896, 16.0252, -11.837, 16.2083, -11.2703, 16.3514, -10.6922, 16.4539, -10.1055, 16.5151, -9.51394, 16.5354, -8.93184, 16.4864, -8.10565, 16.3451, -7.24514, 16.1229, -6.36645, 15.8239, -5.45823, 15.0482, -3.63237, 14.045, -1.73127, 11.5889, 2.08776, 8.77655, 5.81263, 0.470787, 15.1566, 0.470787, 12.1462, 7.2286, 4.54367, 9.94743, 0.94265, 12.3164, -2.74076, 13.2402, -4.49156, 13.9504, -6.16313, 14.2012, -6.92502, 14.3853, -7.65302, 14.496, -8.3275, 14.5334, -8.95628, 14.5187, -9.37597, 14.4717, -9.83019, 14.3933, -10.2793, 14.2837, -10.7218, 14.1435, -11.1556, 13.9734, -11.5787, 13.7743, -11.9886, 13.547, -12.3838, 13.2928, -12.762, 13.0125, -13.1219, 12.7081, -13.4611, 12.3808, -13.7782, 12.0319, -14.072, 11.6636, -14.3405, 11.2773, -14.5827, 10.8752, -14.7973, 10.4591, -14.9835, 10.031, -15.1401, 9.59293, -15.2664, 9.14717, -15.3619, 8.69581, -15.4261, 8.24115, -15.4587, 7.78529, -15.4594, 7.33036, -15.4283, 6.87898, -15.3657, 6.43287, -15.2716, 5.99437, -15.1466, 5.5657, -14.9914, 5.14904, -14.8067, 4.7462, -14.5933, 4.35912, -14.3523, 3.98989, -14.085, 3.64023, -13.7926, 3.3118, -13.4764, 3.0062, -13.1381, 2.72495, -12.7794, 2.46944, -12.4019, 2.24081, -12.0073, 2.04032, -11.598, 1.86886, -11.1756, 1.72728, -10.7423, 1.61627, -10.3001, 1.5364, -9.85136, 1.48799, -9.39794, 1.43483, -7.94328, 0.470787, -7.94405, 0.470787, -12.9404, 0.475403, -12.9498, 0.77401, -13.4651, 1.10785, -13.9583, 1.47528, -14.427, 1.87449, -14.8689, 2.30358, -15.2819, 2.76043, -15.664, 3.2428, -16.0133, 3.74838, -16.3281, 4.27468, -16.6068, 4.81915, -16.8481, 5.37911, -17.0509, 5.95186, -17.2141, 6.53461, -17.337, 7.12449, -17.419, 7.71868, -17.4595) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106], [107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211]] +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Heart"] +color = Color(1, 0, 0, 1) +polygon = PackedVector2Array(0.47074, 13.6515, -7.06108, 5.17816, -9.82667, 1.51521, -12.2392, -2.23601, -13.2027, -4.06197, -13.9456, -5.8107, -14.2205, -6.64575, -14.4237, -7.44909, -14.5497, -8.21657, -14.5929, -8.94406, -14.5734, -9.46941, -14.5172, -9.99212, -14.4247, -10.5096, -14.2964, -11.0194, -14.1328, -11.5191, -13.9348, -12.006, -13.7032, -12.478, -13.4393, -12.9327, -13.1444, -13.3679, -12.8198, -13.7814, -12.4671, -14.1713, -12.0881, -14.5356, -11.6846, -14.8726, -11.2586, -15.1807, -10.8121, -15.4582, -10.3474, -15.704, -9.86665, -15.9167, -9.37223, -16.0954, -8.86656, -16.2392, -8.35208, -16.3473, -7.83132, -16.4193, -7.3068, -16.4547, -6.78109, -16.4535, -6.25674, -16.4157, -5.73631, -16.3413, -5.22233, -16.2309, -4.71731, -16.0848, -4.22371, -15.9039, -3.74394, -15.689, -3.28032, -15.4411, -2.83512, -15.1615, -2.41052, -14.8515, -2.00857, -14.5127, -1.63123, -14.1466, -1.28035, -13.7551, -0.957631, -13.3401, -0.664648, -12.9036, -0.402827, -12.4478, -0.173446, -11.9747, 0.0223805, -11.4868, 0.183697, -10.9865, 0.309717, -10.4761, 0.399828, -9.95816, 0.453589, -9.4352, 0.47074, -8.94406, 0.489943, -9.46943, 0.545746, -9.99217, 0.637878, -10.5097, 0.765891, -11.0196, 0.929159, -11.5194, 1.12689, -12.0065, 1.35812, -12.4786, 1.62171, -12.9335, 1.9164, -13.3688, 2.24074, -13.7826, 2.59314, -14.1727, 2.9719, -14.5372, 3.37518, -14.8745, 3.80099, -15.1828, 4.24727, -15.4607, 4.71185, -15.7067, 5.19247, -15.9198, 5.68677, -16.0988, 6.19235, -16.2429, 6.70676, -16.3513, 7.22747, -16.4237, 7.75197, -16.4595, 8.27768, -16.4586, 8.80206, -16.4211, 9.32253, -16.3471, 9.83658, -16.2369, 10.3417, -16.0912, 10.8354, -15.9106, 11.3153, -15.696, 11.7791, -15.4484, 12.2245, -15.1691, 12.6493, -14.8594, 13.0515, -14.5208, 13.429, -14.155, 13.7802, -13.7638, 14.1032, -13.349, 14.3964, -12.9127, 14.6585, -12.457, 14.8882, -11.9841, 15.0844, -11.4963, 15.246, -10.9961, 15.3724, -10.4858, 15.4628, -9.96788, 15.5169, -9.44496, 15.5344, -8.94406, 15.4912, -8.21657, 15.3652, -7.44909, 15.162, -6.64575, 14.8871, -5.8107, 14.1442, -4.06197, 13.1807, -2.23601, 10.7682, 1.51521, 8.00257, 5.17816) +metadata/_edit_lock_ = true + +[connection signal="body_entered" from="Pivot/Body_fill/Head_fill/Fill/WallDetector" to="." method="_on_wall_detector_body_entered"] +[connection signal="animation_finished" from="AnimationPlayer" to="." method="_on_animation_player_animation_finished"] diff --git a/addons/curved_lines_2d/examples/rat/rats_return.gd b/addons/curved_lines_2d/examples/rat/rats_return.gd new file mode 100644 index 0000000..e654d62 --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/rats_return.gd @@ -0,0 +1,64 @@ +extends Node2D + +var collision_polygon_map : Dictionary[ScalableVectorShape2D, Array] = {} +var TheFinishScene : PackedScene = preload("res://addons/curved_lines_2d/examples/rat/the_finish.tscn") + +func _ready() -> void: + _set_finish() + $Rat.has_won.connect(_set_finish) + + +func _set_finish() -> void: + var cheese_spawns := $CheeseSpawns.get_children() + var finish = TheFinishScene.instantiate() + cheese_spawns[randi() % cheese_spawns.size()].add_child(finish) + $Rat.finish = finish + +func _on_drop_zone_body_entered(body: Node2D) -> void: + if 'die' in body: + body.die() + + +func _on_rat_place_shape(global_pos: Vector2, curve: Curve2D) -> void: + var new_shape = ScalableVectorShape2D.new() + new_shape.update_curve_at_runtime = true + new_shape.curve = curve + new_shape.position = global_pos + new_shape.polygon = Polygon2D.new() + new_shape.polygon.color = Color(0.402, 0.207, 0.0) + new_shape.polygon.texture = NoiseTexture2D.new() + (new_shape.polygon.texture as NoiseTexture2D).noise = FastNoiseLite.new() + (new_shape.polygon.texture as NoiseTexture2D).seamless = true + new_shape.texture_repeat = CanvasItem.TEXTURE_REPEAT_ENABLED + new_shape.add_to_group("blocks") + new_shape.add_child(new_shape.polygon) + new_shape.polygons_updated.connect(_add_collision_polygons) + add_child(new_shape) + + +func _on_rat_cut_shapes(global_pos: Vector2, curve: Curve2D) -> void: + var new_shape = ScalableVectorShape2D.new() + new_shape.update_curve_at_runtime = true + new_shape.curve = curve + new_shape.position = global_pos + add_child(new_shape) + for block in get_tree().get_nodes_in_group("blocks"): + if Rect2(new_shape.position, new_shape.get_bounding_rect().size).intersects( + Rect2(block.position, block.get_bounding_rect().size), true + ): + (block as ScalableVectorShape2D).add_clip_path(new_shape) + + +func _add_collision_polygons(polygons : Array[PackedVector2Array], _poly_strokes : Array[PackedVector2Array], svs : ScalableVectorShape2D): + if svs in collision_polygon_map: + for old_poly : Node in collision_polygon_map.get(svs): + old_poly.queue_free() + collision_polygon_map.get(svs).clear() + else: + collision_polygon_map[svs] = [] + for poly in polygons: + var col_poly := CollisionPolygon2D.new() + col_poly.transform = svs.transform + col_poly.polygon = poly + collision_polygon_map[svs].append(col_poly) + %BlockStaticBody2D.add_child(col_poly) diff --git a/addons/curved_lines_2d/examples/rat/rats_return.gd.uid b/addons/curved_lines_2d/examples/rat/rats_return.gd.uid new file mode 100644 index 0000000..454c4dd --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/rats_return.gd.uid @@ -0,0 +1 @@ +uid://beqwfvhl5f07k diff --git a/addons/curved_lines_2d/examples/rat/rats_return.tscn b/addons/curved_lines_2d/examples/rat/rats_return.tscn new file mode 100644 index 0000000..219cc75 --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/rats_return.tscn @@ -0,0 +1,451 @@ +[gd_scene load_steps=32 format=3 uid="uid://buueak60wkgnf"] + +[ext_resource type="Script" uid="uid://beqwfvhl5f07k" path="res://addons/curved_lines_2d/examples/rat/rats_return.gd" id="1_lur87"] +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="1_qkos6"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="2_lur87"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="3_5jqi6"] +[ext_resource type="PackedScene" uid="uid://kbkwi2nx8ith" path="res://addons/curved_lines_2d/examples/rat/rat.tscn" id="4_w2l5p"] + +[sub_resource type="Gradient" id="Gradient_hj7rf"] +offsets = PackedFloat32Array(0, 0.748969, 0.879489, 0.897081) +colors = PackedColorArray(0.460938, 0.772583, 1, 1, 0.741276, 0.809593, 0.918743, 1, 1, 0.84375, 0.84375, 1, 0, 0, 0, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_ty8b6"] +gradient = SubResource("Gradient_hj7rf") +width = 1487 +height = 1165 +fill_from = Vector2(0.50686, 0.0238519) +fill_to = Vector2(0.51217, 0.981153) + +[sub_resource type="Curve2D" id="Curve2D_lur87"] +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 20.1859, -18.275, 0, 0, 0, 0, -1.25378, -25.1621, 0, 0, 0, 0, -7.76143, -26.8937, 0, 0, 0, 0, -18.1859, -21.571, 0, 0, 0, 0, -22.2008, -22.2011, 0, 0, 0, 0, -34.6552, -10.4688, 0, 0, 0, 0, -26.6916, 0.443052, 0, 0, 0, 0, -26.713, 0.72216, 0, 0, 0, 0, -16.9296, 12.1506, 0, 0, 0, 0, -16.9664, 12.6348, 0, 0, 0, 0, -4.51253, 24.367, 0, 0, 0, 0, 3.18721, 21.8227, 0, 0, 0, 0, 13.8984, 27.6159, 0, 0, 0, 0, 26.3522, 15.8836, 0, 0, 0, 0, 25.8708, 12.6639, 0, 0, 0, 0, 29.6017, 4.33186, 0, 0, 0, 0, 29.277, 1.68612, 0, 0, 0, 0, 34.6552, -7.94157, 0, 0, 0, 0, 20.1859, -18.275, 0, 0, 0, 0, 20.1859, -18.275) +} +point_count = 20 + +[sub_resource type="Resource" id="Resource_q0tfb"] +script = ExtResource("2_lur87") +start_point = 0 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_m08lf"] +script = ExtResource("2_lur87") +start_point = 1 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_h7xxh"] +script = ExtResource("2_lur87") +start_point = 2 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_2y863"] +script = ExtResource("2_lur87") +start_point = 3 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_el6ml"] +script = ExtResource("2_lur87") +start_point = 4 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_pfoxu"] +script = ExtResource("2_lur87") +start_point = 5 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_3ghir"] +script = ExtResource("2_lur87") +start_point = 6 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_xvmfk"] +script = ExtResource("2_lur87") +start_point = 7 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_t7p2c"] +script = ExtResource("2_lur87") +start_point = 8 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_upm0f"] +script = ExtResource("2_lur87") +start_point = 9 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_jnmgg"] +script = ExtResource("2_lur87") +start_point = 10 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_0ig0s"] +script = ExtResource("2_lur87") +start_point = 11 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_gou68"] +script = ExtResource("2_lur87") +start_point = 12 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_42033"] +script = ExtResource("2_lur87") +start_point = 13 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_h1yoj"] +script = ExtResource("2_lur87") +start_point = 14 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_8u3ec"] +script = ExtResource("2_lur87") +start_point = 15 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_50naw"] +script = ExtResource("2_lur87") +start_point = 16 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_a83h2"] +script = ExtResource("2_lur87") +start_point = 17 +radius = Vector2(11.7371, 11.0567) +rotation_deg = 0.0 +sweep_flag = false +large_arc_flag = false + +[sub_resource type="Resource" id="Resource_5jqi6"] +script = ExtResource("3_5jqi6") +arcs = Array[ExtResource("2_lur87")]([SubResource("Resource_q0tfb"), SubResource("Resource_m08lf"), SubResource("Resource_h7xxh"), SubResource("Resource_2y863"), SubResource("Resource_el6ml"), SubResource("Resource_pfoxu"), SubResource("Resource_3ghir"), SubResource("Resource_xvmfk"), SubResource("Resource_t7p2c"), SubResource("Resource_upm0f"), SubResource("Resource_jnmgg"), SubResource("Resource_0ig0s"), SubResource("Resource_gou68"), SubResource("Resource_42033"), SubResource("Resource_h1yoj"), SubResource("Resource_8u3ec"), SubResource("Resource_50naw"), SubResource("Resource_a83h2")]) + +[sub_resource type="Gradient" id="Gradient_nwkfo"] +offsets = PackedFloat32Array(0, 0.308626, 1) +colors = PackedColorArray(1, 1, 1, 1, 0.988493, 0.967342, 0.967342, 0.928441, 1, 0.863281, 0.863281, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_w2l5p"] +gradient = SubResource("Gradient_nwkfo") +width = 69 +height = 57 +fill_from = Vector2(0.482854, 0.914123) +fill_to = Vector2(0.633236, -0.0185821) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_qkos6"] + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_lur87"] +width = 1024 +height = 1024 +seamless = true +noise = SubResource("FastNoiseLite_qkos6") + +[node name="RatsReturn" type="Node2D"] +script = ExtResource("1_lur87") + +[node name="Sky" type="Polygon2D" parent="."] +scale = Vector2(10, 5) +texture = SubResource("GradientTexture2D_ty8b6") +texture_offset = Vector2(743.648, 582.559) +polygon = PackedVector2Array(-743.648, -582.559, 743.648, -582.559, 743.648, 582.559, -743.648, 582.559) +metadata/_edit_lock_ = true + +[node name="Clouds" type="Node2D" parent="."] + +[node name="CloudPath" type="Node2D" parent="Clouds" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(-3441, -926) +rotation = 3.0175 +scale = Vector2(5.95586, 5.95586) +script = ExtResource("1_qkos6") +polygon = NodePath("Fill") +stroke_color = Color(0.441, 0.53235, 0.63, 1) +stroke_width = 2.64583 +line = NodePath("Stroke") +curve = SubResource("Curve2D_lur87") +update_curve_at_runtime = true +tolerance_degrees = 15.0 +arc_list = SubResource("Resource_5jqi6") +clip_paths = [null] + +[node name="Stroke" type="Line2D" parent="Clouds/CloudPath"] +self_modulate = Color(1, 1, 1, 0.818878) +points = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +closed = true +width = 2.64583 +default_color = Color(0.441, 0.53235, 0.63, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Clouds/CloudPath"] +texture = SubResource("GradientTexture2D_w2l5p") +texture_offset = Vector2(34.6552, 30.0076) +polygon = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143]] +metadata/_edit_lock_ = true + +[node name="CloudPath3" type="Node2D" parent="Clouds" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(-1882, -1773) +rotation = -2.85821 +scale = Vector2(5.95586, 5.95586) +script = ExtResource("1_qkos6") +polygon = NodePath("Fill") +stroke_color = Color(0.441, 0.53235, 0.63, 1) +stroke_width = 2.64583 +line = NodePath("Stroke") +curve = SubResource("Curve2D_lur87") +update_curve_at_runtime = true +tolerance_degrees = 15.0 +arc_list = SubResource("Resource_5jqi6") +clip_paths = [null] + +[node name="Stroke" type="Line2D" parent="Clouds/CloudPath3"] +self_modulate = Color(1, 1, 1, 0.818878) +points = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +closed = true +width = 2.64583 +default_color = Color(0.441, 0.53235, 0.63, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Clouds/CloudPath3"] +texture = SubResource("GradientTexture2D_w2l5p") +texture_offset = Vector2(34.6552, 30.0076) +polygon = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143]] +metadata/_edit_lock_ = true + +[node name="CloudPath2" type="Node2D" parent="Clouds" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(421, -2361) +rotation = -2.89401 +scale = Vector2(4.58401, 4.58401) +script = ExtResource("1_qkos6") +polygon = NodePath("Fill") +stroke_color = Color(0.441, 0.53235, 0.63, 1) +stroke_width = 2.64583 +line = NodePath("Stroke") +curve = SubResource("Curve2D_lur87") +update_curve_at_runtime = true +tolerance_degrees = 15.0 +arc_list = SubResource("Resource_5jqi6") +clip_paths = [null] + +[node name="Stroke" type="Line2D" parent="Clouds/CloudPath2"] +self_modulate = Color(1, 1, 1, 0.818878) +points = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +closed = true +width = 2.64583 +default_color = Color(0.441, 0.53235, 0.63, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Clouds/CloudPath2"] +texture = SubResource("GradientTexture2D_w2l5p") +texture_offset = Vector2(34.6552, 30.0076) +polygon = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143]] +metadata/_edit_lock_ = true + +[node name="CloudPath4" type="Node2D" parent="Clouds" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(2500, -1680) +rotation = -2.82285 +scale = Vector2(7.39665, 6.7391) +script = ExtResource("1_qkos6") +polygon = NodePath("Fill") +stroke_color = Color(0.441, 0.53235, 0.63, 1) +stroke_width = 2.64583 +line = NodePath("Stroke") +curve = SubResource("Curve2D_lur87") +update_curve_at_runtime = true +tolerance_degrees = 15.0 +arc_list = SubResource("Resource_5jqi6") +clip_paths = [null] + +[node name="Stroke" type="Line2D" parent="Clouds/CloudPath4"] +self_modulate = Color(1, 1, 1, 0.818878) +points = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +closed = true +width = 2.64583 +default_color = Color(0.441, 0.53235, 0.63, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Clouds/CloudPath4"] +texture = SubResource("GradientTexture2D_w2l5p") +texture_offset = Vector2(34.6552, 30.0076) +polygon = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143]] +metadata/_edit_lock_ = true + +[node name="CloudPath5" type="Node2D" parent="Clouds" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(-426, -187) +rotation = -2.41537 +scale = Vector2(7.39665, 6.7391) +script = ExtResource("1_qkos6") +polygon = NodePath("Fill") +stroke_color = Color(0.441, 0.53235, 0.63, 1) +stroke_width = 2.64583 +line = NodePath("Stroke") +curve = SubResource("Curve2D_lur87") +update_curve_at_runtime = true +tolerance_degrees = 15.0 +arc_list = SubResource("Resource_5jqi6") +clip_paths = [null] + +[node name="Stroke" type="Line2D" parent="Clouds/CloudPath5"] +self_modulate = Color(1, 1, 1, 0.818878) +points = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +closed = true +width = 2.64583 +default_color = Color(0.441, 0.53235, 0.63, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Clouds/CloudPath5"] +texture = SubResource("GradientTexture2D_w2l5p") +texture_offset = Vector2(34.6552, 30.0076) +polygon = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143]] +metadata/_edit_lock_ = true + +[node name="CloudPath6" type="Node2D" parent="Clouds" node_paths=PackedStringArray("polygon", "line", "clip_paths")] +position = Vector2(3879, -1568) +rotation = -2.45118 +scale = Vector2(5.69293, 5.18684) +script = ExtResource("1_qkos6") +polygon = NodePath("Fill") +stroke_color = Color(0.441, 0.53235, 0.63, 1) +stroke_width = 2.64583 +line = NodePath("Stroke") +curve = SubResource("Curve2D_lur87") +update_curve_at_runtime = true +tolerance_degrees = 15.0 +arc_list = SubResource("Resource_5jqi6") +clip_paths = [null] + +[node name="Stroke" type="Line2D" parent="Clouds/CloudPath6"] +self_modulate = Color(1, 1, 1, 0.818878) +points = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +closed = true +width = 2.64583 +default_color = Color(0.441, 0.53235, 0.63, 1) +sharp_limit = 80.0 +metadata/_edit_lock_ = true + +[node name="Fill" type="Polygon2D" parent="Clouds/CloudPath6"] +texture = SubResource("GradientTexture2D_w2l5p") +texture_offset = Vector2(34.6552, 30.0076) +polygon = PackedVector2Array(20.1859, -18.275, 19.9785, -21.1548, 18.987, -23.8858, 17.279, -26.2821, 14.9707, -28.1803, 12.2196, -29.451, 9.21315, -30.0076, 6.15617, -29.8123, 3.25703, -28.8783, 0.713302, -27.2692, -1.25378, -25.1621, -4.03036, -26.3826, -7.04766, -26.8846, -7.76143, -26.8937, -10.8107, -26.6111, -13.6784, -25.5946, -16.1692, -23.9136, -18.1132, -21.6826, -18.1859, -21.571, -21.1836, -22.1683, -22.2008, -22.2011, -25.2578, -22.0057, -28.1569, -21.0716, -30.7006, -19.4625, -32.7155, -17.288, -34.0644, -14.6964, -34.6552, -11.8642, -34.6552, -10.4688, -34.3763, -7.59441, -33.3171, -4.88597, -31.5499, -2.52806, -29.1951, -0.681372, -26.6916, 0.443052, -26.713, 0.72216, -26.4575, 3.59848, -25.4204, 6.31449, -23.6724, 8.68509, -21.3327, 10.5487, -18.5606, 11.7784, -16.9296, 12.1506, -16.9664, 12.6348, -16.7589, 15.5146, -15.7673, 18.2456, -14.0591, 20.6418, -11.7508, 22.5399, -8.99961, 23.8105, -5.99311, 24.367, -4.51253, 24.367, -1.46816, 24.0408, 1.38286, 22.9835, 3.18721, 21.8227, 4.98352, 24.161, 7.36106, 25.9817, 10.1578, 27.1606, 13.1832, 27.6175, 13.8984, 27.6159, 16.9554, 27.4203, 19.8544, 26.4861, 22.398, 24.8769, 24.4128, 22.7023, 25.7615, 20.1106, 26.3522, 17.2784, 26.3522, 15.8836, 25.9755, 13.0191, 25.8708, 12.6639, 27.8201, 10.437, 29.0912, 7.81069, 29.5974, 4.96397, 29.6017, 4.33186, 29.277, 1.68612, 31.6147, -0.179767, 33.3601, -2.55204, 34.3943, -5.26905, 34.6552, -7.94157, 34.1408, -10.787, 32.8622, -13.41, 30.9065, -15.6319, 28.4069, -17.3013, 25.5339, -18.3044, 22.4831, -18.5727, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275, 20.1859, -18.275) +polygons = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143]] +metadata/_edit_lock_ = true + +[node name="CheeseSpawns" type="Node2D" parent="."] + +[node name="Node2D" type="Node2D" parent="CheeseSpawns"] +position = Vector2(-5693, -2305) + +[node name="Node2D2" type="Node2D" parent="CheeseSpawns"] +position = Vector2(3981, 2056) + +[node name="Node2D3" type="Node2D" parent="CheeseSpawns"] +position = Vector2(-3271, 2056) + +[node name="Node2D4" type="Node2D" parent="CheeseSpawns"] +position = Vector2(5871, 1468) + +[node name="Node2D5" type="Node2D" parent="CheeseSpawns"] +position = Vector2(5794, -2452) + +[node name="Node2D6" type="Node2D" parent="CheeseSpawns"] +position = Vector2(-5595, 1202) + +[node name="BlockStaticBody2D" type="StaticBody2D" parent="."] +unique_name_in_owner = true +metadata/_edit_lock_ = true + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BlockStaticBody2D"] +position = Vector2(-7042.77, 3.42383) +polygon = PackedVector2Array(-403.271, -2987.14, 403.271, -2987.14, 403.271, 2987.14, -403.271, 2987.14) + +[node name="Fill" type="Polygon2D" parent="BlockStaticBody2D"] +texture_repeat = 2 +position = Vector2(-7042.77, 3.42383) +color = Color(0.402344, 0.207458, 0, 1) +texture = SubResource("NoiseTexture2D_lur87") +polygon = PackedVector2Array(-403.271, -2987.14, 403.271, -2987.14, 403.271, 2987.14, -403.271, 2987.14) + +[node name="CollisionPolygon2D2" type="CollisionPolygon2D" parent="BlockStaticBody2D"] +position = Vector2(7072.23, 3.42383) +polygon = PackedVector2Array(-403.271, -2987.14, 403.271, -2987.14, 403.271, 2987.14, -403.271, 2987.14) + +[node name="Fill2" type="Polygon2D" parent="BlockStaticBody2D"] +texture_repeat = 2 +position = Vector2(7072.23, 3.42383) +color = Color(0.402344, 0.207458, 0, 1) +texture = SubResource("NoiseTexture2D_lur87") +polygon = PackedVector2Array(-403.271, -2987.14, 403.271, -2987.14, 403.271, 2987.14, -403.271, 2987.14) + +[node name="DropZone" type="Area2D" parent="."] +position = Vector2(48, 2693) +scale = Vector2(10, 5) +metadata/_edit_lock_ = true + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DropZone"] +polygon = PackedVector2Array(-750.523, -65.8353, 750.523, -65.8353, 750.523, 65.8353, -750.523, 65.8353) +metadata/_edit_lock_ = true + +[node name="Rat" parent="." instance=ExtResource("4_w2l5p")] +position = Vector2(7, -2548) + +[connection signal="body_entered" from="DropZone" to="." method="_on_drop_zone_body_entered"] +[connection signal="cut_shapes" from="Rat" to="." method="_on_rat_cut_shapes"] +[connection signal="place_shape" from="Rat" to="." method="_on_rat_place_shape"] diff --git a/addons/curved_lines_2d/examples/rat/the_cheese.tscn b/addons/curved_lines_2d/examples/rat/the_cheese.tscn new file mode 100644 index 0000000..1e27556 --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/the_cheese.tscn @@ -0,0 +1,577 @@ +[gd_scene load_steps=30 format=3 uid="uid://c0m21g8gf1lro"] + +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="1_66gih"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="2_345i0"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="3_r23nx"] +[ext_resource type="Texture2D" uid="uid://cl0eabp7mc2k1" path="res://addons/curved_lines_2d/examples/rat/checkers.png" id="4_345i0"] + +[sub_resource type="Curve2D" id="Curve2D_w78qb"] +_data = { +"points": PackedVector2Array(0, 0, 0, 8.2845, 50, 0, 27.615, 0, -27.615, 0, 0, 15, 0, 8.2845, -1, -41, -50, 0, -32, -1, 41, 0, 0, -48, -1, -47, 0, 0, 50, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_qcy0p"] +script = ExtResource("3_r23nx") +arcs = Array[ExtResource("2_345i0")]([]) + +[sub_resource type="Gradient" id="Gradient_66gih"] +colors = PackedColorArray(0.76, 0.5548, 0.3496, 1, 1, 1, 1, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_345i0"] +gradient = SubResource("Gradient_66gih") +width = 100 +height = 63 +fill_from = Vector2(0.500177, 0.128038) +fill_to = Vector2(0.900035, 1.01585) + +[sub_resource type="Curve2D" id="Curve2D_t2q8j"] +_data = { +"points": PackedVector2Array(0, 0, -19.3125, -1.02083, -11.6, 14.8, 0, 8, -1, -43, -50, 0, -30, 0, -9, 0.157906, 0, -48, 2.36028, -5.93115, -2.36028, 5.93115, -11.9474, -42.3158, -1.20001, -37.2, 0, 0, -11.6, 14.8) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_5ct1n"] +script = ExtResource("3_r23nx") +arcs = Array[ExtResource("2_345i0")]([]) + +[sub_resource type="Gradient" id="Gradient_345i0"] +offsets = PackedFloat32Array(0.254091, 1) +colors = PackedColorArray(1, 1, 1, 1, 0.734375, 0.734375, 0.734375, 0) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_r23nx"] +gradient = SubResource("Gradient_345i0") +width = 50 +height = 62 +fill_from = Vector2(0.0655549, 0.115446) +fill_to = Vector2(0.969109, 0.694847) + +[sub_resource type="Curve2D" id="Curve2D_r23nx"] +_data = { +"points": PackedVector2Array(0, 0, 0, 0, 0.0833321, -0.0833321, -3.4397, 3.44887, 0, 0, 33.0833, -49.0833) +} +point_count = 2 + +[sub_resource type="Resource" id="Resource_w78qb"] +script = ExtResource("3_r23nx") +arcs = Array[ExtResource("2_345i0")]([]) + +[sub_resource type="Curve2D" id="Curve2D_66gih"] +_data = { +"points": PackedVector2Array(0, 0, 7.48748, 3.97172, 0, 0, -4.78517, -4.85226, 3.66234, 3.33064, 18.357, 13.5477, -7.84907, -1.98675, 0, 0, 34.3418, 21.3176) +} +point_count = 3 + +[sub_resource type="Resource" id="Resource_345i0"] +script = ExtResource("3_r23nx") +arcs = Array[ExtResource("2_345i0")]([]) + +[sub_resource type="Curve2D" id="Curve2D_qcy0p"] +_data = { +"points": PackedVector2Array(0, 0, 0, 0.135926, 0.293064, -0.0154343, 0.351563, 0, -0.5523, 0, -0.277248, 0.390816, -0.4375, 0.101563, 0, 0, -0.417873, -0.460747, -0.5523, 0, 0, 0, -0.144436, 0.203316, 0, 0, 0, 0, 0.293064, -0.0154343) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_t2q8j"] +script = ExtResource("3_r23nx") +arcs = Array[ExtResource("2_345i0")]([]) + +[sub_resource type="Curve" id="Curve_5ct1n"] +_data = [Vector2(0, 0.445678), 0.0, 0.0, 0, 0, Vector2(0.2263, 1), 0.0, 0.0, 0, 0, Vector2(1, 1), -0.0704417, 0.0, 0, 0] +point_count = 3 + +[sub_resource type="Gradient" id="Gradient_qywyy"] +colors = PackedColorArray(1, 1, 1, 1, 0.5, 0.5, 0.5, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_hoam1"] +gradient = SubResource("Gradient_qywyy") +fill_to = Vector2(0, 1) + +[sub_resource type="Curve2D" id="Curve2D_0o0eg"] +_data = { +"points": PackedVector2Array(0, 0, 0, 2.7615, 5, 0, 2.7615, 0, -2.7615, 0, 0, 5, 0, 2.7615, 0, -2.7615, -5, 0, -2.7615, 0, 2.7615, 0, 0, -5, 0, -2.7615, 0, 0, 5, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_p8rbp"] +script = ExtResource("3_r23nx") +arcs = Array[ExtResource("2_345i0")]([]) + +[sub_resource type="Gradient" id="Gradient_g22fo"] +offsets = PackedFloat32Array(0.442653, 0.758014) +colors = PackedColorArray(1, 1, 1, 0, 0, 0, 0, 0.345098) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_2pcq7"] +gradient = SubResource("Gradient_g22fo") +width = 10 +height = 10 +fill = 1 +fill_from = Vector2(-1.49231, -0.046154) +fill_to = Vector2(1.68462, 1.00769) + +[sub_resource type="Animation" id="Animation_r23nx"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Ellipse/FlagPole/CheckeredFlag:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.114765] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Ellipse/FlagPole:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.0387345] +} + +[sub_resource type="Animation" id="Animation_345i0"] +resource_name = "flag" +length = 0.5 +loop_mode = 2 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Ellipse/FlagPole/CheckeredFlag:curve:point_0/position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(0, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Ellipse/FlagPole/CheckeredFlag:curve:point_0/out") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(7.83419, 3.03963), Vector2(5.86892, 8.32313)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Ellipse/FlagPole/CheckeredFlag:curve:point_1/position") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(18.409, 13.236), Vector2(18.1144, 15.0028)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Ellipse/FlagPole/CheckeredFlag:curve:point_1/in") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-4.43846, -5.78436), Vector2(-6.40373, -0.50086)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Ellipse/FlagPole/CheckeredFlag:curve:point_1/out") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(3.514, 3.74627), Vector2(4.35486, 1.39031)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Ellipse/FlagPole/CheckeredFlag:curve:point_2/position") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(34.7334, 21.3643), Vector2(32.5137, 21.0994)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Ellipse/FlagPole/CheckeredFlag:curve:point_2/in") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-8.34937, -1.3758), Vector2(-5.51346, -4.83894)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("Ellipse/FlagPole/CheckeredFlag:rotation") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.114765, -0.184938] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("Ellipse/FlagPole:rotation") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.0, -0.0387345] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("Ellipse/FlagPole:curve:point_0/position") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0.0833321, -0.0833321), Vector2(0.0833321, -0.0833321)] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("Ellipse/FlagPole:curve:point_0/out") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(0, 0)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("Ellipse/FlagPole:curve:point_1/position") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(33.0833, -49.0833), Vector2(33.0833, -49.0833)] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("Ellipse/FlagPole:curve:point_1/in") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(-3.60004, 3.00002), Vector2(-2.69118, 5.54428)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_w78qb"] +_data = { +&"RESET": SubResource("Animation_r23nx"), +&"flag": SubResource("Animation_345i0") +} + +[sub_resource type="GDScript" id="GDScript_qcy0p"] +script/source = "extends AnimationPlayer + +func _ready() -> void: + play(\"flag\") +" + +[node name="TheCheese" type="Node2D"] +metadata/_edit_horizontal_guides_ = [-61.0, 32.0] +metadata/_edit_vertical_guides_ = [-73.0, 62.0] + +[node name="Ellipse" type="Node2D" parent="." node_paths=PackedStringArray("polygon", "line")] +position = Vector2(0, 15) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.756863, 0.458824, 0, 1) +stroke_width = 2.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_w78qb") +tolerance_degrees = 1.0 +arc_list = SubResource("Resource_qcy0p") +rx = 50.0 +ry = 15.0 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse"] +color = Color(1, 0.827451, 0, 1) +texture = SubResource("GradientTexture2D_345i0") +texture_offset = Vector2(50.0354, 48.0762) +polygon = PackedVector2Array(50, 0, 49.9837, 0.387167, 49.9349, 0.771918, 49.8542, 1.15414, 49.7419, 1.5337, 49.5983, 1.9105, 49.4239, 2.2844, 49.2191, 2.65531, 48.9842, 3.02309, 48.7197, 3.38763, 48.4259, 3.74881, 48.1033, 4.10651, 47.7522, 4.46063, 47.373, 4.81103, 46.9661, 5.15759, 46.5319, 5.50022, 46.0709, 5.83877, 45.5833, 6.17315, 45.0696, 6.50322, 44.5302, 6.82887, 43.9654, 7.14999, 43.3757, 7.46646, 42.7615, 7.77815, 42.1231, 8.08495, 41.461, 8.38674, 40.7755, 8.68341, 40.067, 8.97484, 38.5827, 9.54149, 37.0112, 10.0858, 35.3556, 10.6067, 33.6192, 11.1034, 31.805, 11.5748, 29.9161, 12.0201, 27.9558, 12.4383, 25.9272, 12.8285, 23.8333, 13.1896, 21.6774, 13.5209, 19.4626, 13.8213, 14.8688, 14.3256, 10.077, 14.6953, 5.11234, 14.9226, 0, 15, -5.11234, 14.9226, -10.077, 14.6953, -14.8688, 14.3256, -19.4626, 13.8213, -21.6774, 13.5209, -23.8333, 13.1896, -25.9272, 12.8285, -27.9558, 12.4383, -29.9161, 12.0201, -31.805, 11.5748, -33.6192, 11.1034, -35.3556, 10.6067, -37.0112, 10.0858, -38.5827, 9.54149, -40.067, 8.97484, -40.7755, 8.68341, -41.461, 8.38674, -42.1231, 8.08495, -42.7615, 7.77815, -43.3757, 7.46646, -43.9654, 7.14999, -44.5302, 6.82887, -45.0696, 6.50322, -45.5833, 6.17315, -46.0709, 5.83877, -46.5319, 5.50022, -46.9661, 5.15759, -47.373, 4.81103, -47.7522, 4.46063, -48.1033, 4.10651, -48.4259, 3.74881, -48.7197, 3.38763, -48.9842, 3.02309, -49.2191, 2.65531, -49.4239, 2.2844, -49.5983, 1.9105, -49.7419, 1.5337, -49.8542, 1.15414, -49.9349, 0.771918, -49.9837, 0.387167, -50, 0, -50.0354, -3.7478, -49.9548, -7.30664, -49.8715, -9.01657, -49.7597, -10.6809, -49.6195, -12.3002, -49.4512, -13.875, -49.2548, -15.4059, -49.0306, -16.8933, -48.7787, -18.3379, -48.4993, -19.7402, -48.1925, -21.1008, -47.8584, -22.4202, -47.4973, -23.6989, -47.1094, -24.9375, -46.6947, -26.1366, -46.2534, -27.2966, -45.7857, -28.4182, -45.2917, -29.502, -44.7717, -30.5483, -44.2257, -31.5579, -43.654, -32.5312, -43.0566, -33.4688, -42.4338, -34.3712, -41.7857, -35.239, -41.1125, -36.0728, -40.4143, -36.873, -39.6913, -37.6404, -38.9436, -38.3752, -38.1715, -39.0783, -37.375, -39.75, -36.5543, -40.391, -35.7097, -41.0017, -34.8412, -41.5828, -33.949, -42.1348, -33.0332, -42.6582, -32.0941, -43.1536, -31.1318, -43.6215, -30.1465, -44.0625, -29.1382, -44.4771, -28.1073, -44.866, -27.0537, -45.2295, -25.9778, -45.5684, -24.8796, -45.883, -23.7593, -46.1741, -22.6171, -46.442, -21.4531, -46.6875, -20.2675, -46.911, -19.0605, -47.113, -17.8322, -47.2942, -16.5828, -47.4551, -14.0211, -47.718, -11.377, -47.9063, -8.65146, -48.0242, -5.84595, -48.0762, -2.9617, -48.0667, 0, -48, 13.8789, -47.8652, 16.9009, -47.7551, 19.7534, -47.5979, 22.4411, -47.3854, 24.9688, -47.1094, 26.174, -46.945, 27.3411, -46.7616, 28.4706, -46.5582, 29.563, -46.3337, 30.619, -46.0872, 31.6391, -45.8177, 32.624, -45.5239, 33.5742, -45.2051, 34.4904, -44.86, 35.3731, -44.4878, 36.223, -44.0873, 37.0405, -43.6575, 37.8264, -43.1974, 38.5812, -42.706, 39.3056, -42.1822, 40, -41.625, 40.6651, -41.0334, 41.3016, -40.4063, 41.9099, -39.7428, 42.4907, -39.0417, 43.0446, -38.3022, 43.5722, -37.523, 44.0741, -36.7032, 44.5508, -35.8418, 45.003, -34.9377, 45.4312, -33.99, 45.8361, -32.9975, 46.2183, -31.9592, 46.5783, -30.8742, 46.9167, -29.7414, 47.2342, -28.5597, 47.5313, -27.3281, 47.8086, -26.0457, 48.0667, -24.7113, 48.3063, -23.3239, 48.5278, -21.8826, 48.9194, -18.8338, 49.2461, -15.5566, 49.5128, -12.0429, 49.7241, -8.28442) +metadata/_edit_lock_ = true + +[node name="Ellipse" type="Node2D" parent="Ellipse" node_paths=PackedStringArray("polygon", "line")] +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.756863, 0.458824, 0, 1) +stroke_width = 0.5 +line = NodePath("Stroke") +curve = SubResource("Curve2D_t2q8j") +tolerance_degrees = 1.0 +arc_list = SubResource("Resource_5ct1n") +rx = 50.0 +ry = 15.0 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse/Ellipse"] +color = Color(1, 0.843137, 0.219608, 1) +texture = SubResource("GradientTexture2D_r23nx") +texture_offset = Vector2(50.0297, 48) +polygon = PackedVector2Array(-11.6, 14.8, -15.2139, 14.5535, -18.7948, 14.1991, -22.3152, 13.7407, -25.7475, 13.1818, -27.4219, 12.866, -29.0639, 12.5264, -30.6701, 12.1635, -32.2369, 11.778, -33.761, 11.3701, -35.2389, 10.9403, -36.6671, 10.4892, -38.0422, 10.0172, -39.3607, 9.52472, -40.6191, 9.01227, -41.8141, 8.4803, -42.3867, 8.20714, -42.9422, 7.92927, -43.48, 7.64676, -43.9998, 7.35966, -44.5011, 7.06803, -44.9836, 6.77193, -45.4467, 6.47141, -45.8901, 6.16653, -46.3133, 5.85736, -46.7158, 5.54395, -47.0973, 5.22635, -47.4573, 4.90463, -47.7954, 4.57884, -48.1112, 4.24904, -48.4042, 3.9153, -48.6739, 3.57766, -48.9201, 3.23619, -49.1421, 2.89094, -49.3397, 2.54198, -49.5123, 2.18935, -49.6595, 1.83313, -49.7809, 1.47336, -49.8761, 1.1101, -49.9447, 0.743416, -49.9861, 0.373364, -50, 0, -50.0297, -3.92093, -49.9969, -5.79979, -49.9329, -7.62524, -49.8377, -9.39806, -49.7119, -11.119, -49.5556, -12.7888, -49.3691, -14.4082, -49.1529, -15.978, -48.907, -17.4989, -48.6319, -18.9718, -48.3279, -20.3972, -47.9952, -21.7761, -47.6341, -23.1091, -47.245, -24.397, -46.8281, -25.6406, -46.3838, -26.8406, -45.9123, -27.9978, -45.4139, -29.113, -44.8889, -30.1868, -44.3377, -31.22, -43.7605, -32.2135, -43.1576, -33.1679, -42.5293, -34.084, -41.8759, -34.9626, -41.1978, -35.8044, -40.4951, -36.6101, -39.7683, -37.3806, -39.0176, -38.1166, -38.2433, -38.8188, -37.4456, -39.488, -36.625, -40.125, -35.7817, -40.7305, -34.9159, -41.3052, -34.0281, -41.85, -33.1184, -42.3655, -32.1872, -42.8525, -31.2348, -43.3119, -30.2615, -43.7442, -29.2676, -44.1504, -28.2533, -44.5311, -27.219, -44.8871, -26.165, -45.2192, -25.0916, -45.5281, -23.999, -45.8145, -22.8875, -46.0793, -21.7576, -46.3232, -20.6094, -46.5469, -19.4432, -46.7512, -18.2594, -46.9368, -15.8401, -47.2551, -13.3537, -47.5079, -10.8027, -47.7012, -8.18948, -47.841, -5.51636, -47.9333, 0, -48, -4.24235, -47.9251, -5.33174, -47.8793, -5.82394, -47.8468, -6.28364, -47.8063, -6.71269, -47.7564, -6.91631, -47.7276, -7.11296, -47.696, -7.30289, -47.6614, -7.48632, -47.6236, -7.6635, -47.5826, -7.83464, -47.5382, -7.99999, -47.4901, -8.15977, -47.4383, -8.31422, -47.3826, -8.46358, -47.3229, -8.60808, -47.2588, -8.74794, -47.1905, -8.88341, -47.1175, -9.01472, -47.0399, -9.14209, -46.9574, -9.26577, -46.8699, -9.38598, -46.7772, -9.50297, -46.6791, -9.61695, -46.5756, -9.72817, -46.4664, -9.83686, -46.3515, -9.94325, -46.2305, -10.0476, -46.1035, -10.1501, -45.9701, -10.251, -45.8303, -10.3505, -45.6839, -10.4489, -45.5308, -10.5464, -45.3708, -10.6432, -45.2036, -10.7396, -45.0293, -10.932, -44.6583, -11.1255, -44.2564, -11.3219, -43.8225, -11.5231, -43.3553, -11.9474, -42.3158, -12.0552, -42.0318, -12.1574, -41.7357, -12.2542, -41.4271, -12.3456, -41.1056, -12.4317, -40.771, -12.5127, -40.4228, -12.5885, -40.0608, -12.6593, -39.6845, -12.7253, -39.2936, -12.7864, -38.8879, -12.8946, -38.0302, -12.9848, -37.1086, -13.0576, -36.1205, -13.1544, -33.9332, -13.1911, -31.4461, -13.1088, -25.4837) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Ellipse/Ellipse"] +points = PackedVector2Array(-11.6, 14.8, -15.2139, 14.5535, -18.7948, 14.1991, -22.3152, 13.7407, -25.7475, 13.1818, -27.4219, 12.866, -29.0639, 12.5264, -30.6701, 12.1635, -32.2369, 11.778, -33.761, 11.3701, -35.2389, 10.9403, -36.6671, 10.4892, -38.0422, 10.0172, -39.3607, 9.52472, -40.6191, 9.01227, -41.8141, 8.4803, -42.3867, 8.20714, -42.9422, 7.92927, -43.48, 7.64676, -43.9998, 7.35966, -44.5011, 7.06803, -44.9836, 6.77193, -45.4467, 6.47141, -45.8901, 6.16653, -46.3133, 5.85736, -46.7158, 5.54395, -47.0973, 5.22635, -47.4573, 4.90463, -47.7954, 4.57884, -48.1112, 4.24904, -48.4042, 3.9153, -48.6739, 3.57766, -48.9201, 3.23619, -49.1421, 2.89094, -49.3397, 2.54198, -49.5123, 2.18935, -49.6595, 1.83313, -49.7809, 1.47336, -49.8761, 1.1101, -49.9447, 0.743416, -49.9861, 0.373364, -50, 0, -50.0297, -3.92093, -49.9969, -5.79979, -49.9329, -7.62524, -49.8377, -9.39806, -49.7119, -11.119, -49.5556, -12.7888, -49.3691, -14.4082, -49.1529, -15.978, -48.907, -17.4989, -48.6319, -18.9718, -48.3279, -20.3972, -47.9952, -21.7761, -47.6341, -23.1091, -47.245, -24.397, -46.8281, -25.6406, -46.3838, -26.8406, -45.9123, -27.9978, -45.4139, -29.113, -44.8889, -30.1868, -44.3377, -31.22, -43.7605, -32.2135, -43.1576, -33.1679, -42.5293, -34.084, -41.8759, -34.9626, -41.1978, -35.8044, -40.4951, -36.6101, -39.7683, -37.3806, -39.0176, -38.1166, -38.2433, -38.8188, -37.4456, -39.488, -36.625, -40.125, -35.7817, -40.7305, -34.9159, -41.3052, -34.0281, -41.85, -33.1184, -42.3655, -32.1872, -42.8525, -31.2348, -43.3119, -30.2615, -43.7442, -29.2676, -44.1504, -28.2533, -44.5311, -27.219, -44.8871, -26.165, -45.2192, -25.0916, -45.5281, -23.999, -45.8145, -22.8875, -46.0793, -21.7576, -46.3232, -20.6094, -46.5469, -19.4432, -46.7512, -18.2594, -46.9368, -15.8401, -47.2551, -13.3537, -47.5079, -10.8027, -47.7012, -8.18948, -47.841, -5.51636, -47.9333, 0, -48, -4.24235, -47.9251, -5.33174, -47.8793, -5.82394, -47.8468, -6.28364, -47.8063, -6.71269, -47.7564, -6.91631, -47.7276, -7.11296, -47.696, -7.30289, -47.6614, -7.48632, -47.6236, -7.6635, -47.5826, -7.83464, -47.5382, -7.99999, -47.4901, -8.15977, -47.4383, -8.31422, -47.3826, -8.46358, -47.3229, -8.60808, -47.2588, -8.74794, -47.1905, -8.88341, -47.1175, -9.01472, -47.0399, -9.14209, -46.9574, -9.26577, -46.8699, -9.38598, -46.7772, -9.50297, -46.6791, -9.61695, -46.5756, -9.72817, -46.4664, -9.83686, -46.3515, -9.94325, -46.2305, -10.0476, -46.1035, -10.1501, -45.9701, -10.251, -45.8303, -10.3505, -45.6839, -10.4489, -45.5308, -10.5464, -45.3708, -10.6432, -45.2036, -10.7396, -45.0293, -10.932, -44.6583, -11.1255, -44.2564, -11.3219, -43.8225, -11.5231, -43.3553, -11.9474, -42.3158, -12.0552, -42.0318, -12.1574, -41.7357, -12.2542, -41.4271, -12.3456, -41.1056, -12.4317, -40.771, -12.5127, -40.4228, -12.5885, -40.0608, -12.6593, -39.6845, -12.7253, -39.2936, -12.7864, -38.8879, -12.8946, -38.0302, -12.9848, -37.1086, -13.0576, -36.1205, -13.1544, -33.9332, -13.1911, -31.4461, -13.1088, -25.4837) +closed = true +width = 0.5 +default_color = Color(0.756863, 0.458824, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Ellipse"] +points = PackedVector2Array(50, 0, 49.9837, 0.387167, 49.9349, 0.771918, 49.8542, 1.15414, 49.7419, 1.5337, 49.5983, 1.9105, 49.4239, 2.2844, 49.2191, 2.65531, 48.9842, 3.02309, 48.7197, 3.38763, 48.4259, 3.74881, 48.1033, 4.10651, 47.7522, 4.46063, 47.373, 4.81103, 46.9661, 5.15759, 46.5319, 5.50022, 46.0709, 5.83877, 45.5833, 6.17315, 45.0696, 6.50322, 44.5302, 6.82887, 43.9654, 7.14999, 43.3757, 7.46646, 42.7615, 7.77815, 42.1231, 8.08495, 41.461, 8.38674, 40.7755, 8.68341, 40.067, 8.97484, 38.5827, 9.54149, 37.0112, 10.0858, 35.3556, 10.6067, 33.6192, 11.1034, 31.805, 11.5748, 29.9161, 12.0201, 27.9558, 12.4383, 25.9272, 12.8285, 23.8333, 13.1896, 21.6774, 13.5209, 19.4626, 13.8213, 14.8688, 14.3256, 10.077, 14.6953, 5.11234, 14.9226, 0, 15, -5.11234, 14.9226, -10.077, 14.6953, -14.8688, 14.3256, -19.4626, 13.8213, -21.6774, 13.5209, -23.8333, 13.1896, -25.9272, 12.8285, -27.9558, 12.4383, -29.9161, 12.0201, -31.805, 11.5748, -33.6192, 11.1034, -35.3556, 10.6067, -37.0112, 10.0858, -38.5827, 9.54149, -40.067, 8.97484, -40.7755, 8.68341, -41.461, 8.38674, -42.1231, 8.08495, -42.7615, 7.77815, -43.3757, 7.46646, -43.9654, 7.14999, -44.5302, 6.82887, -45.0696, 6.50322, -45.5833, 6.17315, -46.0709, 5.83877, -46.5319, 5.50022, -46.9661, 5.15759, -47.373, 4.81103, -47.7522, 4.46063, -48.1033, 4.10651, -48.4259, 3.74881, -48.7197, 3.38763, -48.9842, 3.02309, -49.2191, 2.65531, -49.4239, 2.2844, -49.5983, 1.9105, -49.7419, 1.5337, -49.8542, 1.15414, -49.9349, 0.771918, -49.9837, 0.387167, -50, 0, -50.0354, -3.7478, -49.9548, -7.30664, -49.8715, -9.01657, -49.7597, -10.6809, -49.6195, -12.3002, -49.4512, -13.875, -49.2548, -15.4059, -49.0306, -16.8933, -48.7787, -18.3379, -48.4993, -19.7402, -48.1925, -21.1008, -47.8584, -22.4202, -47.4973, -23.6989, -47.1094, -24.9375, -46.6947, -26.1366, -46.2534, -27.2966, -45.7857, -28.4182, -45.2917, -29.502, -44.7717, -30.5483, -44.2257, -31.5579, -43.654, -32.5312, -43.0566, -33.4688, -42.4338, -34.3712, -41.7857, -35.239, -41.1125, -36.0728, -40.4143, -36.873, -39.6913, -37.6404, -38.9436, -38.3752, -38.1715, -39.0783, -37.375, -39.75, -36.5543, -40.391, -35.7097, -41.0017, -34.8412, -41.5828, -33.949, -42.1348, -33.0332, -42.6582, -32.0941, -43.1536, -31.1318, -43.6215, -30.1465, -44.0625, -29.1382, -44.4771, -28.1073, -44.866, -27.0537, -45.2295, -25.9778, -45.5684, -24.8796, -45.883, -23.7593, -46.1741, -22.6171, -46.442, -21.4531, -46.6875, -20.2675, -46.911, -19.0605, -47.113, -17.8322, -47.2942, -16.5828, -47.4551, -14.0211, -47.718, -11.377, -47.9063, -8.65146, -48.0242, -5.84595, -48.0762, -2.9617, -48.0667, 0, -48, 13.8789, -47.8652, 16.9009, -47.7551, 19.7534, -47.5979, 22.4411, -47.3854, 24.9688, -47.1094, 26.174, -46.945, 27.3411, -46.7616, 28.4706, -46.5582, 29.563, -46.3337, 30.619, -46.0872, 31.6391, -45.8177, 32.624, -45.5239, 33.5742, -45.2051, 34.4904, -44.86, 35.3731, -44.4878, 36.223, -44.0873, 37.0405, -43.6575, 37.8264, -43.1974, 38.5812, -42.706, 39.3056, -42.1822, 40, -41.625, 40.6651, -41.0334, 41.3016, -40.4063, 41.9099, -39.7428, 42.4907, -39.0417, 43.0446, -38.3022, 43.5722, -37.523, 44.0741, -36.7032, 44.5508, -35.8418, 45.003, -34.9377, 45.4312, -33.99, 45.8361, -32.9975, 46.2183, -31.9592, 46.5783, -30.8742, 46.9167, -29.7414, 47.2342, -28.5597, 47.5313, -27.3281, 47.8086, -26.0457, 48.0667, -24.7113, 48.3063, -23.3239, 48.5278, -21.8826, 48.9194, -18.8338, 49.2461, -15.5566, 49.5128, -12.0429, 49.7241, -8.28442) +closed = true +width = 2.0 +default_color = Color(0.756863, 0.458824, 0, 1) +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="FlagPole" type="Node2D" parent="Ellipse" node_paths=PackedStringArray("line")] +position = Vector2(32.9167, -43.9167) +rotation = -0.0387345 +script = ExtResource("1_66gih") +stroke_color = Color(0.8, 0.613333, 0, 1) +stroke_width = 5.0 +begin_cap_mode = 2 +end_cap_mode = 2 +line = NodePath("Stroke") +curve = SubResource("Curve2D_r23nx") +update_curve_at_runtime = true +arc_list = SubResource("Resource_w78qb") +metadata/_svs_version_ = 2 + +[node name="CheckeredFlag" type="Node2D" parent="Ellipse/FlagPole" node_paths=PackedStringArray("line")] +position = Vector2(26.8333, -40) +rotation = 0.114765 +script = ExtResource("1_66gih") +stroke_color = Color(0.980392, 0.960784, 0.713726, 1) +stroke_width = 24.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_66gih") +update_curve_at_runtime = true +tolerance_degrees = 8.0 +arc_list = SubResource("Resource_345i0") +metadata/_svs_version_ = 2 + +[node name="Stroke" type="Line2D" parent="Ellipse/FlagPole/CheckeredFlag"] +texture_repeat = 2 +points = PackedVector2Array(0, 0, 10.1919, 6.44364, 18.357, 13.5477, 21.2959, 15.8875, 24.7794, 17.9366, 34.3418, 21.3176) +width = 24.0 +default_color = Color(0.980392, 0.960784, 0.713726, 1) +texture = ExtResource("4_345i0") +texture_mode = 1 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Ellipse" type="Node2D" parent="Ellipse/FlagPole" node_paths=PackedStringArray("polygon")] +position = Vector2(0.223881, 0.466171) +scale = Vector2(2.27619, 2.27619) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.8, 0.613333, 0, 1) +stroke_width = 0.5 +curve = SubResource("Curve2D_qcy0p") +arc_list = SubResource("Resource_t2q8j") +rx = 1.0 +ry = 0.246108 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse/FlagPole/Ellipse"] +color = Color(0, 0, 0, 0.654902) +polygon = PackedVector2Array(0.293064, -0.0154343, 0.292426, -0.00230984, 0.290522, 0.011528, 0.282978, 0.0410474, 0.270559, 0.072531, 0.253391, 0.105386, 0.2316, 0.13902, 0.205311, 0.172839, 0.17465, 0.206251, 0.139744, 0.238663, 0.100718, 0.269482, 0.0576978, 0.298116, 0.0108094, 0.323971, -0.0398211, 0.346454, -0.094068, 0.364973, -0.151805, 0.378935, -0.212907, 0.387747, -0.277248, 0.390816, -0.327486, 0.388661, -0.37465, 0.382368, -0.418753, 0.372193, -0.459805, 0.358391, -0.497819, 0.341219, -0.532806, 0.320933, -0.564778, 0.297788, -0.593746, 0.272042, -0.619721, 0.243949, -0.642716, 0.213766, -0.662741, 0.18175, -0.679809, 0.148155, -0.693931, 0.113239, -0.705118, 0.0772574, -0.713383, 0.0404658, -0.718736, 0.00312063, -0.721189, -0.0345221, -0.720754, -0.0722063, -0.717442, -0.109676, -0.711265, -0.146675, -0.702235, -0.182947, -0.690362, -0.218237, -0.67566, -0.252288, -0.658138, -0.284843, -0.637809, -0.315648, -0.614684, -0.344446, -0.588775, -0.370981, -0.560094, -0.394997, -0.528651, -0.416237, -0.494459, -0.434446, -0.457529, -0.449368, -0.417873, -0.460747, -0.452816, -0.356987, -0.476982, -0.250633, -0.485048, -0.190647, -0.488267, -0.128716, -0.485014, -0.0667838, -0.480453, -0.036426, -0.473663, -0.00679768, -0.464443, 0.0218579, -0.452588, 0.0492975, -0.437895, 0.075278, -0.420162, 0.0995562, -0.399185, 0.121889, -0.37476, 0.142033, -0.346685, 0.159745, -0.314756, 0.174782, -0.27877, 0.186901, -0.238523, 0.195858, -0.193813, 0.201411, -0.144436, 0.203316) +metadata/_edit_lock_ = true + +[node name="Stroke" type="Line2D" parent="Ellipse/FlagPole"] +texture_repeat = 2 +points = PackedVector2Array(0.0833321, -0.0833321, 33.0833, -49.0833) +width = 5.0 +width_curve = SubResource("Curve_5ct1n") +default_color = Color(0.8, 0.613333, 0, 1) +texture = SubResource("GradientTexture2D_hoam1") +texture_mode = 1 +begin_cap_mode = 2 +end_cap_mode = 2 +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Ellipse2" type="Node2D" parent="." node_paths=PackedStringArray("polygon")] +position = Vector2(-30.0833, -2.9583) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.51, 0.4335, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_0o0eg") +arc_list = SubResource("Resource_p8rbp") +shape_type = 2 +size = Vector2(10, 10) +rx = 5.0 +ry = 5.0 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse2"] +texture = SubResource("GradientTexture2D_2pcq7") +texture_offset = Vector2(5, 5) +polygon = PackedVector2Array(5, 0, 4.97419, 0.511234, 4.89842, 1.0077, 4.77522, 1.48688, 4.60709, 1.94626, 4.39654, 2.38333, 4.1461, 2.79558, 3.85827, 3.1805, 3.53556, 3.53556, 3.1805, 3.85827, 2.79558, 4.1461, 2.38333, 4.39654, 1.94626, 4.60709, 1.48688, 4.77522, 1.0077, 4.89842, 0.511234, 4.97419, 0, 5, -0.511234, 4.97419, -1.0077, 4.89842, -1.48688, 4.77522, -1.94626, 4.60709, -2.38333, 4.39654, -2.79558, 4.1461, -3.1805, 3.85827, -3.53556, 3.53556, -3.85827, 3.1805, -4.1461, 2.79558, -4.39654, 2.38333, -4.60709, 1.94626, -4.77522, 1.48688, -4.89842, 1.0077, -4.97419, 0.511234, -5, 0, -4.97419, -0.511234, -4.89842, -1.0077, -4.77522, -1.48688, -4.60709, -1.94626, -4.39654, -2.38333, -4.1461, -2.79558, -3.85827, -3.1805, -3.53556, -3.53556, -3.1805, -3.85827, -2.79558, -4.1461, -2.38333, -4.39654, -1.94626, -4.60709, -1.48688, -4.77522, -1.0077, -4.89842, -0.511234, -4.97419, 0, -5, 0.511234, -4.97419, 1.0077, -4.89842, 1.48688, -4.77522, 1.94626, -4.60709, 2.38333, -4.39654, 2.79558, -4.1461, 3.1805, -3.85827, 3.53556, -3.53556, 3.85827, -3.1805, 4.1461, -2.79558, 4.39654, -2.38333, 4.60709, -1.94626, 4.77522, -1.48688, 4.89842, -1.0077, 4.97419, -0.511234) +metadata/_edit_lock_ = true + +[node name="Ellipse3" type="Node2D" parent="." node_paths=PackedStringArray("polygon")] +position = Vector2(-25.7334, -20.9833) +rotation = -0.122684 +scale = Vector2(1, 0.72) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.51, 0.4335, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_0o0eg") +arc_list = SubResource("Resource_p8rbp") +shape_type = 2 +size = Vector2(10, 10) +rx = 5.0 +ry = 5.0 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse3"] +texture = SubResource("GradientTexture2D_2pcq7") +texture_offset = Vector2(5, 5) +polygon = PackedVector2Array(5, 0, 4.97419, 0.511234, 4.89842, 1.0077, 4.77522, 1.48688, 4.60709, 1.94626, 4.39654, 2.38333, 4.1461, 2.79558, 3.85827, 3.1805, 3.53556, 3.53556, 3.1805, 3.85827, 2.79558, 4.1461, 2.38333, 4.39654, 1.94626, 4.60709, 1.48688, 4.77522, 1.0077, 4.89842, 0.511234, 4.97419, 0, 5, -0.511234, 4.97419, -1.0077, 4.89842, -1.48688, 4.77522, -1.94626, 4.60709, -2.38333, 4.39654, -2.79558, 4.1461, -3.1805, 3.85827, -3.53556, 3.53556, -3.85827, 3.1805, -4.1461, 2.79558, -4.39654, 2.38333, -4.60709, 1.94626, -4.77522, 1.48688, -4.89842, 1.0077, -4.97419, 0.511234, -5, 0, -4.97419, -0.511234, -4.89842, -1.0077, -4.77522, -1.48688, -4.60709, -1.94626, -4.39654, -2.38333, -4.1461, -2.79558, -3.85827, -3.1805, -3.53556, -3.53556, -3.1805, -3.85827, -2.79558, -4.1461, -2.38333, -4.39654, -1.94626, -4.60709, -1.48688, -4.77522, -1.0077, -4.89842, -0.511234, -4.97419, 0, -5, 0.511234, -4.97419, 1.0077, -4.89842, 1.48688, -4.77522, 1.94626, -4.60709, 2.38333, -4.39654, 2.79558, -4.1461, 3.1805, -3.85827, 3.53556, -3.53556, 3.85827, -3.1805, 4.1461, -2.79558, 4.39654, -2.38333, 4.60709, -1.94626, 4.77522, -1.48688, 4.89842, -1.0077, 4.97419, -0.511234) +metadata/_edit_lock_ = true + +[node name="Ellipse5" type="Node2D" parent="." node_paths=PackedStringArray("polygon")] +position = Vector2(-21, 12) +scale = Vector2(1.43085, 1.43085) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.51, 0.4335, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_0o0eg") +arc_list = SubResource("Resource_p8rbp") +shape_type = 2 +size = Vector2(10, 10) +rx = 5.0 +ry = 5.0 +metadata/_svs_version_ = 2 +metadata/_hover_closest_point_on_curve_ = Object(Object,"script":Resource("res://addons/curved_lines_2d/closest_point_on_curve_meta.gd"),"before_segment":4,"point_position":Vector2(-13.8785, -3.64969),"local_point_position":Vector2(4.97707, -0.45406)) + + +[node name="Fill" type="Polygon2D" parent="Ellipse5"] +texture = SubResource("GradientTexture2D_2pcq7") +texture_offset = Vector2(5, 5) +polygon = PackedVector2Array(5, 0, 4.97419, 0.511234, 4.89842, 1.0077, 4.77522, 1.48688, 4.60709, 1.94626, 4.39654, 2.38333, 4.1461, 2.79558, 3.85827, 3.1805, 3.53556, 3.53556, 3.1805, 3.85827, 2.79558, 4.1461, 2.38333, 4.39654, 1.94626, 4.60709, 1.48688, 4.77522, 1.0077, 4.89842, 0.511234, 4.97419, 0, 5, -0.511234, 4.97419, -1.0077, 4.89842, -1.48688, 4.77522, -1.94626, 4.60709, -2.38333, 4.39654, -2.79558, 4.1461, -3.1805, 3.85827, -3.53556, 3.53556, -3.85827, 3.1805, -4.1461, 2.79558, -4.39654, 2.38333, -4.60709, 1.94626, -4.77522, 1.48688, -4.89842, 1.0077, -4.97419, 0.511234, -5, 0, -4.97419, -0.511234, -4.89842, -1.0077, -4.77522, -1.48688, -4.60709, -1.94626, -4.39654, -2.38333, -4.1461, -2.79558, -3.85827, -3.1805, -3.53556, -3.53556, -3.1805, -3.85827, -2.79558, -4.1461, -2.38333, -4.39654, -1.94626, -4.60709, -1.48688, -4.77522, -1.0077, -4.89842, -0.511234, -4.97419, 0, -5, 0.511234, -4.97419, 1.0077, -4.89842, 1.48688, -4.77522, 1.94626, -4.60709, 2.38333, -4.39654, 2.79558, -4.1461, 3.1805, -3.85827, 3.53556, -3.53556, 3.85827, -3.1805, 4.1461, -2.79558, 4.39654, -2.38333, 4.60709, -1.94626, 4.77522, -1.48688, 4.89842, -1.0077, 4.97419, -0.511234) +metadata/_edit_lock_ = true + +[node name="Ellipse7" type="Node2D" parent="." node_paths=PackedStringArray("polygon")] +position = Vector2(-39, -9.125) +rotation = 0.156977 +scale = Vector2(0.53115, 0.784185) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.51, 0.4335, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_0o0eg") +arc_list = SubResource("Resource_p8rbp") +shape_type = 2 +size = Vector2(10, 10) +rx = 5.0 +ry = 5.0 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse7"] +texture = SubResource("GradientTexture2D_2pcq7") +texture_offset = Vector2(5, 5) +polygon = PackedVector2Array(5, 0, 4.97419, 0.511234, 4.89842, 1.0077, 4.77522, 1.48688, 4.60709, 1.94626, 4.39654, 2.38333, 4.1461, 2.79558, 3.85827, 3.1805, 3.53556, 3.53556, 3.1805, 3.85827, 2.79558, 4.1461, 2.38333, 4.39654, 1.94626, 4.60709, 1.48688, 4.77522, 1.0077, 4.89842, 0.511234, 4.97419, 0, 5, -0.511234, 4.97419, -1.0077, 4.89842, -1.48688, 4.77522, -1.94626, 4.60709, -2.38333, 4.39654, -2.79558, 4.1461, -3.1805, 3.85827, -3.53556, 3.53556, -3.85827, 3.1805, -4.1461, 2.79558, -4.39654, 2.38333, -4.60709, 1.94626, -4.77522, 1.48688, -4.89842, 1.0077, -4.97419, 0.511234, -5, 0, -4.97419, -0.511234, -4.89842, -1.0077, -4.77522, -1.48688, -4.60709, -1.94626, -4.39654, -2.38333, -4.1461, -2.79558, -3.85827, -3.1805, -3.53556, -3.53556, -3.1805, -3.85827, -2.79558, -4.1461, -2.38333, -4.39654, -1.94626, -4.60709, -1.48688, -4.77522, -1.0077, -4.89842, -0.511234, -4.97419, 0, -5, 0.511234, -4.97419, 1.0077, -4.89842, 1.48688, -4.77522, 1.94626, -4.60709, 2.38333, -4.39654, 2.79558, -4.1461, 3.1805, -3.85827, 3.53556, -3.53556, 3.85827, -3.1805, 4.1461, -2.79558, 4.39654, -2.38333, 4.60709, -1.94626, 4.77522, -1.48688, 4.89842, -1.0077, 4.97419, -0.511234) +metadata/_edit_lock_ = true + +[node name="Ellipse4" type="Node2D" parent="." node_paths=PackedStringArray("polygon")] +position = Vector2(-17.6666, -11.6667) +rotation = -0.150597 +scale = Vector2(0.697908, 0.697908) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.51, 0.4335, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_0o0eg") +arc_list = SubResource("Resource_p8rbp") +shape_type = 2 +size = Vector2(10, 10) +rx = 5.0 +ry = 5.0 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse4"] +texture = SubResource("GradientTexture2D_2pcq7") +texture_offset = Vector2(5, 5) +polygon = PackedVector2Array(5, 0, 4.97419, 0.511234, 4.89842, 1.0077, 4.77522, 1.48688, 4.60709, 1.94626, 4.39654, 2.38333, 4.1461, 2.79558, 3.85827, 3.1805, 3.53556, 3.53556, 3.1805, 3.85827, 2.79558, 4.1461, 2.38333, 4.39654, 1.94626, 4.60709, 1.48688, 4.77522, 1.0077, 4.89842, 0.511234, 4.97419, 0, 5, -0.511234, 4.97419, -1.0077, 4.89842, -1.48688, 4.77522, -1.94626, 4.60709, -2.38333, 4.39654, -2.79558, 4.1461, -3.1805, 3.85827, -3.53556, 3.53556, -3.85827, 3.1805, -4.1461, 2.79558, -4.39654, 2.38333, -4.60709, 1.94626, -4.77522, 1.48688, -4.89842, 1.0077, -4.97419, 0.511234, -5, 0, -4.97419, -0.511234, -4.89842, -1.0077, -4.77522, -1.48688, -4.60709, -1.94626, -4.39654, -2.38333, -4.1461, -2.79558, -3.85827, -3.1805, -3.53556, -3.53556, -3.1805, -3.85827, -2.79558, -4.1461, -2.38333, -4.39654, -1.94626, -4.60709, -1.48688, -4.77522, -1.0077, -4.89842, -0.511234, -4.97419, 0, -5, 0.511234, -4.97419, 1.0077, -4.89842, 1.48688, -4.77522, 1.94626, -4.60709, 2.38333, -4.39654, 2.79558, -4.1461, 3.1805, -3.85827, 3.53556, -3.53556, 3.85827, -3.1805, 4.1461, -2.79558, 4.39654, -2.38333, 4.60709, -1.94626, 4.77522, -1.48688, 4.89842, -1.0077, 4.97419, -0.511234) +metadata/_edit_lock_ = true + +[node name="Ellipse6" type="Node2D" parent="." node_paths=PackedStringArray("polygon")] +position = Vector2(-40, 13) +rotation = 0.0576541 +scale = Vector2(0.633748, 0.633748) +script = ExtResource("1_66gih") +polygon = NodePath("Fill") +stroke_color = Color(0.51, 0.4335, 0, 1) +stroke_width = 2.0 +curve = SubResource("Curve2D_0o0eg") +arc_list = SubResource("Resource_p8rbp") +shape_type = 2 +size = Vector2(10, 10) +rx = 5.0 +ry = 5.0 +metadata/_svs_version_ = 2 + +[node name="Fill" type="Polygon2D" parent="Ellipse6"] +texture = SubResource("GradientTexture2D_2pcq7") +texture_offset = Vector2(5, 5) +polygon = PackedVector2Array(5, 0, 4.97419, 0.511234, 4.89842, 1.0077, 4.77522, 1.48688, 4.60709, 1.94626, 4.39654, 2.38333, 4.1461, 2.79558, 3.85827, 3.1805, 3.53556, 3.53556, 3.1805, 3.85827, 2.79558, 4.1461, 2.38333, 4.39654, 1.94626, 4.60709, 1.48688, 4.77522, 1.0077, 4.89842, 0.511234, 4.97419, 0, 5, -0.511234, 4.97419, -1.0077, 4.89842, -1.48688, 4.77522, -1.94626, 4.60709, -2.38333, 4.39654, -2.79558, 4.1461, -3.1805, 3.85827, -3.53556, 3.53556, -3.85827, 3.1805, -4.1461, 2.79558, -4.39654, 2.38333, -4.60709, 1.94626, -4.77522, 1.48688, -4.89842, 1.0077, -4.97419, 0.511234, -5, 0, -4.97419, -0.511234, -4.89842, -1.0077, -4.77522, -1.48688, -4.60709, -1.94626, -4.39654, -2.38333, -4.1461, -2.79558, -3.85827, -3.1805, -3.53556, -3.53556, -3.1805, -3.85827, -2.79558, -4.1461, -2.38333, -4.39654, -1.94626, -4.60709, -1.48688, -4.77522, -1.0077, -4.89842, -0.511234, -4.97419, 0, -5, 0.511234, -4.97419, 1.0077, -4.89842, 1.48688, -4.77522, 1.94626, -4.60709, 2.38333, -4.39654, 2.79558, -4.1461, 3.1805, -3.85827, 3.53556, -3.53556, 3.85827, -3.1805, 4.1461, -2.79558, 4.39654, -2.38333, 4.60709, -1.94626, 4.77522, -1.48688, 4.89842, -1.0077, 4.97419, -0.511234) +metadata/_edit_lock_ = true + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +&"": SubResource("AnimationLibrary_w78qb") +} +script = SubResource("GDScript_qcy0p") diff --git a/addons/curved_lines_2d/examples/rat/the_finish.tscn b/addons/curved_lines_2d/examples/rat/the_finish.tscn new file mode 100644 index 0000000..0db0de6 --- /dev/null +++ b/addons/curved_lines_2d/examples/rat/the_finish.tscn @@ -0,0 +1,8 @@ +[gd_scene load_steps=2 format=3 uid="uid://bmiq78m8c3ctp"] + +[ext_resource type="PackedScene" uid="uid://c0m21g8gf1lro" path="res://addons/curved_lines_2d/examples/rat/the_cheese.tscn" id="1_5twdw"] + +[node name="TheFinish" type="VisibleOnScreenNotifier2D"] +rect = Rect2(-60, -39, 120, 70) + +[node name="TheCheese" parent="." instance=ExtResource("1_5twdw")] diff --git a/addons/curved_lines_2d/external_video_button.gd b/addons/curved_lines_2d/external_video_button.gd new file mode 100644 index 0000000..9e329da --- /dev/null +++ b/addons/curved_lines_2d/external_video_button.gd @@ -0,0 +1,51 @@ +@tool +extends PanelContainer + +signal prop_updated() + +@export var img : Texture2D: + set(_img): + img = _img + prop_updated.emit() + +@export var uri : String: + set(_uri): + uri = _uri + prop_updated.emit() + +@export var text : String: + set(_text): + text = _text + prop_updated.emit() + +var stylebox : StyleBoxFlat = preload("res://addons/curved_lines_2d/external_video_button.stylebox") +var stylebox_hover : StyleBoxFlat = preload("res://addons/curved_lines_2d/external_video_button_hover.stylebox") + +func _enter_tree() -> void: + if not prop_updated.is_connected(_on_prop_updated): + prop_updated.connect(_on_prop_updated) + _on_prop_updated() + +func _on_prop_updated() -> void: + %LinkButtonWithCopyHint.uri = uri + %TextureButton.texture_normal = img + %LinkButtonWithCopyHint.text = text + %TextureButton.tooltip_text = %LinkButtonWithCopyHint.tooltip_text + tooltip_text = %LinkButtonWithCopyHint.tooltip_text + +func _on_gui_input(event: InputEvent) -> void: + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + OS.shell_open(uri) + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and not Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): + DisplayServer.clipboard_set(%LinkButtonWithCopyHint.uri) + if Engine.is_editor_hint(): + EditorInterface.get_editor_toaster().push_toast("Link copied!") + + +func _on_mouse_entered() -> void: + add_theme_stylebox_override("panel", stylebox_hover) + + +func _on_mouse_exited() -> void: + add_theme_stylebox_override("panel", stylebox) + diff --git a/addons/curved_lines_2d/external_video_button.gd.uid b/addons/curved_lines_2d/external_video_button.gd.uid new file mode 100644 index 0000000..658f262 --- /dev/null +++ b/addons/curved_lines_2d/external_video_button.gd.uid @@ -0,0 +1 @@ +uid://cxvx3xc5wngfl diff --git a/addons/curved_lines_2d/external_video_button.stylebox b/addons/curved_lines_2d/external_video_button.stylebox new file mode 100644 index 0000000..44d47d0 Binary files /dev/null and b/addons/curved_lines_2d/external_video_button.stylebox differ diff --git a/addons/curved_lines_2d/external_video_button.tscn b/addons/curved_lines_2d/external_video_button.tscn new file mode 100644 index 0000000..e6f37c5 --- /dev/null +++ b/addons/curved_lines_2d/external_video_button.tscn @@ -0,0 +1,62 @@ +[gd_scene load_steps=5 format=3 uid="uid://bhpmwhbdlsp1g"] + +[ext_resource type="Script" uid="uid://cxvx3xc5wngfl" path="res://addons/curved_lines_2d/external_video_button.gd" id="1_1kn8h"] +[ext_resource type="StyleBox" uid="uid://dufypbh4pb3v8" path="res://addons/curved_lines_2d/external_video_button.stylebox" id="1_tia4j"] +[ext_resource type="Script" uid="uid://c1dbllgwqxjjn" path="res://addons/curved_lines_2d/link_button_with_copy_hint.gd" id="3_c8xqg"] +[ext_resource type="Texture2D" uid="uid://dsn2lxwf0mvoq" path="res://addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png" id="3_gf0w2"] + +[node name="ExternalVideoButton" type="PanelContainer"] +clip_contents = true +custom_minimum_size = Vector2(320, 220) +offset_right = 320.0 +offset_bottom = 220.0 +size_flags_vertical = 0 +tooltip_text = "This link will open a webpage in your browser: https://example.com +Right click to copy this link" +mouse_default_cursor_shape = 2 +theme_override_styles/panel = ExtResource("1_tia4j") +script = ExtResource("1_1kn8h") +img = ExtResource("3_gf0w2") +uri = "https://example.com" +text = "example" + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_constants/separation = 0 + +[node name="TextureButton" type="TextureButton" parent="VBoxContainer"] +unique_name_in_owner = true +clip_contents = true +custom_minimum_size = Vector2(320, 180) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +tooltip_text = "This link will open a webpage in your browser: https://example.com +Right click to copy this link" +mouse_default_cursor_shape = 2 +texture_normal = ExtResource("3_gf0w2") +ignore_texture_size = true +stretch_mode = 5 + +[node name="LinkButtonWithCopyHint" type="LinkButton" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 6 +tooltip_text = "This link will open a webpage in your browser: https://example.com +Right click to copy this link" +text = "example" +uri = "https://example.com" +script = ExtResource("3_c8xqg") +metadata/_custom_type_script = "uid://c1dbllgwqxjjn" + +[connection signal="gui_input" from="." to="." method="_on_gui_input"] +[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"] +[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"] +[connection signal="gui_input" from="VBoxContainer/TextureButton" to="." method="_on_gui_input"] +[connection signal="mouse_entered" from="VBoxContainer/TextureButton" to="." method="_on_mouse_entered"] +[connection signal="mouse_exited" from="VBoxContainer/TextureButton" to="." method="_on_mouse_exited"] +[connection signal="mouse_entered" from="VBoxContainer/LinkButtonWithCopyHint" to="." method="_on_mouse_entered"] +[connection signal="mouse_exited" from="VBoxContainer/LinkButtonWithCopyHint" to="." method="_on_mouse_exited"] diff --git a/addons/curved_lines_2d/external_video_button_hover.stylebox b/addons/curved_lines_2d/external_video_button_hover.stylebox new file mode 100644 index 0000000..778b04e Binary files /dev/null and b/addons/curved_lines_2d/external_video_button_hover.stylebox differ diff --git a/addons/curved_lines_2d/geometry_2d_util.gd b/addons/curved_lines_2d/geometry_2d_util.gd new file mode 100644 index 0000000..61adf34 --- /dev/null +++ b/addons/curved_lines_2d/geometry_2d_util.gd @@ -0,0 +1,228 @@ +@tool +extends Object +class_name Geometry2DUtil + +const THRESHOLD = 0.1 + +static func get_polygon_bounding_rect(points : PackedVector2Array) -> Rect2: + var minx := INF + var miny := INF + var maxx := -INF + var maxy := -INF + for p : Vector2 in points: + minx = p.x if p.x < minx else minx + miny = p.y if p.y < miny else miny + maxx = p.x if p.x > maxx else maxx + maxy = p.y if p.y > maxy else maxy + return Rect2(minx, miny, maxx - minx, maxy - miny) + + +static func get_polygon_center(points : PackedVector2Array) -> Vector2: + return get_polygon_bounding_rect(points).get_center() + + +static func slice_polygon_vertical(polygon : PackedVector2Array, slice_target : Vector2) -> Array[PackedVector2Array]: + var box := get_polygon_bounding_rect(polygon).grow(1.0) + if not box.has_point(slice_target): + return [polygon] + return Geometry2D.intersect_polygons([ + box.position, + Vector2(slice_target.x, box.position.y), + Vector2(slice_target.x, box.position.y + box.size.y), + Vector2(box.position.x, box.position.y + box.size.y), + ], polygon) + Geometry2D.intersect_polygons([ + Vector2(slice_target.x, box.position.y), + Vector2(box.position.x + box.size.x, box.position.y), + box.position + box.size, + Vector2(slice_target.x, box.position.y + box.size.y), + ], polygon) + + +static func apply_polygon_bool_operation_in_place( + current_polygons : Array[PackedVector2Array], + other_polygons : Array[PackedVector2Array], + operation : Geometry2D.PolyBooleanOperation) -> Array[PackedVector2Array]: + var holes : Array[PackedVector2Array] = [] + for other_poly in other_polygons: + var result_polygons : Array[PackedVector2Array] = [] + for current_points : PackedVector2Array in current_polygons: + if other_poly == current_points: + continue + var result = ( + Geometry2D.merge_polygons(current_points, other_poly) + if operation == Geometry2D.PolyBooleanOperation.OPERATION_UNION else + Geometry2D.intersect_polygons(current_points, other_poly) + if operation == Geometry2D.PolyBooleanOperation.OPERATION_INTERSECTION else + Geometry2D.clip_polygons(current_points, other_poly) + ) + for poly_points in result: + if Geometry2D.is_polygon_clockwise(poly_points): + holes.append(poly_points) + else: + result_polygons.append(poly_points) + current_polygons.clear() + current_polygons.append_array(result_polygons) + return holes + +## TODO: document +static func apply_clips_to_polygon( + current_polygons : Array[PackedVector2Array], + clips : Array[PackedVector2Array], + operation : Geometry2D.PolyBooleanOperation) -> Array[PackedVector2Array]: + var holes := apply_polygon_bool_operation_in_place( + current_polygons, clips, operation + ) + if not holes.is_empty(): + slice_polygons_with_holes(current_polygons, holes) + return current_polygons + + +static func slice_polygons_with_holes(current_polygons : Array[PackedVector2Array], holes : Array[PackedVector2Array]) -> void: + var result_polygons : Array[PackedVector2Array] = [] + for hole in holes: + for current_points : PackedVector2Array in current_polygons: + var slices := slice_polygon_vertical( + current_points, get_polygon_center(hole) + ) + for slice in slices: + var result = Geometry2D.clip_polygons(slice, hole) + for poly_points in result: + if not Geometry2D.is_polygon_clockwise(poly_points): + result_polygons.append(poly_points) + current_polygons.clear() + current_polygons.append_array(result_polygons) + result_polygons.clear() + + + +static func calculate_outlines(result : Array[PackedVector2Array]) -> Array[PackedVector2Array]: + if result.size() <= 1: + return result + var succesful_merges := true + var guard = 0 + var holes : Array[PackedVector2Array] = [] + while succesful_merges and result.size() > 1 and guard < 1000: + succesful_merges = false + guard += 1 + var indices_to_be_removed : Dictionary[int, bool] = {} + var merged_to_be_appended : Array[PackedVector2Array] = [] + + for current_poly_idx in result.size(): + if current_poly_idx in indices_to_be_removed: + continue + for other_poly_idx in result.size(): + if current_poly_idx == other_poly_idx or other_poly_idx in indices_to_be_removed: + continue + var merge_result := Geometry2D.merge_polygons( + result[current_poly_idx], result[other_poly_idx]) + var regular := merge_result.filter(func(x): return not Geometry2D.is_polygon_clockwise(x)) + var clockwise := merge_result.filter(Geometry2D.is_polygon_clockwise) + if regular.size() == 1: + succesful_merges = true + indices_to_be_removed[current_poly_idx] = true + indices_to_be_removed[other_poly_idx] = true + merged_to_be_appended.append(regular[0]) + holes.append_array(clockwise) + var sorted_indices = indices_to_be_removed.keys() + sorted_indices.sort() + sorted_indices.reverse() + for idx in sorted_indices: + result.remove_at(idx) + result.append_array(merged_to_be_appended) + return result + holes + + +static func calculate_polystroke(outline : PackedVector2Array, stroke_width : float, + end_mode : Geometry2D.PolyEndType, joint_mode : Geometry2D.PolyJoinType) -> Array[PackedVector2Array]: + if outline.is_empty(): + return [] + var poly_strokes := Geometry2D.offset_polyline(outline, stroke_width, joint_mode, end_mode) + var result_poly_strokes := Array(poly_strokes.filter(func(ps): return not Geometry2D.is_polygon_clockwise(ps)), TYPE_PACKED_VECTOR2_ARRAY, "", null) + var result_poly_holes := Array(poly_strokes.filter(Geometry2D.is_polygon_clockwise), TYPE_PACKED_VECTOR2_ARRAY, "", null) + if not result_poly_holes.is_empty(): + slice_polygons_with_holes(result_poly_strokes, result_poly_holes) + return result_poly_strokes + + +static func get_polygon_indices(polygons : Array[PackedVector2Array], indices : Array) -> PackedVector2Array: + var result : PackedVector2Array = [] + var p_count = 0 + indices.clear() + for poly_points in polygons: + var p_range := range(p_count, poly_points.size() + p_count) + result.append_array(poly_points) + indices.append(p_range) + p_count += poly_points.size() + return result + + +static func is_point_on_segment(p : Vector2, s1 : Vector2, s2: Vector2) -> bool: + return Geometry2D.segment_intersects_circle(s1, s2, p, 0.01) > -1 + + +static func get_progress_ratio_for_point_on_curve(p : Vector2, c : Curve2D, max_stages := 5, + tolerance_degrees := 4.0) -> float: + # Heuristic to find progress_ratio of cpc + var d := 0.0 + var pts := c.tessellate(max_stages, tolerance_degrees) + var p1 := pts[0] + for i in range(1, pts.size()): + if Geometry2DUtil.is_point_on_segment(p, p1, pts[i]): + d += p1.distance_to(p) + break + d += p1.distance_to(pts[i]) + p1 = pts[i] + return d / c.get_baked_length() + + +static func get_halfway_point_on_bezier(c : Curve2D, max_stages := 5, tolerance_degrees := 4.0) -> Vector2: + var pts := c.tessellate(max_stages, tolerance_degrees) + var tot_d := c.get_baked_length() + var d := 0.0 + var p1 := pts[0] + for i in range(1, pts.size()): + var prev_d := d + d += p1.distance_to(pts[i]) + if d >= tot_d * 0.5: + var d_ratio := 0.5 - (prev_d / tot_d) if prev_d > 0.0 else 0.5 + var d_abs := tot_d * d_ratio + return pts[i-1] + pts[i-1].direction_to(pts[i]) * d_abs + p1 = pts[i] + return Vector2.ZERO + + +# Adapted from: https://stackoverflow.com/a/8405756/1081548 +static func slice_bezier(p1: Vector2, cp2 : Vector2, cp3 : Vector2, p4 : Vector2, + t : float) -> Curve2D: + var x1 := p1.x + var y1 := p1.y + var x2 := x1 + cp2.x + var y2 := y1 + cp2.y + var x4 := p4.x + var y4 := p4.y + var x3 := x4 + cp3.x + var y3 := y4 + cp3.y + + var x12 := (x2-x1)*t+x1 + var y12 = (y2-y1)*t+y1 + var x23 = (x3-x2)*t+x2 + var y23 = (y3-y2)*t+y2 + var x34 = (x4-x3)*t+x3 + var y34 = (y4-y3)*t+y3 + var x123 = (x23-x12)*t+x12 + var y123 = (y23-y12)*t+y12 + var x234 = (x34-x23)*t+x23 + var y234 = (y34-y23)*t+y23 + var x1234 = (x234-x123)*t+x123 + var y1234 = (y234-y123)*t+y123 + var sliced_curve := Curve2D.new() + sliced_curve.add_point(Vector2(x1, y1)) + sliced_curve.add_point(Vector2(x1234, y1234)) + sliced_curve.add_point(Vector2(x4, y4)) + + sliced_curve.set_point_out(0, Vector2(x12, y12) - sliced_curve.get_point_position(0)) + sliced_curve.set_point_in(1, Vector2(x123, y123) - sliced_curve.get_point_position(1)) + sliced_curve.set_point_out(1, Vector2(x234, y234) - sliced_curve.get_point_position(1)) + sliced_curve.set_point_in(2, Vector2(x34, y34) - sliced_curve.get_point_position(2)) + + return sliced_curve diff --git a/addons/curved_lines_2d/geometry_2d_util.gd.uid b/addons/curved_lines_2d/geometry_2d_util.gd.uid new file mode 100644 index 0000000..dd5d2e3 --- /dev/null +++ b/addons/curved_lines_2d/geometry_2d_util.gd.uid @@ -0,0 +1 @@ +uid://xxcxayuo68rs diff --git a/addons/curved_lines_2d/gui_debug_util.gd b/addons/curved_lines_2d/gui_debug_util.gd new file mode 100644 index 0000000..fd8db76 --- /dev/null +++ b/addons/curved_lines_2d/gui_debug_util.gd @@ -0,0 +1,13 @@ +@tool +extends Object + +class_name GUIDebugUtil + +## Will print the tree (use with care, because your plugin will probably not be forward compatible across versions) +static func dump_interface(n : Node, max_d : int = 2, d : int = 0) -> void: + if n.name.contains("Dialog") or n.name.contains("Popup"): + return + print(n.name.lpad(d + n.name.length(), "-") + " (%d)" % [n.get_child_count()]) + for c in n.get_children(): + if d < max_d: + dump_interface(c, max_d, d + 1) diff --git a/addons/curved_lines_2d/gui_debug_util.gd.uid b/addons/curved_lines_2d/gui_debug_util.gd.uid new file mode 100644 index 0000000..bc882f9 --- /dev/null +++ b/addons/curved_lines_2d/gui_debug_util.gd.uid @@ -0,0 +1 @@ +uid://clmtno0e5m2u5 diff --git a/addons/curved_lines_2d/info_label_settings.tres b/addons/curved_lines_2d/info_label_settings.tres new file mode 100644 index 0000000..be75d27 --- /dev/null +++ b/addons/curved_lines_2d/info_label_settings.tres @@ -0,0 +1,4 @@ +[gd_resource type="LabelSettings" format=3 uid="uid://bspk1rkq1cmhx"] + +[resource] +font_color = Color(0.886835, 0.891068, 0.89742, 1) diff --git a/addons/curved_lines_2d/keyframe_button_capable_inspector_form_base.gd b/addons/curved_lines_2d/keyframe_button_capable_inspector_form_base.gd new file mode 100644 index 0000000..f6fb347 --- /dev/null +++ b/addons/curved_lines_2d/keyframe_button_capable_inspector_form_base.gd @@ -0,0 +1,155 @@ +@tool +extends Control + +class_name KeyframeButtonCapableInspectorFormBase + +var animation_player_editor : Control +var animation_under_edit_button : OptionButton +var animation_postion_spinbox : SpinBox + +func _initialize_keyframe_capabilities(): + animation_player_editor = EditorInterface.get_base_control().find_child("*AnimationPlayerEditor*", true, false) + if not is_instance_valid(animation_player_editor): + # Fallback locator for Godot 4.6-stable (and later?) + var editor_bottom_panel = EditorInterface.get_base_control().find_child("*EditorBottomPanel*", true, false) + animation_player_editor = editor_bottom_panel.find_child("Animation", true, false) + + if is_instance_valid(animation_player_editor): + animation_under_edit_button = animation_player_editor.find_child("*OptionButton*", true, false) + animation_postion_spinbox = animation_player_editor.find_child("*SpinBox*", true, false) + animation_player_editor.visibility_changed.connect(_on_key_frame_capabilities_changed) + if is_instance_valid(animation_under_edit_button): + animation_under_edit_button.item_selected.connect(func(_sid): _on_key_frame_capabilities_changed) + _on_key_frame_capabilities_changed() + + +func _on_key_frame_capabilities_changed(): + printerr("_on_key_frame_capabilities_changed should be overridden") + + +func _is_key_frame_capable() -> bool: + if not is_instance_valid(animation_player_editor): + return false + if not is_instance_valid(animation_under_edit_button): + return false + if animation_under_edit_button.get_selected_id() < 0: + return false + if not animation_player_editor.visible: + return false + if not _find_animation_player( + animation_under_edit_button.get_item_text(animation_under_edit_button.get_selected_id())): + return false + return true + + +func _find_animation_player(with_anim_name : String) -> AnimationPlayer: + for n in EditorInterface.get_edited_scene_root().find_children("*", "AnimationPlayer", true): + if (n is AnimationPlayer and (n as AnimationPlayer).has_animation(with_anim_name) + and n.owner == EditorInterface.get_edited_scene_root()): + return n + return null + + +func _guarded_get_path_to_node(animation_player : AnimationPlayer, node : Node) -> String: + var root_node := animation_player.get_node(animation_player.root_node) + if not is_instance_valid(root_node): + printerr("Could not find root node for %s by path: %s" % [str(animation_player), animation_player.root_node]) + return "" + var path_to_node = root_node.get_path_to(node) + if path_to_node.is_empty(): + printerr("Could not find a path from AnimationPlayer's root node (%s) to this node (%s)" % [ + animation_player.root_node, str(node)]) + return "" + return path_to_node + + +func _guarded_get_animation(animation_player : AnimationPlayer) -> Animation: + if not is_instance_valid(animation_player): + return null + if not is_instance_valid(animation_under_edit_button): + return null + var selected_anim_id := animation_under_edit_button.get_selected_id() + var selected_anim_name := "" + if selected_anim_id < 0: + return null + else: + selected_anim_name = animation_under_edit_button.get_item_text(selected_anim_id) + if not animation_player.has_animation(selected_anim_name): + printerr("Could not find animation %s in in %s" % [selected_anim_name, str(animation_player)]) + return null + return animation_player.get_animation(selected_anim_name) + + +func _guarded_get_track_position() -> float: + if is_instance_valid(animation_postion_spinbox): + return animation_postion_spinbox.value + return 0.0 + + +func add_key_frame(node : Node, property_path : String, val : Variant): + var animation_name := animation_under_edit_button.get_item_text(animation_under_edit_button.get_selected_id()) + var animation_player := _find_animation_player(animation_name) + var track_position := _guarded_get_track_position() + var animation := _guarded_get_animation(animation_player) + var path_to_node := _guarded_get_path_to_node(animation_player, node) + if not animation: + return + if path_to_node.is_empty(): + return + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Add key frame on %s of %s" % [property_path, str(node)]) + _add_key_frame(undo_redo, animation, NodePath("%s:%s" % [path_to_node, property_path]), + track_position, val) + undo_redo.commit_action() + + +func _add_key_frame(undo_redo : EditorUndoRedoManager, animation : Animation, node_path : NodePath, + track_position : float, val : Variant): + undo_redo.add_do_reference(animation) + var t_idx := animation.find_track(node_path, Animation.TrackType.TYPE_VALUE) + if t_idx < 0: + undo_redo.add_do_method(self, 'add_anim_track_if_absent', animation, node_path) + undo_redo.add_undo_method(self, 'remove_anim_track_by_path', animation, node_path) + + undo_redo.add_do_method(self, 'add_key_to_anim_track_by_path', animation, node_path, + track_position, val) + + var k_idx := animation.track_find_key(t_idx, track_position) if t_idx > -1 else -1 + if k_idx < 0: + undo_redo.add_undo_method(self, 'remove_key_from_anim_track_by_path_and_position', animation, + node_path, track_position) + else: + undo_redo.add_undo_method(self, 'add_key_to_anim_track_by_path', animation, node_path, + track_position, animation.track_get_key_value(t_idx, k_idx)) + + +func remove_key_from_anim_track_by_path_and_position(animation : Animation, node_path : NodePath, + track_position : float): + var t_idx := animation.find_track(node_path, Animation.TrackType.TYPE_VALUE) + if t_idx < 0: + return + var k_idx := animation.track_find_key(t_idx, track_position) + if k_idx < 0: + return + animation.track_remove_key(t_idx, k_idx) + + +func add_key_to_anim_track_by_path(animation : Animation, node_path : NodePath, + track_position : float, val : Variant): + var t_idx := animation.find_track(node_path, Animation.TrackType.TYPE_VALUE) + if t_idx < 0: + return + animation.track_insert_key(t_idx, track_position, val) + + +func add_anim_track_if_absent(animation : Animation, node_path : NodePath): + var t_idx := animation.find_track(node_path, Animation.TrackType.TYPE_VALUE) + if t_idx < 0: + t_idx = animation.add_track(Animation.TrackType.TYPE_VALUE) + animation.track_set_path(t_idx, node_path) + + +func remove_anim_track_by_path(animation : Animation, node_path : NodePath) -> void: + var t_idx := animation.find_track(node_path, Animation.TrackType.TYPE_VALUE) + if t_idx > -1: + animation.remove_track(t_idx) diff --git a/addons/curved_lines_2d/keyframe_button_capable_inspector_form_base.gd.uid b/addons/curved_lines_2d/keyframe_button_capable_inspector_form_base.gd.uid new file mode 100644 index 0000000..46c6c5d --- /dev/null +++ b/addons/curved_lines_2d/keyframe_button_capable_inspector_form_base.gd.uid @@ -0,0 +1 @@ +uid://b4n1llm1c7x7r diff --git a/addons/curved_lines_2d/line_2d_generator_inspector_plugin.gd b/addons/curved_lines_2d/line_2d_generator_inspector_plugin.gd new file mode 100644 index 0000000..f16eb47 --- /dev/null +++ b/addons/curved_lines_2d/line_2d_generator_inspector_plugin.gd @@ -0,0 +1,396 @@ +@tool +extends EditorInspectorPlugin + +class_name Line2DGeneratorInspectorPlugin + +const GROUP_NAME_CURVE_SETTINGS := "Curve settings" +const GROUP_NAME_EXPORT_OPTIONS := "Export Options" + +var LineCapEditor = preload("res://addons/curved_lines_2d/line_cap_editor_property.gd") +var LineJointModeEditor = preload("res://addons/curved_lines_2d/line_joint_editor_property.gd") + +func _can_handle(obj) -> bool: + return ( + obj is DrawablePath2D or + obj is ScalableVectorShape2D or + obj is AdaptableVectorShape3D or + obj is TextureRect or + obj is Button or + obj is TextureButton + ) + + +func _parse_begin(object: Object) -> void: + if object is DrawablePath2D: + var warning_label := Label.new() + warning_label.text = "⚠️ DrawablePath2D is Deprecated" + add_custom_control(warning_label) + var button : Button = Button.new() + button.text = "Convert to ScalableVectorShape2D" + add_custom_control(button) + button.pressed.connect(func(): _on_convert_button_pressed(object)) + if object is ScalableVectorShape2D and object.shape_type != ScalableVectorShape2D.ShapeType.PATH: + var button : Button = Button.new() + button.text = "Convert to Path*" + button.tooltip_text = "Pressing this button will change the way it is edited to Path mode." + add_custom_control(button) + button.pressed.connect(func(): _on_convert_to_path_button_pressed(object, button)) + + +func _parse_group(object: Object, group: String) -> void: + if group == GROUP_NAME_CURVE_SETTINGS and object is ScalableVectorShape2D: + var key_frame_form = load("res://addons/curved_lines_2d/batch_insert_curve_point_key_frames_inspector_form.tscn").instantiate() + key_frame_form.scalable_vector_shape_2d = object + add_custom_control(key_frame_form) + elif group == GROUP_NAME_EXPORT_OPTIONS and object is ScalableVectorShape2D: + var box := VBoxContainer.new() + var export_png_button : Button = Button.new() + export_png_button.text = "Export as PNG*" + export_png_button.tooltip_text = "The export will only contain this node and its children, + assigned nodes outside this subtree will not be drawn." + var bake_button : Button = Button.new() + bake_button.text = "Export as baked scene*" + bake_button.tooltip_text = "The export will only contain this node and its children, + assigned nodes outside this subtree will not be drawn.\n + ⚠️ Warning: An exported AnimationPlayer will not support animated curves" + var export_3d_scene_button := Button.new() + export_3d_scene_button.text = "Export 3D scene*" + export_3d_scene_button.tooltip_text = "This export uses CSGPolygon3D\n + ⚠️ Warning: AnimationPlayer will be ignored for export, to animate curves, use the 'path_changed' or 'polygons_updated' signal (advanced)" + box.add_theme_constant_override("separation", 5) + box.add_spacer(true) + box.add_child(export_png_button) + box.add_child(bake_button) + box.add_child(export_3d_scene_button) + box.add_spacer(false) + add_custom_control(box) + export_png_button.pressed.connect(func(): _on_export_png_button_pressed(object)) + bake_button.pressed.connect(func(): _show_exported_scene_dialog(object, _export_baked_scene)) + export_3d_scene_button.pressed.connect(func(): _show_exported_scene_dialog(object, _export_3d_scene)) + + +func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool: + if name == "line" and (object is ScalableVectorShape2D): + var assign_stroke_inspector_form = load("res://addons/curved_lines_2d/assign_stroke_inspector_form.tscn").instantiate() + assign_stroke_inspector_form.scalable_vector_shape_2d = object + add_custom_control(assign_stroke_inspector_form) + elif name == "polygon" and (object is ScalableVectorShape2D): + var assign_fill_inspector_form = load("res://addons/curved_lines_2d/assign_fill_inspector_form.tscn").instantiate() + assign_fill_inspector_form.scalable_vector_shape_2d = object + add_custom_control(assign_fill_inspector_form) + elif name == "collision_polygon" and (object is ScalableVectorShape2D): + #if object.collision_polygon == null: + #return true + var assign_collision_inspector_form = load("res://addons/curved_lines_2d/assign_collision_inspector_form.tscn").instantiate() + assign_collision_inspector_form.scalable_vector_shape_2d = object + add_custom_control(assign_collision_inspector_form) + elif name == "collision_object" and (object is ScalableVectorShape2D): + var assign_collision_inspector_form = load("res://addons/curved_lines_2d/assign_collision_object_inspector_form.tscn").instantiate() + assign_collision_inspector_form.scalable_vector_shape_2d = object + add_custom_control(assign_collision_inspector_form) + elif name == "navigation_region" and (object is ScalableVectorShape2D): + var assign_nav_form = load("res://addons/curved_lines_2d/assign_navigation_region_inspector_form.tscn").instantiate() + assign_nav_form.scalable_vector_shape_2d = object as ScalableVectorShape2D + add_custom_control(assign_nav_form) + elif name == "show_export_options" and (object is ScalableVectorShape2D): + return true + elif (name == "begin_cap_mode" or name == "end_cap_mode") and (object is ScalableVectorShape2D): + add_property_editor(name, LineCapEditor.new()) + return true + elif name == "line_joint_mode" and (object is ScalableVectorShape2D): + add_property_editor(name, LineJointModeEditor.new()) + return true + elif name == "guide_svs" and object is AdaptableVectorShape3D: + if object.has_meta(AdaptableVectorShape3D.STORED_CURVE_META_NAME) and object.guide_svs == null: + var button := Button.new() + button.text = "Add 2D Shape Editor" + add_custom_control(button) + button.pressed.connect(func(): _add_guide_svs(object)) + return true + elif object is TextureRect or object is Button or object is TextureButton: + var svg_texture_helpers : Array[Node] = ( + object.get_children().filter(func(ch): return ch is SVGTextureHelper) + ) + if name in svg_texture_helpers.map(func(x): return x.target_property): + var helper = svg_texture_helpers.filter(func(x): return x.target_property == name).pop_back() + var box = VBoxContainer.new() + var button := Button.new() + button.text = name.replace("texture_", "").to_pascal_case() + button.tooltip_text = '''Select a new SVG file as a texture. Remove the SVGTextureHelper + child node of this node to set a texture the godot way again.''' + button.alignment = HORIZONTAL_ALIGNMENT_LEFT + button.icon = object.get(name) + button.expand_icon = true + button.custom_minimum_size.y = 48 + box.add_spacer(true) + box.add_child(button) + button.pressed.connect(func(): _on_change_svg_helper_pressed(object, helper, name)) + add_custom_control(box) + return true + elif hint_string == "Texture2D": + var box = VBoxContainer.new() + var button := Button.new() + button.text = "Set Scalable SVG Texture*" + button.tooltip_text = '''Pressing this button will create + an SVGTextureHelper child node, which then manages an auto- + scaling texture based on an SVG file.''' + box.add_spacer(true) + box.add_child(button) + button.pressed.connect(func(): _on_add_svg_helper_pressed(object, name, button)) + add_custom_control(box) + return false + if svg_texture_helpers.size() > 0 and ( + name == "expand_mode" or #name == "stretch_mode" or + name == "expand_icon" or name == "ignore_texture_size" + ): + return true + return false + + +func _on_convert_button_pressed(orig : DrawablePath2D): + var replacement := ScalableVectorShape2D.new() + replacement.transform = orig.transform + replacement.tolerance_degrees = orig.tolerance_degrees + replacement.max_stages = orig.max_stages + replacement.lock_assigned_shapes = orig.lock_assigned_shapes + replacement.update_curve_at_runtime = orig.update_curve_at_runtime + if orig.curve: + replacement.curve = orig.curve + if is_instance_valid(orig.line): + replacement.line = orig.line + if is_instance_valid(orig.polygon): + replacement.polygon = orig.polygon + if is_instance_valid(orig.collision_polygon): + replacement.collision_polygon = orig.collision_polygon + orig.replace_by(replacement, true) + replacement.name = "ScalableVectorShape2D" if orig.name == "DrawablePath2D" else orig.name + EditorInterface.call_deferred('edit_node', replacement) + + +func _on_convert_to_path_button_pressed(svs : ScalableVectorShape2D, button : Button): + var undo_redo := EditorInterface.get_editor_undo_redo() + undo_redo.create_action("Change shape type to path for %s" % str(svs)) + undo_redo.add_do_property(svs, 'shape_type', ScalableVectorShape2D.ShapeType.PATH) + undo_redo.add_undo_property(svs, 'shape_type', svs.shape_type) + undo_redo.add_undo_property(svs, 'size', svs.size) + undo_redo.add_undo_property(svs, 'rx', svs.rx) + undo_redo.add_undo_property(svs, 'ry', svs.ry) + undo_redo.add_undo_property(svs, 'offset', svs.offset) + undo_redo.commit_action() + button.hide() + + +func _on_change_svg_helper_pressed(parent_control : Control, helper : SVGTextureHelper, target_property : String): + var dialog := EditorFileDialog.new() + dialog.add_filter("*.svg", "SVG Image") + dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE + dialog.file_selected.connect(func(path): + dialog.queue_free() + helper.svg_resource.svg_file_path = path + parent_control.notify_property_list_changed() + ) + EditorInterface.get_base_control().add_child(dialog) + dialog.popup_centered(Vector2i(800, 400)) + + + +func _on_add_svg_helper_pressed(parent_control : Control, target_property : String, button : Button): + var dialog := EditorFileDialog.new() + dialog.add_filter("*.svg", "SVG Image") + dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE + dialog.file_selected.connect(func(path): + dialog.queue_free() + _add_svg_helper(path, parent_control, target_property, button)) + EditorInterface.get_base_control().add_child(dialog) + dialog.popup_centered(Vector2i(800, 400)) + + +func _add_svg_helper(file_path : String, parent_control : Control, target_property : String, button : Button): + var svg_helper := SVGTextureHelper.new() + svg_helper.name = "%sSVGTextureHelper" % target_property.to_pascal_case() + parent_control.add_child(svg_helper, true) + svg_helper.owner = parent_control.owner if parent_control.owner else parent_control + svg_helper.target_property = target_property + svg_helper.svg_resource = SVGResource.new() + svg_helper.svg_resource.svg_file_path = file_path + parent_control.notify_property_list_changed() + button.hide() + + +static func _on_export_png_button_pressed(export_root_node : Node) -> void: + var dialog := EditorFileDialog.new() + dialog.add_filter("*.png", "PNG image") + dialog.current_file = export_root_node.name.to_snake_case() + dialog.file_mode = EditorFileDialog.FILE_MODE_SAVE_FILE + dialog.file_selected.connect(func(path): _export_png(export_root_node, path, dialog)) + EditorInterface.get_base_control().add_child(dialog) + dialog.popup_centered(Vector2i(800, 400)) + + +static func _show_exported_scene_dialog(export_root_node : Node, callable : Callable) -> void: + var dialog := EditorFileDialog.new() + dialog.add_filter("*.tscn", "Scene") + dialog.current_file = export_root_node.name.to_snake_case() + dialog.file_mode = EditorFileDialog.FILE_MODE_SAVE_FILE + dialog.file_selected.connect(func(path): callable.call(export_root_node, path, dialog)) + EditorInterface.get_base_control().add_child(dialog) + dialog.popup_centered(Vector2i(800, 400)) + + +static func _export_png(export_root_node : Node, filename : String, dialog : Node) -> void: + dialog.queue_free() + var img = await SVSSceneExporter.export_image(export_root_node, {}, EditorInterface.get_base_control()) + img.save_png(filename) + EditorInterface.get_resource_filesystem().scan() + + +static func _export_3d_scene(export_root_node : Node, filepath : String, dialog : Node) -> void: + dialog.queue_free() + var new_node := Node3D.new() + new_node.name = "%s3D" % export_root_node.name + EditorInterface.get_edited_scene_root().add_child(new_node, true) + new_node.owner = EditorInterface.get_edited_scene_root() + var result := _copy_as_3d_node(export_root_node, new_node, EditorInterface.get_edited_scene_root()) + if result is Node3D: + result.rotation_degrees.x = 180.0 + for node in new_node.get_children(): + _recursive_set_owner(node, new_node, EditorInterface.get_edited_scene_root()) + var scene := PackedScene.new() + scene.pack(new_node) + ResourceSaver.save(scene, filepath, ResourceSaver.FLAG_NONE) + new_node.queue_free() + EditorInterface.open_scene_from_path(filepath) + + +func _add_guide_svs(avs_3d : AdaptableVectorShape3D) -> void: + var guide_svs := ScalableVectorShape2D.new() + guide_svs.name = "ShapeEditorScalableVectorShape2D" + guide_svs.update_curve_at_runtime = true + guide_svs.curve = avs_3d.get_meta(AdaptableVectorShape3D.STORED_CURVE_META_NAME) + guide_svs.arc_list = avs_3d.get_meta(AdaptableVectorShape3D.STORED_ARC_LIST_META_NAME) + guide_svs.shape_type = avs_3d.get_meta(AdaptableVectorShape3D.STORED_SHAPE_TYPE_META_NAME) + guide_svs.size = avs_3d.get_meta(AdaptableVectorShape3D.STORED_SIZE_META_NAME) + guide_svs.offset = avs_3d.get_meta(AdaptableVectorShape3D.STORED_OFFSET_META_NAME) + guide_svs.stroke_width = avs_3d.get_meta(AdaptableVectorShape3D.STORED_STROKE_WIDTH_META_NAME) + guide_svs.begin_cap_mode = avs_3d.get_meta(AdaptableVectorShape3D.STORED_LINE_CAP_META_NAME) + guide_svs.line_joint_mode = avs_3d.get_meta(AdaptableVectorShape3D.STORED_JOINT_MODE_META_NAME) + guide_svs.rx = avs_3d.get_meta(AdaptableVectorShape3D.STORED_RX_META_NAME) + guide_svs.ry = avs_3d.get_meta(AdaptableVectorShape3D.STORED_RY_META_NAME) + avs_3d.add_child(guide_svs, true) + guide_svs.owner = avs_3d.owner + + if not avs_3d.fill_polygons.is_empty(): + guide_svs.polygon = Polygon2D.new() + guide_svs.polygon.name = avs_3d.fill_polygons[0].name + guide_svs.add_child(guide_svs.polygon, true) + guide_svs.polygon.owner = avs_3d.owner + guide_svs.polygon.color = avs_3d.fill_polygons[0].material.albedo_color + guide_svs.polygon.texture = avs_3d.fill_polygons[0].material.albedo_texture + if not avs_3d.stroke_polygons.is_empty(): + guide_svs.poly_stroke = Polygon2D.new() + guide_svs.poly_stroke.name = avs_3d.stroke_polygons[0].name + guide_svs.add_child(guide_svs.poly_stroke, true) + guide_svs.poly_stroke.owner = avs_3d.owner + guide_svs.stroke_color = avs_3d.stroke_polygons[0].material.albedo_color + guide_svs.poly_stroke.texture = avs_3d.stroke_polygons[0].material.albedo_texture + avs_3d.guide_svs = guide_svs + + +static func _copy_as_3d_node(src_node : Node, dst_parent : Node, dst_owner : Node, node_depth := 0, render_depth := 0) -> Node: + if (src_node is Polygon2D or src_node is Line2D) and src_node.get_child_count() == 0: + return null + var dst_node : Node = ( + AdaptableVectorShape3D.new() if src_node is ScalableVectorShape2D else + Node3D.new() if src_node is Node2D else Node.new() + ) + dst_node.name = src_node.name + dst_parent.add_child(dst_node, true) + if dst_node is Node3D: + dst_node.transform = src_node.transform + dst_node.position.z = -(node_depth + render_depth) * 0.02 + if src_node is ScalableVectorShape2D and src_node.is_visible_in_tree(): + dst_node.set_meta(AdaptableVectorShape3D.STORED_CURVE_META_NAME, src_node.curve.duplicate()) + dst_node.set_meta(AdaptableVectorShape3D.STORED_ARC_LIST_META_NAME, src_node.arc_list.duplicate(true)) + dst_node.set_meta(AdaptableVectorShape3D.STORED_SHAPE_TYPE_META_NAME, src_node.shape_type) + dst_node.set_meta(AdaptableVectorShape3D.STORED_SIZE_META_NAME, src_node.size) + dst_node.set_meta(AdaptableVectorShape3D.STORED_OFFSET_META_NAME, src_node.offset) + dst_node.set_meta(AdaptableVectorShape3D.STORED_STROKE_WIDTH_META_NAME, src_node.stroke_width) + dst_node.set_meta(AdaptableVectorShape3D.STORED_RX_META_NAME, src_node.rx) + dst_node.set_meta(AdaptableVectorShape3D.STORED_RY_META_NAME, src_node.ry) + dst_node.set_meta(AdaptableVectorShape3D.STORED_LINE_CAP_META_NAME, src_node.begin_cap_mode) + dst_node.set_meta(AdaptableVectorShape3D.STORED_JOINT_MODE_META_NAME, src_node.line_joint_mode) + + var has_valid_stroke : bool = ( + is_instance_valid(src_node.line) or is_instance_valid(src_node.poly_stroke) + ) and src_node.stroke_width > 0.0 + if is_instance_valid(src_node.polygon): + var target_z_index := 1 + if has_valid_stroke and not AdaptableVectorShape3D.is_stroke_in_front_of_fill(src_node): + target_z_index = 0 + for csg_polygon in AdaptableVectorShape3D.extract_csg_polygons_from_scalable_vector_shapes( + src_node, false, false, target_z_index): + dst_node.add_child(csg_polygon, true) + dst_node.fill_polygons.append(csg_polygon) + csg_polygon.owner = dst_owner + if has_valid_stroke: + for csg_polygon in AdaptableVectorShape3D.extract_csg_polygons_from_scalable_vector_shapes( + src_node, true, is_instance_valid(src_node.line), + (0 if AdaptableVectorShape3D.is_stroke_in_front_of_fill(src_node) else 1) + ): + dst_node.add_child(csg_polygon, true) + dst_node.stroke_polygons.append(csg_polygon) + csg_polygon.owner = dst_owner + + dst_node.owner = dst_owner + render_depth = node_depth + for ch in src_node.get_children().filter(func(ch): return ch != dst_parent): + render_depth += 1 + var result := _copy_as_3d_node(ch, dst_node, dst_owner, node_depth + 1, render_depth) + return dst_node + + +static func _export_baked_scene(export_root_node : Node, filepath : String, dialog : Node) -> void: + dialog.queue_free() + var new_node := Node2D.new() + EditorInterface.get_edited_scene_root().add_child(new_node) + new_node.owner = EditorInterface.get_edited_scene_root() + var result := _copy_baked_node(export_root_node, new_node, EditorInterface.get_edited_scene_root()) + result.transform = Transform2D.IDENTITY + for node in result.get_children(): + _recursive_set_owner(node, result, EditorInterface.get_edited_scene_root()) + var scene := PackedScene.new() + scene.pack(result) + ResourceSaver.save(scene, filepath, ResourceSaver.FLAG_NONE) + new_node.queue_free() + EditorInterface.open_scene_from_path(filepath) + + +static func _copy_baked_node(src_node : Node, dst_parent : Node, dst_owner : Node) -> Node: + if src_node is ScalableVectorShape2D and src_node.get_children().is_empty(): + return null + var dst_node : Node = ( + Node2D.new() if src_node is ScalableVectorShape2D else + ClassDB.instantiate(src_node.get_class()) + ) + dst_parent.add_child(dst_node) + + for prop in src_node.get_property_list(): + if prop.name == "owner": + continue + if src_node is ScalableVectorShape2D and prop.name == "script": + break + if prop.name in dst_node: + dst_node.set(prop.name, src_node.get(prop.name)) + + dst_node.owner = dst_owner + for ch in src_node.get_children().filter(func(ch): return ch != dst_parent): + _copy_baked_node(ch, dst_node, dst_owner) + return dst_node + + +static func _recursive_set_owner(node : Node, new_owner : Node, root : Node): + if node.owner != root: + return + node.set_owner(new_owner) + for child in node.get_children(): + _recursive_set_owner(child, new_owner, root) diff --git a/addons/curved_lines_2d/line_2d_generator_inspector_plugin.gd.uid b/addons/curved_lines_2d/line_2d_generator_inspector_plugin.gd.uid new file mode 100644 index 0000000..c84e8f0 --- /dev/null +++ b/addons/curved_lines_2d/line_2d_generator_inspector_plugin.gd.uid @@ -0,0 +1 @@ +uid://5cl8wfdpwb2d diff --git a/addons/curved_lines_2d/line_cap_editor_property.gd b/addons/curved_lines_2d/line_cap_editor_property.gd new file mode 100644 index 0000000..d0d372c --- /dev/null +++ b/addons/curved_lines_2d/line_cap_editor_property.gd @@ -0,0 +1,38 @@ +@tool +extends EditorProperty + +# The main control for editing the property. +var property_control : Control +# An internal value of the property. +var current_value := Line2D.LINE_CAP_NONE +# A guard against internal changes when the property is updated. +var updating = false + +func _init(): + property_control = load("res://addons/curved_lines_2d/line_cap_toggle_buttons.tscn").instantiate() + # Add the control as a direct child of EditorProperty node. + add_child(property_control) + # Make sure the control is able to retain the focus. + add_focusable(property_control) + # Setup the initial state and connect to the signal to track changes. + property_control.changed.connect(_on_changed) + + +func _on_changed(cap : Line2D.LineCapMode) -> void: + if updating: + return + current_value = cap + emit_changed(get_edited_property(), current_value) + + +func _update_property() -> void: + # Read the current value from the property. + var new_value = get_edited_object()[get_edited_property()] + if new_value == current_value: + return + + # Update the control with the new value. + updating = true + current_value = new_value + property_control.set_toggle_to(new_value) + updating = false diff --git a/addons/curved_lines_2d/line_cap_editor_property.gd.uid b/addons/curved_lines_2d/line_cap_editor_property.gd.uid new file mode 100644 index 0000000..6c6ca8b --- /dev/null +++ b/addons/curved_lines_2d/line_cap_editor_property.gd.uid @@ -0,0 +1 @@ +uid://bb7kkqme7ky4j diff --git a/addons/curved_lines_2d/line_cap_toggle_buttons.gd b/addons/curved_lines_2d/line_cap_toggle_buttons.gd new file mode 100644 index 0000000..c4fcc03 --- /dev/null +++ b/addons/curved_lines_2d/line_cap_toggle_buttons.gd @@ -0,0 +1,30 @@ +@tool +extends Control + +signal changed(cap : Line2D.LineCapMode) + + +func set_toggle_to(cap : Line2D.LineCapMode) -> void: + match cap: + Line2D.LINE_CAP_BOX: + %BoxCapToggleButton.button_pressed = true + Line2D.LINE_CAP_ROUND: + %RoundCapToggleButton.button_pressed = true + Line2D.LINE_CAP_NONE, _: + %NoCapToggleButton.button_pressed = true + + +func _on_no_cap_toggle_button_toggled(toggled_on: bool) -> void: + if toggled_on: + changed.emit(Line2D.LINE_CAP_NONE) + + +func _on_box_cap_toggle_button_toggled(toggled_on: bool) -> void: + if toggled_on: + changed.emit(Line2D.LINE_CAP_BOX) + + +func _on_round_cap_toggle_button_toggled(toggled_on: bool) -> void: + if toggled_on: + changed.emit(Line2D.LINE_CAP_ROUND) + diff --git a/addons/curved_lines_2d/line_cap_toggle_buttons.gd.uid b/addons/curved_lines_2d/line_cap_toggle_buttons.gd.uid new file mode 100644 index 0000000..3011112 --- /dev/null +++ b/addons/curved_lines_2d/line_cap_toggle_buttons.gd.uid @@ -0,0 +1 @@ +uid://cfu3r76f6aocm diff --git a/addons/curved_lines_2d/line_cap_toggle_buttons.tscn b/addons/curved_lines_2d/line_cap_toggle_buttons.tscn new file mode 100644 index 0000000..7f1c641 --- /dev/null +++ b/addons/curved_lines_2d/line_cap_toggle_buttons.tscn @@ -0,0 +1,87 @@ +[gd_scene load_steps=8 format=3 uid="uid://cx2oiwhsrb3wk"] + +[ext_resource type="Script" uid="uid://cfu3r76f6aocm" path="res://addons/curved_lines_2d/line_cap_toggle_buttons.gd" id="1_k7j3x"] +[ext_resource type="StyleBox" uid="uid://v0ueesjbdyrk" path="res://addons/curved_lines_2d/snazzy_toggle_button.stylebox" id="2_q65j6"] +[ext_resource type="Texture2D" uid="uid://cdkf2g8b5e55r" path="res://addons/curved_lines_2d/LineCaps.svg" id="3_ymr1k"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_kh00m"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_85hwe"] +atlas = ExtResource("3_ymr1k") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_nh347"] +atlas = ExtResource("3_ymr1k") +region = Rect2(64, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_exygk"] +atlas = ExtResource("3_ymr1k") +region = Rect2(32, 0, 32, 32) + +[node name="LineCapToggleButtons" type="HBoxContainer"] +size_flags_horizontal = 3 +script = ExtResource("1_k7j3x") + +[node name="NoCapToggleButton" type="Button" parent="."] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the begin_cap_mode of the assigned Line2D node to: +- Line Cap None +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_q65j6") +toggle_mode = true +button_pressed = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_kh00m") +icon = SubResource("AtlasTexture_85hwe") + +[node name="BoxCapToggleButton" type="Button" parent="."] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the begin_cap_mode of the assigned Line2D node to: +- Line Cap Box + +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_q65j6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_kh00m") +icon = SubResource("AtlasTexture_nh347") + +[node name="RoundCapToggleButton" type="Button" parent="."] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the begin_cap_mode of the assigned Line2D node to: +- Line Cap Round + +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_q65j6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_kh00m") +icon = SubResource("AtlasTexture_exygk") + +[connection signal="toggled" from="NoCapToggleButton" to="." method="_on_no_cap_toggle_button_toggled"] +[connection signal="toggled" from="BoxCapToggleButton" to="." method="_on_box_cap_toggle_button_toggled"] +[connection signal="toggled" from="RoundCapToggleButton" to="." method="_on_round_cap_toggle_button_toggled"] diff --git a/addons/curved_lines_2d/line_joint_editor_property.gd b/addons/curved_lines_2d/line_joint_editor_property.gd new file mode 100644 index 0000000..130560a --- /dev/null +++ b/addons/curved_lines_2d/line_joint_editor_property.gd @@ -0,0 +1,38 @@ +@tool +extends EditorProperty + +# The main control for editing the property. +var property_control : Control +# An internal value of the property. +var current_value := Line2D.LINE_JOINT_SHARP +# A guard against internal changes when the property is updated. +var updating = false + +func _init(): + property_control = load("res://addons/curved_lines_2d/line_joint_toggle_buttons.tscn").instantiate() + # Add the control as a direct child of EditorProperty node. + add_child(property_control) + # Make sure the control is able to retain the focus. + add_focusable(property_control) + # Setup the initial state and connect to the signal to track changes. + property_control.changed.connect(_on_changed) + + +func _on_changed(joint_mode : Line2D.LineJointMode) -> void: + if updating: + return + current_value = joint_mode + emit_changed(get_edited_property(), current_value) + + +func _update_property() -> void: + # Read the current value from the property. + var new_value = get_edited_object()[get_edited_property()] + if new_value == current_value: + return + + # Update the control with the new value. + updating = true + current_value = new_value + property_control.set_toggle_to(new_value) + updating = false diff --git a/addons/curved_lines_2d/line_joint_editor_property.gd.uid b/addons/curved_lines_2d/line_joint_editor_property.gd.uid new file mode 100644 index 0000000..a7e68b8 --- /dev/null +++ b/addons/curved_lines_2d/line_joint_editor_property.gd.uid @@ -0,0 +1 @@ +uid://btowchyl0rhaj diff --git a/addons/curved_lines_2d/line_joint_toggle_buttons.gd b/addons/curved_lines_2d/line_joint_toggle_buttons.gd new file mode 100644 index 0000000..a5b84af --- /dev/null +++ b/addons/curved_lines_2d/line_joint_toggle_buttons.gd @@ -0,0 +1,28 @@ +@tool +extends Control + +signal changed(joint_mode : Line2D.LineJointMode) + + +func set_toggle_to(joint_mode : Line2D.LineJointMode) -> void: + match joint_mode: + Line2D.LINE_JOINT_BEVEL: + %LineJointBevelToggleButton.button_pressed = true + Line2D.LINE_JOINT_ROUND: + %LineJointRoundToggleButton.button_pressed = true + Line2D.LINE_JOINT_SHARP, _: + %LineJointSharpToggleButton.button_pressed = true + + +func _on_line_joint_sharp_toggle_button_toggled(toggled_on: bool) -> void: + if toggled_on: + changed.emit(Line2D.LINE_JOINT_SHARP) + + +func _on_line_joint_round_toggle_button_toggled(toggled_on: bool) -> void: + if toggled_on: + changed.emit(Line2D.LINE_JOINT_ROUND) + +func _on_line_joint_bevel_toggle_button_toggled(toggled_on: bool) -> void: + if toggled_on: + changed.emit(Line2D.LINE_JOINT_BEVEL) diff --git a/addons/curved_lines_2d/line_joint_toggle_buttons.gd.uid b/addons/curved_lines_2d/line_joint_toggle_buttons.gd.uid new file mode 100644 index 0000000..7f131f2 --- /dev/null +++ b/addons/curved_lines_2d/line_joint_toggle_buttons.gd.uid @@ -0,0 +1 @@ +uid://d100v4j1v1mpa diff --git a/addons/curved_lines_2d/line_joint_toggle_buttons.tscn b/addons/curved_lines_2d/line_joint_toggle_buttons.tscn new file mode 100644 index 0000000..f0c5c94 --- /dev/null +++ b/addons/curved_lines_2d/line_joint_toggle_buttons.tscn @@ -0,0 +1,82 @@ +[gd_scene load_steps=8 format=3 uid="uid://b6gmekfqgre3o"] + +[ext_resource type="Script" uid="uid://d100v4j1v1mpa" path="res://addons/curved_lines_2d/line_joint_toggle_buttons.gd" id="1_jujfb"] +[ext_resource type="StyleBox" uid="uid://v0ueesjbdyrk" path="res://addons/curved_lines_2d/snazzy_toggle_button.stylebox" id="1_yalwy"] +[ext_resource type="Texture2D" uid="uid://cdkf2g8b5e55r" path="res://addons/curved_lines_2d/LineCaps.svg" id="2_jujfb"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_xku8w"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_k2toy"] +atlas = ExtResource("2_jujfb") +region = Rect2(64, 32, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_em7di"] +atlas = ExtResource("2_jujfb") +region = Rect2(0, 32, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_84wj1"] +atlas = ExtResource("2_jujfb") +region = Rect2(32, 32, 32, 32) + +[node name="LineJointToggleButtons" type="HBoxContainer"] +size_flags_horizontal = 3 +script = ExtResource("1_jujfb") + +[node name="LineJointSharpToggleButton" type="Button" parent="."] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the joint_mode of the assigned Line2D node to: +- Sharp" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("1_yalwy") +toggle_mode = true +button_pressed = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_xku8w") +icon = SubResource("AtlasTexture_k2toy") + +[node name="LineJointBevelToggleButton" type="Button" parent="."] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the joint_mode of the assigned Line2D node to: +- Bevel" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("1_yalwy") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_xku8w") +icon = SubResource("AtlasTexture_em7di") + +[node name="LineJointRoundToggleButton" type="Button" parent="."] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the joint_mode of the assigned Line2D node to: +- Round" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("1_yalwy") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_xku8w") +icon = SubResource("AtlasTexture_84wj1") + +[connection signal="toggled" from="LineJointSharpToggleButton" to="." method="_on_line_joint_sharp_toggle_button_toggled"] +[connection signal="toggled" from="LineJointBevelToggleButton" to="." method="_on_line_joint_bevel_toggle_button_toggled"] +[connection signal="toggled" from="LineJointRoundToggleButton" to="." method="_on_line_joint_round_toggle_button_toggled"] diff --git a/addons/curved_lines_2d/link_button_with_copy_hint.gd b/addons/curved_lines_2d/link_button_with_copy_hint.gd new file mode 100644 index 0000000..7535097 --- /dev/null +++ b/addons/curved_lines_2d/link_button_with_copy_hint.gd @@ -0,0 +1,26 @@ +@tool +extends LinkButton + +func _set(property: StringName, value: Variant) -> bool: + match property: + "uri": + uri = value + _update_tooltip_text() + return true + return false + + +func _enter_tree() -> void: + _update_tooltip_text() + + +func _update_tooltip_text(): + tooltip_text = "This link will open a webpage in your browser: " + uri + tooltip_text += "\nRight click to copy this link" + + +func _gui_input(event: InputEvent) -> void: + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and not Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): + DisplayServer.clipboard_set(uri) + if Engine.is_editor_hint(): + EditorInterface.get_editor_toaster().push_toast("Link copied!") diff --git a/addons/curved_lines_2d/link_button_with_copy_hint.gd.uid b/addons/curved_lines_2d/link_button_with_copy_hint.gd.uid new file mode 100644 index 0000000..add536e --- /dev/null +++ b/addons/curved_lines_2d/link_button_with_copy_hint.gd.uid @@ -0,0 +1 @@ +uid://c1dbllgwqxjjn diff --git a/addons/curved_lines_2d/link_button_with_copy_hint.tscn b/addons/curved_lines_2d/link_button_with_copy_hint.tscn new file mode 100644 index 0000000..1c33764 --- /dev/null +++ b/addons/curved_lines_2d/link_button_with_copy_hint.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=2 format=3 uid="uid://cmoxkoulpd7so"] + +[ext_resource type="Script" uid="uid://c1dbllgwqxjjn" path="res://addons/curved_lines_2d/link_button_with_copy_hint.gd" id="1_e1f1u"] + +[node name="LinkButton" type="LinkButton"] +tooltip_text = "This link will open a webpage in your browser: https://www.youtube.com/watch?v=q_NaZq1zZdY +Right click to copy this link" +theme_override_colors/font_color = Color(0.439216, 0.729412, 0.980392, 1) +text = "Watch the Basic Drawing explainer on Youtube" +uri = "https://www.youtube.com/watch?v=q_NaZq1zZdY" +script = ExtResource("1_e1f1u") +metadata/_custom_type_script = "uid://c1dbllgwqxjjn" diff --git a/addons/curved_lines_2d/play_tatra_tab.tscn b/addons/curved_lines_2d/play_tatra_tab.tscn new file mode 100644 index 0000000..a3ad680 --- /dev/null +++ b/addons/curved_lines_2d/play_tatra_tab.tscn @@ -0,0 +1,35 @@ +[gd_scene load_steps=4 format=3 uid="uid://r23wu41l5ng5"] + +[ext_resource type="PackedScene" uid="uid://bhpmwhbdlsp1g" path="res://addons/curved_lines_2d/external_video_button.tscn" id="1_xmmam"] +[ext_resource type="Texture2D" uid="uid://bp5h8cgmsys0a" path="res://addons/curved_lines_2d/video_thumbnails/tatra.png" id="2_b7w2k"] +[ext_resource type="Texture2D" uid="uid://dacelkfuv24fv" path="res://addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg" id="3_eberd"] + +[node name="PlayTatraTab" type="CenterContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +metadata/_tab_index = 5 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="ExternalVideoButton" parent="HBoxContainer" instance=ExtResource("1_xmmam")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://renevanderark.codeberg.page/tatra/ +Right click to copy this link" +img = ExtResource("2_b7w2k") +uri = "https://renevanderark.codeberg.page/tatra/" +text = "Play Tatra Online!" + +[node name="ExternalVideoButton2" parent="HBoxContainer" instance=ExtResource("1_xmmam")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra#this-is-tatra +Right click to copy this link" +img = ExtResource("3_eberd") +uri = "https://codeberg.org/renevanderark/tatra#this-is-tatra" +text = "Clone the project from Codeberg!" diff --git a/addons/curved_lines_2d/plugin.cfg b/addons/curved_lines_2d/plugin.cfg new file mode 100644 index 0000000..21f8ca7 --- /dev/null +++ b/addons/curved_lines_2d/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Scalable Vector Shapes 2D" +description="This plugin and SVG importer helps you draw 2D scalable vector shapes as Godot nodes directly in the 2D viewport." +author="René van der Ark, Mark Hedberg, Thiago Lages de Alencar and @kcfresh53" +version="2.20.1" +script="curved_lines_2d.gd" diff --git a/addons/curved_lines_2d/project_settings_tab.gd b/addons/curved_lines_2d/project_settings_tab.gd new file mode 100644 index 0000000..3a2777a --- /dev/null +++ b/addons/curved_lines_2d/project_settings_tab.gd @@ -0,0 +1,93 @@ +@tool +extends Control + +var snap_resolution_input : EditorSpinSlider +var tolerance_degrees_input : EditorSpinSlider +var max_stages_input : EditorSpinSlider + +func _enter_tree() -> void: + %EnableEditingCheckbox.button_pressed = CurvedLines2D._is_editing_enabled() + %EnableHintsCheckbox.button_pressed = CurvedLines2D._are_hints_enabled() + %EnablePointNumbersCheckbox.button_pressed = CurvedLines2D._am_showing_point_numbers() + %SnapToPixelCheckBox.button_pressed = CurvedLines2D._is_snapped_to_pixel() + %UpdateCurveAtRuntimeCheckbox.button_pressed = CurvedLines2D._is_setting_update_curve_at_runtime() + %MakeResourcesLocalToSceneCheckBox.button_pressed = CurvedLines2D._is_making_curve_resources_local_to_scene() + + snap_resolution_input = _make_number_input("Snap distance", CurvedLines2D._get_snap_resolution(), 1.0, 1024.0, "px", 1.0) + %SnapResolutionInputContainer.add_child(snap_resolution_input) + snap_resolution_input.value_changed.connect(_on_snap_resolution_value_changed) + if not snap_resolution_input.focus_exited.is_connected(ProjectSettings.save): + snap_resolution_input.focus_exited.connect(ProjectSettings.save) + + tolerance_degrees_input = _make_number_input("Tolerance Degrees", CurvedLines2D._get_default_tolerance_degrees(), 0.0, 180.0, "°", 0.5) + %ToleranceDegreesInputContainer.add_child(tolerance_degrees_input) + tolerance_degrees_input.value_changed.connect(_on_tolerance_degrees_input_changed) + if not tolerance_degrees_input.focus_exited.is_connected(ProjectSettings.save): + tolerance_degrees_input.focus_exited.connect(ProjectSettings.save) + + max_stages_input = _make_number_input("Max Stages", CurvedLines2D._get_default_max_stages(), 1, 10, "") + %MaxStagesInputContainer.add_child(max_stages_input) + max_stages_input.value_changed.connect(_on_max_stages_input_changed) + if not max_stages_input.focus_exited.is_connected(ProjectSettings.save): + max_stages_input.focus_exited.connect(ProjectSettings.save) + + %AddAntialiasedLine2DCheckbox.button_pressed = CurvedLines2D._use_antialiased_line_2d() + +func _make_number_input(lbl : String, value : float, min_value : float, max_value : float, suffix : String, step := 1.0) -> EditorSpinSlider: + var x_slider := EditorSpinSlider.new() + x_slider.value = value + x_slider.min_value = min_value + x_slider.max_value = max_value + x_slider.suffix = suffix + x_slider.label = lbl + x_slider.step = step + return x_slider + + +func _on_enable_editing_checkbox_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_EDITING_ENABLED, toggled_on) + ProjectSettings.save() + + +func _on_enable_hints_checkbox_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_HINTS_ENABLED, toggled_on) + ProjectSettings.save() + + +func _on_enable_point_numbers_checkbox_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_SHOW_POINT_NUMBERS, toggled_on) + ProjectSettings.save() + + +func _on_snap_to_pixel_check_box_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_SNAP_TO_PIXEL, + toggled_on) + ProjectSettings.save() + + +func _on_snap_resolution_value_changed(val : float) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_SNAP_RESOLUTION, val) + + +func _on_tolerance_degrees_input_changed(val : float) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_CURVE_TOLERANCE_DEGREES, val) + + +func _on_max_stages_input_changed(val : int) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_CURVE_MAX_STAGES, val) + + +func _on_update_curve_at_runtime_checkbox_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_CURVE_UPDATE_CURVE_AT_RUNTIME, toggled_on) + ProjectSettings.save() + + +func _on_make_resources_local_to_scene_check_box_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_CURVE_RESOURCE_LOCAL_TO_SCENE, toggled_on) + ProjectSettings.save() + + + +func _on_add_antialiased_line_2d_checkbox_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_ANTIALIASED_LINE_2D, toggled_on) + ProjectSettings.save() diff --git a/addons/curved_lines_2d/project_settings_tab.gd.uid b/addons/curved_lines_2d/project_settings_tab.gd.uid new file mode 100644 index 0000000..9b008a7 --- /dev/null +++ b/addons/curved_lines_2d/project_settings_tab.gd.uid @@ -0,0 +1 @@ +uid://xijifdpi2kw diff --git a/addons/curved_lines_2d/project_settings_tab.tscn b/addons/curved_lines_2d/project_settings_tab.tscn new file mode 100644 index 0000000..14ef7d6 --- /dev/null +++ b/addons/curved_lines_2d/project_settings_tab.tscn @@ -0,0 +1,149 @@ +[gd_scene load_steps=3 format=3 uid="uid://d3j2c8gduqsuu"] + +[ext_resource type="Script" uid="uid://xijifdpi2kw" path="res://addons/curved_lines_2d/project_settings_tab.gd" id="1_q4g58"] +[ext_resource type="PackedScene" uid="uid://cmoxkoulpd7so" path="res://addons/curved_lines_2d/link_button_with_copy_hint.tscn" id="2_mgx58"] + +[node name="ProjectSettingsTab" type="ScrollContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_q4g58") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 8 +metadata/_tab_index = 2 + +[node name="EditorSettingsContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 13 + +[node name="Label" type="Label" parent="VBoxContainer/EditorSettingsContainer"] +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 +tooltip_text = "Determines what settings apply to the 2D Editor Viewport." +mouse_filter = 0 +text = "Editor Settings*" + +[node name="EnableEditingCheckbox" type="CheckBox" parent="VBoxContainer/EditorSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +button_pressed = true +text = "Enable ScalableVectorShape2D Editing" + +[node name="EnableHintsCheckbox" type="CheckBox" parent="VBoxContainer/EditorSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +button_pressed = true +text = "Show Edit Hints" + +[node name="EnablePointNumbersCheckbox" type="CheckBox" parent="VBoxContainer/EditorSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "When active, when hovering over a point / handle in the curve +- shows the point number index +- shows the point (handle) position" +button_pressed = true +text = "Show Point Details*" + +[node name="SnapToPixelCheckBox" type="CheckBox" parent="VBoxContainer/EditorSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "When active, points you move will snap to whole numbers: +- this will use the snapped global_position in the scene +- .. so if any parent is not snapped to pixel, the local position of this point is also still not snapped" +text = "Snap to pixel*" + +[node name="SnapResolutionInputContainer" type="PanelContainer" parent="VBoxContainer/EditorSettingsContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(170, 0) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="CurveSettingsContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 13 + +[node name="Label" type="Label" parent="VBoxContainer/CurveSettingsContainer"] +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 +tooltip_text = "These are the default properties that will apply to the `curve : Curve2D` property of all the shapes created via this bottom dock and shortcuts: +- Create Shapes Tab +- Import SVG File Tab +- Making cutouts using Ctrl+Shift+Click" +mouse_filter = 0 +text = "Curve Settings*" + +[node name="UpdateCurveAtRuntimeCheckbox" type="CheckBox" parent="VBoxContainer/CurveSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "When toggled On, shape changes to the curve will also take effect at runtime, not only while editing. + +This needs to be flagged On for animated curves to work, but should be used with care regarding potential performance impact." +button_pressed = true +text = "Update Curve at Runtime" + +[node name="MakeResourcesLocalToSceneCheckBox" type="CheckBox" parent="VBoxContainer/CurveSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +button_pressed = true +text = "Make Curve Local to Scene" + +[node name="ToleranceDegreesInputContainer" type="PanelContainer" parent="VBoxContainer/CurveSettingsContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(170, 0) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="MaxStagesInputContainer" type="PanelContainer" parent="VBoxContainer/CurveSettingsContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(170, 0) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HSeparator3" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 13 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 +mouse_filter = 0 +text = "Extra's" + +[node name="AddAntialiasedLine2DCheckbox" type="CheckBox" parent="VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Add Line2D antialiasing texture for Compatibility mode" + +[node name="LinkButton" parent="VBoxContainer/HBoxContainer" instance=ExtResource("2_mgx58")] +layout_mode = 2 +size_flags_vertical = 4 +tooltip_text = "This link will open a webpage in your browser: https://godotengine.org/asset-library/asset/3103 +Right click to copy this link" +text = "Inspired by Calinou's Antialiased Line2D plugin" +uri = "https://godotengine.org/asset-library/asset/3103" + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[connection signal="toggled" from="VBoxContainer/EditorSettingsContainer/EnableEditingCheckbox" to="." method="_on_enable_editing_checkbox_toggled"] +[connection signal="toggled" from="VBoxContainer/EditorSettingsContainer/EnableHintsCheckbox" to="." method="_on_enable_hints_checkbox_toggled"] +[connection signal="toggled" from="VBoxContainer/EditorSettingsContainer/EnablePointNumbersCheckbox" to="." method="_on_enable_point_numbers_checkbox_toggled"] +[connection signal="toggled" from="VBoxContainer/EditorSettingsContainer/SnapToPixelCheckBox" to="." method="_on_snap_to_pixel_check_box_toggled"] +[connection signal="toggled" from="VBoxContainer/CurveSettingsContainer/UpdateCurveAtRuntimeCheckbox" to="." method="_on_update_curve_at_runtime_checkbox_toggled"] +[connection signal="toggled" from="VBoxContainer/CurveSettingsContainer/MakeResourcesLocalToSceneCheckBox" to="." method="_on_make_resources_local_to_scene_check_box_toggled"] +[connection signal="toggled" from="VBoxContainer/HBoxContainer/AddAntialiasedLine2DCheckbox" to="." method="_on_add_antialiased_line_2d_checkbox_toggled"] diff --git a/addons/curved_lines_2d/scalable_arc.gd b/addons/curved_lines_2d/scalable_arc.gd new file mode 100644 index 0000000..c329991 --- /dev/null +++ b/addons/curved_lines_2d/scalable_arc.gd @@ -0,0 +1,40 @@ +@tool +class_name ScalableArc +extends Resource + +@export var start_point : int = 0: + set(sp): + start_point = sp + emit_changed() + + +@export var radius : Vector2 = Vector2.ZERO: + set(r): + radius = r + emit_changed() + + +@export var rotation_deg : float = 0.0: + set(r): + rotation_deg = r + emit_changed() + + +@export var sweep_flag : bool = true: + set(f): + sweep_flag = f + emit_changed() + + +@export var large_arc_flag : bool = false: + set(f): + large_arc_flag = f + emit_changed() + + +func _init(sp : int = 0, r := Vector2.ZERO, rd := 0.0, lf := false, sf := true) -> void: + start_point = sp + radius = r + rotation_deg = rd + large_arc_flag = lf + sweep_flag = sf diff --git a/addons/curved_lines_2d/scalable_arc.gd.uid b/addons/curved_lines_2d/scalable_arc.gd.uid new file mode 100644 index 0000000..c72bfe9 --- /dev/null +++ b/addons/curved_lines_2d/scalable_arc.gd.uid @@ -0,0 +1 @@ +uid://dlbv4pit17dnu diff --git a/addons/curved_lines_2d/scalable_arc_list.gd b/addons/curved_lines_2d/scalable_arc_list.gd new file mode 100644 index 0000000..621f3c5 --- /dev/null +++ b/addons/curved_lines_2d/scalable_arc_list.gd @@ -0,0 +1,87 @@ +@tool +class_name ScalableArcList +extends Resource + +@export var arcs : Array[ScalableArc] = []: + set(_arcs): + arcs = _arcs + for i in arcs.size(): + if arcs[i] == null: + arcs[i] = ScalableArc.new() + emit_changed() + + +func _init(a : Array[ScalableArc] = []) -> void: + arcs = a + if not changed.is_connected(_on_changed): + changed.connect(_on_changed) + _on_changed() + + +func _get(property: StringName) -> Variant: + var components := property.split("/", true, 2) + if components.size() >= 2: + var arc_idx := components[0].trim_prefix("arc_").to_int() + if arc_idx >= arcs.size(): + return null + var arc := arcs[arc_idx] + if components[1] in arc: + return arc[components[1]] + return null + return null + + +func _set(property: StringName, value: Variant) -> bool: + var components := property.split("/", true, 2) + if components.size() >= 2: + var arc_idx := components[0].trim_prefix("arc_").to_int() + if arc_idx >= arcs.size(): + return false + var arc := arcs[arc_idx] + if components[1] in arc: + arc[components[1]] = value + return true + return false + + +func _on_changed(): + for a : ScalableArc in arcs: + if a and not a.changed.is_connected(_item_changed): + a.changed.connect(_item_changed) + + +func _item_changed(): + emit_changed() + + +func remove_arc_for_point(p_idx : int) -> void: + arcs = arcs.filter(func(a): return a.start_point != p_idx) + emit_changed() + + +func add_arc(arc : ScalableArc) -> void: + arcs.append(arc) + _on_changed() + emit_changed() + + +func get_arc_for_point(p_idx : int) -> ScalableArc: + var idx = arcs.find_custom(func(a : ScalableArc): return a.start_point == p_idx) + if idx > -1: + return arcs[idx] + else: + return null + + +func handle_point_added_at_index(new_idx) -> void: + for a : ScalableArc in arcs: + if a.start_point >= new_idx: + a.start_point += 1 + + +func handle_point_removed_at_index(removed_idx) -> void: + for a : ScalableArc in arcs: + if a.start_point == removed_idx or a.start_point + 1 == removed_idx: + remove_arc_for_point(a.start_point) + elif a.start_point >= removed_idx: + a.start_point -= 1 diff --git a/addons/curved_lines_2d/scalable_arc_list.gd.uid b/addons/curved_lines_2d/scalable_arc_list.gd.uid new file mode 100644 index 0000000..23a8323 --- /dev/null +++ b/addons/curved_lines_2d/scalable_arc_list.gd.uid @@ -0,0 +1 @@ +uid://dl1t88tthmwts diff --git a/addons/curved_lines_2d/scalable_vector_shape_2d.gd b/addons/curved_lines_2d/scalable_vector_shape_2d.gd new file mode 100644 index 0000000..d6b15f2 --- /dev/null +++ b/addons/curved_lines_2d/scalable_vector_shape_2d.gd @@ -0,0 +1,1348 @@ +@tool +extends Node2D +## A custom node that uses a Curve2D to control shapes like Line2D, Polygon2D with +## Original adapted code: https://www.hedberggames.com/blog/rendering-curves-in-godot +class_name ScalableVectorShape2D + +## Emitted when a new set of points was calculated for the [member curve]. +signal path_changed(new_points : PackedVector2Array) + + +## Emitted when all polygons are computed, also provides [member self] in order to keep track of the +## owning [ScalableVectorShape2D] +signal polygons_updated(polygons : Array[PackedVector2Array], poly_strokes : Array[PackedVector2Array], myself : ScalableVectorShape2D) + +## Emitted when [member CanvasItem.set_notify_transform] was toggled on upon +## every transformation (used internally to handle changes in the position of cutouts) +signal transform_changed(ref_to_self : ScalableVectorShape2D) + +## This signal is used internally in editor-mode to tell the DrawablePath2D tool that +## the instance of assigned [member line], [member polygon], or [member collision_polygon] has changed. +signal assigned_node_changed() + +## This signal is emitted when the properties for describing an ellipse or rectangle change. +## Further reading: [member shape_type] +signal dimensions_changed() + +signal clip_paths_changed() + +## The constant used to convert a radius unit to the equivalent cubic Beziér control point length +const R_TO_CP = 0.5523 + +const CAP_MODE_MAP : Dictionary[Line2D.LineCapMode, Geometry2D.PolyEndType] = { + Line2D.LINE_CAP_NONE: Geometry2D.END_BUTT, + Line2D.LINE_CAP_ROUND: Geometry2D.END_ROUND, + Line2D.LINE_CAP_BOX: Geometry2D.END_SQUARE, +} + +const JOINT_MODE_MAP : Dictionary[Line2D.LineJointMode, Geometry2D.PolyJoinType] = { + Line2D.LINE_JOINT_SHARP: Geometry2D.JOIN_MITER, + Line2D.LINE_JOINT_BEVEL: Geometry2D.JOIN_SQUARE, + Line2D.LINE_JOINT_ROUND: Geometry2D.JOIN_ROUND, +} + + + +enum ShapeType { + ## Gives every point in the [member curve] a handle, as well as their in- and out- control points. + ## Ignores the [member size], [member offset], [member rx] and [member ry] properties when + ## drawing the shape. + PATH, + ## Keeps the shape of the [member curve] as a rectangle, based on the [member offset], + ## [member size], [member rx] and [member ry]. + ## Provides one handle to change [member size], and two handles to change [member rx] and + ## [member ry] for rounded corners. + ## The [member offset] can change by using the pivot-tool in the 2D Editor + RECT, + ## Keeps the shape of the [member curve] as an ellipse, based on the [member offset] and + ## [member size] + ## Provides one handle to change [member size]. The [member size] determines the radii of the + ## ellipse on the y- and x- axis, so [member rx] and [member ry] are always sync'ed with + ## [member size] (and vice-versa) + ## The [member offset] can change by using the pivot-tool in the 2D Editor + ELLIPSE +} + + +enum CollisionObjectType { + NONE, + STATIC_BODY_2D, + AREA_2D, + ANIMATABLE_BODY_2D, + RIGID_BODY_2D, + CHARACTER_BODY_2D, + PHYSICAL_BONE_2D +} + +@export_group("Fill") +## The 'Fill' of a [ScalableVectorShape2D] is simply an instance of a [Polygon2D] node +## assigned to the `polygon` property. +## If you remove that [Polygon2D] node, you need to unassign it here as well, before +## you can add a new 'Fill' with the 'Add Fill' button +## The polygon's shape is controlled by this node's curve ([Curve2D]) property, +## it does _not_ have to be the child of this ScalableVectorShape2D +@export var polygon: Polygon2D: + set(_poly): + polygon = _poly + assigned_node_changed.emit() + +@export_group("Stroke") + +## The color of the stroke, also sets the [member Line2D.default_color] of the +## [member line] and the [member Polygon2D.color] of the [member poly_stroke] +@export var stroke_color := Color.WHITE: + set(_c): + stroke_color = _c + if is_instance_valid(line): + line.default_color = _c + if is_instance_valid(poly_stroke): + poly_stroke.color = _c + assigned_node_changed.emit() + +## The width of the stroke, also sets the [member Line2D.width] of the [member line] +@export_range(0.5, 100.0, 0.5, "suffix:px", "or_greater", "or_less") +var stroke_width := 10.0: + set(_sw): + stroke_width = _sw + if is_instance_valid(line): + line.width = _sw + assigned_node_changed.emit() + +## The cap mode of the stroke start point, also sets the [member Line2D.begin_cap_mode] +## of the [member line]. +## The [member poly_stroke] and [member collision_object] can only set _one_ cap mode +## using this property ([member begin_cap_mode]). +## Therefore the [member end_cap_mode] is ignored +@export var begin_cap_mode := Line2D.LINE_CAP_NONE: + set(_bcm): + begin_cap_mode = _bcm + if is_instance_valid(line): + line.begin_cap_mode = _bcm + assigned_node_changed.emit() + + +## The cap mode of the stroke end point, also sets the [member Line2D.end_cap_mode] of the +## [member line]. +## The [member poly_stroke] and [member collision_object] can only set _one_ cap mode +## using the [member begin_cap_mode]-property +## This property ([member end_cap_mode]) is ignored by them! +@export var end_cap_mode := Line2D.LINE_CAP_NONE: + set(_ecm): + end_cap_mode = _ecm + if is_instance_valid(line): + line.end_cap_mode = _ecm + assigned_node_changed.emit() + +## The line joint mode of the stroke, also sets the [member Line2D.line_joint_mode] of the +## [member line] +@export var line_joint_mode := Line2D.LINE_JOINT_SHARP: + set(_ljm): + line_joint_mode = _ljm + if is_instance_valid(line): + line.joint_mode = _ljm + assigned_node_changed.emit() + +## The 'Stroke' of a [ScalableVectorShape2D] is simply an instance of a [Line2D] node +## assigned to the `line` property. +## If you remove that Line2D node, you need to unassign it here as well, before +## you can add a new 'Line2D Stroke' with the 'Add Line2D Stroke' button +## The line's shape is controlled by this node's curve ([Curve2D]) pproperty, it +## does _not_ have to be the child of this [ScalableVectorShape2D] +@export var line: Line2D: + set(_line): + line = _line + assigned_node_changed.emit() + +## The 'Stroke' of a [ScalableVectorShape2D] can be an instance of a [Polygon2D] node +## assigned to the `poly_stroke` property. +## If you remove that Polygon2D node, you need to unassign it here as well, before +## you can add a new 'Poly Stroke' with the 'Add Polygon2D Stroke' button +## The line's shape is controlled by this node's curve ([Curve2D]) pproperty, it +## does _not_ have to be the child of this [ScalableVectorShape2D] +@export var poly_stroke: Polygon2D: + set(_ps): + poly_stroke = _ps + assigned_node_changed.emit() + + +@export_group("Collision") +## The [CollisionObject2D] containing the [CollisionPolygon2D] node(s) generated +## by this shape +@export var collision_object: CollisionObject2D: + set(_coll): + collision_object = _coll + assigned_node_changed.emit() + + +@export_subgroup("Collision Polygon2D*") +## The CollisionPolygon2D controlled by this node's curve property +## @deprecated: Use [member collision_object] instead. +@export var collision_polygon: CollisionPolygon2D: + set(_poly): + collision_polygon = _poly + assigned_node_changed.emit() + +@export_group("Navigation") +@export var navigation_region: NavigationRegion2D: + set(_nav): + navigation_region = _nav + assigned_node_changed.emit() + + +## Controls the paramaters used to divide up the line in segments. +## These settings are prefilled with the default values. +@export_group("Curve settings") +## The [Curve2D] that dynamically triggers updates of the shapes assigned to this node +## Changes to this curve will also emit the path_changed signal with the updated points array +@export var curve: Curve2D = Curve2D.new(): + set(_curve): + curve = _curve if _curve != null else Curve2D.new() + assigned_node_changed.emit() + +## Controls whether the path is treated as static (only update in editor) or dynamic (can be updated during runtime) +## If you set this to true, be alert for potential performance issues +@export var update_curve_at_runtime: bool = false + +## Controls how many subdivisions a curve segment may face before it is considered approximate enough. +## Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions +## per curve segment. Increase with care! +@export_range(1, 10) var max_stages : int = 5: + set(_max_stages): + max_stages = _max_stages + assigned_node_changed.emit() + +## Controls how many degrees the midpoint of a segment may deviate from the real curve, before the +## segment has to be subdivided. +@export_range(0.0, 180.0) var tolerance_degrees := 4.0: + set(_tolerance_degrees): + tolerance_degrees = _tolerance_degrees + assigned_node_changed.emit() + +## Manages the line segments which should be treated as arcs in stead of Bézier +## curves, see [class ScalableArc] for arc properties +@export var arc_list : ScalableArcList = ScalableArcList.new(): + set(_arc_list): + arc_list = _arc_list if _arc_list != null else ScalableArcList.new() + assigned_node_changed.emit() + + +## You can assign a [class Node2D] to a point in the curve (by point index) in order to control +## that [class Node2D]'s [member Node2D.position]: it's global position will be set exactly to the +## curve point's global position +@export var glue_map : Dictionary[int, Node2D] = {}: + set(_map): + glue_map = _map + for p_idx in glue_map.keys(): + if p_idx < 0 or p_idx >= curve.point_count: + printerr("Warning: point index key for glue_map not present in curve: ", p_idx) + assigned_node_changed.emit() + + +@export_group("Masking") +## Holds the list of shapes used to make cutouts out of this shape, or +## clippings of this shape when their [member use_interect_when_clipping] +## is flagged on +@export var clip_paths : Array[ScalableVectorShape2D] = []: + set(_clip_paths): + clip_paths = _clip_paths if clip_paths != null else [] + for i in clip_paths.size(): + if clip_paths[i] == self: + clip_paths[i] = null + clip_paths_changed.emit() + +## When this shape is used as a cutout, this tells the parent shape to use +## the [method Geometry2D.intersect_polygons] operation in stead of the +## [method Geometry2D.clip_polygons] operation +@export var use_interect_when_clipping := false: + set(flag): + if flag: + use_union_in_stead_of_clipping = false + use_interect_when_clipping = flag + path_changed.emit() + +## When this shape is used as a cutout, this tells the parent shape to use +## the [method Geometry2D.intersect_polygons] operation in stead of the +## [method Geometry2D.clip_polygons] operation +@export var use_union_in_stead_of_clipping := false: + set(flag): + if flag: + use_interect_when_clipping = false + use_union_in_stead_of_clipping = flag + path_changed.emit() + + +@export_group("Shape Type Settings") +## Determines what handles are shown in the editor and how the [member curve] is (re)drawn on changing +## properties [member size], [member offset], [member rx], and [member ry]. +@export var shape_type := ShapeType.PATH: + set(st): + shape_type = st + if st == ShapeType.PATH: + assigned_node_changed.emit() + else: + if shape_type == ShapeType.RECT: + rx = 0.0 + ry = 0.0 + dimensions_changed.emit() + +## The Ellipse/Rect's center relative to its pivot +@export var offset : Vector2 = Vector2(0.0, 0.0): + set(ofs): + offset = ofs + dimensions_changed.emit() + +## The natural (unscaled) size of the Ellipse/Rect +@export var size : Vector2 = Vector2(100.0, 100.0): + set(sz): + if sz.x < 0: + sz.x = 0.001 + if sz.y < 0: + sz.y = 0.001 + if shape_type == ShapeType.RECT: + if sz.x < rx * 2.001: + sz.x = rx * 2.001 + if sz.y < ry * 2.001: + sz.y = ry * 2.001 + size = sz + dimensions_changed.emit() + elif shape_type == ShapeType.ELLIPSE: + size = sz + rx = sz.x * 0.5 + ry = sz.y * 0.5 + +## The rotation of the Rect/Ellipse's points relative to its natural center +@export_range(-180.0, 180.0, 0.1, "radians_as_degrees") var spin := 0.0: + set(a): + spin = a + dimensions_changed.emit() + +## The Ellipse's radius / the Rect's rounded corder along the x-axis. +@export var rx : float = 0.0: + set(_rx): + rx = _rx if _rx > 0 else 0 + if shape_type == ShapeType.RECT: + if rx > size.x * 0.49: + rx = size.x * 0.49 + dimensions_changed.emit() + +## The Ellipse's radius / the Rect's rounded corder along the y-axis. +@export var ry : float = 0.0: + set(_ry): + ry = _ry if _ry > 0 else 0 + if shape_type == ShapeType.RECT: + if ry > size.y * 0.49: + ry = size.y * 0.49 + dimensions_changed.emit() + +@export_group("Editor settings") +## The [Color] used to draw the this shape's curve in the editor +@export var shape_hint_color := Color.LIME_GREEN +## When this field is checked, the 'Strokes', 'Fills' and 'Collisions' created +## with the 'Add ...' buttons will be locked from transforming to prevent +## inadvertently changing them, whilst the idea is that [ScalableVectorShape2D] +## controls them +@export var lock_assigned_shapes := true + +@export_group("Export Options") +@export var show_export_options := true + +var cached_outline : PackedVector2Array = [] +var cached_clipped_polygons : Array[PackedVector2Array] = [] +var cached_poly_strokes : Array[PackedVector2Array] = [] + +var should_update_curve := false + +# Wire up signals at runtime +func _ready(): + if update_curve_at_runtime: + if not curve.changed.is_connected(curve_changed): + curve.changed.connect(curve_changed) + if not arc_list.changed.is_connected(curve_changed): + arc_list.changed.connect(curve_changed) + if not clip_paths_changed.is_connected(_on_clip_paths_changed): + clip_paths_changed.connect(_on_clip_paths_changed) + _on_clip_paths_changed() + if not dimensions_changed.is_connected(_on_dimensions_changed): + dimensions_changed.connect(_on_dimensions_changed) + + +# Wire up signals on enter tree for the editor +func _enter_tree(): + # ensure backward compatibility by overriding stroke properties by line's properties + if is_instance_valid(line): + if stroke_color != line.default_color: + stroke_color = line.default_color + if stroke_width != line.width: + stroke_width = line.width + if begin_cap_mode != line.begin_cap_mode: + begin_cap_mode = line.begin_cap_mode + if end_cap_mode != line.end_cap_mode: + end_cap_mode = line.end_cap_mode + if line_joint_mode != line.joint_mode: + line_joint_mode = line.joint_mode + # ensure forward compatibility by assigning the default ShapeType + if shape_type == null: + shape_type = ShapeType.PATH + # ensure forward compatibility by assigning the default arc_list + if arc_list == null: + arc_list = ScalableArcList.new() + # ensure forward compatibility by assigning an empty array to clip_paths + if clip_paths == null: + clip_paths = [] + # ensure forward compatibility by assigning an empty dict to glue_map + if glue_map == null: + glue_map = {} + + if Engine.is_editor_hint(): + if not curve.changed.is_connected(curve_changed): + curve.changed.connect(curve_changed) + if not arc_list.changed.is_connected(curve_changed): + arc_list.changed.connect(curve_changed) + if not assigned_node_changed.is_connected(_on_assigned_node_changed): + assigned_node_changed.connect(_on_assigned_node_changed) + if not clip_paths_changed.is_connected(_on_clip_paths_changed): + clip_paths_changed.connect(_on_clip_paths_changed) + _on_clip_paths_changed() + # handles update when reparenting + if update_curve_at_runtime: + if not curve.changed.is_connected(curve_changed): + curve.changed.connect(curve_changed) + if not arc_list.changed.is_connected(curve_changed): + arc_list.changed.connect(curve_changed) + if not clip_paths_changed.is_connected(_on_clip_paths_changed): + clip_paths_changed.connect(_on_clip_paths_changed) + _on_clip_paths_changed() + # updates the curve points when size, offset, rx, or ry prop changes + # (used for ShapeType.RECT and ShapeType.ELLIPSE) + if not dimensions_changed.is_connected(_on_dimensions_changed): + dimensions_changed.connect(_on_dimensions_changed) + _on_dimensions_changed() + +# Clean up signals (ie. when closing scene) to prevent error messages in the editor +func _exit_tree(): + if curve.changed.is_connected(curve_changed): + curve.changed.disconnect(curve_changed) + if arc_list.changed.is_connected(curve_changed): + arc_list.changed.disconnect(curve_changed) + + +func _process(_delta: float) -> void: + if should_update_curve: + _update_curve() + should_update_curve = false + + +func _on_clip_paths_changed(): + for cp in clip_paths: + if is_instance_valid(cp) and not cp.path_changed.is_connected(_on_assigned_node_changed): + cp.path_changed.connect(_on_assigned_node_changed) + cp.transform_changed.connect(_on_assigned_node_changed) + cp.tree_entered.connect(_on_assigned_node_changed) + cp.tree_exited.connect(func(): if is_inside_tree(): _on_assigned_node_changed()) + if Engine.is_editor_hint() or update_curve_at_runtime: + cp.set_notify_local_transform(true) + if not cp in get_children(): + set_notify_local_transform(true) + transform_changed.connect(func(_x): curve_changed()) + _on_assigned_node_changed() + + +func _notification(what: int) -> void: + if what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED: + transform_changed.emit(self) + + +func _on_dimensions_changed(): + if shape_type == ShapeType.RECT: + var width = size.x + var height = size.y + # curve is passed by reference to trigger changed on existing instance + set_rect_points(curve, width, height, rx, ry, offset, spin) + elif shape_type == ShapeType.ELLIPSE: + # curve is passed by reference to trigger changed on existing instance + set_ellipse_points(curve, size, offset, spin) + + +func _on_assigned_node_changed(_x : Variant = null): + if Engine.is_editor_hint() or update_curve_at_runtime: + if not curve.changed.is_connected(curve_changed): + curve.changed.connect(curve_changed) + if not arc_list.changed.is_connected(curve_changed): + arc_list.changed.connect(curve_changed) + + if lock_assigned_shapes: + if is_instance_valid(line): + line.set_meta("_edit_lock_", true) + if is_instance_valid(poly_stroke): + poly_stroke.set_meta("_edit_lock_", true) + if is_instance_valid(polygon): + polygon.set_meta("_edit_lock_", true) + if is_instance_valid(collision_polygon): + collision_polygon.set_meta("_edit_lock_", true) + if is_instance_valid(collision_object): + collision_object.set_meta("_edit_lock_", true) + if is_instance_valid(navigation_region): + navigation_region.set_meta("_edit_lock_", true) + curve_changed() + + +## Exposes assigned_node_changed signal to outside callers +func notify_assigned_node_change(): + assigned_node_changed.emit() + + +func tessellate() -> PackedVector2Array: + if not cached_outline.is_empty(): + return cached_outline + if not arc_list or arc_list.arcs.is_empty(): + return curve.tessellate(max_stages, tolerance_degrees) + var poly_points = [] + var arc_starts := (arc_list.arcs + .filter(func(a): return a != null) + .map(func(a : ScalableArc): return a.start_point) + ) + for p_idx in curve.point_count - 1: + if p_idx in arc_starts: + var seg := _get_curve_segment(p_idx) + var arc = arc_list.get_arc_for_point(p_idx) + if arc: + var seg_points := tessellate_arc_segment(seg.get_point_position(0), arc.radius, + arc.rotation_deg, arc.large_arc_flag, arc.sweep_flag, seg.get_point_position(1)) + for i in seg_points.size(): + if i == 0 and not poly_points.is_empty(): + continue + poly_points.append(seg_points[i]) + else: + printerr("Illegal state: there should be an arc int arc_list with start_point=%d - (%s)" % [p_idx, name]) + if poly_points.is_empty(): + poly_points.append(seg.get_point_position(0)) + poly_points.append(seg.get_point_position(1)) + else: + var seg_points := _get_curve_segment(p_idx).tessellate(max_stages, tolerance_degrees) + for i in seg_points.size(): + if i == 0 and not poly_points.is_empty(): + continue + poly_points.append(seg_points[i]) + return poly_points + + +## Redraw the line based on the new curve, using its tessellate method +func curve_changed(): + if (not is_instance_valid(line) and not is_instance_valid(polygon) + and not is_instance_valid(poly_stroke) + and not is_instance_valid(collision_polygon) + and not is_instance_valid(collision_object) + and not is_instance_valid(navigation_region) + and not path_changed.has_connections() + and not polygons_updated.has_connections()): + # guard against needlessly invoking expensive tessellate operation + return + should_update_curve = true + + +func _update_curve(): + # recalculate the polygon points for this shape based on curve and arc_list + cached_outline.clear() + cached_poly_strokes.clear() + cached_outline.append_array(self.tessellate()) + # emit updated path to listeners + path_changed.emit(cached_outline) + + for p_idx in glue_map.keys(): + if p_idx > -1 and p_idx < curve.point_count and is_instance_valid(glue_map[p_idx]): + glue_map[p_idx].global_position = to_global(curve.get_point_position(p_idx)) + + + var polygon_points := cached_outline.duplicate() + # Fixes cases start- and end-node are so close to each other that + # polygons won't fill and closed lines won't cap nicely + if (polygon_points.size() > 0 and + polygon_points[0].distance_to(polygon_points[polygon_points.size()-1]) < 0.001): + polygon_points.remove_at(polygon_points.size() - 1) + + var valid_clip_paths : Array[ScalableVectorShape2D] = (clip_paths + .filter(func(cp): return is_instance_valid(cp)) + .filter(func(cp : Node2D): return cp.is_inside_tree()) + ) + + if clip_paths.is_empty(): + _update_assigned_nodes(polygon_points) + polygons_updated.emit( + Array([cached_outline] if is_instance_valid(polygon) else [], TYPE_PACKED_VECTOR2_ARRAY, "", null), + cached_poly_strokes, self) + else: + _update_assigned_nodes_with_clips(polygon_points, valid_clip_paths) + polygons_updated.emit(cached_clipped_polygons if is_instance_valid(polygon) else Array([], TYPE_PACKED_VECTOR2_ARRAY, "", null), cached_poly_strokes, self) + + +func _update_assigned_nodes(polygon_points : PackedVector2Array) -> void: + var collision_polygons : Array[PackedVector2Array] = [] + var navigation_polygons : Array[PackedVector2Array] = [] + # calculate stroke as polygon and cache it + + if (is_instance_valid(poly_stroke) or (is_instance_valid(line) and is_instance_valid(collision_object)) or (is_instance_valid(line) and is_instance_valid(navigation_region))) and not cached_outline.size() < 2: + var cap_mode := Geometry2D.END_JOINED if is_curve_closed() else CAP_MODE_MAP[begin_cap_mode] + var result := Geometry2DUtil.calculate_polystroke(cached_outline, + stroke_width * 0.5, cap_mode, JOINT_MODE_MAP[line_joint_mode]) + cached_poly_strokes = result + # add to list of updated collision polygons + if is_instance_valid(collision_object): + collision_polygons.append_array(cached_poly_strokes) + if is_instance_valid(navigation_region): + navigation_polygons.append_array(cached_poly_strokes) + + # i. if there is a fill assigned, also generate collision polygon for the entire outline + # ii. if there is no fill assigned and no stroke assigned, we assume the user _does_ want nav and collision + if is_instance_valid(polygon) or (collision_polygons.is_empty() and not is_instance_valid(polygon)): + collision_polygons.append(polygon_points) + navigation_polygons.append(polygon_points) + + if is_instance_valid(line): + line.points = polygon_points + line.closed = is_curve_closed() + if is_instance_valid(poly_stroke): + var polygon_indices : Array = [] + var poly := Geometry2DUtil.get_polygon_indices(cached_poly_strokes, polygon_indices) + poly_stroke.polygon = poly + poly_stroke.polygons = polygon_indices + _update_polygon_texture(poly_stroke, true) + if is_instance_valid(polygon): + polygon.polygons.clear() + polygon.polygon = polygon_points + _update_polygon_texture() + if is_instance_valid(collision_polygon): + collision_polygon.polygon = polygon_points + if is_instance_valid(collision_object): + var existing = collision_object.get_children().filter(func(ch): return ch is CollisionPolygon2D) + for idx in existing.size(): + if idx >= collision_polygons.size(): + existing[idx].hide() + existing[idx].disabled = true + for polygon_index in collision_polygons.size(): + if polygon_index >= existing.size(): + existing.append(_make_new_collision_polygon_2d()) + existing[polygon_index].polygon = collision_polygons[polygon_index] + existing[polygon_index].show() + existing[polygon_index].disabled = false + + if is_instance_valid(navigation_region): + var navigation_poly = NavigationPolygon.new() + for poly_points in navigation_polygons: + navigation_poly.add_outline(poly_points) + NavigationServer2D.bake_from_source_geometry_data(navigation_poly, NavigationMeshSourceGeometryData2D.new()) + navigation_region.navigation_polygon = navigation_poly + + +func add_clip_path(svs : ScalableVectorShape2D): + clip_paths.append(svs) + _on_clip_paths_changed() + + +func _update_polygon_texture(poly := polygon, grow := false): + if poly.texture is GradientTexture2D or poly.texture is ImageTexture: + var box := get_bounding_rect().grow(0.5 * stroke_width) if grow else get_bounding_rect() + poly.texture_offset = -box.position if grow else -box.position + if poly.texture is GradientTexture2D: + poly.texture.width = 1 if box.size.x < 1 else box.size.x + poly.texture.height = 1 if box.size.y < 1 else box.size.y + else: + if not poly.texture_repeat: + poly.texture_scale = poly.texture.get_size() / box.size + + +func _update_assigned_nodes_with_clips(polygon_points : PackedVector2Array, valid_clip_paths : Array[ScalableVectorShape2D]) -> void: + + var merges := valid_clip_paths.filter(func(cp : ScalableVectorShape2D): return cp.use_union_in_stead_of_clipping) + var clips := valid_clip_paths.filter(func(cp : ScalableVectorShape2D): return cp.use_interect_when_clipping) + var cutouts := valid_clip_paths.filter(func(cp : ScalableVectorShape2D): return not cp.use_interect_when_clipping and not cp.use_union_in_stead_of_clipping) + + var merge_results := Geometry2DUtil.apply_clips_to_polygon( + [polygon_points], + Array(merges.map(_clip_path_to_local), TYPE_PACKED_VECTOR2_ARRAY, "", null), + Geometry2D.PolyBooleanOperation.OPERATION_UNION + ) + var cutout_results := Geometry2DUtil.apply_clips_to_polygon( + merge_results, + Array(cutouts.map(_clip_path_to_local), TYPE_PACKED_VECTOR2_ARRAY, "", null), + Geometry2D.PolyBooleanOperation.OPERATION_DIFFERENCE + ) + + var intersect_results_polystroke : Array[PackedVector2Array] = [] + if (is_instance_valid(poly_stroke) or (is_instance_valid(line) and is_instance_valid(collision_object)) or (is_instance_valid(line) and is_instance_valid(navigation_region))) and not cached_outline.size() < 2: + var cutout_result_polylines : Array[PackedVector2Array] = ( + Geometry2DUtil.calculate_outlines(cutout_results.duplicate()) + if is_instance_valid(line) or is_instance_valid(poly_stroke) else + [] + ) + var polystroke_result : Array[PackedVector2Array] = [] + for polyline in cutout_result_polylines: + polystroke_result.append_array(Geometry2DUtil.calculate_polystroke(polyline, + stroke_width * 0.5, Geometry2D.END_JOINED, JOINT_MODE_MAP[line_joint_mode])) + intersect_results_polystroke = Geometry2DUtil.apply_clips_to_polygon( + polystroke_result, + Array(clips.map(_clip_path_to_local), TYPE_PACKED_VECTOR2_ARRAY, "", null), + Geometry2D.PolyBooleanOperation.OPERATION_INTERSECTION + ) + + var intersect_results_fill_polygon := Geometry2DUtil.apply_clips_to_polygon( + cutout_results, + Array(clips.map(_clip_path_to_local), TYPE_PACKED_VECTOR2_ARRAY, "", null), + Geometry2D.PolyBooleanOperation.OPERATION_INTERSECTION + ) + + cached_poly_strokes = intersect_results_polystroke + cached_clipped_polygons = intersect_results_fill_polygon + + var collision_polygons : Array[PackedVector2Array] = [] + if is_instance_valid(collision_object): + collision_polygons.append_array(cached_poly_strokes) + if is_instance_valid(polygon) or (collision_polygons.is_empty() and not is_instance_valid(polygon)): + collision_polygons.append_array(cached_clipped_polygons) + var navigation_polygons : Array[PackedVector2Array] = [] + if is_instance_valid(navigation_region): + navigation_polygons.append_array(cached_poly_strokes) + if is_instance_valid(polygon) or (navigation_polygons.is_empty() and not is_instance_valid(polygon)): + navigation_polygons.append_array(cached_clipped_polygons) + + if is_instance_valid(line): + if cached_clipped_polygons.is_empty(): + line.hide() + else: + var polylines := Geometry2DUtil.calculate_outlines(cached_clipped_polygons.duplicate()) + line.show() + line.points = polylines.pop_front() + # FIXME: closes the loop when original line is not closed + line.closed = true + var existing = line.get_children().filter(func(c): return c is Line2D) + for idx in existing.size(): + if idx >= polylines.size(): + existing[idx].hide() + for polyline_index in polylines.size(): + if polyline_index >= existing.size(): + existing.append(_make_new_line_2d()) + existing[polyline_index].points = polylines[polyline_index] + existing[polyline_index].width = line.width + existing[polyline_index].begin_cap_mode = line.begin_cap_mode + existing[polyline_index].end_cap_mode = line.end_cap_mode + existing[polyline_index].joint_mode = line.joint_mode + existing[polyline_index].default_color = line.default_color + existing[polyline_index].show() + if is_instance_valid(poly_stroke): + if cached_poly_strokes.is_empty(): + poly_stroke.hide() + else: + poly_stroke.show() + var polygon_indices : Array = [] + var poly := Geometry2DUtil.get_polygon_indices(cached_poly_strokes, polygon_indices) + poly_stroke.polygon = poly + poly_stroke.polygons = polygon_indices + _update_polygon_texture(poly_stroke, true) + if is_instance_valid(polygon): + if cached_clipped_polygons.is_empty(): + polygon.hide() + else: + polygon.show() + var polygon_indices : Array = [] + var poly := Geometry2DUtil.get_polygon_indices(cached_clipped_polygons, polygon_indices) + polygon.polygon = poly + polygon.polygons = polygon_indices + _update_polygon_texture() + if is_instance_valid(collision_polygon): + collision_polygon.polygon = polygon_points + if is_instance_valid(collision_object): + var existing = collision_object.get_children().filter(func(ch): return ch is CollisionPolygon2D) + for idx in existing.size(): + if idx >= collision_polygons.size(): + existing[idx].hide() + existing[idx].disabled = true + for polygon_index in collision_polygons.size(): + if polygon_index >= existing.size(): + existing.append(_make_new_collision_polygon_2d()) + existing[polygon_index].polygon = collision_polygons[polygon_index] + existing[polygon_index].show() + existing[polygon_index].disabled = false + + if is_instance_valid(navigation_region): + var navigation_poly = NavigationPolygon.new() + for outline in navigation_polygons: + navigation_poly.add_outline(outline) + NavigationServer2D.bake_from_source_geometry_data(navigation_poly, NavigationMeshSourceGeometryData2D.new()) + navigation_region.navigation_polygon = navigation_poly + + +func _make_new_collision_polygon_2d() -> CollisionPolygon2D: + var c_poly = CollisionPolygon2D.new() + collision_object.add_child(c_poly, true) + if collision_object.owner: + c_poly.set_owner(collision_object.owner) + if Engine.is_editor_hint() and lock_assigned_shapes: + c_poly.set_meta("_edit_lock_", true) + if collision_object not in get_children(): + c_poly.global_transform = global_transform + return c_poly + + +func _make_new_line_2d() -> Line2D: + var ln := Line2D.new() + ln.name = "ExtraStroke" + line.add_child(ln, true) + ln.closed = true + if line.owner: + ln.set_owner(line.owner) + if Engine.is_editor_hint() and lock_assigned_shapes: + ln.set_meta("_edit_lock_", true) + return ln + + +func _clip_path_to_local(clip_path : ScalableVectorShape2D) -> PackedVector2Array: + var pts := clip_path.global_transform * clip_path.tessellate() + return self.global_transform.affine_inverse() * pts + + +func get_center() -> Vector2: + if shape_type != ShapeType.PATH: + return offset + return get_bounding_rect().get_center() + + +## Calculate and return the bounding rect in local space +func get_bounding_rect() -> Rect2: + if not curve: + return Rect2(Vector2.ZERO, Vector2.ZERO) + var points := self.tessellate() + if points.size() < 1: + # Cannot calculate a center for 0 points + return Rect2(Vector2.ZERO, Vector2.ZERO) + return Geometry2DUtil.get_polygon_bounding_rect(points) + + +func has_point(global_pos : Vector2) -> bool: + return get_bounding_rect().grow( + stroke_width / 2.0 if is_instance_valid(line) or is_instance_valid(poly_stroke) else 0 + ).has_point(to_local(global_pos)) + + +func has_fine_point(global_pos : Vector2) -> bool: + var poly_points := self.tessellate() + if Geometry2D.is_point_in_polygon(to_local(global_pos), poly_points): + return true + for poly_points1 in cached_poly_strokes: + if Geometry2D.is_point_in_polygon(to_local(global_pos), poly_points1): + return true + return false + + +func clipped_polygon_has_point(global_pos : Vector2) -> bool: + if not has_point(global_pos) or not has_fine_point(global_pos): + return false + + if cached_clipped_polygons.is_empty() and has_fine_point(global_pos): + return true + + for poly_points1 in cached_poly_strokes: + if Geometry2D.is_point_in_polygon(to_local(global_pos), poly_points1): + return true + + for poly_points in cached_clipped_polygons: + if Geometry2D.is_point_in_polygon(to_local(global_pos), poly_points): + return true + return false + + +func set_position_to_center() -> void: + var c = get_center() + position += c + for i in range(curve.get_point_count()): + curve.set_point_position(i, curve.get_point_position(i) - c) + + +func set_origin(global_pos : Vector2) -> void: + var local_pos = to_local(global_pos) + match shape_type: + ShapeType.RECT, ShapeType.ELLIPSE: + offset = offset - to_local(global_pos) + global_position = global_pos + if is_instance_valid(polygon) and polygon.texture is GradientTexture2D: + polygon.texture_offset = -get_bounding_rect().position + ShapeType.PATH, _: + for i in range(curve.get_point_count()): + curve.set_point_position(i, curve.get_point_position(i) - local_pos) + global_position = global_pos + if is_instance_valid(polygon) and polygon.texture is GradientTexture2D: + polygon.texture_offset = -get_bounding_rect().position + + + +func get_bounding_box() -> Array[Vector2]: + var rect = get_bounding_rect().grow( + stroke_width / 2.0 if is_instance_valid(line) or is_instance_valid(poly_stroke) else 0 + ) + return [ + to_global(rect.position), + to_global(Vector2(rect.position.x + rect.size.x, rect.position.y)), + to_global(rect.position + rect.size), + to_global(Vector2(rect.position.x, rect.position.y + rect.size.y)), + to_global(rect.position) + ] + + +func get_poly_points() -> Array: + return Array(self.tessellate()).map(to_global) + + +func get_farthest_point(from_local_pos := Vector2.ZERO) -> Vector2: + var farthest_point = from_local_pos + for p in self.tessellate(): + if p.distance_to(from_local_pos) > farthest_point.distance_to(from_local_pos): + farthest_point = p + return farthest_point + + +func is_curve_closed() -> bool: + var n = curve.point_count + return n > 2 and curve.get_point_position(0).distance_to(curve.get_point_position(n - 1)) < 0.001 + + +func get_curve_handles() -> Array: + if shape_type == ShapeType.RECT or shape_type == ShapeType.ELLIPSE: + var size_handle_pos := (size * 0.5).rotated(spin) + offset + var top_left := (-size * 0.5).rotated(spin) + offset + var rx_handle := ((-size * 0.5) + Vector2(rx, 0)).rotated(spin) + offset + var ry_handle := ((-size * 0.5) + Vector2(0, ry)).rotated(spin) + offset + return [{ + "top_left_pos": to_global(top_left), + "point_position": to_global(size_handle_pos), + "mirrored": true, + "in": rx_handle, + "out": ry_handle, + "in_position": to_global(rx_handle), + "out_position": to_global(ry_handle), + "is_closed": "", + }] + + + var n = curve.point_count + var is_closed := is_curve_closed() + var result := [] + for i in range(n): + var p = curve.get_point_position(i) + var c_i = curve.get_point_in(i) + var c_o = curve.get_point_out(i) + if i == 0 and is_closed: + c_i = curve.get_point_in(n - 1) + elif i == n - 1 and is_closed: + continue + result.append({ + 'point_position': to_global(p), + 'in': c_i, + 'out': c_o, + 'mirrored': c_i.length() and c_i.distance_to(-c_o) < 0.01, + 'in_position': to_global(p + c_i), + 'out_position': to_global(p + c_o), + 'is_closed': (" ∞ " + str(n - 1) if i == 0 and is_closed else "") + }) + return result + + +func get_gradient_handles() -> Dictionary: + if not ( + is_instance_valid(polygon) and polygon.texture is GradientTexture2D + ): + return {} + var gradient_tex : GradientTexture2D = polygon.texture + var box := get_bounding_rect() + var stop_colors = Array( + gradient_tex.gradient.colors if gradient_tex.gradient.colors else [ + Color.WHITE, Color.BLACK + ] + ).map(func(gc): return gc * polygon.color) + var stop_positions = Array(gradient_tex.gradient.offsets).map( + func(offs): return (gradient_tex.fill_to - gradient_tex.fill_from) * offs + ).map(func(offs_p): return gradient_tex.fill_from + offs_p + ).map(func(offs_p1): return to_global((offs_p1 * box.size) + box.position)) + + var result := { + "fill_from": gradient_tex.fill_from, + "fill_to": gradient_tex.fill_to, + "fill_from_pos": to_global((gradient_tex.fill_from * box.size) + box.position), + "fill_to_pos": to_global((gradient_tex.fill_to * box.size) + box.position), + "start_color": stop_colors[0] * polygon.color, + "end_color": stop_colors[stop_colors.size() - 1] * polygon.color, + "stop_positions": stop_positions, + "stop_colors": stop_colors + } + + return result + + +func flip_points(flip_dir := Vector2(-1, 1)) -> void: + if shape_type == ShapeType.PATH: + curve.set_block_signals(true) + arc_list.set_block_signals(true) + for i in curve.point_count: + curve.set_point_position(i, curve.get_point_position(i) * flip_dir) + curve.set_point_in(i, curve.get_point_in(i) * flip_dir) + curve.set_point_out(i, curve.get_point_out(i) * flip_dir) + for i in arc_list.arcs.size(): + arc_list.arcs[i].sweep_flag = not arc_list.arcs[i].sweep_flag + arc_list.set_block_signals(false) + curve.set_block_signals(false) + curve.emit_changed() + arc_list.emit_changed() + else: + spin = -spin + + +func translate_points_by(global_vector : Vector2) -> void: + var delta := global_vector.rotated(-global_rotation) / global_scale + if shape_type == ShapeType.PATH: + curve.set_block_signals(true) + for idx in curve.point_count: + curve.set_point_position(idx, curve.get_point_position(idx) + delta) + curve.set_block_signals(false) + curve.emit_changed() + else: + offset += delta + + +func scale_points_by(from_global_vector : Vector2, to_global_vector : Vector2, around_center := false) -> void: + var local_from := to_local(from_global_vector) + var local_to := to_local(to_global_vector) + var origin := get_center() if around_center else Vector2.ZERO + var s := origin.distance_to(local_to) / origin.distance_to(local_from) + if shape_type == ShapeType.PATH: + curve.set_block_signals(true) + for idx in curve.point_count: + var p := curve.get_point_position(idx) + var p1 := (p - origin) * s + origin + var cp_in_abs := curve.get_point_in(idx) + p + var cp_out_abs := curve.get_point_out(idx) + p + var cp_in_abs_1 := (cp_in_abs - origin) * s + origin + var cp_out_abs_1 := (cp_out_abs - origin) * s + origin + curve.set_point_position(idx, p1) + curve.set_point_in(idx, cp_in_abs_1 - p1) + curve.set_point_out(idx, cp_out_abs_1 - p1) + + curve.set_block_signals(false) + curve.emit_changed() + else: + size *= s + + +func rotate_points_by(angle : float, rotation_origin := Vector2.ZERO) -> void: + if shape_type != ShapeType.PATH: + spin += angle + return + var transform := Transform2D.IDENTITY.rotated(-angle) + curve.set_block_signals(true) + for idx in curve.point_count: + var p := curve.get_point_position(idx) + var p1 := (p - rotation_origin) * transform + rotation_origin + var cp_in_abs := curve.get_point_in(idx) + p + var cp_out_abs := curve.get_point_out(idx) + p + var cp_in_abs_1 := (cp_in_abs - rotation_origin) * transform + rotation_origin + var cp_out_abs_1 := (cp_out_abs - rotation_origin) * transform + rotation_origin + curve.set_point_position(idx, p1) + curve.set_point_in(idx, cp_in_abs_1 - p1) + curve.set_point_out(idx, cp_out_abs_1 - p1) + curve.set_block_signals(false) + curve.emit_changed() + + +func set_global_curve_point_position(global_pos : Vector2, point_idx : int, snapped : bool, + snap : float) -> void: + if curve.point_count > point_idx: + if snapped: + global_pos = snapped(global_pos, Vector2.ONE * snap) + curve.set_point_position(point_idx, to_local(global_pos)) + + +func set_global_curve_cp_in_position(global_pos : Vector2, point_idx : int, snapped : bool, + snap : float) -> void: + if curve.point_count > point_idx: + if snapped: + global_pos = snapped(global_pos, Vector2.ONE * snap) + curve.set_point_in(point_idx, to_local(global_pos) - curve.get_point_position(point_idx)) + + +func set_global_curve_cp_out_position(global_pos : Vector2, point_idx : int, snapped : bool, + snap : float) -> void: + if curve.point_count > point_idx: + if snapped: + global_pos = snapped(global_pos, Vector2.ONE * snap) + curve.set_point_out(point_idx, to_local(global_pos) - curve.get_point_position(point_idx)) + + +func replace_curve_points(curve_in : Curve2D) -> void: + curve.clear_points() + for i in range(curve_in.point_count): + curve.add_point(curve_in.get_point_position(i), + curve_in.get_point_in(i), curve_in.get_point_out(i)) + + +func add_arc(segment_p1_idx : int) -> void: + var seg := _get_curve_segment(segment_p1_idx) + var r := seg.get_point_position(0).distance_to(seg.get_point_position(1)) * 0.5 + arc_list.add_arc(ScalableArc.new(segment_p1_idx, Vector2.ONE * r, 0.0)) + + +func _get_curve_segment(segment_p1_idx : int) -> Curve2D: + var curve_segment := Curve2D.new() + curve_segment.add_point( + curve.get_point_position(segment_p1_idx), + Vector2.ZERO, + curve.get_point_out(segment_p1_idx) + ) + var segment_p2_idx = (0 if segment_p1_idx == curve.point_count - 1 + else segment_p1_idx + 1) + curve_segment.add_point( + curve.get_point_position(segment_p2_idx), + curve.get_point_in(segment_p2_idx) + ) + return curve_segment + + +func is_arc_start(p_idx) -> bool: + return arc_list.get_arc_for_point(p_idx) != null + + +func _get_closest_point_on_curve_segment(p : Vector2, segment_p1_idx : int) -> Vector2: + var arc := arc_list.get_arc_for_point(segment_p1_idx) + var seg := _get_curve_segment(segment_p1_idx) + var poly_points := ( + tessellate_arc_segment(seg.get_point_position(0), arc.radius, arc.rotation_deg, + arc.large_arc_flag, arc.sweep_flag, seg.get_point_position(1)) + if arc else + seg.tessellate(max_stages, tolerance_degrees) + ) + var closest_result := Vector2.INF + for i in range(1, poly_points.size()): + var p_a := poly_points[i - 1] + var p_b := poly_points[i] + var c_p := Geometry2D.get_closest_point_to_segment(p, p_a, p_b) + if p.distance_to(c_p) < p.distance_to(closest_result): + closest_result = c_p + return closest_result + + +func get_closest_point_on_curve(global_pos : Vector2) -> ClosestPointOnCurveMeta: + var p := to_local(global_pos) + if curve.point_count < 2: + return ClosestPointOnCurveMeta.new(1, global_pos, p) + + var closest_result := Vector2.INF + var before_segment := 1 + for i in range(curve.point_count): + var c_p := _get_closest_point_on_curve_segment(p, i) + if p.distance_to(c_p) < p.distance_to(closest_result): + closest_result = c_p + before_segment = i + 1 + return ClosestPointOnCurveMeta.new(before_segment, to_global(closest_result), closest_result) + + +func get_sliced_curve_segment(before_segment : int, point_position : Vector2) -> Curve2D: + var curve_segment := Curve2D.new() + curve_segment.add_point(curve.get_point_position(before_segment - 1)) + curve_segment.set_point_out(0, curve.get_point_out(before_segment - 1)) + curve_segment.add_point(curve.get_point_position(before_segment)) + curve_segment.set_point_in(1, curve.get_point_in(before_segment)) + var progress_ratio := Geometry2DUtil.get_progress_ratio_for_point_on_curve( + point_position, curve_segment, max_stages, tolerance_degrees) + return Geometry2DUtil.slice_bezier( + curve_segment.get_point_position(0), + curve_segment.get_point_out(0), + curve_segment.get_point_in(1), + curve_segment.get_point_position(1), + progress_ratio + ) + + +func get_curve_segment_halfway_point(before_segment : int) -> Vector2: + var p_idx_1 := before_segment if before_segment < curve.point_count else 0 + var curve_segment := Curve2D.new() + curve_segment.add_point(curve.get_point_position(before_segment - 1)) + curve_segment.set_point_out(0, curve.get_point_out(before_segment - 1)) + curve_segment.add_point(curve.get_point_position(p_idx_1)) + curve_segment.set_point_in(1, curve.get_point_in(p_idx_1)) + return Geometry2DUtil.get_halfway_point_on_bezier(curve_segment, max_stages, tolerance_degrees) + + +func get_subdivided_curve() -> Curve2D: + if curve.point_count < 2: + return curve + var new_curve := Curve2D.new() + new_curve.add_point(curve.get_point_position(0)) + for i in range(1, curve.point_count): + var segment := get_sliced_curve_segment(i, get_curve_segment_halfway_point(i)) + new_curve.add_point(segment.get_point_position(1)) + new_curve.add_point(segment.get_point_position(2)) + if curve.get_point_out(i - 1).length() > 0.0 or curve.get_point_in(i).length() > 0.0: + new_curve.set_point_out((i * 2) - 2, segment.get_point_out(0)) + new_curve.set_point_in((i * 2) - 1, segment.get_point_in(1)) + new_curve.set_point_out((i * 2) - 1, segment.get_point_out(1)) + new_curve.set_point_in(i * 2, segment.get_point_in(2)) + return new_curve + + +# Adapted from the GodSVG repository to draw arc in stead of determine bounding box. +# https://github.com/MewPurPur/GodSVG/blob/53168a8cf74739fe828f488901eada02d5d97b69/src/data_classes/ElementPath.gd#L118 +func tessellate_arc_segment(start : Vector2, arc_radius : Vector2, arc_rotation_deg : float, + large_arc_flag : bool, sweep_flag : bool, end : Vector2) -> PackedVector2Array: + + if start == end or arc_radius.x == 0 or arc_radius.y == 0: + return [start, end] + + var r := arc_radius.abs() + # Obtain center parametrization. + var rot := deg_to_rad(arc_rotation_deg) + var cosine := cos(rot) + var sine := sin(rot) + var half := (start - end) / 2 + var x1 := half.x * cosine + half.y * sine + var y1 := -half.x * sine + half.y * cosine + var r2 := Vector2(r.x * r.x, r.y * r.y) + var x12 := x1 * x1 + var y12 := y1 * y1 + var cr := x12 / r2.x + y12 / r2.y + if cr > 1: + cr = sqrt(cr) + r *= cr + r2 = Vector2(r.x * r.x, r.y * r.y) + + var dq := r2.x * y12 + r2.y * x12 + var pq := (r2.x * r2.y - dq) / dq + var sc := sqrt(maxf(0, pq)) + if large_arc_flag == sweep_flag: + sc = -sc + + var ct := Vector2(r.x * sc * y1 / r.y, -r.y * sc * x1 / r.x) + var c := Vector2(ct.x * cosine - ct.y * sine, + ct.x * sine + ct.y * cosine) + start.lerp(end, 0.5) + var tv := Vector2(x1 - ct.x, y1 - ct.y) / r + var theta1 := tv.angle() + var delta_theta := fposmod(tv.angle_to( + Vector2(-x1 - ct.x, -y1 - ct.y) / r), TAU) + if not sweep_flag: + theta1 += delta_theta + delta_theta = TAU - delta_theta + theta1 = fposmod(theta1, TAU) + + var step := deg_to_rad(1.0 if tolerance_degrees < 1.0 else tolerance_degrees) + var angle := theta1 if sweep_flag else theta1 + delta_theta + var init_pnt := Vector2(c.x + r.x * cos(angle) * cosine - r.y * sin(angle) * sine, + c.y + r.x * cos(angle) * sine + r.y * sin(angle) * cosine) + var points : PackedVector2Array = [] + while (sweep_flag and angle < theta1 + delta_theta) or (not sweep_flag and angle > theta1): + var pnt := Vector2(c.x + r.x * cos(angle) * cosine - r.y * sin(angle) * sine, + c.y + r.x * cos(angle) * sine + r.y * sin(angle) * cosine) + points.append(pnt) + if sweep_flag: + angle += step + else: + angle -= step + if points[points.size() - 1] != end: + if points[points.size() - 1].distance_to(end) < 0.01: + points[points.size() - 1] = end + else: + points.append(end) + return points + + +## Convert an existing [Curve2D] instance to a (rounded) rectangle. +## [param curve] is passed by reference so the curve's [signal Resource.changed] +## signal is emitted. +static func set_rect_points(curve : Curve2D, width : float, height : float, rx := 0.0, ry := 0.0, + offset := Vector2.ZERO, rotation := 0.0) -> void: + curve.set_block_signals(true) + curve.clear_points() + var top_left := Vector2(-width, -height) * 0.5 + var top_right := Vector2(width, -height) * 0.5 + var bottom_right := Vector2(width, height) * 0.5 + var bottom_left := Vector2(-width, height) * 0.5 + if rx == 0 and ry == 0: + curve.add_point(top_left.rotated(rotation) + offset) + curve.add_point(top_right.rotated(rotation) + offset) + curve.add_point(bottom_right.rotated(rotation) + offset) + curve.add_point(bottom_left.rotated(rotation) + offset) + curve.add_point(top_left.rotated(rotation) + offset) + else: + curve.add_point( + (top_left + Vector2(width - rx, 0)).rotated(rotation) + offset, + Vector2.ZERO, + Vector2(rx * R_TO_CP, 0).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(width, ry)).rotated(rotation) + offset, + Vector2(0, -ry * R_TO_CP).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(width, height - ry)).rotated(rotation) + offset, + Vector2.ZERO, + Vector2(0, ry * R_TO_CP).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(width - rx, height)).rotated(rotation) + offset, + Vector2(rx * R_TO_CP, 0).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(rx, height)).rotated(rotation) + offset, + Vector2.ZERO, + Vector2(-rx * R_TO_CP, 0).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(0, height - ry)).rotated(rotation) + offset, + Vector2(0, ry * R_TO_CP).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(0, ry)).rotated(rotation) + offset, + Vector2.ZERO, + Vector2(0, -ry * R_TO_CP).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(rx, 0)).rotated(rotation) + offset, + Vector2(-rx * R_TO_CP, 0).rotated(rotation) + ) + curve.add_point( + (top_left + Vector2(width - rx, 0)).rotated(rotation) + offset, + Vector2.ZERO, + Vector2(rx * R_TO_CP, 0).rotated(rotation) + ) + + curve.set_block_signals(false) + curve.changed.emit() + + +## Convert an existing [Curve2D] instance to an ellipse. +## [param curve] is passed by reference so the curve's [signal Resource.changed] +## signal is emitted. +static func set_ellipse_points(curve : Curve2D, size: Vector2, offset := Vector2.ZERO, rotation := 0.0): + curve.set_block_signals(true) + curve.clear_points() + curve.add_point( + offset + Vector2(size.x * 0.5, 0).rotated(rotation), + Vector2.ZERO, + Vector2(0, size.y * 0.5 * R_TO_CP).rotated(rotation) + ) + curve.add_point( + offset + Vector2(0, size.y * 0.5).rotated(rotation), + Vector2(size.x * 0.5 * R_TO_CP, 0).rotated(rotation), + Vector2(-size.x * 0.5 * R_TO_CP, 0).rotated(rotation) + ) + curve.add_point( + offset + Vector2(-size.x * 0.5, 0).rotated(rotation), + Vector2(0, size.y * 0.5 * R_TO_CP).rotated(rotation), + Vector2(0, -size.y * 0.5 * R_TO_CP).rotated(rotation) + ) + curve.add_point( + offset + Vector2(0, -size.y * 0.5).rotated(rotation), + Vector2(-size.x * 0.5 * R_TO_CP, 0).rotated(rotation), + Vector2(size.x * 0.5 * R_TO_CP, 0).rotated(rotation) + ) + curve.add_point( + offset + Vector2(size.x * 0.5, 0).rotated(rotation), + Vector2(0, -size.y * 0.5 * R_TO_CP).rotated(rotation) + ) + curve.set_block_signals(false) + curve.changed.emit() + + diff --git a/addons/curved_lines_2d/scalable_vector_shape_2d.gd.uid b/addons/curved_lines_2d/scalable_vector_shape_2d.gd.uid new file mode 100644 index 0000000..e9cd70f --- /dev/null +++ b/addons/curved_lines_2d/scalable_vector_shape_2d.gd.uid @@ -0,0 +1 @@ +uid://de3jpss66xjfh diff --git a/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.gd b/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.gd new file mode 100644 index 0000000..68a53b3 --- /dev/null +++ b/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.gd @@ -0,0 +1,48 @@ +@tool +extends TabContainer + +signal shape_created(curve : Curve2D, scene_root : Node2D, node_name : String) +signal set_shape_preview(curve : Curve2D) + +const TABS_NAME := [ + "Project Settings", + "Create Shapes", + "Import SVG File", + "Advanced Editing", + "Video Explainers", + "Play Tatra!" +] + +var warning_dialog : AcceptDialog +var edit_tab : Control +var import_tab : Control + +func _enter_tree() -> void: + for i in min(TABS_NAME.size(), get_child_count()): + set_tab_title(i, TABS_NAME[i]) + + edit_tab = %SVSEditTab + import_tab = %SVGImportTab + warning_dialog = AcceptDialog.new() + EditorInterface.get_base_control().add_child(warning_dialog) + edit_tab.warning_dialog = warning_dialog + import_tab.warning_dialog = warning_dialog + + if not edit_tab.shape_created.is_connected(shape_created.emit): + edit_tab.shape_created.connect(shape_created.emit) + if not edit_tab.set_shape_preview.is_connected(set_shape_preview.emit): + edit_tab.set_shape_preview.connect(set_shape_preview.emit) + + +func _can_drop_data(at_position: Vector2, data: Variant) -> bool: + if not typeof(data) == TYPE_DICTIONARY and "type" in data and data["type"] == "files": + return false + for file : String in data["files"]: + if file.ends_with(".svg"): + import_tab.show() + return true + return false + + +func set_selected_animation_player(animation_player : AnimationPlayer) -> void: + %AdvancedTab.set_animation_player(animation_player) diff --git a/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.gd.uid b/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.gd.uid new file mode 100644 index 0000000..f1de700 --- /dev/null +++ b/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.gd.uid @@ -0,0 +1 @@ +uid://dtiys8sevuh65 diff --git a/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.tscn b/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.tscn new file mode 100644 index 0000000..b978c46 --- /dev/null +++ b/addons/curved_lines_2d/scalable_vector_shapes_2d_dock.tscn @@ -0,0 +1,59 @@ +[gd_scene load_steps=8 format=3 uid="uid://drrarjj0668n"] + +[ext_resource type="Script" uid="uid://dtiys8sevuh65" path="res://addons/curved_lines_2d/scalable_vector_shapes_2d_dock.gd" id="1_1mm15"] +[ext_resource type="PackedScene" uid="uid://cfeemeccrtef7" path="res://addons/curved_lines_2d/svg_import_tab.tscn" id="2_0fwlu"] +[ext_resource type="PackedScene" uid="uid://dwns40mbgt82s" path="res://addons/curved_lines_2d/svs_edit_tab.tscn" id="3_psho1"] +[ext_resource type="PackedScene" uid="uid://3r7rlhrwfmfe" path="res://addons/curved_lines_2d/advanced_tab.tscn" id="4_0fwlu"] +[ext_resource type="PackedScene" uid="uid://d3j2c8gduqsuu" path="res://addons/curved_lines_2d/project_settings_tab.tscn" id="4_psho1"] +[ext_resource type="PackedScene" uid="uid://hr7df18ngxmj" path="res://addons/curved_lines_2d/video_explainer_tab.tscn" id="6_mi8vn"] +[ext_resource type="PackedScene" uid="uid://r23wu41l5ng5" path="res://addons/curved_lines_2d/play_tatra_tab.tscn" id="7_8qxkf"] + +[node name="ScalableVectorShapes2DDock" type="TabContainer"] +custom_minimum_size = Vector2(0, 302) +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +current_tab = 1 +script = ExtResource("1_1mm15") + +[node name="ProjectSettingsTab" parent="." instance=ExtResource("4_psho1")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +metadata/_tab_index = 0 +metadata/_tab_name = "Project Settings" + +[node name="SVSEditTab" parent="." instance=ExtResource("3_psho1")] +unique_name_in_owner = true +layout_mode = 2 +metadata/_tab_index = 1 +metadata/_tab_name = "Create Shapes" + +[node name="SVGImportTab" parent="." instance=ExtResource("2_0fwlu")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +metadata/_tab_index = 2 +metadata/_tab_name = "Import SVG File" + +[node name="AdvancedTab" parent="." instance=ExtResource("4_0fwlu")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +metadata/_tab_index = 3 +metadata/_tab_name = "Advanced Editing" + +[node name="VideoExplainerTab" parent="." instance=ExtResource("6_mi8vn")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +metadata/_tab_index = 4 +metadata/_tab_name = "Video Explainers" + +[node name="PlayTatraTab" parent="." instance=ExtResource("7_8qxkf")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +metadata/_tab_name = "Play Tatra!" diff --git a/addons/curved_lines_2d/screenshots/.gdignore b/addons/curved_lines_2d/screenshots/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/addons/curved_lines_2d/screenshots/00-converter.png b/addons/curved_lines_2d/screenshots/00-converter.png new file mode 100644 index 0000000..c4b7de7 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/00-converter.png differ diff --git a/addons/curved_lines_2d/screenshots/01-heart-scene.png b/addons/curved_lines_2d/screenshots/01-heart-scene.png new file mode 100644 index 0000000..9350c00 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/01-heart-scene.png differ diff --git a/addons/curved_lines_2d/screenshots/02-create-node.png b/addons/curved_lines_2d/screenshots/02-create-node.png new file mode 100644 index 0000000..ba65d4d Binary files /dev/null and b/addons/curved_lines_2d/screenshots/02-create-node.png differ diff --git a/addons/curved_lines_2d/screenshots/03-double-click.png b/addons/curved_lines_2d/screenshots/03-double-click.png new file mode 100644 index 0000000..b200c88 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/03-double-click.png differ diff --git a/addons/curved_lines_2d/screenshots/04-double-click2.png b/addons/curved_lines_2d/screenshots/04-double-click2.png new file mode 100644 index 0000000..e0f3884 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/04-double-click2.png differ diff --git a/addons/curved_lines_2d/screenshots/04-generate.png b/addons/curved_lines_2d/screenshots/04-generate.png new file mode 100644 index 0000000..1447fb4 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/04-generate.png differ diff --git a/addons/curved_lines_2d/screenshots/05-bend.png b/addons/curved_lines_2d/screenshots/05-bend.png new file mode 100644 index 0000000..cbf5bd4 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/05-bend.png differ diff --git a/addons/curved_lines_2d/screenshots/06-scalable-vector-shapes-panel.png b/addons/curved_lines_2d/screenshots/06-scalable-vector-shapes-panel.png new file mode 100644 index 0000000..24b2236 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/06-scalable-vector-shapes-panel.png differ diff --git a/addons/curved_lines_2d/screenshots/07-mirrored-handles.png b/addons/curved_lines_2d/screenshots/07-mirrored-handles.png new file mode 100644 index 0000000..79eb396 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/07-mirrored-handles.png differ diff --git a/addons/curved_lines_2d/screenshots/08-sharp.png b/addons/curved_lines_2d/screenshots/08-sharp.png new file mode 100644 index 0000000..5da322f Binary files /dev/null and b/addons/curved_lines_2d/screenshots/08-sharp.png differ diff --git a/addons/curved_lines_2d/screenshots/09-loop.png b/addons/curved_lines_2d/screenshots/09-loop.png new file mode 100644 index 0000000..cc34a7a Binary files /dev/null and b/addons/curved_lines_2d/screenshots/09-loop.png differ diff --git a/addons/curved_lines_2d/screenshots/10-path_changed-signal.png b/addons/curved_lines_2d/screenshots/10-path_changed-signal.png new file mode 100644 index 0000000..f4a516d Binary files /dev/null and b/addons/curved_lines_2d/screenshots/10-path_changed-signal.png differ diff --git a/addons/curved_lines_2d/screenshots/11-line2d-closed.png b/addons/curved_lines_2d/screenshots/11-line2d-closed.png new file mode 100644 index 0000000..5543439 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/11-line2d-closed.png differ diff --git a/addons/curved_lines_2d/screenshots/11a-line2d-closed.png b/addons/curved_lines_2d/screenshots/11a-line2d-closed.png new file mode 100644 index 0000000..1515bbb Binary files /dev/null and b/addons/curved_lines_2d/screenshots/11a-line2d-closed.png differ diff --git a/addons/curved_lines_2d/screenshots/12a-assigned.png b/addons/curved_lines_2d/screenshots/12a-assigned.png new file mode 100644 index 0000000..1a12e38 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/12a-assigned.png differ diff --git a/addons/curved_lines_2d/screenshots/12b-assigned.png b/addons/curved_lines_2d/screenshots/12b-assigned.png new file mode 100644 index 0000000..5f81e2c Binary files /dev/null and b/addons/curved_lines_2d/screenshots/12b-assigned.png differ diff --git a/addons/curved_lines_2d/screenshots/12c-assigned.png b/addons/curved_lines_2d/screenshots/12c-assigned.png new file mode 100644 index 0000000..0bd9c2b Binary files /dev/null and b/addons/curved_lines_2d/screenshots/12c-assigned.png differ diff --git a/addons/curved_lines_2d/screenshots/13-svg-importer-dock.png b/addons/curved_lines_2d/screenshots/13-svg-importer-dock.png new file mode 100644 index 0000000..2f2db31 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/13-svg-importer-dock.png differ diff --git a/addons/curved_lines_2d/screenshots/14-import-warnings.png b/addons/curved_lines_2d/screenshots/14-import-warnings.png new file mode 100644 index 0000000..1d6a5ac Binary files /dev/null and b/addons/curved_lines_2d/screenshots/14-import-warnings.png differ diff --git a/addons/curved_lines_2d/screenshots/15-imported-rat.png b/addons/curved_lines_2d/screenshots/15-imported-rat.png new file mode 100644 index 0000000..ad9aa4b Binary files /dev/null and b/addons/curved_lines_2d/screenshots/15-imported-rat.png differ diff --git a/addons/curved_lines_2d/screenshots/16-set-origin.png b/addons/curved_lines_2d/screenshots/16-set-origin.png new file mode 100644 index 0000000..ccc4018 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/16-set-origin.png differ diff --git a/addons/curved_lines_2d/screenshots/16a-set_origin.png b/addons/curved_lines_2d/screenshots/16a-set_origin.png new file mode 100644 index 0000000..10fea26 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/16a-set_origin.png differ diff --git a/addons/curved_lines_2d/screenshots/17-hold-ctrl-to-start-adding.png b/addons/curved_lines_2d/screenshots/17-hold-ctrl-to-start-adding.png new file mode 100644 index 0000000..62149ed Binary files /dev/null and b/addons/curved_lines_2d/screenshots/17-hold-ctrl-to-start-adding.png differ diff --git a/addons/curved_lines_2d/screenshots/18-add-point-to-line.png b/addons/curved_lines_2d/screenshots/18-add-point-to-line.png new file mode 100644 index 0000000..2d9760c Binary files /dev/null and b/addons/curved_lines_2d/screenshots/18-add-point-to-line.png differ diff --git a/addons/curved_lines_2d/screenshots/3d_shape_promo.png b/addons/curved_lines_2d/screenshots/3d_shape_promo.png new file mode 100644 index 0000000..84395ff Binary files /dev/null and b/addons/curved_lines_2d/screenshots/3d_shape_promo.png differ diff --git a/addons/curved_lines_2d/screenshots/a-z-explainer-youtube-thumbnail.png b/addons/curved_lines_2d/screenshots/a-z-explainer-youtube-thumbnail.png new file mode 100644 index 0000000..50ddd1f Binary files /dev/null and b/addons/curved_lines_2d/screenshots/a-z-explainer-youtube-thumbnail.png differ diff --git a/addons/curved_lines_2d/screenshots/adaptable-vector-shape-3d.png b/addons/curved_lines_2d/screenshots/adaptable-vector-shape-3d.png new file mode 100644 index 0000000..6a9d7de Binary files /dev/null and b/addons/curved_lines_2d/screenshots/adaptable-vector-shape-3d.png differ diff --git a/addons/curved_lines_2d/screenshots/add-arc.png b/addons/curved_lines_2d/screenshots/add-arc.png new file mode 100644 index 0000000..7d5c189 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/add-arc.png differ diff --git a/addons/curved_lines_2d/screenshots/add_a_hole.png b/addons/curved_lines_2d/screenshots/add_a_hole.png new file mode 100644 index 0000000..9462f72 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/add_a_hole.png differ diff --git a/addons/curved_lines_2d/screenshots/add_color_stop.png b/addons/curved_lines_2d/screenshots/add_color_stop.png new file mode 100644 index 0000000..69232e9 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/add_color_stop.png differ diff --git a/addons/curved_lines_2d/screenshots/advanced-tab.png b/addons/curved_lines_2d/screenshots/advanced-tab.png new file mode 100644 index 0000000..e8ceeed Binary files /dev/null and b/addons/curved_lines_2d/screenshots/advanced-tab.png differ diff --git a/addons/curved_lines_2d/screenshots/alt-click-subdivide.png b/addons/curved_lines_2d/screenshots/alt-click-subdivide.png new file mode 100644 index 0000000..0524371 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/alt-click-subdivide.png differ diff --git a/addons/curved_lines_2d/screenshots/animating-in-2.4.0.png b/addons/curved_lines_2d/screenshots/animating-in-2.4.0.png new file mode 100644 index 0000000..170f7de Binary files /dev/null and b/addons/curved_lines_2d/screenshots/animating-in-2.4.0.png differ diff --git a/addons/curved_lines_2d/screenshots/animating-youtube-thumbnail.png b/addons/curved_lines_2d/screenshots/animating-youtube-thumbnail.png new file mode 100644 index 0000000..85eac73 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/animating-youtube-thumbnail.png differ diff --git a/addons/curved_lines_2d/screenshots/animating.png b/addons/curved_lines_2d/screenshots/animating.png new file mode 100644 index 0000000..eb5eb30 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/animating.png differ diff --git a/addons/curved_lines_2d/screenshots/arc-settings.png b/addons/curved_lines_2d/screenshots/arc-settings.png new file mode 100644 index 0000000..32256e5 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/arc-settings.png differ diff --git a/addons/curved_lines_2d/screenshots/banner1280x720.png b/addons/curved_lines_2d/screenshots/banner1280x720.png new file mode 100644 index 0000000..18c673f Binary files /dev/null and b/addons/curved_lines_2d/screenshots/banner1280x720.png differ diff --git a/addons/curved_lines_2d/screenshots/basic-drawing-youtube-thumnail.png b/addons/curved_lines_2d/screenshots/basic-drawing-youtube-thumnail.png new file mode 100644 index 0000000..dac4d0d Binary files /dev/null and b/addons/curved_lines_2d/screenshots/basic-drawing-youtube-thumnail.png differ diff --git a/addons/curved_lines_2d/screenshots/butterfly_net.png b/addons/curved_lines_2d/screenshots/butterfly_net.png new file mode 100644 index 0000000..cda2a2d Binary files /dev/null and b/addons/curved_lines_2d/screenshots/butterfly_net.png differ diff --git a/addons/curved_lines_2d/screenshots/changing-curve.gif b/addons/curved_lines_2d/screenshots/changing-curve.gif new file mode 100644 index 0000000..041a0fd Binary files /dev/null and b/addons/curved_lines_2d/screenshots/changing-curve.gif differ diff --git a/addons/curved_lines_2d/screenshots/colliding_stroke_promo.png b/addons/curved_lines_2d/screenshots/colliding_stroke_promo.png new file mode 100644 index 0000000..a68557c Binary files /dev/null and b/addons/curved_lines_2d/screenshots/colliding_stroke_promo.png differ diff --git a/addons/curved_lines_2d/screenshots/collision-inspector-form.png b/addons/curved_lines_2d/screenshots/collision-inspector-form.png new file mode 100644 index 0000000..3aab863 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/collision-inspector-form.png differ diff --git a/addons/curved_lines_2d/screenshots/create-ellipse-as-path.png b/addons/curved_lines_2d/screenshots/create-ellipse-as-path.png new file mode 100644 index 0000000..a76bc14 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/create-ellipse-as-path.png differ diff --git a/addons/curved_lines_2d/screenshots/create-rect-as-rect.png b/addons/curved_lines_2d/screenshots/create-rect-as-rect.png new file mode 100644 index 0000000..0383bff Binary files /dev/null and b/addons/curved_lines_2d/screenshots/create-rect-as-rect.png differ diff --git a/addons/curved_lines_2d/screenshots/curve_settings_inspector_form.png b/addons/curved_lines_2d/screenshots/curve_settings_inspector_form.png new file mode 100644 index 0000000..359026e Binary files /dev/null and b/addons/curved_lines_2d/screenshots/curve_settings_inspector_form.png differ diff --git a/addons/curved_lines_2d/screenshots/dock-in-2.2.1.png b/addons/curved_lines_2d/screenshots/dock-in-2.2.1.png new file mode 100644 index 0000000..677a117 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/dock-in-2.2.1.png differ diff --git a/addons/curved_lines_2d/screenshots/drag_gradient_start.png b/addons/curved_lines_2d/screenshots/drag_gradient_start.png new file mode 100644 index 0000000..be2681b Binary files /dev/null and b/addons/curved_lines_2d/screenshots/drag_gradient_start.png differ diff --git a/addons/curved_lines_2d/screenshots/drag_remove_color_stops.png b/addons/curved_lines_2d/screenshots/drag_remove_color_stops.png new file mode 100644 index 0000000..f2ac322 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/drag_remove_color_stops.png differ diff --git a/addons/curved_lines_2d/screenshots/dualview-preview.png b/addons/curved_lines_2d/screenshots/dualview-preview.png new file mode 100644 index 0000000..9d27f03 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/dualview-preview.png differ diff --git a/addons/curved_lines_2d/screenshots/fill-form-no-fill.png b/addons/curved_lines_2d/screenshots/fill-form-no-fill.png new file mode 100644 index 0000000..ee37863 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/fill-form-no-fill.png differ diff --git a/addons/curved_lines_2d/screenshots/global_position_popup.png b/addons/curved_lines_2d/screenshots/global_position_popup.png new file mode 100644 index 0000000..5479557 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/global_position_popup.png differ diff --git a/addons/curved_lines_2d/screenshots/glue_map.png b/addons/curved_lines_2d/screenshots/glue_map.png new file mode 100644 index 0000000..1715c7b Binary files /dev/null and b/addons/curved_lines_2d/screenshots/glue_map.png differ diff --git a/addons/curved_lines_2d/screenshots/heart-scene-in-2.2.1.png b/addons/curved_lines_2d/screenshots/heart-scene-in-2.2.1.png new file mode 100644 index 0000000..3e2c4a3 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/heart-scene-in-2.2.1.png differ diff --git a/addons/curved_lines_2d/screenshots/heart_scene_focus.png b/addons/curved_lines_2d/screenshots/heart_scene_focus.png new file mode 100644 index 0000000..95e7479 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/heart_scene_focus.png differ diff --git a/addons/curved_lines_2d/screenshots/hole_added.png b/addons/curved_lines_2d/screenshots/hole_added.png new file mode 100644 index 0000000..08693a1 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/hole_added.png differ diff --git a/addons/curved_lines_2d/screenshots/image-0.png b/addons/curved_lines_2d/screenshots/image-0.png new file mode 100644 index 0000000..631989a Binary files /dev/null and b/addons/curved_lines_2d/screenshots/image-0.png differ diff --git a/addons/curved_lines_2d/screenshots/image-1.png b/addons/curved_lines_2d/screenshots/image-1.png new file mode 100644 index 0000000..e24d8e6 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/image-1.png differ diff --git a/addons/curved_lines_2d/screenshots/image-2.png b/addons/curved_lines_2d/screenshots/image-2.png new file mode 100644 index 0000000..bdc8f9a Binary files /dev/null and b/addons/curved_lines_2d/screenshots/image-2.png differ diff --git a/addons/curved_lines_2d/screenshots/image-3.png b/addons/curved_lines_2d/screenshots/image-3.png new file mode 100644 index 0000000..604793f Binary files /dev/null and b/addons/curved_lines_2d/screenshots/image-3.png differ diff --git a/addons/curved_lines_2d/screenshots/image-4.png b/addons/curved_lines_2d/screenshots/image-4.png new file mode 100644 index 0000000..b426607 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/image-4.png differ diff --git a/addons/curved_lines_2d/screenshots/importing-svg-files-youtube-thumbnail.png b/addons/curved_lines_2d/screenshots/importing-svg-files-youtube-thumbnail.png new file mode 100644 index 0000000..1f20332 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/importing-svg-files-youtube-thumbnail.png differ diff --git a/addons/curved_lines_2d/screenshots/inspector-in-2.5.png b/addons/curved_lines_2d/screenshots/inspector-in-2.5.png new file mode 100644 index 0000000..ba49eb7 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/inspector-in-2.5.png differ diff --git a/addons/curved_lines_2d/screenshots/inspector-in-2.6.png b/addons/curved_lines_2d/screenshots/inspector-in-2.6.png new file mode 100644 index 0000000..f4811b3 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/inspector-in-2.6.png differ diff --git a/addons/curved_lines_2d/screenshots/known-issues-youtube-thumbnail.png b/addons/curved_lines_2d/screenshots/known-issues-youtube-thumbnail.png new file mode 100644 index 0000000..5a16450 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/known-issues-youtube-thumbnail.png differ diff --git a/addons/curved_lines_2d/screenshots/leopard.png b/addons/curved_lines_2d/screenshots/leopard.png new file mode 100644 index 0000000..86f6f5c Binary files /dev/null and b/addons/curved_lines_2d/screenshots/leopard.png differ diff --git a/addons/curved_lines_2d/screenshots/local_to_scene.png b/addons/curved_lines_2d/screenshots/local_to_scene.png new file mode 100644 index 0000000..446a1fd Binary files /dev/null and b/addons/curved_lines_2d/screenshots/local_to_scene.png differ diff --git a/addons/curved_lines_2d/screenshots/make-unique.png b/addons/curved_lines_2d/screenshots/make-unique.png new file mode 100644 index 0000000..5f17c26 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/make-unique.png differ diff --git a/addons/curved_lines_2d/screenshots/merge_2_points.png b/addons/curved_lines_2d/screenshots/merge_2_points.png new file mode 100644 index 0000000..6cde064 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/merge_2_points.png differ diff --git a/addons/curved_lines_2d/screenshots/merge_mode_button.png b/addons/curved_lines_2d/screenshots/merge_mode_button.png new file mode 100644 index 0000000..a512f7d Binary files /dev/null and b/addons/curved_lines_2d/screenshots/merge_mode_button.png differ diff --git a/addons/curved_lines_2d/screenshots/more-on-node-hierarchy.png b/addons/curved_lines_2d/screenshots/more-on-node-hierarchy.png new file mode 100644 index 0000000..7f774bc Binary files /dev/null and b/addons/curved_lines_2d/screenshots/more-on-node-hierarchy.png differ diff --git a/addons/curved_lines_2d/screenshots/new-in-2.9.1-yt-thumbnail.png b/addons/curved_lines_2d/screenshots/new-in-2.9.1-yt-thumbnail.png new file mode 100644 index 0000000..ef35c13 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/new-in-2.9.1-yt-thumbnail.png differ diff --git a/addons/curved_lines_2d/screenshots/project-settings.png b/addons/curved_lines_2d/screenshots/project-settings.png new file mode 100644 index 0000000..96c8d4c Binary files /dev/null and b/addons/curved_lines_2d/screenshots/project-settings.png differ diff --git a/addons/curved_lines_2d/screenshots/rat_tail.png b/addons/curved_lines_2d/screenshots/rat_tail.png new file mode 100644 index 0000000..306ba42 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/rat_tail.png differ diff --git a/addons/curved_lines_2d/screenshots/rats-return.png b/addons/curved_lines_2d/screenshots/rats-return.png new file mode 100644 index 0000000..2920e39 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/rats-return.png differ diff --git a/addons/curved_lines_2d/screenshots/remove-arc.png b/addons/curved_lines_2d/screenshots/remove-arc.png new file mode 100644 index 0000000..fd40be1 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/remove-arc.png differ diff --git a/addons/curved_lines_2d/screenshots/scaling_textures.png b/addons/curved_lines_2d/screenshots/scaling_textures.png new file mode 100644 index 0000000..2001fae Binary files /dev/null and b/addons/curved_lines_2d/screenshots/scaling_textures.png differ diff --git a/addons/curved_lines_2d/screenshots/sculpting-paths-on-youtube.png b/addons/curved_lines_2d/screenshots/sculpting-paths-on-youtube.png new file mode 100644 index 0000000..13b53f6 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/sculpting-paths-on-youtube.png differ diff --git a/addons/curved_lines_2d/screenshots/settings_panel.png b/addons/curved_lines_2d/screenshots/settings_panel.png new file mode 100644 index 0000000..ef715a2 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/settings_panel.png differ diff --git a/addons/curved_lines_2d/screenshots/simple_line.png b/addons/curved_lines_2d/screenshots/simple_line.png new file mode 100644 index 0000000..9aa7466 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/simple_line.png differ diff --git a/addons/curved_lines_2d/screenshots/snail-in-2.2.1.png b/addons/curved_lines_2d/screenshots/snail-in-2.2.1.png new file mode 100644 index 0000000..fa5b2f0 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/snail-in-2.2.1.png differ diff --git a/addons/curved_lines_2d/screenshots/spring-ball.png b/addons/curved_lines_2d/screenshots/spring-ball.png new file mode 100644 index 0000000..acae2b6 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/spring-ball.png differ diff --git a/addons/curved_lines_2d/screenshots/static_screenshot.png b/addons/curved_lines_2d/screenshots/static_screenshot.png new file mode 100644 index 0000000..fb4d7e6 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/static_screenshot.png differ diff --git a/addons/curved_lines_2d/screenshots/stroke-form-no-stroke.png b/addons/curved_lines_2d/screenshots/stroke-form-no-stroke.png new file mode 100644 index 0000000..d50d8c7 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/stroke-form-no-stroke.png differ diff --git a/addons/curved_lines_2d/screenshots/stroke_inspector.png b/addons/curved_lines_2d/screenshots/stroke_inspector.png new file mode 100644 index 0000000..75deeec Binary files /dev/null and b/addons/curved_lines_2d/screenshots/stroke_inspector.png differ diff --git a/addons/curved_lines_2d/screenshots/subdivide.gif b/addons/curved_lines_2d/screenshots/subdivide.gif new file mode 100644 index 0000000..557b236 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/subdivide.gif differ diff --git a/addons/curved_lines_2d/screenshots/svg_importer_dock.png b/addons/curved_lines_2d/screenshots/svg_importer_dock.png new file mode 100644 index 0000000..3f876fa Binary files /dev/null and b/addons/curved_lines_2d/screenshots/svg_importer_dock.png differ diff --git a/addons/curved_lines_2d/screenshots/svg_importer_screenshot.png b/addons/curved_lines_2d/screenshots/svg_importer_screenshot.png new file mode 100644 index 0000000..23c3808 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/svg_importer_screenshot.png differ diff --git a/addons/curved_lines_2d/screenshots/svg_texture_helper_in_scene_tree.png b/addons/curved_lines_2d/screenshots/svg_texture_helper_in_scene_tree.png new file mode 100644 index 0000000..2ab6d3c Binary files /dev/null and b/addons/curved_lines_2d/screenshots/svg_texture_helper_in_scene_tree.png differ diff --git a/addons/curved_lines_2d/screenshots/svs_vertex_merge_2d_node.png b/addons/curved_lines_2d/screenshots/svs_vertex_merge_2d_node.png new file mode 100644 index 0000000..4701f07 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/svs_vertex_merge_2d_node.png differ diff --git a/addons/curved_lines_2d/screenshots/uniform_rotate_a_path_hole.png b/addons/curved_lines_2d/screenshots/uniform_rotate_a_path_hole.png new file mode 100644 index 0000000..cb2ead0 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/uniform_rotate_a_path_hole.png differ diff --git a/addons/curved_lines_2d/screenshots/uniform_transforms.png b/addons/curved_lines_2d/screenshots/uniform_transforms.png new file mode 100644 index 0000000..01291f6 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/uniform_transforms.png differ diff --git a/addons/curved_lines_2d/screenshots/update-curve-at-runtime-in-2.4.0.png b/addons/curved_lines_2d/screenshots/update-curve-at-runtime-in-2.4.0.png new file mode 100644 index 0000000..67a91f0 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/update-curve-at-runtime-in-2.4.0.png differ diff --git a/addons/curved_lines_2d/screenshots/update-runtime.png b/addons/curved_lines_2d/screenshots/update-runtime.png new file mode 100644 index 0000000..e78ca3d Binary files /dev/null and b/addons/curved_lines_2d/screenshots/update-runtime.png differ diff --git a/addons/curved_lines_2d/screenshots/updated-inspector.png b/addons/curved_lines_2d/screenshots/updated-inspector.png new file mode 100644 index 0000000..42526f7 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/updated-inspector.png differ diff --git a/addons/curved_lines_2d/screenshots/yt_short_thumb.png b/addons/curved_lines_2d/screenshots/yt_short_thumb.png new file mode 100644 index 0000000..8d0bc2c Binary files /dev/null and b/addons/curved_lines_2d/screenshots/yt_short_thumb.png differ diff --git a/addons/curved_lines_2d/screenshots/yt_thumb-2.png b/addons/curved_lines_2d/screenshots/yt_thumb-2.png new file mode 100644 index 0000000..d541c1d Binary files /dev/null and b/addons/curved_lines_2d/screenshots/yt_thumb-2.png differ diff --git a/addons/curved_lines_2d/screenshots/yt_thumb.png b/addons/curved_lines_2d/screenshots/yt_thumb.png new file mode 100644 index 0000000..eaa6ad6 Binary files /dev/null and b/addons/curved_lines_2d/screenshots/yt_thumb.png differ diff --git a/addons/curved_lines_2d/set_global_position_popup_panel.gd b/addons/curved_lines_2d/set_global_position_popup_panel.gd new file mode 100644 index 0000000..33dc7ee --- /dev/null +++ b/addons/curved_lines_2d/set_global_position_popup_panel.gd @@ -0,0 +1,70 @@ +@tool +extends PopupPanel + +signal value_changed(value : Vector2, meta_name : String, point_idx : int) + +var x_pos_input : EditorSpinSlider +var y_pos_input : EditorSpinSlider +var meta_name := CurvedLines2D.META_NAME_HOVER_POINT_IDX +var point_idx : int = 0 +var _dragging := false +var _drag_start := Vector2.ZERO + +func _enter_tree() -> void: + visible = false + x_pos_input = _mk_input() + y_pos_input = _mk_input() + %XPosInputContainer.add_child(x_pos_input) + %YPosInputContainer.add_child(y_pos_input) + if not x_pos_input.value_changed.is_connected(_on_value_changed): + x_pos_input.value_changed.connect(_on_value_changed) + if not y_pos_input.value_changed.is_connected(_on_value_changed): + y_pos_input.value_changed.connect(_on_value_changed) + + +func _on_button_pressed() -> void: + hide() + + +func _on_value_changed(_v : Variant = null): + value_changed.emit(Vector2(x_pos_input.value, y_pos_input.value), meta_name, point_idx) + + +func popup_with_value(metadata : Dictionary, snapped : bool, snap_step : float): + point_idx = metadata['point_idx'] + meta_name = metadata['meta_name'] + x_pos_input.set_value_no_signal(metadata['global_pos'].x) + y_pos_input.set_value_no_signal(metadata['global_pos'].y) + if snapped: + x_pos_input.step = snap_step + y_pos_input.step = snap_step + else: + x_pos_input.step = 0.001 + y_pos_input.step = 0.001 + _on_value_changed() + popup_centered() + + +func _mk_input() -> EditorSpinSlider: + var num_input := EditorSpinSlider.new() + num_input.suffix = "px" + num_input.hide_slider = true + num_input.value = 0.0 + num_input.editing_integer = false + num_input.allow_lesser = true + num_input.allow_greater = true + num_input.step = 0.001 + return num_input + + +func _on_label_gui_input(event: InputEvent) -> void: + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + if not _dragging: + _dragging = true + _drag_start = EditorInterface.get_base_control().get_local_mouse_position() + else: + _dragging = false + if event is InputEventMouseMotion and _dragging: + position += Vector2i(EditorInterface.get_base_control().get_local_mouse_position() - _drag_start) + _drag_start = EditorInterface.get_base_control().get_local_mouse_position() diff --git a/addons/curved_lines_2d/set_global_position_popup_panel.gd.uid b/addons/curved_lines_2d/set_global_position_popup_panel.gd.uid new file mode 100644 index 0000000..9f480b2 --- /dev/null +++ b/addons/curved_lines_2d/set_global_position_popup_panel.gd.uid @@ -0,0 +1 @@ +uid://bq4xfmsr6k2te diff --git a/addons/curved_lines_2d/set_global_position_popup_panel.tscn b/addons/curved_lines_2d/set_global_position_popup_panel.tscn new file mode 100644 index 0000000..52f8c7f --- /dev/null +++ b/addons/curved_lines_2d/set_global_position_popup_panel.tscn @@ -0,0 +1,106 @@ +[gd_scene load_steps=7 format=3 uid="uid://c4d61or7beyf5"] + +[ext_resource type="Script" uid="uid://bq4xfmsr6k2te" path="res://addons/curved_lines_2d/set_global_position_popup_panel.gd" id="1_tnog5"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3qpoy"] +content_margin_left = 4.0 +content_margin_top = 2.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(0.133333, 0.12549, 0.14902, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tnog5"] +bg_color = Color(0, 0, 0, 1) +corner_radius_top_left = 2 +corner_radius_bottom_left = 2 + +[sub_resource type="LabelSettings" id="LabelSettings_u6amf"] +line_spacing = 0.0 +font_color = Color(0.54, 0.33696, 0.2808, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_vlbak"] +bg_color = Color(0.133333, 0.12549, 0.14902, 1) + +[sub_resource type="LabelSettings" id="LabelSettings_0n4is"] +font_color = Color(0.345098, 0.47451, 0.396078, 1) + +[node name="SetGlobalPositionPopupPanel" type="PopupPanel"] +initial_position = 4 +size = Vector2i(160, 140) +theme_override_styles/panel = SubResource("StyleBoxFlat_3qpoy") +script = ExtResource("1_tnog5") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 2.0 +offset_right = -4.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +theme_override_constants/separation = 5 + +[node name="Label" type="Label" parent="VBoxContainer"] +layout_mode = 2 +mouse_filter = 0 +text = "Set global position" +horizontal_alignment = 1 + +[node name="PanelContainer" type="PanelContainer" parent="VBoxContainer"] +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_tnog5") + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/PanelContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/PanelContainer/HBoxContainer"] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "x" +label_settings = SubResource("LabelSettings_u6amf") +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="XPosInputContainer" type="PanelContainer" parent="VBoxContainer/PanelContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_vlbak") + +[node name="PanelContainer2" type="PanelContainer" parent="VBoxContainer"] +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_tnog5") + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/PanelContainer2"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/PanelContainer2/HBoxContainer"] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 1 +text = "y" +label_settings = SubResource("LabelSettings_0n4is") +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="YPosInputContainer" type="PanelContainer" parent="VBoxContainer/PanelContainer2/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_vlbak") + +[node name="Button" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Ok" + +[connection signal="gui_input" from="VBoxContainer/Label" to="." method="_on_label_gui_input"] +[connection signal="pressed" from="VBoxContainer/Button" to="." method="_on_button_pressed"] diff --git a/addons/curved_lines_2d/snazzy_toggle_button.stylebox b/addons/curved_lines_2d/snazzy_toggle_button.stylebox new file mode 100644 index 0000000..0a90b43 Binary files /dev/null and b/addons/curved_lines_2d/snazzy_toggle_button.stylebox differ diff --git a/addons/curved_lines_2d/svg_import_tab.gd b/addons/curved_lines_2d/svg_import_tab.gd new file mode 100644 index 0000000..e94b1ff --- /dev/null +++ b/addons/curved_lines_2d/svg_import_tab.gd @@ -0,0 +1,988 @@ +@tool +extends Control + +# Fraction of a radius for a bezier control point +const R_TO_CP = 0.5523 +const PLC_EXP = "__PLC_EXP__" + +const SVG_ROOT_META_NAME := "svg_root" +const SVG_STYLE_META_NAME := "svg_style" + +const PAINT_ORDER_MAP := { + "normal": ['add_fill_to_path', 'add_stroke_to_path', 'add_collision_to_path'], + "fill stroke markers": ['add_fill_to_path', 'add_stroke_to_path', 'add_collision_to_path'], + "stroke fill markers": ['add_stroke_to_path', 'add_fill_to_path', 'add_collision_to_path'], + "fill markers stroke": ['add_fill_to_path', 'add_collision_to_path', 'add_stroke_to_path'], + "markers fill stroke": ['add_collision_to_path', 'add_fill_to_path', 'add_stroke_to_path'], + "stroke markers fill": ['add_stroke_to_path', 'add_collision_to_path', 'add_fill_to_path'], + "markers stroke fill": ['add_collision_to_path', 'add_stroke_to_path', 'add_fill_to_path'] +} +const STROKE_CAP_MAP := { + "butt": Line2D.LineCapMode.LINE_CAP_NONE, + "round": Line2D.LineCapMode.LINE_CAP_ROUND, + "square": Line2D.LineCapMode.LINE_CAP_BOX +} +const STROKE_JOINT_MAP := { + "miter": Line2D.LineJointMode.LINE_JOINT_SHARP, + "miter-clip": Line2D.LineJointMode.LINE_JOINT_SHARP, + "round": Line2D.LineJointMode.LINE_JOINT_ROUND, + "bevel": Line2D.LineJointMode.LINE_JOINT_BEVEL, + "arc": Line2D.LineJointMode.LINE_JOINT_SHARP +} + +enum LogLevel { DEBUG, INFO, WARN, ERROR } +var error_label_settings : LabelSettings = null +var warning_label_settings : LabelSettings = null +var info_label_settings : LabelSettings = null +var debug_label_settings : LabelSettings = null + +## Settings +var collision_object_type := ScalableVectorShape2D.CollisionObjectType.NONE +var import_as_svs := true +var lock_shapes := true +var antialiased_shapes := false +var import_stroke_as_line_2d := true +var import_file_dialog : EditorFileDialog = null +var warning_dialog : AcceptDialog = null +var undo_redo : EditorUndoRedoManager = null +var LinkButtonScene : PackedScene = null + +func _enter_tree() -> void: + error_label_settings = preload("res://addons/curved_lines_2d/error_label_settings.tres") + warning_label_settings = preload("res://addons/curved_lines_2d/warn_label_settings.tres") + info_label_settings = preload("res://addons/curved_lines_2d/info_label_settings.tres") + debug_label_settings = preload("res://addons/curved_lines_2d/debug_label_settings.tres") + LinkButtonScene = preload("res://addons/curved_lines_2d/link_button_with_copy_hint.tscn") + %LogScrollContainer.get_v_scroll_bar().connect("changed", func(): %LogScrollContainer.scroll_vertical = %LogScrollContainer.get_v_scroll_bar().max_value ) + import_file_dialog = EditorFileDialog.new() + import_file_dialog.add_filter("*.svg", "SVG image") + import_file_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE + import_file_dialog.file_selected.connect(_load_svg) + EditorInterface.get_base_control().add_child(import_file_dialog) + undo_redo = EditorInterface.get_editor_undo_redo() + + +func _can_drop_data(at_position: Vector2, data: Variant) -> bool: + if not typeof(data) == TYPE_DICTIONARY and "type" in data and data["type"] == "files": + return false + for file : String in data["files"]: + if file.ends_with(".svg"): + return true + return false + + +func log_message(msg : String, log_level : LogLevel = LogLevel.INFO) -> void: + var lbl := Label.new() + match log_level: + LogLevel.ERROR: + warning_dialog.dialog_text = msg + warning_dialog.popup_centered() + lbl.label_settings = error_label_settings + LogLevel.WARN: + lbl.label_settings = warning_label_settings + LogLevel.DEBUG: + lbl.label_settings = debug_label_settings + LogLevel.INFO,_: + lbl.label_settings = info_label_settings + lbl.text = msg + + %ImportLogContainer.add_child(lbl) + + +func _drop_data(at_position: Vector2, data: Variant) -> void: + if _can_drop_data(at_position, data): + _load_svg(data["files"][0]) + + +func _get_viewport_center() -> Vector2: + var tr := EditorInterface.get_editor_viewport_2d().global_canvas_transform + var og := tr.get_origin() + var sz := Vector2(EditorInterface.get_editor_viewport_2d().size) + return (sz / 2) / tr.get_scale() - og / tr.get_scale() + + +func _load_svg(file_path : String) -> void: + for child in %ImportLogContainer.get_children(): + child.queue_free() + var xml_parser = XMLParser.new() + var scene_root := EditorInterface.get_edited_scene_root() + var selected_nodes := EditorInterface.get_selection().get_selected_nodes() + var parent_node := scene_root if selected_nodes.is_empty() else selected_nodes[0] + if not scene_root is Node: + log_message("ERROR: Can only import into an opened scene", LogLevel.ERROR) + return + if xml_parser.open(file_path) != OK: + log_message("ERROR: Failed to open %s for reading" % file_path, LogLevel.ERROR) + return + + log_message("Importing SVG file: %s" % file_path, LogLevel.INFO) + var svg_root := Node2D.new() + svg_root.name = file_path.get_file().replace(".svg", "").to_pascal_case() + undo_redo.create_action("Import SVG file as Nodes: %s" % svg_root.name) + svg_root.set_meta(SVG_ROOT_META_NAME, true) + + _managed_add_child_and_set_owner(parent_node, svg_root, scene_root) + + var current_node := svg_root + var svg_gradients : Array[Dictionary] = [] + + var svg_xml_node : SVGXMLElement = parse_svg_xml_file(xml_parser) + process_svg_xml_tree(svg_xml_node, scene_root, svg_root, current_node, svg_gradients) + undo_redo.commit_action(false) + + + if not import_as_svs: + await RenderingServer.frame_post_draw + Line2DGeneratorInspectorPlugin._copy_baked_node(svg_root, parent_node, scene_root) + parent_node.remove_child(svg_root) + + + log_message("Import finished.\n\nThe SVG importer is still incrementally improving (slowly).") + var link_button = LinkButtonScene.instantiate() + link_button.text = "Click here to report issues or improvement requests on github" + link_button.uri = "https://github.com/Teaching-myself-Godot/ez-curved-lines-2d/issues" + %ImportLogContainer.add_child(link_button) + + var selection_target = ( + svg_root.find_children("*", "ScalableVectorShape2D") + .filter(func(n : CanvasItem): return n.is_visible_in_tree()).pop_front() + ) + if not is_instance_valid(selection_target): + selection_target = svg_root + EditorInterface.call_deferred('edit_node', selection_target) + await get_tree().create_timer(0.0167).timeout + EditorInterface.get_editor_viewport_2d().get_parent().grab_focus() + var key_ev := InputEventKey.new() + key_ev.keycode = KEY_F + key_ev.pressed = true + Input.parse_input_event(key_ev) + +func parse_svg_xml_file(xml_parser : XMLParser) -> SVGXMLElement: + var svg_xml_node : SVGXMLElement = null + while xml_parser.read() == OK: + if not xml_parser.get_node_type() in [XMLParser.NODE_ELEMENT, XMLParser.NODE_ELEMENT_END]: + continue + if xml_parser.get_node_type() == XMLParser.NODE_ELEMENT and xml_parser.is_empty() and xml_parser.get_node_name() in ["defs", "g", "clipPath"]: + continue + if xml_parser.get_node_type() == XMLParser.NODE_ELEMENT_END: + if svg_xml_node.parent: + svg_xml_node = svg_xml_node.parent + else: + var new_svg_xml_node := SVGXMLElement.new(xml_parser, svg_xml_node) + if svg_xml_node: + svg_xml_node.add_child(new_svg_xml_node) + if not xml_parser.is_empty(): + svg_xml_node = new_svg_xml_node + return svg_xml_node + +func process_svg_xml_tree(xml_data : SVGXMLElement, scene_root : Node, svg_root : + Node2D, current_node : Node2D, svg_gradients : Array[Dictionary]) -> void: + + if xml_data.name == "use": + var href = xml_data.get_named_attribute_value_safe("xlink:href") + if href.is_empty(): + href = xml_data.get_named_attribute_value_safe("href") + var reuse_xml_node = xml_data.find_by_id(href.replace("#", "")) + var style = xml_data.get_svg_style(log_message) + style.merge(reuse_xml_node.get_merged_styles(log_message)) + var preserve_id := xml_data.get_named_attribute_value_safe("id") + xml_data.attributes.erase("xlink:href") + xml_data.attributes.merge(reuse_xml_node.attributes) + xml_data.attributes["id"] = preserve_id + xml_data.attributes["style"] = "; ".join(style.keys().map(func(k): return k + ": " + style[k])) + if preserve_id.is_empty(): + xml_data.attributes.erase("id") + xml_data.name = reuse_xml_node.name + + match xml_data.name: + "svg": + if xml_data.has_attribute("viewBox") and xml_data.has_attribute("width") and xml_data.has_attribute("height"): + var view_box = xml_data.get_named_attribute_value("viewBox").split_floats(" ") + var width := float(xml_data.get_named_attribute_value("width")) + var height := float(xml_data.get_named_attribute_value("height")) + svg_root.scale.x = width / view_box[2] + svg_root.scale.y = height / view_box[3] + if xml_data.get_named_attribute_value("width").ends_with("mm"): # unit conversion to pixel + log_message("⚠️ Units for this image are millimeters (mm), image scale set to 3.78") + svg_root.scale *= 3.78 + elif xml_data.get_named_attribute_value("width").ends_with("cm"): + log_message("⚠️ Units for this image are centimeters (cm), image scale set to 37.8") + svg_root.scale *= 37.8 + if xml_data.has_attribute("style"): + current_node.set_meta(SVG_STYLE_META_NAME, xml_data.get_merged_styles(log_message)) + "g": + current_node = process_group(xml_data, current_node, scene_root) + "clipPath", "defs": + current_node = process_group(xml_data, current_node, scene_root, xml_data.name) + current_node.hide() + "rect": + process_svg_rectangle(xml_data, current_node, scene_root, svg_gradients) + "image": + process_svg_image(xml_data, current_node, scene_root, svg_gradients) + "polygon": + process_svg_polygon(xml_data, current_node, scene_root, true, svg_gradients) + "polyline": + process_svg_polygon(xml_data, current_node, scene_root, false, svg_gradients) + "path": + process_svg_path(xml_data, current_node, scene_root, svg_gradients) + "circle": + process_svg_circle(xml_data, current_node, scene_root, svg_gradients) + "ellipse": + process_svg_ellipse(xml_data, current_node, scene_root, svg_gradients) + "linearGradient", "radialGradient": + svg_gradients.append(parse_gradient(xml_data)) + "stop": + pass + _: log_message("⚠️ Skipping unsupported node: <%s>" % xml_data.name, LogLevel.DEBUG) + + var defs := xml_data.children.filter(func(ch): return ch.name == "defs") + var clip_paths := xml_data.children.filter(func(ch): return ch.name == "clipPath") + var remainder := xml_data.children.filter(func(ch): return ch.name != "defs" and ch.name != "clipPath") + for ch in defs + clip_paths + remainder: + process_svg_xml_tree(ch, scene_root, svg_root, current_node, svg_gradients) + + +func get_gradient_by_href(href : String, gradients : Array[Dictionary]) -> Dictionary: + var idx := gradients.find_custom(func(x): return "id" in x and "#" + x["id"] == href) + if idx < 0: + return {} + return gradients[idx] + + +func parse_gradient(gradient_xml : SVGXMLElement) -> Dictionary: + var new_gradient = { + 'is_radial': gradient_xml.get_node_name() == "radialGradient" + } + for x in gradient_xml.attributes: + new_gradient[x] = gradient_xml.attributes[x] + if not gradient_xml.is_empty(): + new_gradient["stops"] = [] + for element in gradient_xml.children: + if element.get_node_name() == "stop": + new_gradient["stops"].append({ + "style": element.get_merged_styles(log_message), + "offset": float(element.get_named_attribute_value_safe("offset")), + "id": element.get_named_attribute_value_safe("id") + }) + + return new_gradient + + +func process_group(element:SVGXMLElement, current_node : Node2D, scene_root : Node, alt_name := "Group") -> Node2D: + var new_group = Node2D.new() + new_group.name = element.get_named_attribute_value("id") if element.has_attribute("id") else alt_name + new_group.transform = get_svg_transform(element) + var style := element.get_merged_styles(log_message) + new_group.set_meta(SVG_STYLE_META_NAME, style) + + if style.has("display") and style['display'] == "none": + new_group.visible = false + _managed_add_child_and_set_owner(current_node, new_group, scene_root) + return new_group + + +func process_svg_circle(element:SVGXMLElement, current_node : Node2D, scene_root : Node, + gradients : Array[Dictionary]) -> void: + var cx = float(element.get_named_attribute_value("cx")) + var cy = float(element.get_named_attribute_value("cy")) + var r = float(element.get_named_attribute_value("r")) + var path_name = element.get_named_attribute_value("id") if element.has_attribute("id") else "Circle" + create_path_from_ellipse(element, path_name, r, r, Vector2(cx, cy), current_node, scene_root, gradients) + + +func process_svg_ellipse(element:SVGXMLElement, current_node : Node2D, scene_root : Node, + gradients : Array[Dictionary]) -> void: + var cx = float(element.get_named_attribute_value("cx")) + var cy = float(element.get_named_attribute_value("cy")) + var rx = float(element.get_named_attribute_value("rx")) + var ry = float(element.get_named_attribute_value("ry")) + var path_name = element.get_named_attribute_value("id") if element.has_attribute("id") else "Ellipse" + create_path_from_ellipse(element, path_name, rx, ry, Vector2(cx, cy), current_node, scene_root, gradients) + + +func create_path_from_ellipse(element:SVGXMLElement, path_name : String, rx : float, ry: float, + pos : Vector2, current_node : Node2D, scene_root : Node, + gradients : Array[Dictionary]) -> void: + var new_ellipse := ScalableVectorShape2D.new() + new_ellipse.shape_type = ScalableVectorShape2D.ShapeType.ELLIPSE + new_ellipse.size = Vector2(rx * 2, ry * 2) + new_ellipse.position = pos + new_ellipse.name = path_name + _post_process_shape(new_ellipse, current_node, get_svg_transform(element), + element.get_merged_styles(log_message), scene_root, gradients) + +func process_svg_image(element:SVGXMLElement, current_node : Node2D, scene_root : Node, + gradients : Array[Dictionary]) -> void: + var x = float(element.get_named_attribute_value("x")) if element.has_attribute("x") else 0.0 + var y = float(element.get_named_attribute_value("y")) if element.has_attribute("y") else 0.0 + var width = float(element.get_named_attribute_value("width")) + var height = float(element.get_named_attribute_value("height")) + var new_image_rect := ScalableVectorShape2D.new() + new_image_rect.shape_type = ScalableVectorShape2D.ShapeType.RECT + new_image_rect.size = Vector2(width, height) + new_image_rect.position = Vector2(x, y) + new_image_rect.size * 0.5 + new_image_rect.name = element.get_named_attribute_value("id") if element.has_attribute("id") else "Image" + var image_data : String = ( + element.get_named_attribute_value("xlink:href") + if element.has_attribute("xlink:href") else + element.get_named_attribute_value_safe("href") + ) + var image_texture : ImageTexture = null + if image_data.begins_with("data:image") and image_data.contains("base64"): + var parts_a := image_data.split(",") + var parts_b := parts_a[0].split("/") + var format := parts_b[1].replace(";", "").replace("base64", "").strip_edges() + var base_64_data := parts_a[1].strip_edges() + var unmarshalled := Marshalls.base64_to_raw(base_64_data) + var image := Image.new() + image.call("load_%s_from_buffer" % format.to_lower(), unmarshalled) + image_texture = ImageTexture.create_from_image(image) + log_message("Parsed image format: %s" % format, LogLevel.DEBUG) + else: + log_message("⚠️ Only base64 encoded embedded images are supported", LogLevel.WARN) + + _post_process_shape(new_image_rect, current_node, get_svg_transform(element), + element.get_merged_styles(log_message), scene_root, gradients, false, image_texture) + + +func process_svg_rectangle(element:SVGXMLElement, current_node : Node2D, scene_root : Node, + gradients : Array[Dictionary]) -> void: + var x = float(element.get_named_attribute_value("x")) + var y = float(element.get_named_attribute_value("y")) + var rx = float(element.get_named_attribute_value("rx")) if element.has_attribute("rx") else 0 + var ry = float(element.get_named_attribute_value("ry")) if element.has_attribute("ry") else 0 + if rx == 0 and ry != 0: + rx = ry + if ry == 0 and rx != 0: + ry = rx + var width = float(element.get_named_attribute_value("width")) + var height = float(element.get_named_attribute_value("height")) + var new_rect := ScalableVectorShape2D.new() + new_rect.shape_type = ScalableVectorShape2D.ShapeType.RECT + new_rect.size = Vector2(width, height) + new_rect.position = Vector2(x, y) + new_rect.size * 0.5 + new_rect.rx = rx + new_rect.ry = ry + new_rect.name = element.get_named_attribute_value("id") if element.has_attribute("id") else "Rectangle" + _post_process_shape(new_rect, current_node, get_svg_transform(element), + element.get_merged_styles(log_message), scene_root, gradients) + + +func process_svg_polygon(element:SVGXMLElement, current_node : Node2D, scene_root : Node, is_closed : bool, + gradients : Array[Dictionary]) -> void: + var points_split = element.get_named_attribute_value("points").split(" ", false) + var curve = Curve2D.new() + for p in points_split: + var values = p.split_floats(",", false) + curve.add_point(Vector2(values[0], values[1])) + var path_name = (element.get_named_attribute_value("id") if element.has_attribute("id") else + "Polygon" if is_closed else + "Polyline" + ) + create_path2d(path_name, current_node, curve, [], get_svg_transform(element), + element.get_merged_styles(log_message), scene_root, gradients, is_closed) + + +func process_svg_path(element:SVGXMLElement, current_node : Node2D, scene_root : Node, + gradients : Array[Dictionary]) -> void: + + # FIXME: implement better parsing here + var str_path = parse_attribute_string( + element.get_named_attribute_value("d")).replacen(",", " ") + var shape_name := element.get_named_attribute_value("id") if element.has_attribute("id") else "Path" + + for symbol in ["m", "M", "v", "V", "h", "H", "l", "L", "c", "C", "s", "S", "a", "A", "q", "Q", "t", "T", "z", "Z"]: + str_path = str_path.replace(symbol, " " + symbol + " ") + + # FIXME: this bit is especially problematic + str_path = str_path.replace("e-", PLC_EXP) + str_path = str_path.replace("-", " -") + str_path = str_path.replace(PLC_EXP, "e-") + var str_path_array = str_path.split(" ", false) + var string_arrays = [] + var string_array_top : PackedStringArray + for a in str_path_array: + if a == "m" or a == "M": + if string_array_top.size() > 0: + string_arrays.append(string_array_top.duplicate()) + string_array_top.resize(0) + string_array_top.append(a) + string_arrays.append(string_array_top) + + if string_arrays.size() > 1: + log_message("⚠️ Support for the m/M (move to) command is limited to cut-outs in svg paths") + var string_array_count = 0 + var cursor = Vector2.ZERO + var shapes : Array[ScalableVectorShape2D] = [] + for string_array in string_arrays: + var curve = Curve2D.new() + var arcs : Array[ScalableArc] = [] + string_array_count += 1 + var cursor_start := Vector2.ZERO + for i in string_array.size(): + var cursor_start_is_set := false + match string_array[i]: + "m": + while string_array.size() > i + 2 and string_array[i+1].is_valid_float(): + cursor += Vector2(float(string_array[i+1]), float(string_array[i+2])) + curve.add_point(cursor) + i += 2 + if not cursor_start_is_set: + cursor_start_is_set = true + cursor_start = cursor + "M": + while string_array.size() > i + 2 and string_array[i+1].is_valid_float(): + cursor = Vector2(float(string_array[i+1]), float(string_array[i+2])) + curve.add_point(cursor) + i += 2 + if not cursor_start_is_set: + cursor_start_is_set = true + cursor_start = cursor + "v": + while string_array[i+1].is_valid_float(): + cursor.y += float(string_array[i+1]) + curve.add_point(cursor) + i += 1 + "V": + while string_array[i+1].is_valid_float(): + cursor.y = float(string_array[i+1]) + curve.add_point(cursor) + i += 1 + "h": + while string_array[i+1].is_valid_float(): + cursor.x += float(string_array[i+1]) + curve.add_point(cursor) + i += 1 + "H": + while string_array[i+1].is_valid_float(): + cursor.x = float(string_array[i+1]) + curve.add_point(cursor) + i += 1 + "l": + while string_array.size() > i + 2 and string_array[i+1].is_valid_float(): + cursor += Vector2(float(string_array[i+1]), float(string_array[i+2])) + curve.add_point(cursor) + i += 2 + "L": + while string_array.size() > i + 2 and string_array[i+1].is_valid_float(): + cursor = Vector2(float(string_array[i+1]), float(string_array[i+2])) + curve.add_point(cursor) + i += 2 + "c": + while string_array.size() > i + 6 and string_array[i+1].is_valid_float(): + var c_out := Vector2(float(string_array[i+1]), float(string_array[i+2])) + var c_2 := Vector2(float(string_array[i+3]), float(string_array[i+4])) + var c_in_absolute = cursor + c_2 + curve.set_point_out(curve.get_point_count() - 1, c_out) + cursor += Vector2(float(string_array[i+5]), float(string_array[i+6])) + var c_in = c_in_absolute - cursor + curve.add_point(cursor) + curve.set_point_in(curve.get_point_count() - 1, c_in) + i += 6 + "C": + while string_array.size() > i + 6 and string_array[i+1].is_valid_float(): + var c_out := Vector2(float(string_array[i+1]), float(string_array[i+2])) + var prev_point := curve.get_point_position(curve.get_point_count() - 1) + var c_in := Vector2(float(string_array[i+3]), float(string_array[i+4])) + curve.set_point_out(curve.get_point_count() - 1, c_out - prev_point) + cursor = Vector2(float(string_array[i+5]), float(string_array[i+6])) + curve.add_point(cursor, c_in - cursor) + i += 6 + "s": + while string_array.size() > i + 4 and string_array[i+1].is_valid_float(): + var c_out := -curve.get_point_in(curve.get_point_count() - 1) + var c_2 := Vector2(float(string_array[i+1]), float(string_array[i+2])) + var c_in_absolute = cursor + c_2 + curve.set_point_out(curve.get_point_count() - 1, c_out) + cursor += Vector2(float(string_array[i+3]), float(string_array[i+4])) + var c_in = c_in_absolute - cursor + curve.add_point(cursor) + curve.set_point_in(curve.get_point_count() - 1, c_in) + i += 4 + "S": + while string_array.size() > i + 4 and string_array[i+1].is_valid_float(): + var c_out := -curve.get_point_in(curve.get_point_count() - 1) + curve.set_point_out(curve.get_point_count() - 1, c_out) + cursor = Vector2(float(string_array[i+3]), float(string_array[i+4])) + var c_in := Vector2(float(string_array[i+1]), float(string_array[i+2])) + curve.add_point(cursor, c_in - cursor) + i += 4 + "q": + while string_array.size() > i + 4 and string_array[i+1].is_valid_float(): + var prev_point := curve.get_point_position(curve.get_point_count() - 1) + var quadratic_control_point = cursor + Vector2(float(string_array[i+1]), float(string_array[i+2])) + var c_out = (quadratic_control_point - prev_point) * (2.0/3.0) + cursor += Vector2(float(string_array[i+3]), float(string_array[i+4])) + var c_in = (quadratic_control_point - cursor) * (2.0/3.0) + curve.set_point_out(curve.get_point_count() - 1, c_out) + curve.add_point(cursor, c_in) + i += 4 + "Q": + while string_array.size() > i + 4 and string_array[i+1].is_valid_float(): + var prev_point := curve.get_point_position(curve.get_point_count() - 1) + var quadratic_control_point := Vector2(float(string_array[i+1]), float(string_array[i+2])) + var c_out = (quadratic_control_point - prev_point) * (2.0/3.0) + cursor = Vector2(float(string_array[i+3]), float(string_array[i+4])) + var c_in = (quadratic_control_point - cursor) * (2.0/3.0) + curve.set_point_out(curve.get_point_count() - 1, c_out) + curve.add_point(cursor, c_in) + i += 4 + "t": + while string_array.size() > i + 2 and string_array[i+2].is_valid_float(): + var c_out := -curve.get_point_in(curve.get_point_count() - 1) + var quadratic_control_point := curve.get_point_position(curve.get_point_count() - 1) + (c_out / (2.0/3.0)) + curve.set_point_out(curve.get_point_count() - 1, c_out) + cursor += Vector2(float(string_array[i+1]), float(string_array[i+2])) + var c_in = (quadratic_control_point - cursor) * (2.0/3.0) + curve.add_point(cursor, c_in) + i += 2 + "T": + while string_array.size() > i + 2 and string_array[i+2].is_valid_float(): + var c_out := -curve.get_point_in(curve.get_point_count() - 1) + var quadratic_control_point := curve.get_point_position(curve.get_point_count() - 1) + (c_out / (2.0/3.0)) + curve.set_point_out(curve.get_point_count() - 1, c_out) + cursor = Vector2(float(string_array[i+1]), float(string_array[i+2])) + var c_in = (quadratic_control_point - cursor) * (2.0/3.0) + curve.add_point(cursor, c_in) + i += 2 + "a": + while string_array.size() > i + 7 and string_array[i+1].is_valid_float(): + arcs.append(ScalableArc.new( + curve.point_count - 1, + Vector2(float(string_array[i+1]), float(string_array[i+2])), + float(string_array[i+3]), + int(string_array[i+4]) == 1, + int(string_array[i+5]) == 1 + )) + cursor += Vector2(float(string_array[i+6]), float(string_array[i+7])) + curve.add_point(cursor) + i += 7 + "A": + while string_array.size() > i + 7 and string_array[i+1].is_valid_float(): + arcs.append(ScalableArc.new( + curve.point_count - 1, + Vector2(float(string_array[i+1]), float(string_array[i+2])), + float(string_array[i+3]), + int(string_array[i+4]) == 1, + int(string_array[i+5]) == 1 + )) + cursor = Vector2(float(string_array[i+6]), float(string_array[i+7])) + curve.add_point(cursor) + i += 7 + "z", "Z": + cursor = cursor_start + # Add a new ScalableVectorShape2D to the list for this section of + # the path definition (`d`-attribute of the path element) + var shape := ScalableVectorShape2D.new() + shape.name = shape_name + shape.curve = curve + shape.arc_list = ScalableArcList.new(arcs) + shape.set_meta("is_closed", string_array[string_array.size()-1].to_upper() == "Z") + shapes.append(shape) + + log_message("Postprocessing for %s" % shape_name, LogLevel.DEBUG) + # Loop through al the shapes in this element looking for holes + # if a shape is a hole, make sure it is not in the post_processed_shapes + # array after this loop, but a member of the surrounding shape's clip_paths + # array. + var post_processed_shapes : Array[ScalableVectorShape2D] = [] + for shape : ScalableVectorShape2D in shapes: + var poly := shape.tessellate() + post_processed_shapes.append(shape) + for shape1 : ScalableVectorShape2D in shapes: + if shape1 == shape: + continue + var poly1 := shape1.tessellate() + var res := Geometry2D.intersect_polygons(poly, poly1) + if res.size() > 0: + if Geometry2D.is_point_in_polygon(poly[0], poly1): + if shape not in shape1.clip_paths: + shape1.clip_paths.append(shape) + post_processed_shapes.erase(shape) + else: + if shape1 not in shape.clip_paths: + shape.clip_paths.append(shape1) + post_processed_shapes.erase(shape1) + + # Append actual new shapes to the scene by copying the `curve`, `arc_list` and + # `clip_paths`. Also, the shapes inside the `clip_paths` property are added as + # actual node in the resulting scene + for shape in post_processed_shapes: + var new_path := create_path2d(shape_name, current_node, shape.curve.duplicate(true), shape.arc_list.arcs.duplicate(true), get_svg_transform(element), + element.get_merged_styles(log_message), scene_root, gradients, shape.get_meta("is_closed")) + var clips : Array[ScalableVectorShape2D] = [] + for cutout in shape.clip_paths: + clips.append(create_path2d("CutoutFor%s" % shape_name, current_node, cutout.curve.duplicate(true), cutout.arc_list.arcs.duplicate(true), + Transform2D.IDENTITY, {}, scene_root, gradients, cutout.get_meta("is_closed"), new_path)) + cutout.free() + shape.free() + # append_array is used here, because clip paths may already have been added via the + # `create_path2d(...)` call chain. + new_path.clip_paths.append_array(clips) + undo_redo.add_do_property(new_path, 'clip_paths', new_path.clip_paths) + undo_redo.add_undo_property(new_path, 'clip_paths', []) + + +func create_path2d(path_name: String, parent: Node, curve: Curve2D, arcs: Array[ScalableArc], + transform: Transform2D, style: Dictionary, scene_root: Node, + gradients : Array[Dictionary], is_closed := false, + is_cutout_for : ScalableVectorShape2D = null) -> ScalableVectorShape2D: + var new_path = ScalableVectorShape2D.new() + new_path.name = path_name + new_path.curve = curve + new_path.arc_list = ScalableArcList.new(arcs) + if (is_closed and curve.point_count > 1 and curve.get_point_position(0).distance_to( + curve.get_point_position(curve.point_count - 1)) > 0.001): + curve.add_point(curve.get_point_position(0)) + + if is_cutout_for: + new_path.transform = is_cutout_for.transform.affine_inverse() + new_path.set_position_to_center() + _post_process_shape(new_path, is_cutout_for, transform, style, scene_root, gradients, true) + else: + new_path.set_position_to_center() + _post_process_shape(new_path, parent, transform, style, scene_root, gradients, false) + return new_path + + +func _apply_clip_path_by_href(href : String, svs : ScalableVectorShape2D, scene_root : Node): + var clip_path_node := scene_root.find_child(href.replace("url(#", "").replace(")", "")) + var new_clip_paths : Array[ScalableVectorShape2D] = [] + for clip_path : ScalableVectorShape2D in clip_path_node.find_children("*", "ScalableVectorShape2D"): + clip_path.use_interect_when_clipping = true + if clip_path.line: + clip_path.line.hide() + if clip_path.polygon: + clip_path.polygon.hide() + var applied_clip_path = clip_path.duplicate() + new_clip_paths.append(applied_clip_path) + _managed_add_child_and_set_owner(svs.get_parent(), applied_clip_path, scene_root) + + log_message("Processing %d clip-paths for %s" % [new_clip_paths.size(), svs.name], LogLevel.DEBUG) + svs.clip_paths = new_clip_paths + undo_redo.add_do_property(svs, 'clip_paths', new_clip_paths) + undo_redo.add_undo_property(svs, 'clip_paths', []) + + +func _post_process_shape(svs : ScalableVectorShape2D, parent : Node, transform : Transform2D, + style : Dictionary, scene_root : Node, gradients : Array[Dictionary], + is_cutout := false, image_texture : ImageTexture = null) -> void: + svs.lock_assigned_shapes = import_as_svs and lock_shapes + svs.update_curve_at_runtime = CurvedLines2D._is_setting_update_curve_at_runtime() + svs.arc_list.resource_local_to_scene = CurvedLines2D._is_making_curve_resources_local_to_scene() + svs.curve.resource_local_to_scene = CurvedLines2D._is_making_curve_resources_local_to_scene() + svs.tolerance_degrees = CurvedLines2D._get_default_tolerance_degrees() + svs.max_stages = CurvedLines2D._get_default_max_stages() + var gradient_point_parent : Node2D = parent + if transform == Transform2D.IDENTITY: + _managed_add_child_and_set_owner(parent, svs, scene_root) + else: + var transform_node := Node2D.new() + transform_node.name = svs.name + "Transform" + transform_node.transform = transform + _managed_add_child_and_set_owner(parent, transform_node, scene_root) + _managed_add_child_and_set_owner(transform_node, svs, scene_root) + gradient_point_parent = transform_node + + if style.has("opacity"): + svs.modulate.a = float(style["opacity"]) + + if style.is_empty() or ("fill" not in style and "stroke" not in style): + style["fill"] = "#000000" + + if style.has("display") and style['display'] == "none": + svs.visible = false + + if not is_cutout: + for func_name in PAINT_ORDER_MAP[get_paint_order(style)]: + call(func_name, svs, style, scene_root, gradients, + gradient_point_parent, image_texture) + + if "clip-path" in style: + _apply_clip_path_by_href(style["clip-path"], svs, scene_root) + + +func get_paint_order(style : Dictionary) -> String: + if style.has("paint-order") and style['paint-order'] in PAINT_ORDER_MAP: + return style['paint-order'] + else: + return "normal" + + +func add_stroke_to_path(new_path : ScalableVectorShape2D, style: Dictionary, scene_root : Node, + gradients : Array[Dictionary], gradient_point_parent : Node2D, + _image_texture : ImageTexture): + if style.has("stroke") and style["stroke"] != "none": + var stroke : Node2D = Line2D.new() if import_stroke_as_line_2d else Polygon2D.new() + var prop_name := "line" if import_stroke_as_line_2d else "poly_stroke" + stroke.name = "Stroke" + stroke.antialiased = antialiased_shapes + _managed_add_child_and_set_owner(new_path, stroke, scene_root, prop_name) + if style["stroke"].begins_with("url"): + if stroke is Line2D: + log_message("⚠️ Gradient stroke style not supported by Line2D: " + style["stroke"]) + else: + var href : String = style["stroke"].replace("url(", "").replace(")", "") + var svg_gradient = get_gradient_by_href(href, gradients) + if svg_gradient.is_empty(): + log_message("⚠️ Cannot find gradient for href=%s" % href, LogLevel.WARN) + else: + add_gradient_to_fill(new_path, svg_gradient, stroke, scene_root, gradients, gradient_point_parent) + elif style["stroke"].begins_with("rgba"): + var parts := _parse_svg_transform_params(style["stroke"].replace("rgba", "")) + new_path.stroke_color = Color.from_rgba8(parts[0], parts[1], parts[2], parts[3]) + elif style["stroke"].begins_with("rgb"): + var parts := _parse_svg_transform_params(style["stroke"].replace("rgb", "")) + new_path.stroke_color = Color.from_rgba8(parts[0], parts[1], parts[2]) + else: + new_path.stroke_color = Color(style["stroke"]) + if style.has("stroke-width"): + new_path.stroke_width = float(style['stroke-width']) + if style.has("stroke-opacity"): + new_path.stroke_color.a = float(style["stroke-opacity"]) + + if style.has("stroke-linecap") and style["stroke-linecap"] in STROKE_CAP_MAP: + new_path.end_cap_mode = STROKE_CAP_MAP[style["stroke-linecap"]] + new_path.begin_cap_mode = STROKE_CAP_MAP[style["stroke-linecap"]] + else: + new_path.end_cap_mode = Line2D.LINE_CAP_NONE + new_path.begin_cap_mode = Line2D.LINE_CAP_NONE + + if style.has("stroke-linejoin") and style["stroke-linejoin"] in STROKE_JOINT_MAP: + new_path.line_joint_mode = STROKE_JOINT_MAP[style["stroke-linejoin"]] + else: + new_path.line_joint_mode = Line2D.LINE_JOINT_SHARP + if stroke is Line2D: + if style.has("stroke-miterlimit"): + stroke.sharp_limit = float(style["stroke-miterlimit"]) + else: + stroke.sharp_limit = 4.0 # svg default + if CurvedLines2D._use_antialiased_line_2d(): + stroke.texture = load("res://addons/curved_lines_2d/LumAlpha8.tex") + stroke.texture_mode = Line2D.LINE_TEXTURE_TILE + stroke.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC + + + +func add_fill_to_path(new_path : ScalableVectorShape2D, style: Dictionary, scene_root : Node, + gradients : Array[Dictionary], gradient_point_parent : Node2D, + image_texture : ImageTexture): + + if image_texture or style.has("fill") and style["fill"] != "none": + var polygon := Polygon2D.new() + polygon.name = "Fill" + polygon.antialiased = antialiased_shapes + _managed_add_child_and_set_owner(new_path, polygon, scene_root, 'polygon') + if image_texture != null: + var box := new_path.get_bounding_rect() + polygon.texture = image_texture + polygon.texture_offset = -box.position + polygon.texture_scale = polygon.texture.get_size() / box.size + elif style["fill"].begins_with("url"): + var href : String = style["fill"].replace("url(", "").replace(")", "") + var svg_gradient = get_gradient_by_href(href, gradients) + if svg_gradient.is_empty(): + log_message("⚠️ Cannot find gradient for href=%s" % href, LogLevel.WARN) + else: + add_gradient_to_fill(new_path, svg_gradient, polygon, scene_root, gradients, gradient_point_parent) + elif style["fill"].begins_with("rgba"): + var parts := _parse_svg_transform_params(style["fill"].replace("rgba", "")) + polygon.color = Color.from_rgba8(parts[0], parts[1], parts[2], parts[3]) + elif style["fill"].begins_with("rgb"): + var parts := _parse_svg_transform_params(style["fill"].replace("rgb", "")) + polygon.color = Color.from_rgba8(parts[0], parts[1], parts[2]) + else: + polygon.color = Color(style["fill"]) + if style.has("fill-opacity"): + polygon.color.a = float(style["fill-opacity"]) + + +func add_collision_to_path(new_path : ScalableVectorShape2D, style : Dictionary, scene_root : Node, + _gradients : Array[Dictionary], _gradient_point_parent : Node2D, + _image_texture : ImageTexture) -> void: + if collision_object_type != ScalableVectorShape2D.CollisionObjectType.NONE: + match collision_object_type: + ScalableVectorShape2D.CollisionObjectType.STATIC_BODY_2D: + _managed_add_child_and_set_owner(new_path, StaticBody2D.new(), scene_root, 'collision_object') + ScalableVectorShape2D.CollisionObjectType.AREA_2D: + _managed_add_child_and_set_owner(new_path, Area2D.new(), scene_root, 'collision_object') + ScalableVectorShape2D.CollisionObjectType.ANIMATABLE_BODY_2D: + _managed_add_child_and_set_owner(new_path, AnimatableBody2D.new(), scene_root, 'collision_object') + ScalableVectorShape2D.CollisionObjectType.RIGID_BODY_2D: + _managed_add_child_and_set_owner(new_path, RigidBody2D.new(), scene_root, 'collision_object') + ScalableVectorShape2D.CollisionObjectType.CHARACTER_BODY_2D: + _managed_add_child_and_set_owner(new_path, CharacterBody2D.new(), scene_root, 'collision_object') + ScalableVectorShape2D.CollisionObjectType.PHYSICAL_BONE_2D: + _managed_add_child_and_set_owner(new_path, PhysicalBone2D.new(), scene_root, 'collision_object') + + +func add_gradient_to_fill(new_path : ScalableVectorShape2D, svg_gradient: Dictionary, polygon : Polygon2D, + scene_root : Node, gradients : Array[Dictionary], gradient_point_parent : Node2D) -> void: + if "xlink:href" in svg_gradient: + svg_gradient.merge(get_gradient_by_href(svg_gradient["xlink:href"], gradients), false) + elif "href" in svg_gradient: + svg_gradient.merge(get_gradient_by_href(svg_gradient["href"], gradients), false) + + var texture := GradientTexture2D.new() + var box := new_path.get_bounding_rect() + texture.width = ceil(box.size.x) + texture.height = ceil(box.size.y) + texture.gradient = Gradient.new() + var stops = svg_gradient["stops"] if "stops" in svg_gradient else [] + var gradient_data := {} + for i in range(stops.size()): + var stop_style = stops[i]["style"] if "style" in stops[i] else { "stop-color": "#ffffff" } + var stop_color = stop_style["stop-color"] if "stop-color" in stop_style else "#ffffff" + var stop_opacity = stop_style["stop-opacity"] if "stop-opacity" in stop_style else "1" + gradient_data[float(stops[i]["offset"])] = Color(stop_color, float(stop_opacity)) + texture.gradient.colors = gradient_data.values() + texture.gradient.offsets = gradient_data.keys() + + if svg_gradient["is_radial"] and "cx" in svg_gradient and "cy" in svg_gradient and "r" in svg_gradient: + var gradient_transform = ( + process_svg_transform(svg_gradient["gradientTransform"]) if "gradientTransform" in svg_gradient else + Transform2D.IDENTITY + ) + var fill_from = Vector2(float(svg_gradient["cx"]), float(svg_gradient["cy"])) + var fill_to = fill_from + Vector2.RIGHT * float(svg_gradient["r"]) + apply_gradient(new_path, svg_gradient, polygon, scene_root, gradients, gradient_point_parent, + box, texture, fill_from, fill_to, gradient_transform) + texture.fill = GradientTexture2D.FILL_RADIAL + elif "x1" in svg_gradient and "y1" in svg_gradient and "x2" in svg_gradient and "y2" in svg_gradient: + var gradient_transform = ( + process_svg_transform(svg_gradient["gradientTransform"]) if "gradientTransform" in svg_gradient else + Transform2D.IDENTITY + ) + var fill_from = Vector2(float(svg_gradient["x1"]), float(svg_gradient["y1"])) + var fill_to = Vector2(float(svg_gradient["x2"]), float(svg_gradient["y2"])) + apply_gradient(new_path, svg_gradient, polygon, scene_root, gradients, gradient_point_parent, + box, texture, fill_from, fill_to, gradient_transform) + polygon.texture_offset = -box.position + polygon.texture = texture + + +func apply_gradient(new_path : ScalableVectorShape2D, svg_gradient: Dictionary, polygon : Polygon2D, + scene_root : Node, gradients : Array[Dictionary], gradient_point_parent : Node2D, box : Rect2, + texture : GradientTexture2D, fill_from : Vector2, fill_to : Vector2, gradient_transform : Transform2D) -> void: + var gradient_transform_node = create_helper_node("Gradient(%s)" % new_path.name, gradient_point_parent, scene_root, Vector2.ZERO, gradient_transform) + var from_node = create_helper_node("From(%s)" % new_path.name, gradient_transform_node, scene_root, fill_from) + var to_node = create_helper_node("To(%s)" % new_path.name, gradient_transform_node, scene_root, fill_to) + var box_tl_node = create_helper_node("BoxTopLeft(%s)" % new_path.name, gradient_point_parent, scene_root, new_path.position + box.position) + var box_br_node = create_helper_node("BoxBottomRight(%s)" % new_path.name, gradient_point_parent, scene_root, box_tl_node.position + box.size) + texture.fill_from = (from_node.global_position - box_tl_node.global_position) / (box_br_node.global_position - box_tl_node.global_position) + texture.fill_to = (to_node.global_position - box_tl_node.global_position) / (box_br_node.global_position - box_tl_node.global_position) + gradient_transform_node.queue_free() + box_tl_node.queue_free() + box_br_node.queue_free() + + +func create_helper_node(node_name : String, node_parent : Node2D, node_owner : Node, + node_position := Vector2.ZERO, node_transform := Transform2D.IDENTITY) -> Node2D: + var helper_node := Node2D.new() + helper_node.name = node_name + node_parent.add_child(helper_node, true) + helper_node.set_owner(node_owner) + if node_position != Vector2.ZERO: + helper_node.position = node_position + if node_transform != Transform2D.IDENTITY: + helper_node.transform = node_transform + return helper_node + + +func get_svg_transform(element:SVGXMLElement) -> Transform2D: + if element.has_attribute("transform"): + return process_svg_transform(element.get_named_attribute_value("transform")) + else: + return Transform2D.IDENTITY + + +func _parse_svg_transform_params(svg_transform_params : String) -> PackedFloat64Array: + return (svg_transform_params + .replace("(", "").replace(")", "").replace(",", " ") + .split_floats(" ", false)) + + +func process_svg_transform(svg_transform_attr : String) -> Transform2D: + var svg_commands = ( + Array(svg_transform_attr.split(")", false)) + .map(func(cmd): return cmd.lstrip(" \t\r\n") + ")") + ) + svg_commands.reverse() + var transform = Transform2D.IDENTITY + for svg_transform in svg_commands: + if svg_transform.begins_with("translate"): + svg_transform = svg_transform.replace("translate", "") + var transform_split = _parse_svg_transform_params(svg_transform) + if transform_split.size() >= 2: + transform = transform.translated(Vector2(transform_split[0], transform_split[1])) + else: + transform = transform.translated(Vector2(transform_split[0], 0)) + elif svg_transform.begins_with("scale"): + svg_transform = svg_transform.replace("scale", "") + var transform_split = _parse_svg_transform_params(svg_transform) + if transform_split.size() >= 2: + transform = transform.scaled(Vector2(transform_split[0], transform_split[1])) + else: + transform = transform.scaled(Vector2(transform_split[0], transform_split[0])) + elif svg_transform.begins_with("rotate"): + svg_transform = svg_transform.replace("rotate", "") + var transform_split = _parse_svg_transform_params(svg_transform) + if transform_split.size() == 1: + transform = transform.rotated(deg_to_rad(transform_split[0])) + elif transform_split.size() == 3: + transform = transform.translated(-Vector2(transform_split[1], transform_split[2])) + transform = transform.rotated(deg_to_rad(transform_split[0])) + transform = transform.translated(Vector2(transform_split[1], transform_split[2])) + elif svg_transform.begins_with("matrix"): + svg_transform = svg_transform.replace("matrix", "") + var matrix = _parse_svg_transform_params(svg_transform) + for i in 3: + transform[i] = Vector2(matrix[i*2], matrix[i*2+1]) + return transform + + +func _managed_add_child_and_set_owner(parent : Node, child : Node, + scene_root : Node, as_property := ""): + parent.add_child(child, true) + child.set_owner(scene_root) + undo_redo.add_do_method(parent, 'add_child', child, true) + undo_redo.add_do_method(child, 'set_owner', scene_root) + undo_redo.add_do_reference(child) + undo_redo.add_undo_method(parent, 'remove_child', child) + if not as_property.is_empty(): + parent.call("set", as_property, child) + undo_redo.add_do_property(parent, as_property, child) + + +static func parse_attribute_string(raw_attribute_str : String) -> String: + var regex = RegEx.new() + regex.compile("\\S+") + var str_path = "" + for result in regex.search_all(raw_attribute_str): + str_path += result.get_string() + " " + return str_path.strip_edges() + + +func _on_collision_object_type_option_button_type_selected(obj_type: ScalableVectorShape2D.CollisionObjectType) -> void: + collision_object_type = obj_type + + +func _on_keep_drawable_path_2d_node_check_box_toggled(toggled_on: bool) -> void: + import_as_svs = toggled_on + %LockShapesCheckBox.visible = toggled_on + + +func _on_lock_shapes_check_box_toggled(toggled_on: bool) -> void: + lock_shapes = toggled_on + + +func _on_antialiased_check_box_toggled(toggled_on: bool) -> void: + antialiased_shapes = toggled_on + + +func _on_open_file_dialog_button_pressed() -> void: + import_file_dialog.popup_file_dialog() + + +func _on_use_line_2d_check_box_toggled(toggled_on: bool) -> void: + import_stroke_as_line_2d = toggled_on diff --git a/addons/curved_lines_2d/svg_import_tab.gd.uid b/addons/curved_lines_2d/svg_import_tab.gd.uid new file mode 100644 index 0000000..f90273a --- /dev/null +++ b/addons/curved_lines_2d/svg_import_tab.gd.uid @@ -0,0 +1 @@ +uid://bp5vvj23w57js diff --git a/addons/curved_lines_2d/svg_import_tab.tscn b/addons/curved_lines_2d/svg_import_tab.tscn new file mode 100644 index 0000000..449e89c --- /dev/null +++ b/addons/curved_lines_2d/svg_import_tab.tscn @@ -0,0 +1,152 @@ +[gd_scene load_steps=8 format=3 uid="uid://cfeemeccrtef7"] + +[ext_resource type="Script" uid="uid://bp5vvj23w57js" path="res://addons/curved_lines_2d/svg_import_tab.gd" id="1_dlf5g"] +[ext_resource type="Texture2D" uid="uid://b8ludy6aqsejg" path="res://addons/curved_lines_2d/LockViewport.svg" id="2_v8p2q"] +[ext_resource type="PackedScene" uid="uid://cjbkvx1pj7gq2" path="res://addons/curved_lines_2d/collision_object_type_option_button.tscn" id="3_tqnmm"] +[ext_resource type="LabelSettings" uid="uid://bspk1rkq1cmhx" path="res://addons/curved_lines_2d/info_label_settings.tres" id="4_4seqe"] +[ext_resource type="PackedScene" uid="uid://cmoxkoulpd7so" path="res://addons/curved_lines_2d/link_button_with_copy_hint.tscn" id="5_wpk81"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rycm0"] +content_margin_left = 10.0 +content_margin_top = 10.0 +content_margin_right = 10.0 +content_margin_bottom = 10.0 +bg_color = Color(0.180392, 0.180392, 0.180392, 1) +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_width_bottom = 4 +border_color = Color(0.262933, 0.262932, 0.262932, 1) +border_blend = true + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gt4al"] +bg_color = Color(0.180005, 0.180005, 0.180005, 1) +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_width_bottom = 4 +border_color = Color(0.439216, 0.729412, 0.980392, 1) +border_blend = true + +[node name="SVGImportTab" type="HBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 20 +script = ExtResource("1_dlf5g") +metadata/_tab_index = 0 + +[node name="VBoxContainer2" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="VBoxContainer2"] +layout_mode = 2 +text = "Import Settings" + +[node name="PanelContainer" type="PanelContainer" parent="VBoxContainer2"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 1 +theme_override_styles/panel = SubResource("StyleBoxFlat_rycm0") + +[node name="VBoxContainer2" type="VBoxContainer" parent="VBoxContainer2/PanelContainer"] +layout_mode = 2 + +[node name="SettingsScrollContainer" type="ScrollContainer" parent="VBoxContainer2/PanelContainer/VBoxContainer2"] +layout_mode = 2 +size_flags_vertical = 3 +size_flags_stretch_ratio = 10.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer"] +layout_mode = 2 + +[node name="KeepDrawablePath2DNodeCheckBox" type="CheckBox" parent="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer"] +layout_mode = 2 +tooltip_text = "- When checked on, all shapes in the SVG file will be imported as ScalableVectorShape2D (this is advised) +- Checking this off will only add builtin nodes the scene (Line2D, Polygon2D, CollisionPolygon2D as child of Node2D). It will print errors, because of missing references. +- If you're unsure, it is advised to keep this checked on." +button_pressed = true +text = "Import as ScalableVectorShape2D*" + +[node name="LockShapesCheckBox" type="CheckBox" parent="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "- Adds a lock to the Line2D, Polygon2D and CollisionPolygon2D assigned to the ScalableVectorShape2D +- This lock makes sure these nodes are not transformed via the 2D editor" +button_pressed = true +text = "Lock imported shapes in editor *" +icon = ExtResource("2_v8p2q") + +[node name="AntialiasedCheckBox" type="CheckBox" parent="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer"] +layout_mode = 2 +tooltip_text = "It's probably better to use project settings for this, but checking this on will ensure that the antialised property is checked on for imported Line2D and Polygon2D" +text = "Flag on antialiased for Polygon2D and Line2D*" + +[node name="UseLine2DCheckBox" type="CheckBox" parent="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Use a Line2D node to represent the stroke with in stead of a Polygon2D. Cost/Benefit: +- A Polygon2D stroke can be more neatly clipped than a Line2D +- CollisionPolygon2D's match Polygon2D Stroke better +- A Polygon2D stroke can be textured with gradients like Fills are textured +- Line2D has sharper caps and line joints at high zoom +- Line2D can be textured directionally in stead of like a Fill texture +- Line2D can set different Begin and End Cap Modes where Polygon2D can only pick one" +button_pressed = true +text = "Use Line2D for Strokes*" + +[node name="CollisionObjectTypeOptionButton" parent="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer" instance=ExtResource("3_tqnmm")] +layout_mode = 2 + +[node name="OpenFileDialogButton" type="Button" parent="VBoxContainer2/PanelContainer/VBoxContainer2"] +layout_mode = 2 +size_flags_vertical = 10 +text = "Pick a file to import" + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "SVG Import Log" + +[node name="LogScrollContainer" type="ScrollContainer" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_gt4al") + +[node name="ImportLogContainer" type="VBoxContainer" parent="VBoxContainer/LogScrollContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_constants/separation = -5 + +[node name="Label" type="Label" parent="VBoxContainer/LogScrollContainer/ImportLogContainer"] +layout_mode = 2 +size_flags_vertical = 10 +text = " - Drag/Drop an svg-file here to start import -" +label_settings = ExtResource("4_4seqe") +horizontal_alignment = 1 + +[node name="LinkButton2" parent="VBoxContainer/LogScrollContainer/ImportLogContainer" instance=ExtResource("5_wpk81")] +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/5PIVoQcm8QE +Right click to copy this link" +text = "Watch an explainer on Youtube" +uri = "https://youtu.be/5PIVoQcm8QE" + +[connection signal="toggled" from="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer/KeepDrawablePath2DNodeCheckBox" to="." method="_on_keep_drawable_path_2d_node_check_box_toggled"] +[connection signal="toggled" from="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer/LockShapesCheckBox" to="." method="_on_lock_shapes_check_box_toggled"] +[connection signal="toggled" from="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer/AntialiasedCheckBox" to="." method="_on_antialiased_check_box_toggled"] +[connection signal="toggled" from="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer/UseLine2DCheckBox" to="." method="_on_use_line_2d_check_box_toggled"] +[connection signal="type_selected" from="VBoxContainer2/PanelContainer/VBoxContainer2/SettingsScrollContainer/VBoxContainer/CollisionObjectTypeOptionButton" to="." method="_on_collision_object_type_option_button_type_selected"] +[connection signal="pressed" from="VBoxContainer2/PanelContainer/VBoxContainer2/OpenFileDialogButton" to="." method="_on_open_file_dialog_button_pressed"] diff --git a/addons/curved_lines_2d/svg_resource.gd b/addons/curved_lines_2d/svg_resource.gd new file mode 100644 index 0000000..c4a8fba --- /dev/null +++ b/addons/curved_lines_2d/svg_resource.gd @@ -0,0 +1,49 @@ +@tool +class_name SVGResource +extends Resource + +## Emitted when the SVG texture has been rendered or re-rendered. +signal texture_updated(new_texture: Texture2D) + +@export_file("*.svg") var svg_file_path: String = "" : set = _set_svg_file_path +@export var render_scale: float = 1.0 : set = _set_render_scale # I'd recommend rendering at half scale +@export var svg_string := "" +@export var original_size := Vector2.ZERO + +var texture: Texture2D + +func _set_svg_file_path(path: String) -> void: + if Engine.is_editor_hint(): + if svg_file_path == path: + return + svg_file_path = path + if FileAccess.file_exists(path): + var file := FileAccess.open(path, FileAccess.READ) + svg_string = Marshalls.utf8_to_base64(file.get_as_text()) + var image := Image.new() + var error := image.load_svg_from_string(Marshalls.base64_to_utf8(svg_string)) + if error != OK: + push_error("Failed to render SVG: " + str(error)) + return + original_size = image.get_size() + file.close() + else: + svg_string = "" + texture = null + + # Notify that the resource has changed. The helper will trigger a re-render. + emit_changed() + +func _set_render_scale(scale: float) -> void: + if render_scale == scale: + return + render_scale = scale + # Notify that the resource has changed. The helper will trigger a re-render. + emit_changed() + +## Internal method called by the manager upon render completion. +func _update_texture(new_texture: Texture2D) -> void: + texture = new_texture + texture_updated.emit(texture) + # Notify the editor that this resource has changed, so it updates the inspector. + emit_changed() diff --git a/addons/curved_lines_2d/svg_resource.gd.uid b/addons/curved_lines_2d/svg_resource.gd.uid new file mode 100644 index 0000000..a3f05d8 --- /dev/null +++ b/addons/curved_lines_2d/svg_resource.gd.uid @@ -0,0 +1 @@ +uid://yh2davxk4fh7 diff --git a/addons/curved_lines_2d/svg_texture_helper.gd b/addons/curved_lines_2d/svg_texture_helper.gd new file mode 100644 index 0000000..1803970 --- /dev/null +++ b/addons/curved_lines_2d/svg_texture_helper.gd @@ -0,0 +1,293 @@ +@tool +extends Node + +class_name SVGTextureHelper + +# May use a class name if clutter is not a concern +# Map property names → default values +const PROPERTY_MAPPINGS: Dictionary = { + "expand_mode": TextureRect.EXPAND_IGNORE_SIZE, + "expand_icon": true, + "ignore_texture_size": true +} + +@export var svg_resource := SVGResource.new(): set = _set_svg_resource +@export var target_property: String = "" : set = _set_target_property + +var _available_texture_properties: Array[String] = [] +var _is_saving_scene: bool = false +var _cached_texture: Texture2D # Store the actual texture to restore after save + +func _ready() -> void: + # Ensure the parent is a Control node. + if not get_parent() is Control: + push_error("SVGTextureHelper must be a child of a Control node.") + queue_free() + return + + # Detect available texture properties + _detect_texture_properties() + + # Auto-select first available property if none is set + if target_property.is_empty() and not _available_texture_properties.is_empty(): + target_property = _available_texture_properties[0] + + # Connect to the parent's resize signal to trigger re-renders. + get_parent().resized.connect(_queue_render) + + # Change parent texture properties + _update_parent_properties() + + # Connect to save signals if in editor + if Engine.is_editor_hint(): + _connect_save_signals() + + # Perform initial render if we have a resource. + if svg_resource: + _queue_render() + +func _connect_save_signals() -> void: + if Engine.is_editor_hint(): + if get_tree(): + get_tree().node_configuration_warning_changed.connect(_on_scene_tree_changed) + + +func _on_editor_visibility_changed() -> void: + # This is a heuristic that often correlates with save operations + if Engine.is_editor_hint(): + _prepare_for_potential_save() + +func _on_scene_tree_changed(node: Node) -> void: + # Another heuristic for detecting editor operations that might include saving + if Engine.is_editor_hint() and is_ancestor_of(node): + _prepare_for_potential_save() + +# Override the notification method to catch save notifications +func _notification(what: int) -> void: + match what: + NOTIFICATION_EDITOR_PRE_SAVE: + _prepare_for_save() + NOTIFICATION_EDITOR_POST_SAVE: + _restore_after_save() + # Also catch when the node is about to be saved + NOTIFICATION_WM_CLOSE_REQUEST: + if Engine.is_editor_hint(): + _prepare_for_save() + +func _prepare_for_potential_save() -> void: + # Use a timer to briefly set texture to null, then restore + # This catches most save scenarios + if _is_saving_scene: + return + + _prepare_for_save() + # Restore after a brief delay + get_tree().create_timer(0.1).timeout.connect(_restore_after_save, CONNECT_ONE_SHOT) + +func _prepare_for_save() -> void: + if not Engine.is_editor_hint() or not get_parent() or target_property.is_empty(): + return + + if not _has_property(get_parent(), target_property): + return + + _is_saving_scene = true + + # Store the current texture + _cached_texture = get_parent().get(target_property) as Texture2D + + # Set texture to null to prevent it from being saved + get_parent().set(target_property, null) + + print_rich("[color=yellow]SVGTextureHelper: Texture temporarily set to null for saving[/color]") + +func _restore_after_save() -> void: + if not Engine.is_editor_hint() or not _is_saving_scene: + return + + _is_saving_scene = false + + # Restore the cached texture + if get_parent() and not target_property.is_empty() and _cached_texture: + if _has_property(get_parent(), target_property): + get_parent().set(target_property, _cached_texture) + print_rich("[color=green]SVGTextureHelper: Texture restored after save[/color]") + + # Clear the cache + _cached_texture = null + +func _detect_texture_properties() -> void: + _available_texture_properties.clear() + + if not get_parent(): + return + + # Get all properties from the parent control + var property_list = get_parent().get_property_list() + + for prop_info in property_list: + var prop_name: String = prop_info.name + var prop_type = prop_info.type + var prop_class_name = prop_info.class_name + + # Check if this property accepts a Texture2D + # This covers properties with type TYPE_OBJECT and class_name "Texture2D" + # or properties that are explicitly documented as texture properties + if (prop_type == TYPE_OBJECT and + (prop_class_name == "Texture2D" or + prop_class_name == "Texture" or + prop_class_name == "ImageTexture" or + prop_class_name == "CompressedTexture2D")): + _available_texture_properties.append(prop_name) + # Also check for commonly named texture properties + elif (prop_name.to_lower().contains("texture") or + prop_name.to_lower().contains("icon") or + prop_name in ["normal", "pressed", "hover", "disabled", "focused"]): + # Verify it can actually accept a texture by checking if it's an Object type + if prop_type == TYPE_OBJECT: + _available_texture_properties.append(prop_name) + + # Sort alphabetically for better UX + _available_texture_properties.sort() + + # Ensure we have at least some common fallbacks + if _available_texture_properties.is_empty(): + # Add common texture property names as fallbacks + var common_properties = ["texture", "icon", "normal", "pressed"] + for prop in common_properties: + if _has_property(get_parent(), prop): + _available_texture_properties.append(prop) + + +func _set_target_property(new_property: String) -> void: + if target_property == new_property: + return + + target_property = new_property + + # Re-apply texture if we have one + if svg_resource and svg_resource.texture and get_parent(): + _on_texture_updated(svg_resource.texture) + +func _update_parent_properties() -> void: + if get_parent() == null: + return + + for prop in PROPERTY_MAPPINGS.keys(): + if _has_property(get_parent(), prop): + get_parent().set(prop, PROPERTY_MAPPINGS[prop]) + +func _has_property(target: Object, prop_name: StringName) -> bool: + for info in target.get_property_list(): + if info.name == prop_name: + return true + return false + +func _set_svg_resource(new_resource: SVGResource) -> void: + if svg_resource == new_resource: + return + + # Disconnect from old resource if it exists + if svg_resource: + if svg_resource.is_connected("texture_updated", _on_texture_updated): + svg_resource.texture_updated.disconnect(_on_texture_updated) + # Disconnect from the changed signal + if svg_resource.is_connected("changed", _on_resource_changed): + svg_resource.changed.disconnect(_on_resource_changed) + + svg_resource = new_resource + + if svg_resource: + svg_resource.texture_updated.connect(_on_texture_updated) + # CONNECT TO THE CHANGED SIGNAL + svg_resource.changed.connect(_on_resource_changed) + + # If the resource already has a texture, apply it immediately. + if svg_resource.texture: + _on_texture_updated(svg_resource.texture) + + # Queue a render to ensure it's the correct size. + _queue_render() + +# Handles resource changes +func _on_resource_changed() -> void: + # This gets called when svg_file_path or render_scale changes + _queue_render() + +func _on_texture_updated(new_texture: Texture2D) -> void: + if get_parent() and not target_property.is_empty(): + # Don't update texture if we're in the middle of a save operation + if _is_saving_scene: + _cached_texture = new_texture # Update our cache instead + return + + # Validate that the property exists before setting it + if _has_property(get_parent(), target_property): + # Set the new texture on the parent control + get_parent().set_deferred(target_property, new_texture) + else: + push_warning("Property '%s' not found on parent node '%s'" % [target_property, get_parent().name]) + +## Called on resize or when the resource changes. +func _queue_render() -> void: + if svg_resource == null or svg_resource.svg_string.is_empty(): + get_parent().set(target_property, null) + return + # Don't render during save operations + if _is_saving_scene: + return + + # Check for valid conditions before requesting a render. + if not is_instance_valid(svg_resource) or not is_instance_valid(get_parent()): + return + + if Engine.is_editor_hint() or get_tree(): + var target_size: Vector2i = get_parent().size + var rescale_factor := 1.0 + # If parent size is invalid or zero, use a minimal 1x1 placeholder. + # This prevents rendering a huge texture during initialization in the editor. + # The 'resized' signal will trigger a correct render once the size is calculated. + if target_size.x <= 0 or target_size.y <= 0: + target_size = Vector2i(1, 1) + + var stretch_mode : TextureRect.StretchMode = get_parent().stretch_mode if "stretch_mode" in get_parent() else TextureRect.STRETCH_SCALE + if ( + stretch_mode == TextureRect.StretchMode.STRETCH_KEEP or + stretch_mode == TextureRect.StretchMode.STRETCH_TILE or + stretch_mode == TextureRect.StretchMode.STRETCH_KEEP_CENTERED + ): + rescale_factor = 1.0 + else: + rescale_factor = (target_size.x / svg_resource.original_size.x) * svg_resource.render_scale + + var image := Image.new() + var error := image.load_svg_from_string(Marshalls.base64_to_utf8(svg_resource.svg_string), rescale_factor) + + if error != OK: + push_error("Failed to render SVG: " + str(error)) + return + + var image_texture := ImageTexture.create_from_image(image) + if ( + stretch_mode == TextureRect.StretchMode.STRETCH_KEEP or + stretch_mode == TextureRect.StretchMode.STRETCH_TILE or + stretch_mode == TextureRect.StretchMode.STRETCH_KEEP_CENTERED + ): + image_texture.set_size_override(svg_resource.original_size) + else: + get_parent().set(target_property, image_texture) + + +# Helper function to refresh the property list in the editor +func _refresh_properties() -> void: + if Engine.is_editor_hint(): + _detect_texture_properties() + notify_property_list_changed() + +# Manual save preparation - you can call this from editor plugins or scripts +func manual_prepare_for_save() -> void: + _prepare_for_save() + +# Manual save restoration - you can call this from editor plugins or scripts +func manual_restore_after_save() -> void: + _restore_after_save() diff --git a/addons/curved_lines_2d/svg_texture_helper.gd.uid b/addons/curved_lines_2d/svg_texture_helper.gd.uid new file mode 100644 index 0000000..53a7129 --- /dev/null +++ b/addons/curved_lines_2d/svg_texture_helper.gd.uid @@ -0,0 +1 @@ +uid://cd2hrik4wvt1o diff --git a/addons/curved_lines_2d/svg_xml_element.gd b/addons/curved_lines_2d/svg_xml_element.gd new file mode 100644 index 0000000..324848b --- /dev/null +++ b/addons/curved_lines_2d/svg_xml_element.gd @@ -0,0 +1,107 @@ +@tool +extends Object + +class_name SVGXMLElement + +const SUPPORTED_STYLES : Array[String] = ["opacity", "stroke", "stroke-width", "stroke-opacity", + "fill", "fill-opacity", "paint-order", "stroke-linecap", "stroke-linejoin", + "stroke-miterlimit", "clip-path"] + +var name : String +var attributes : Dictionary[String, String] +var children : Array[SVGXMLElement] +var parent : SVGXMLElement + +func _init(xml_parser : XMLParser, with_parent : SVGXMLElement = null): + name = xml_parser.get_node_name() + for i in xml_parser.get_attribute_count(): + attributes[xml_parser.get_attribute_name(i)] = xml_parser.get_attribute_value(i) + parent = with_parent + +func add_child(ch : SVGXMLElement) -> void: + children.append(ch) + + +func has_attribute(x : String) -> bool: + return x in attributes + + +func get_named_attribute_value(x : String) -> String: + if x in attributes: + return attributes[x] + printerr("WARNING: element <%s> does not have %s" % [name, x]) + return "" + + +func get_node_name() -> String: + return name + + +func get_named_attribute_value_safe(x : String) -> String: + if x in attributes: + return attributes[x] + return "" + + +func find_by_id(id : String) -> SVGXMLElement: + var ancestor = self + while ancestor.parent != null: + ancestor = ancestor.parent + return find_child_by_id(id, ancestor) + + +func find_child_by_id(id : String, n := self) -> SVGXMLElement: + if "id" in n.attributes and n.attributes["id"] == id: + return n + for nn in n.children: + var result := find_child_by_id(id, nn) + if result: + return result + return null + + + +func is_empty() -> bool: + return children.is_empty() + + +func _to_string() -> String: + var attrs := PackedStringArray(attributes.keys().map(func(k): return k + "=\"" + attributes[k] + "\"")) + var ch := PackedStringArray(children.map(str)) + if children.is_empty(): + return "<" + name + " " + " ".join(attrs) + " />" + else: + return "<" + name + " " + " ".join(attrs) + ">" + "\n".join(ch) + "" + + +func get_svg_style(log_message : Callable) -> Dictionary: + var style = {} + if has_attribute("style"): + var svg_style = get_named_attribute_value("style") + svg_style = svg_style.rstrip(";") + svg_style = svg_style.replacen(": ", ":") + svg_style = svg_style.replacen(":", "\":\"") + svg_style = svg_style.replacen("; ", "\",\"") + svg_style = svg_style.replacen(";", "\",\"") + svg_style = "{\"" + svg_style + "\"}" + var json = JSON.new() + var error = json.parse(svg_style) + if error == OK: + style = json.data + else: + log_message.call("Failed to parse some styles for <%s id=\"%s\">" % [name, + get_named_attribute_value("id") if has_attribute("id") else "?"], 2) + for style_prop in SUPPORTED_STYLES: + if has_attribute(style_prop): + style[style_prop] = get_named_attribute_value(style_prop) + return style + + +func get_merged_styles(log_message : Callable) -> Dictionary: + var style = get_svg_style(log_message) + var ancestor = self + while ancestor.parent != null: + style.merge(ancestor.get_svg_style(log_message)) + ancestor = ancestor.parent + style.merge(ancestor.get_svg_style(log_message)) + return style diff --git a/addons/curved_lines_2d/svg_xml_element.gd.uid b/addons/curved_lines_2d/svg_xml_element.gd.uid new file mode 100644 index 0000000..7b58e60 --- /dev/null +++ b/addons/curved_lines_2d/svg_xml_element.gd.uid @@ -0,0 +1 @@ +uid://cp0kha11lwv1g diff --git a/addons/curved_lines_2d/svs_edit_tab.gd b/addons/curved_lines_2d/svs_edit_tab.gd new file mode 100644 index 0000000..15fa868 --- /dev/null +++ b/addons/curved_lines_2d/svs_edit_tab.gd @@ -0,0 +1,288 @@ +@tool +extends Control + +signal shape_created(curve : Curve2D, scene_root : Node2D, node_name : String) +signal rect_created(width : float, height : float, rx : float, ry : float, scene_root : Node2D) +signal ellipse_created(rx : float, ry : float, scene_root : Node2D) +signal set_shape_preview(curve : Curve2D) + +const OPEN_SCENE_ERROR_MESSAGE := "Can only create a shape in an open scene" + +var stroke_width_input : EditorSpinSlider + +var rect_width_input : EditorSpinSlider +var rect_height_input : EditorSpinSlider +var rect_rx_input : EditorSpinSlider +var rect_ry_input : EditorSpinSlider + +var ellipse_rx_input : EditorSpinSlider +var ellipse_ry_input : EditorSpinSlider + +var warning_dialog : AcceptDialog = null + +var begin_cap_button_map = {} +var end_cap_button_map = {} +var joint_button_map = {} + +func _enter_tree() -> void: + rect_width_input = _make_number_input("Width", 100, 2, 1000, "") + rect_height_input = _make_number_input("Height", 100, 2, 1000, "") + rect_rx_input = _make_number_input("Corner Radius X", 0, 0, 500, "") + rect_ry_input = _make_number_input("Corner Radius Y", 0, 0, 500, "") + + stroke_width_input = _make_number_input("Width", 10.0, 0.5, 100.0, "px", 0.5) + %WidthSliderContainer.add_child(rect_width_input) + %HeightSliderContainer.add_child(rect_height_input) + %XRadiusSliderContainer.add_child(rect_rx_input) + %YRadiusSliderContainer.add_child(rect_ry_input) + %StrokeWidthContainer.add_child(stroke_width_input) + ellipse_rx_input = _make_number_input("Horizontal Radius (RX)", 50, 1, 500, "") + ellipse_ry_input = _make_number_input("Vertical Radius (RY)", 50, 1, 500, "") + %EllipseXRadiusSliderContainer.add_child(ellipse_rx_input) + %EllipseYRadiusSliderContainer.add_child(ellipse_ry_input) + stroke_width_input.value = CurvedLines2D._get_default_stroke_width() + stroke_width_input.value_changed.connect(_on_stroke_width_input_value_changed) + %StrokePickerButton.color = CurvedLines2D._get_default_stroke_color() + %UseLine2DCheckButton.button_pressed = CurvedLines2D._using_line_2d_for_stroke() + %FillPickerButton.color = CurvedLines2D._get_default_fill_color() + %StrokeCheckButton.button_pressed = CurvedLines2D._is_add_stroke_enabled() + %FillCheckButton.button_pressed = CurvedLines2D._is_add_fill_enabled() + (%CollisionObjectTypeOptionButton as OptionButton).select(CurvedLines2D._add_collision_object_type()) + + begin_cap_button_map[Line2D.LineCapMode.LINE_CAP_NONE] = %BeginNoCapToggleButton + begin_cap_button_map[Line2D.LineCapMode.LINE_CAP_BOX] = %BeginBoxCapToggleButton + begin_cap_button_map[Line2D.LineCapMode.LINE_CAP_ROUND] = %BeginRoundCapToggleButton + end_cap_button_map[Line2D.LineCapMode.LINE_CAP_NONE] = %EndNoCapToggleButton + end_cap_button_map[Line2D.LineCapMode.LINE_CAP_BOX] = %EndBoxCapToggleButton + end_cap_button_map[Line2D.LineCapMode.LINE_CAP_ROUND] = %EndRoundCapToggleButton + joint_button_map[Line2D.LineJointMode.LINE_JOINT_SHARP] = %LineJointSharpToggleButton + joint_button_map[Line2D.LineJointMode.LINE_JOINT_BEVEL] = %LineJointBevelToggleButton + joint_button_map[Line2D.LineJointMode.LINE_JOINT_ROUND] = %LineJointRoundToggleButton + begin_cap_button_map[CurvedLines2D._get_default_begin_cap()].button_pressed = true + end_cap_button_map[CurvedLines2D._get_default_end_cap()].button_pressed = true + joint_button_map[CurvedLines2D._get_default_joint_mode()].button_pressed = true + + + if not stroke_width_input.value_focus_exited.is_connected(ProjectSettings.save): + stroke_width_input.value_focus_exited.connect(ProjectSettings.save) + if not %StrokePickerButton.focus_exited.is_connected(ProjectSettings.save): + %StrokePickerButton.focus_exited.connect(ProjectSettings.save) + if not %FillPickerButton.focus_exited.is_connected(ProjectSettings.save): + %FillPickerButton.focus_exited.connect(ProjectSettings.save) + + find_children("PaintOrderButton*")[CurvedLines2D._get_default_paint_order()].button_pressed = true + + +func _make_number_input(lbl : String, value : float, min_value : float, max_value : float, suffix : String, step := 1.0) -> EditorSpinSlider: + var x_slider := EditorSpinSlider.new() + x_slider.value = value + x_slider.min_value = min_value + x_slider.max_value = max_value + x_slider.suffix = suffix + x_slider.label = lbl + x_slider.step = step + return x_slider + + +func _get_rect_curve() -> Curve2D: + var curve := Curve2D.new() + ScalableVectorShape2D.set_rect_points(curve, rect_width_input.value, rect_height_input.value, rect_rx_input.value, rect_ry_input.value) + return curve + + +func _on_create_rect_as_path_button_pressed() -> void: + var scene_root := EditorInterface.get_edited_scene_root() + if not scene_root is Node: + warning_dialog.dialog_text = OPEN_SCENE_ERROR_MESSAGE + warning_dialog.popup_centered() + return + shape_created.emit(_get_rect_curve(), scene_root, "Rectangle") + + +func _on_create_rect_button_pressed() -> void: + var scene_root := EditorInterface.get_edited_scene_root() + if not scene_root is Node: + warning_dialog.dialog_text = OPEN_SCENE_ERROR_MESSAGE + warning_dialog.popup_centered() + return + rect_created.emit(rect_width_input.value, rect_height_input.value, + rect_rx_input.value, rect_ry_input.value, scene_root) + + +func _on_create_ellipse_button_pressed() -> void: + var scene_root := EditorInterface.get_edited_scene_root() + if not scene_root is Node: + warning_dialog.dialog_text = OPEN_SCENE_ERROR_MESSAGE + warning_dialog.popup_centered() + return + ellipse_created.emit(ellipse_rx_input.value, ellipse_ry_input.value, scene_root) + + +func _get_ellipse_curve() -> Curve2D: + var curve := Curve2D.new() + ScalableVectorShape2D.set_ellipse_points(curve, Vector2(ellipse_rx_input.value * 2, ellipse_ry_input.value * 2)) + return curve + + +func _on_create_rect_button_mouse_entered() -> void: + set_shape_preview.emit(_get_rect_curve()) + + +func _on_create_rect_button_mouse_exited() -> void: + set_shape_preview.emit(null) + + +func _on_create_circle_button_pressed() -> void: + var scene_root := EditorInterface.get_edited_scene_root() + + if not scene_root is Node: + warning_dialog.dialog_text = OPEN_SCENE_ERROR_MESSAGE + warning_dialog.popup_centered() + return + + var node_name := "Circle" if ellipse_rx_input.value == ellipse_ry_input.value else "Ellipse" + shape_created.emit(_get_ellipse_curve(), scene_root, node_name) + + +func _on_create_circle_button_mouse_entered() -> void: + set_shape_preview.emit(_get_ellipse_curve()) + + +func _on_create_circle_button_mouse_exited() -> void: + set_shape_preview.emit(null) + + +func _on_create_empty_shape_button_pressed() -> void: + var scene_root := EditorInterface.get_edited_scene_root() + + if not scene_root is Node: + warning_dialog.dialog_text = OPEN_SCENE_ERROR_MESSAGE + warning_dialog.popup_centered() + return + var curve := Curve2D.new() + var node_name := "Path" + shape_created.emit(curve, scene_root, node_name) + + +func _on_stroke_width_input_value_changed(new_value: float) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_STROKE_WIDTH, new_value) + + +func _on_fill_picker_button_color_changed(color: Color) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_FILL_COLOR, color) + + +func _on_stroke_picker_button_color_changed(color: Color) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_STROKE_COLOR, color) + + +func _on_stroke_check_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_ADD_STROKE_ENABLED, toggled_on) + ProjectSettings.save() + + +func _on_fill_check_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_ADD_FILL_ENABLED, toggled_on) + ProjectSettings.save() + + +func _on_paint_order_button_0_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_PAINT_ORDER, + CurvedLines2D.PaintOrder.FILL_STROKE_MARKERS) + ProjectSettings.save() + + +func _on_paint_order_button_1_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_PAINT_ORDER, + CurvedLines2D.PaintOrder.STROKE_FILL_MARKERS) + ProjectSettings.save() + + +func _on_paint_order_button_2_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_PAINT_ORDER, + CurvedLines2D.PaintOrder.FILL_MARKERS_STROKE) + ProjectSettings.save() + + +func _on_paint_order_button_3_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_PAINT_ORDER, + CurvedLines2D.PaintOrder.MARKERS_FILL_STROKE) + ProjectSettings.save() + + +func _on_paint_order_button_4_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_PAINT_ORDER, + CurvedLines2D.PaintOrder.STROKE_MARKERS_FILL) + ProjectSettings.save() + + +func _on_paint_order_button_5_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_PAINT_ORDER, + CurvedLines2D.PaintOrder.MARKERS_STROKE_FILL) + ProjectSettings.save() + + +func _on_begin_no_cap_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_BEGIN_CAP, + Line2D.LineCapMode.LINE_CAP_NONE) + ProjectSettings.save() + + +func _on_begin_box_cap_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_BEGIN_CAP, + Line2D.LineCapMode.LINE_CAP_BOX) + ProjectSettings.save() + + +func _on_begin_round_cap_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_BEGIN_CAP, + Line2D.LineCapMode.LINE_CAP_ROUND) + ProjectSettings.save() + + +func _on_end_no_cap_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_END_CAP, + Line2D.LineCapMode.LINE_CAP_NONE) + ProjectSettings.save() + + +func _on_end_box_cap_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_END_CAP, + Line2D.LineCapMode.LINE_CAP_BOX) + ProjectSettings.save() + + +func _on_end_round_cap_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_END_CAP, + Line2D.LineCapMode.LINE_CAP_ROUND) + ProjectSettings.save() + + +func _on_line_joint_sharp_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_JOINT_MODE, + Line2D.LineJointMode.LINE_JOINT_SHARP) + ProjectSettings.save() + + +func _on_line_joint_bevel_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_JOINT_MODE, + Line2D.LineJointMode.LINE_JOINT_BEVEL) + ProjectSettings.save() + + +func _on_line_joint_round_toggle_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_DEFAULT_LINE_JOINT_MODE, + Line2D.LineJointMode.LINE_JOINT_ROUND) + ProjectSettings.save() + + +func _on_collision_object_type_option_button_type_selected(obj_type: ScalableVectorShape2D.CollisionObjectType) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_ADD_COLLISION_TYPE, obj_type) + + +func _on_use_line_2d_check_button_toggled(toggled_on: bool) -> void: + ProjectSettings.set_setting(CurvedLines2D.SETTING_NAME_USE_LINE_2D_FOR_STROKE, toggled_on) + if toggled_on: + %EndCapForm.show() + else: + %EndCapForm.hide() diff --git a/addons/curved_lines_2d/svs_edit_tab.gd.uid b/addons/curved_lines_2d/svs_edit_tab.gd.uid new file mode 100644 index 0000000..6ac1f55 --- /dev/null +++ b/addons/curved_lines_2d/svs_edit_tab.gd.uid @@ -0,0 +1 @@ +uid://tl3hcapnk7lb diff --git a/addons/curved_lines_2d/svs_edit_tab.tscn b/addons/curved_lines_2d/svs_edit_tab.tscn new file mode 100644 index 0000000..296abc2 --- /dev/null +++ b/addons/curved_lines_2d/svs_edit_tab.tscn @@ -0,0 +1,646 @@ +[gd_scene load_steps=26 format=3 uid="uid://dwns40mbgt82s"] + +[ext_resource type="Script" uid="uid://tl3hcapnk7lb" path="res://addons/curved_lines_2d/svs_edit_tab.gd" id="1_nt5in"] +[ext_resource type="StyleBox" uid="uid://v0ueesjbdyrk" path="res://addons/curved_lines_2d/snazzy_toggle_button.stylebox" id="2_3cgh6"] +[ext_resource type="PackedScene" uid="uid://cjbkvx1pj7gq2" path="res://addons/curved_lines_2d/collision_object_type_option_button.tscn" id="2_kh00m"] +[ext_resource type="Texture2D" uid="uid://7hhlkt6n4b32" path="res://addons/curved_lines_2d/PaintOrder.svg" id="2_qgati"] +[ext_resource type="PackedScene" uid="uid://cmoxkoulpd7so" path="res://addons/curved_lines_2d/link_button_with_copy_hint.tscn" id="2_xxhaf"] +[ext_resource type="Texture2D" uid="uid://cdkf2g8b5e55r" path="res://addons/curved_lines_2d/LineCaps.svg" id="4_xku8w"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_qgati"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_3cgh6"] +resource_local_to_scene = true +atlas = ExtResource("2_qgati") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_xku8w"] +atlas = ExtResource("2_qgati") +region = Rect2(32, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_kh00m"] +atlas = ExtResource("2_qgati") +region = Rect2(64, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_4mj77"] +atlas = ExtResource("2_qgati") +region = Rect2(0, 32, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_jq58x"] +atlas = ExtResource("2_qgati") +region = Rect2(32, 32, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_hip06"] +atlas = ExtResource("2_qgati") +region = Rect2(64, 32, 32, 32) + +[sub_resource type="ButtonGroup" id="ButtonGroup_kh00m"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_85hwe"] +atlas = ExtResource("4_xku8w") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_nh347"] +atlas = ExtResource("4_xku8w") +region = Rect2(64, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_exygk"] +atlas = ExtResource("4_xku8w") +region = Rect2(32, 0, 32, 32) + +[sub_resource type="ButtonGroup" id="ButtonGroup_k2toy"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_2t4g6"] +atlas = ExtResource("4_xku8w") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_pf6gx"] +atlas = ExtResource("4_xku8w") +region = Rect2(64, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_jph0d"] +atlas = ExtResource("4_xku8w") +region = Rect2(32, 0, 32, 32) + +[sub_resource type="ButtonGroup" id="ButtonGroup_xku8w"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_k2toy"] +atlas = ExtResource("4_xku8w") +region = Rect2(64, 32, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_em7di"] +atlas = ExtResource("4_xku8w") +region = Rect2(0, 32, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_84wj1"] +atlas = ExtResource("4_xku8w") +region = Rect2(32, 32, 32, 32) + +[node name="SVSEditTab" type="ScrollContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_nt5in") +metadata/_edit_vertical_guides_ = [176.0] + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_constants/separation = 8 +metadata/_tab_index = 1 +metadata/_edit_vertical_guides_ = [170.0] + +[node name="DrawSettingsContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="VBoxContainer/DrawSettingsContainer"] +custom_minimum_size = Vector2(130, 0) +layout_mode = 2 +tooltip_text = "These settings apply to all new shapes created via the buttons in this dock." +mouse_filter = 0 +text = "Draw Settings*" + +[node name="FillCheckButton" type="CheckButton" parent="VBoxContainer/DrawSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 8 +tooltip_text = "- Toggled On: when creating a new shape via this panel, a Fill (Polygon2D) of this color will be automatically added +- When a new ScalableVectorShape2D is generated via the Scene Tree or the 2D Viewport using add node, a Fill will _not_ be automatically assigned. +- When generating a Fill via the Inspector button for ScalableVectorShape2D, the color configured here will be automatically picked." +button_pressed = true +text = "Fill*" +alignment = 2 + +[node name="FillPickerButton" type="ColorPickerButton" parent="VBoxContainer/DrawSettingsContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(42, 0) +layout_mode = 2 +size_flags_horizontal = 8 +text = "Fill" +color = Color(1, 1, 1, 1) + +[node name="StrokeCheckButton" type="CheckButton" parent="VBoxContainer/DrawSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 8 +tooltip_text = "- Toggled On: when creating a new shape via this panel, a Stroke (Line2D) of this color will be automatically added +- When a new ScalableVectorShape2D is generated via the Scene Tree or the 2D Viewport using add node, a Stroke will _not_ be automatically assigned. +- When generating a Stroke via the Inspector button for ScalableVectorShape2D, the color configured here will be automatically picked." +button_pressed = true +text = "Stroke*" +alignment = 2 + +[node name="StrokePickerButton" type="ColorPickerButton" parent="VBoxContainer/DrawSettingsContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(42, 0) +layout_mode = 2 +size_flags_horizontal = 8 +text = "Fill" + +[node name="CollisionObjectTypeOptionButton" parent="VBoxContainer/DrawSettingsContainer" instance=ExtResource("2_kh00m")] +unique_name_in_owner = true +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/DrawSettingsContainer"] +layout_mode = 2 +tooltip_text = "- This toggle determines in what order 'Fills', 'Strokes' and 'Markers' are drawn when creating a new shape using this panel +- This plugin treats CollisionPolygon2D as a marker, Line2D as stroke and Polygon2D as fill. +- Button hints will show the order from back to front and use the term 'Collision' in stead of 'Marker'" +mouse_filter = 0 +text = "Paint Order*" + +[node name="PaintOrderButton0" type="Button" parent="VBoxContainer/DrawSettingsContainer"] +layout_mode = 2 +tooltip_text = "Use Paint Order: +Fills, Strokes, Collision" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +button_pressed = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_qgati") +icon = SubResource("AtlasTexture_3cgh6") + +[node name="PaintOrderButton1" type="Button" parent="VBoxContainer/DrawSettingsContainer"] +layout_mode = 2 +tooltip_text = "Use Paint Order: +Strokes, Fills, Collision" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_qgati") +icon = SubResource("AtlasTexture_xku8w") + +[node name="PaintOrderButton2" type="Button" parent="VBoxContainer/DrawSettingsContainer"] +layout_mode = 2 +tooltip_text = "Use Paint Order: +Fills, Collision, Strokes" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_qgati") +icon = SubResource("AtlasTexture_kh00m") + +[node name="PaintOrderButton3" type="Button" parent="VBoxContainer/DrawSettingsContainer"] +layout_mode = 2 +tooltip_text = "Use Paint Order: +Collision, Fills, Strokes" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_qgati") +icon = SubResource("AtlasTexture_4mj77") + +[node name="PaintOrderButton4" type="Button" parent="VBoxContainer/DrawSettingsContainer"] +layout_mode = 2 +tooltip_text = "Use Paint Order: +Strokes, Collision, Fills" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_qgati") +icon = SubResource("AtlasTexture_jq58x") + +[node name="PaintOrderButton5" type="Button" parent="VBoxContainer/DrawSettingsContainer"] +layout_mode = 2 +tooltip_text = "Use Paint Order: +Collision, Strokes, Fills" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_qgati") +icon = SubResource("AtlasTexture_hip06") + +[node name="CreateEmptyShapeButton" type="Button" parent="VBoxContainer/DrawSettingsContainer"] +custom_minimum_size = Vector2(160, 0) +layout_mode = 2 +size_flags_horizontal = 10 +tooltip_text = "Will create a ScalableVectorShape2D with zero points" +text = "Create Empty Path" + +[node name="HSeparator5" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="StrokeSettingsContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="VBoxContainer/StrokeSettingsContainer"] +custom_minimum_size = Vector2(130, 0) +layout_mode = 2 +tooltip_text = "These settings apply to the Line2D assigned to a new node created via the buttons in this dock." +mouse_filter = 0 +text = "Stroke Settings*" + +[node name="StrokeWidthContainer" type="PanelContainer" parent="VBoxContainer/StrokeSettingsContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/StrokeSettingsContainer"] +layout_mode = 2 +size_flags_horizontal = 0 + +[node name="UseLine2DCheckButton" type="CheckButton" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "Use a Line2D node to represent the stroke with in stead of a Polygon2D. Cost/Benefit: +- A Polygon2D stroke can be more neatly clipped than a Line2D +- CollisionPolygon2D's match Polygon2D Stroke better +- A Polygon2D stroke can be textured with gradients like Fills are textured +- Line2D has sharper caps and line joints at high zoom +- Line2D can be textured directionally in stead of like a Fill texture +- Line2D can set different Begin and End Cap Modes where Polygon2D can only pick one" +button_pressed = true +text = "Use Line2D*" + +[node name="Label2" type="Label" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will set the begin_cap_mode of the assigned Line2D node to: +- Line Cap None +- Line Cap Box +- Line Cap Round + +" +mouse_filter = 0 +text = "Begin Cap Mode*" +horizontal_alignment = 2 + +[node name="BeginNoCapToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the begin_cap_mode of the assigned Line2D node to: +- Line Cap None +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +button_pressed = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_kh00m") +icon = SubResource("AtlasTexture_85hwe") + +[node name="BeginBoxCapToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the begin_cap_mode of the assigned Line2D node to: +- Line Cap Box + +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_kh00m") +icon = SubResource("AtlasTexture_nh347") + +[node name="BeginRoundCapToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the begin_cap_mode of the assigned Line2D node to: +- Line Cap Round + +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_kh00m") +icon = SubResource("AtlasTexture_exygk") + +[node name="EndCapForm" type="HBoxContainer" parent="VBoxContainer/StrokeSettingsContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 0 + +[node name="Label3" type="Label" parent="VBoxContainer/StrokeSettingsContainer/EndCapForm"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will set the end_cap_mode of the assigned Line2D node to: +- Line Cap None +- Line Cap Box +- Line Cap Round + +" +mouse_filter = 0 +text = "End Cap Mode *" +horizontal_alignment = 2 + +[node name="EndNoCapToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/EndCapForm"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the end_cap_mode of the assigned Line2D node to: +- Line Cap None +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +button_pressed = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_k2toy") +icon = SubResource("AtlasTexture_2t4g6") + +[node name="EndBoxCapToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/EndCapForm"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the end_cap_mode of the assigned Line2D node to: +- Line Cap Box + +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_k2toy") +icon = SubResource("AtlasTexture_pf6gx") + +[node name="EndRoundCapToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/EndCapForm"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the end_cap_mode of the assigned Line2D node to: +- Line Cap Round + +" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_k2toy") +icon = SubResource("AtlasTexture_jph0d") + +[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer/StrokeSettingsContainer"] +layout_mode = 2 +size_flags_horizontal = 0 + +[node name="Label" type="Label" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer3"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "This will set the joint_mode of the assigned Line2D node to: +- Sharp +- Bevel +- Round" +mouse_filter = 0 +text = "Joint Mode*" +horizontal_alignment = 2 + +[node name="LineJointSharpToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer3"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the joint_mode of the assigned Line2D node to: +- Sharp" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +button_pressed = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_xku8w") +icon = SubResource("AtlasTexture_k2toy") + +[node name="LineJointBevelToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer3"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the joint_mode of the assigned Line2D node to: +- Bevel" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_xku8w") +icon = SubResource("AtlasTexture_em7di") + +[node name="LineJointRoundToggleButton" type="Button" parent="VBoxContainer/StrokeSettingsContainer/HBoxContainer3"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +tooltip_text = "This will set the joint_mode of the assigned Line2D node to: +- Round" +theme_override_colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_hover_color = Color(1, 1, 1, 1) +theme_override_colors/icon_pressed_color = Color(1, 1, 1, 1) +theme_override_colors/icon_focus_color = Color(1, 1, 1, 1) +theme_override_colors/icon_normal_color = Color(1, 1, 1, 1) +theme_override_styles/pressed = ExtResource("2_3cgh6") +toggle_mode = true +keep_pressed_outside = true +button_group = SubResource("ButtonGroup_xku8w") +icon = SubResource("AtlasTexture_84wj1") + +[node name="HSeparator4" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="RectBuilderContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/RectBuilderContainer"] +custom_minimum_size = Vector2(130, 0) +layout_mode = 2 +tooltip_text = "Create a Rectangle as: +- ScalableRect2D: a primitive rect, which extends from ScalableVectorShape2D (easier to edit) + - ScalableVectorShape2D (editable as a path)" +mouse_filter = 0 +text = "Create Rectangle*" + +[node name="WidthSliderContainer" type="PanelContainer" parent="VBoxContainer/RectBuilderContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HeightSliderContainer" type="PanelContainer" parent="VBoxContainer/RectBuilderContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="XRadiusSliderContainer" type="PanelContainer" parent="VBoxContainer/RectBuilderContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="YRadiusSliderContainer" type="PanelContainer" parent="VBoxContainer/RectBuilderContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="CreateRectButton" type="Button" parent="VBoxContainer/RectBuilderContainer"] +custom_minimum_size = Vector2(140, 0) +layout_mode = 2 +size_flags_horizontal = 8 +tooltip_text = "Create a new ScalableRect2D" +text = "Create Rectangle" + +[node name="CreateRectAsPathButton" type="Button" parent="VBoxContainer/RectBuilderContainer"] +custom_minimum_size = Vector2(140, 0) +layout_mode = 2 +size_flags_horizontal = 8 +tooltip_text = "Create a new Rectangle as a ScalableVectorShape2D" +text = "Create Path" + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="EllipseBuilderContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/EllipseBuilderContainer"] +custom_minimum_size = Vector2(130, 0) +layout_mode = 2 +tooltip_text = "Create an Ellipse as: +- ScalableEllipse2D: a primitive ellipse, which extends from ScalableVectorShape2D (easier to edit) + - ScalableVectorShape2D (editable as a path)" +mouse_filter = 0 +text = "Create Ellipse*" + +[node name="EllipseXRadiusSliderContainer" type="PanelContainer" parent="VBoxContainer/EllipseBuilderContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="EllipseYRadiusSliderContainer" type="PanelContainer" parent="VBoxContainer/EllipseBuilderContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="CreateEllipseButton" type="Button" parent="VBoxContainer/EllipseBuilderContainer"] +custom_minimum_size = Vector2(140, 0) +layout_mode = 2 +text = "Create Ellipse" + +[node name="CreateCircleButton" type="Button" parent="VBoxContainer/EllipseBuilderContainer"] +custom_minimum_size = Vector2(140, 0) +layout_mode = 2 +text = "Create Path" + +[node name="HSeparator3" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="CenterContainer" type="CenterContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="LinkButton" parent="VBoxContainer/CenterContainer" instance=ExtResource("2_xxhaf")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/gaug5zv57IE +Right click to copy this link" +uri = "https://youtu.be/gaug5zv57IE" + +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/FillCheckButton" to="." method="_on_fill_check_button_toggled"] +[connection signal="color_changed" from="VBoxContainer/DrawSettingsContainer/FillPickerButton" to="." method="_on_fill_picker_button_color_changed"] +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/StrokeCheckButton" to="." method="_on_stroke_check_button_toggled"] +[connection signal="color_changed" from="VBoxContainer/DrawSettingsContainer/StrokePickerButton" to="." method="_on_stroke_picker_button_color_changed"] +[connection signal="type_selected" from="VBoxContainer/DrawSettingsContainer/CollisionObjectTypeOptionButton" to="." method="_on_collision_object_type_option_button_type_selected"] +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/PaintOrderButton0" to="." method="_on_paint_order_button_0_toggled"] +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/PaintOrderButton1" to="." method="_on_paint_order_button_1_toggled"] +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/PaintOrderButton2" to="." method="_on_paint_order_button_2_toggled"] +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/PaintOrderButton3" to="." method="_on_paint_order_button_3_toggled"] +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/PaintOrderButton4" to="." method="_on_paint_order_button_4_toggled"] +[connection signal="toggled" from="VBoxContainer/DrawSettingsContainer/PaintOrderButton5" to="." method="_on_paint_order_button_5_toggled"] +[connection signal="pressed" from="VBoxContainer/DrawSettingsContainer/CreateEmptyShapeButton" to="." method="_on_create_empty_shape_button_pressed"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/HBoxContainer/UseLine2DCheckButton" to="." method="_on_use_line_2d_check_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/HBoxContainer/BeginNoCapToggleButton" to="." method="_on_begin_no_cap_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/HBoxContainer/BeginBoxCapToggleButton" to="." method="_on_begin_box_cap_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/HBoxContainer/BeginRoundCapToggleButton" to="." method="_on_begin_round_cap_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/EndCapForm/EndNoCapToggleButton" to="." method="_on_end_no_cap_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/EndCapForm/EndBoxCapToggleButton" to="." method="_on_end_box_cap_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/EndCapForm/EndRoundCapToggleButton" to="." method="_on_end_round_cap_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/HBoxContainer3/LineJointSharpToggleButton" to="." method="_on_line_joint_sharp_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/HBoxContainer3/LineJointBevelToggleButton" to="." method="_on_line_joint_bevel_toggle_button_toggled"] +[connection signal="toggled" from="VBoxContainer/StrokeSettingsContainer/HBoxContainer3/LineJointRoundToggleButton" to="." method="_on_line_joint_round_toggle_button_toggled"] +[connection signal="mouse_entered" from="VBoxContainer/RectBuilderContainer/CreateRectButton" to="." method="_on_create_rect_button_mouse_entered"] +[connection signal="mouse_exited" from="VBoxContainer/RectBuilderContainer/CreateRectButton" to="." method="_on_create_rect_button_mouse_exited"] +[connection signal="pressed" from="VBoxContainer/RectBuilderContainer/CreateRectButton" to="." method="_on_create_rect_button_pressed"] +[connection signal="mouse_entered" from="VBoxContainer/RectBuilderContainer/CreateRectAsPathButton" to="." method="_on_create_rect_button_mouse_entered"] +[connection signal="mouse_exited" from="VBoxContainer/RectBuilderContainer/CreateRectAsPathButton" to="." method="_on_create_rect_button_mouse_exited"] +[connection signal="pressed" from="VBoxContainer/RectBuilderContainer/CreateRectAsPathButton" to="." method="_on_create_rect_as_path_button_pressed"] +[connection signal="mouse_entered" from="VBoxContainer/EllipseBuilderContainer/CreateEllipseButton" to="." method="_on_create_circle_button_mouse_entered"] +[connection signal="mouse_exited" from="VBoxContainer/EllipseBuilderContainer/CreateEllipseButton" to="." method="_on_create_circle_button_mouse_exited"] +[connection signal="pressed" from="VBoxContainer/EllipseBuilderContainer/CreateEllipseButton" to="." method="_on_create_ellipse_button_pressed"] +[connection signal="mouse_entered" from="VBoxContainer/EllipseBuilderContainer/CreateCircleButton" to="." method="_on_create_circle_button_mouse_entered"] +[connection signal="mouse_exited" from="VBoxContainer/EllipseBuilderContainer/CreateCircleButton" to="." method="_on_create_circle_button_mouse_exited"] +[connection signal="pressed" from="VBoxContainer/EllipseBuilderContainer/CreateCircleButton" to="." method="_on_create_circle_button_pressed"] diff --git a/addons/curved_lines_2d/svs_scene_exporter.gd b/addons/curved_lines_2d/svs_scene_exporter.gd new file mode 100644 index 0000000..19c8962 --- /dev/null +++ b/addons/curved_lines_2d/svs_scene_exporter.gd @@ -0,0 +1,92 @@ +@tool +extends Object +class_name SVSSceneExporter + + +static func export_image(export_root_node : Node, stored_box_ref : Dictionary[String, Vector2] = {}, + render_parent := Node.new(), forward_aa := true) -> Image: + var sub_viewport := SubViewport.new() + render_parent.add_child(sub_viewport) + sub_viewport.transparent_bg = true + sub_viewport.render_target_update_mode = SubViewport.UPDATE_ONCE + var copied : Node = export_root_node.duplicate() + sub_viewport.add_child(copied) + var box = copied.get_bounding_box() if copied is ScalableVectorShape2D else [Vector2.ZERO] + var child_list := copied.get_children() + var min_x = box.map(func(corner): return corner.x).min() + var min_y = box.map(func(corner): return corner.y).min() + var max_x = box.map(func(corner): return corner.x).max() + var max_y = box.map(func(corner): return corner.y).max() + + while child_list.size() > 0: + var child : Node = child_list.pop_back() + if child is Camera2D: + child.enabled = false + child_list.append_array(child.get_children()) + if child is ScalableVectorShape2D: + var box1 = child.get_bounding_box() + var min_x1 = box1.map(func(corner): return corner.x).min() + var min_y1 = box1.map(func(corner): return corner.y).min() + var max_x1 = box1.map(func(corner): return corner.x).max() + var max_y1 = box1.map(func(corner): return corner.y).max() + min_x = floori(min_x if min_x1 > min_x else min_x1) + min_y = floori(min_y if min_y1 > min_y else min_y1) + max_x = ceili(max_x if max_x1 < max_x else max_x1) + max_y = ceili(max_y if max_y1 < max_y else max_y1) + sub_viewport.canvas_transform.origin = -Vector2(min_x, min_y) + sub_viewport.size = Vector2(max_x, max_y) - Vector2(min_x, min_y) + if forward_aa: + sub_viewport.msaa_2d = Viewport.MSAA_8X + else: + sub_viewport.screen_space_aa = Viewport.SCREEN_SPACE_AA_FXAA + + stored_box_ref["tl"] = Vector2(min_x, min_y) + stored_box_ref["br"] = Vector2(max_x, max_y) + await RenderingServer.frame_post_draw + var img = sub_viewport.get_texture().get_image() + sub_viewport.queue_free() + return img + + +static func export_sprite_frames(root_node : Node, + animation_player : AnimationPlayer, + anim_name : String, fps : int, + render_parent : Node, on_progress : Callable, + forward_aa := false) -> Array[Image]: + var interval := 1.0 / fps + animation_player.stop() + animation_player.current_animation = anim_name + animation_player.get_animation(anim_name) + var boxes : Array[Dictionary] = [] + var images : Array[Image] = [] + var frame_count := ceili(animation_player.current_animation_length / interval) + if on_progress: + on_progress.call("Rendering animation %s at %d fps to %d frames" % [anim_name, fps, frame_count]) + # Render each frame into an image + for idx in range(frame_count): + var pos = idx * interval + if pos > animation_player.current_animation_length: + pos = animation_player.current_animation_length + animation_player.seek(pos, true) + animation_player.pause() + var box : Dictionary[String, Vector2] = {} + var im = await export_image(root_node, box, render_parent, forward_aa) + boxes.append(box) + images.append(im) + animation_player.stop() + + # Determine the bounding box into which all the rendered images would fit + var min_x = boxes.map(func(box): return box["tl"].x).min() + var min_y = boxes.map(func(box): return box["tl"].y).min() + var max_x = boxes.map(func(box): return box["br"].x).max() + var max_y = boxes.map(func(box): return box["br"].y).max() + var return_list : Array[Image] = [] + + # rerender and realign the images such that they all have the same size + for idx in images.size(): + var im : Image = Image.create_empty(ceili(max_x) - floori(min_x), ceili(max_y) - floor(min_y), false, images[idx].get_format()) + for x in images[idx].get_size().x: + for y in images[idx].get_size().y: + im.set_pixel(floori(boxes[idx]["tl"].x) - min_x + x, floori(boxes[idx]["tl"].y) - min_y + y, images[idx].get_pixel(x, y)) + return_list.append(im) + return return_list diff --git a/addons/curved_lines_2d/svs_scene_exporter.gd.uid b/addons/curved_lines_2d/svs_scene_exporter.gd.uid new file mode 100644 index 0000000..0a0652e --- /dev/null +++ b/addons/curved_lines_2d/svs_scene_exporter.gd.uid @@ -0,0 +1 @@ +uid://v1635p58ds2s diff --git a/addons/curved_lines_2d/svs_vertex_merge_2d.gd b/addons/curved_lines_2d/svs_vertex_merge_2d.gd new file mode 100644 index 0000000..ea5968e --- /dev/null +++ b/addons/curved_lines_2d/svs_vertex_merge_2d.gd @@ -0,0 +1,81 @@ +@tool +extends Node2D + +class_name SVSVertexMerge2D + +@export var vertex_map : Dictionary[ScalableVectorShape2D, int] = {}: + set = _set_vertex_owners + +var _vertex_counts : Dictionary[ScalableVectorShape2D, int] = {} +var _closed_shapes : Dictionary[ScalableVectorShape2D, bool] = {} + + +func _enter_tree() -> void: + set_meta("_edit_lock_", true) + _connect_signals() + + +func _exit_tree() -> void: + _disconnect_signals() + + +func _set_vertex_owners(new_lst : Dictionary[ScalableVectorShape2D, int]): + _disconnect_signals() + vertex_map = new_lst + _connect_signals() + + +func _disconnect_signals() -> void: + for svs : ScalableVectorShape2D in vertex_map.keys().filter(is_instance_valid): + if svs.polygons_updated.is_connected(_on_svs_curve_changed): + svs.polygons_updated.disconnect(_on_svs_curve_changed) + if svs.transform_changed.is_connected(_on_svs_transform_changed): + svs.transform_changed.disconnect(_on_svs_transform_changed) + + +func _connect_signals(): + for svs : ScalableVectorShape2D in vertex_map.keys().filter(is_instance_valid): + _vertex_counts[svs] = svs.curve.point_count + _closed_shapes[svs] = svs.is_curve_closed() + if not svs.polygons_updated.is_connected(_on_svs_curve_changed): + svs.polygons_updated.connect(_on_svs_curve_changed) + if not svs.transform_changed.is_connected(_on_svs_transform_changed): + svs.set_notify_local_transform(true) + svs.transform_changed.connect(_on_svs_transform_changed) + if vertex_map.size() > 0 and is_instance_valid(vertex_map.keys()[0]): + _align_vertices(vertex_map.keys()[0]) + + +func _on_svs_transform_changed(svs : ScalableVectorShape2D): + _align_vertices(svs) + + +func _on_svs_curve_changed( + _a : Array[PackedVector2Array], + _b : Array[PackedVector2Array], + svs : ScalableVectorShape2D): + _align_vertices(svs) + + +func _align_vertices(svs : ScalableVectorShape2D): + if _vertex_counts[svs] != svs.curve.point_count: + for i in svs.curve.point_count: + if svs.to_global(svs.curve.get_point_position(i)).is_equal_approx(global_position): + vertex_map[svs] = i + break + _vertex_counts[svs] = svs.curve.point_count + _closed_shapes[svs] = svs.is_curve_closed() + + var global_vertex_pos := svs.to_global(svs.curve.get_point_position(vertex_map[svs])) + global_position = global_vertex_pos + for svs1 : ScalableVectorShape2D in vertex_map.keys().filter(is_instance_valid): + if svs1 != svs: + var idx := vertex_map[svs1] + var new_pos := svs1.to_local(global_vertex_pos) + var old_pos := svs1.curve.get_point_position(idx) + if not old_pos.is_equal_approx(new_pos): + if _closed_shapes[svs1] and idx == 0: + svs1.curve.set_point_position(svs1.curve.point_count - 1, new_pos) + elif _closed_shapes[svs1] and idx == svs1.curve.point_count - 1: + svs1.curve.set_point_position(0, new_pos) + svs1.curve.set_point_position(idx, new_pos) diff --git a/addons/curved_lines_2d/svs_vertex_merge_2d.gd.uid b/addons/curved_lines_2d/svs_vertex_merge_2d.gd.uid new file mode 100644 index 0000000..017937d --- /dev/null +++ b/addons/curved_lines_2d/svs_vertex_merge_2d.gd.uid @@ -0,0 +1 @@ +uid://dn747ucen5o8b diff --git a/addons/curved_lines_2d/tests/01-godot-icon.svg b/addons/curved_lines_2d/tests/01-godot-icon.svg new file mode 100644 index 0000000..3c5d355 --- /dev/null +++ b/addons/curved_lines_2d/tests/01-godot-icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/01-godot-icon.svg.import b/addons/curved_lines_2d/tests/01-godot-icon.svg.import new file mode 100644 index 0000000..c1aea9a --- /dev/null +++ b/addons/curved_lines_2d/tests/01-godot-icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0tet2m4kvugc" +path="res://.godot/imported/01-godot-icon.svg-9889ecc7bb588307638e013527c25d03.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/01-godot-icon.svg" +dest_files=["res://.godot/imported/01-godot-icon.svg-9889ecc7bb588307638e013527c25d03.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/02-butterfly.svg b/addons/curved_lines_2d/tests/02-butterfly.svg new file mode 100644 index 0000000..3638c43 --- /dev/null +++ b/addons/curved_lines_2d/tests/02-butterfly.svg @@ -0,0 +1,158 @@ + + + + +Created by potrace 1.15, written by Peter Selinger 2001-2017 + + + + + diff --git a/addons/curved_lines_2d/tests/02-butterfly.svg.import b/addons/curved_lines_2d/tests/02-butterfly.svg.import new file mode 100644 index 0000000..3532554 --- /dev/null +++ b/addons/curved_lines_2d/tests/02-butterfly.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgodvoocwkpko" +path="res://.godot/imported/02-butterfly.svg-abbd6b95db38c0e1b68321c62ff6870f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/02-butterfly.svg" +dest_files=["res://.godot/imported/02-butterfly.svg-abbd6b95db38c0e1b68321c62ff6870f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/03-floral-ornament.svg b/addons/curved_lines_2d/tests/03-floral-ornament.svg new file mode 100644 index 0000000..3b99ceb --- /dev/null +++ b/addons/curved_lines_2d/tests/03-floral-ornament.svg @@ -0,0 +1,560 @@ + + + + +Created by potrace 1.15, written by Peter Selinger 2001-2017 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/03-floral-ornament.svg.import b/addons/curved_lines_2d/tests/03-floral-ornament.svg.import new file mode 100644 index 0000000..32b8396 --- /dev/null +++ b/addons/curved_lines_2d/tests/03-floral-ornament.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ci44l41xnx5pw" +path="res://.godot/imported/03-floral-ornament.svg-81a5270e7ccc4cfa26e2b12bbbd92a0c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/03-floral-ornament.svg" +dest_files=["res://.godot/imported/03-floral-ornament.svg-81a5270e7ccc4cfa26e2b12bbbd92a0c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/04-inkscape-clippath.svg b/addons/curved_lines_2d/tests/04-inkscape-clippath.svg new file mode 100644 index 0000000..98b53be --- /dev/null +++ b/addons/curved_lines_2d/tests/04-inkscape-clippath.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/04-inkscape-clippath.svg.import b/addons/curved_lines_2d/tests/04-inkscape-clippath.svg.import new file mode 100644 index 0000000..cc5bb1e --- /dev/null +++ b/addons/curved_lines_2d/tests/04-inkscape-clippath.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cp8dg0v2kx5vh" +path="res://.godot/imported/04-inkscape-clippath.svg-ab0ca48181d3a497add2e38880f1071c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/04-inkscape-clippath.svg" +dest_files=["res://.godot/imported/04-inkscape-clippath.svg-ab0ca48181d3a497add2e38880f1071c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/05-mdn-clippath.svg b/addons/curved_lines_2d/tests/05-mdn-clippath.svg new file mode 100644 index 0000000..59c0ce0 --- /dev/null +++ b/addons/curved_lines_2d/tests/05-mdn-clippath.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/05-mdn-clippath.svg.import b/addons/curved_lines_2d/tests/05-mdn-clippath.svg.import new file mode 100644 index 0000000..7187622 --- /dev/null +++ b/addons/curved_lines_2d/tests/05-mdn-clippath.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqba3g0xnne7x" +path="res://.godot/imported/05-mdn-clippath.svg-590440088038bd95eebaefb0c694e76e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/05-mdn-clippath.svg" +dest_files=["res://.godot/imported/05-mdn-clippath.svg-590440088038bd95eebaefb0c694e76e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/06-stroke-with-a-gradient.svg b/addons/curved_lines_2d/tests/06-stroke-with-a-gradient.svg new file mode 100644 index 0000000..55817c5 --- /dev/null +++ b/addons/curved_lines_2d/tests/06-stroke-with-a-gradient.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/06-stroke-with-a-gradient.svg.import b/addons/curved_lines_2d/tests/06-stroke-with-a-gradient.svg.import new file mode 100644 index 0000000..a6df267 --- /dev/null +++ b/addons/curved_lines_2d/tests/06-stroke-with-a-gradient.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vn6yj7f572le" +path="res://.godot/imported/06-stroke-with-a-gradient.svg-9888fa4cb8203d8a5033e7a9ad0e91b2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/06-stroke-with-a-gradient.svg" +dest_files=["res://.godot/imported/06-stroke-with-a-gradient.svg-9888fa4cb8203d8a5033e7a9ad0e91b2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/07-multiple-cutouts-and-shape2-in-1-path.svg b/addons/curved_lines_2d/tests/07-multiple-cutouts-and-shape2-in-1-path.svg new file mode 100644 index 0000000..929fb94 --- /dev/null +++ b/addons/curved_lines_2d/tests/07-multiple-cutouts-and-shape2-in-1-path.svg @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/addons/curved_lines_2d/tests/07-multiple-cutouts-and-shape2-in-1-path.svg.import b/addons/curved_lines_2d/tests/07-multiple-cutouts-and-shape2-in-1-path.svg.import new file mode 100644 index 0000000..17ad7eb --- /dev/null +++ b/addons/curved_lines_2d/tests/07-multiple-cutouts-and-shape2-in-1-path.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d0h70u2y105ok" +path="res://.godot/imported/07-multiple-cutouts-and-shape2-in-1-path.svg-8697300bec6f1b0a4159870110a4cb56.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/07-multiple-cutouts-and-shape2-in-1-path.svg" +dest_files=["res://.godot/imported/07-multiple-cutouts-and-shape2-in-1-path.svg-8697300bec6f1b0a4159870110a4cb56.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/arc.svg b/addons/curved_lines_2d/tests/arc.svg new file mode 100644 index 0000000..430178d --- /dev/null +++ b/addons/curved_lines_2d/tests/arc.svg @@ -0,0 +1,22 @@ + + + Example arcs01 - arc commands in path data + Picture of a pie chart with two pie wedges and + a picture of a line with arc blips + + + + + + + + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/arc.svg.import b/addons/curved_lines_2d/tests/arc.svg.import new file mode 100644 index 0000000..c7c0233 --- /dev/null +++ b/addons/curved_lines_2d/tests/arc.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cyq5h6ttjq56q" +path="res://.godot/imported/arc.svg-ef6bb300d3fee8f843f8cde6ae8089af.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/arc.svg" +dest_files=["res://.godot/imported/arc.svg-ef6bb300d3fee8f843f8cde6ae8089af.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/arcs02.svg b/addons/curved_lines_2d/tests/arcs02.svg new file mode 100644 index 0000000..013626b --- /dev/null +++ b/addons/curved_lines_2d/tests/arcs02.svg @@ -0,0 +1,91 @@ + + + Example arcs02 - arc options in paths + Pictures showing the result of setting + large-arc-flag and sweep-flag to the four + possible combinations of 0 and 1. + + + + + + Arc start + Arc end + + + + + + + + + + Arc start + Arc end + + + + large-arc-flag=0 + sweep-flag=0 + + + + Arc start + Arc end + + + + + large-arc-flag=0 + sweep-flag=1 + + + + Arc start + Arc end + + + + + large-arc-flag=1 + sweep-flag=0 + + + + Arc start + Arc end + + + + + large-arc-flag=1 + sweep-flag=1 + + + + Arc start + Arc end + + + + + + diff --git a/addons/curved_lines_2d/tests/arcs02.svg.import b/addons/curved_lines_2d/tests/arcs02.svg.import new file mode 100644 index 0000000..bb4c667 --- /dev/null +++ b/addons/curved_lines_2d/tests/arcs02.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://oefjpw72ajxw" +path="res://.godot/imported/arcs02.svg-f759bf90069d25e5f49001136ef5d811.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/arcs02.svg" +dest_files=["res://.godot/imported/arcs02.svg-f759bf90069d25e5f49001136ef5d811.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/arcs03.svg b/addons/curved_lines_2d/tests/arcs03.svg new file mode 100644 index 0000000..47c2c03 --- /dev/null +++ b/addons/curved_lines_2d/tests/arcs03.svg @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/arcs03.svg.import b/addons/curved_lines_2d/tests/arcs03.svg.import new file mode 100644 index 0000000..7e5572a --- /dev/null +++ b/addons/curved_lines_2d/tests/arcs03.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxkfyrxaiobua" +path="res://.godot/imported/arcs03.svg-983b7cb8bc8ef6dc04c8a0480cd8e4db.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/arcs03.svg" +dest_files=["res://.godot/imported/arcs03.svg-983b7cb8bc8ef6dc04c8a0480cd8e4db.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/bat_concept_art.svg b/addons/curved_lines_2d/tests/bat_concept_art.svg new file mode 100644 index 0000000..f60d07a --- /dev/null +++ b/addons/curved_lines_2d/tests/bat_concept_art.svg @@ -0,0 +1,686 @@ + + + +123456789 diff --git a/addons/curved_lines_2d/tests/bat_concept_art.svg.import b/addons/curved_lines_2d/tests/bat_concept_art.svg.import new file mode 100644 index 0000000..e279205 --- /dev/null +++ b/addons/curved_lines_2d/tests/bat_concept_art.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://jw8onewwuwpy" +path="res://.godot/imported/bat_concept_art.svg-836bed6a7b86e5265ace0fc07ac7357e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/bat_concept_art.svg" +dest_files=["res://.godot/imported/bat_concept_art.svg-836bed6a7b86e5265ace0fc07ac7357e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/chair.svg b/addons/curved_lines_2d/tests/chair.svg new file mode 100644 index 0000000..76447fb --- /dev/null +++ b/addons/curved_lines_2d/tests/chair.svg @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/chair.svg.import b/addons/curved_lines_2d/tests/chair.svg.import new file mode 100644 index 0000000..f36460a --- /dev/null +++ b/addons/curved_lines_2d/tests/chair.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://drjvftvi4j1a1" +path="res://.godot/imported/chair.svg-5ff6195345d24e6d73885231ef06916e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/chair.svg" +dest_files=["res://.godot/imported/chair.svg-5ff6195345d24e6d73885231ef06916e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/cloud.svg b/addons/curved_lines_2d/tests/cloud.svg new file mode 100644 index 0000000..c1e9637 --- /dev/null +++ b/addons/curved_lines_2d/tests/cloud.svg @@ -0,0 +1,42 @@ + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/cloud.svg.import b/addons/curved_lines_2d/tests/cloud.svg.import new file mode 100644 index 0000000..51822a6 --- /dev/null +++ b/addons/curved_lines_2d/tests/cloud.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6se0htj0bgka" +path="res://.godot/imported/cloud.svg-5dcfea09a78ac83c437b85727e5a96c7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/cloud.svg" +dest_files=["res://.godot/imported/cloud.svg-5dcfea09a78ac83c437b85727e5a96c7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/cubic_bezier.svg b/addons/curved_lines_2d/tests/cubic_bezier.svg new file mode 100644 index 0000000..5c98752 --- /dev/null +++ b/addons/curved_lines_2d/tests/cubic_bezier.svg @@ -0,0 +1,37 @@ + + + Example cubic01- cubic Bézier commands in path data + Picture showing a simple example of path data + using both a "C" and an "S" command, + along with annotations showing the control points + and end points + + + + + + + + + + + + + + + + + M100,200 C100,100 250,100 250,200 + S400,300 400,200 + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/cubic_bezier.svg.import b/addons/curved_lines_2d/tests/cubic_bezier.svg.import new file mode 100644 index 0000000..0be3f72 --- /dev/null +++ b/addons/curved_lines_2d/tests/cubic_bezier.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dktfks1bwulbg" +path="res://.godot/imported/cubic_bezier.svg-a2212226fba104526e348c284ba8f5cd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/cubic_bezier.svg" +dest_files=["res://.godot/imported/cubic_bezier.svg-a2212226fba104526e348c284ba8f5cd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/cubic_bezier2.svg b/addons/curved_lines_2d/tests/cubic_bezier2.svg new file mode 100644 index 0000000..a9ed014 --- /dev/null +++ b/addons/curved_lines_2d/tests/cubic_bezier2.svg @@ -0,0 +1,349 @@ + + + + + Example cubic02 - cubic Bézier commands in path data + Picture showing examples of "C" and "S" commands, + along with annotations showing the control points + and end points + + + + + + + + + + + M100,200 C100,100 400,100 400,200 + + + + + + + + + M100,500 C25,400 475,400 400,500 + + + + + + + + + M100,800 C175,700 325,700 400,800 + + + + + + + + + M600,200 C675,100 975,100 900,200 + + + + + + + + + M600,500 C600,350 900,650 900,500 + + + + + + + + + + + + + + M600,800 C625,700 725,700 750,800 + S875,900 900,800 + + + + Example cubic02 - cubic Bézier commands in path data + + + + diff --git a/addons/curved_lines_2d/tests/cubic_bezier2.svg.import b/addons/curved_lines_2d/tests/cubic_bezier2.svg.import new file mode 100644 index 0000000..16ebd47 --- /dev/null +++ b/addons/curved_lines_2d/tests/cubic_bezier2.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dxynraofh6r7" +path="res://.godot/imported/cubic_bezier2.svg-ec68d648e9dce6b5bf760ab58bf54740.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/cubic_bezier2.svg" +dest_files=["res://.godot/imported/cubic_bezier2.svg-ec68d648e9dce6b5bf760ab58bf54740.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/cubic_bezier_with_transforms.svg b/addons/curved_lines_2d/tests/cubic_bezier_with_transforms.svg new file mode 100644 index 0000000..2f04a64 --- /dev/null +++ b/addons/curved_lines_2d/tests/cubic_bezier_with_transforms.svg @@ -0,0 +1,83 @@ + + + + + Example cubic01- cubic Bézier commands in path data + Picture showing a simple example of path data + using both a "C" and an "S" command, + along with annotations showing the control points + and end points + + + + + + + Example cubic01- cubic Bézier commands in path data + + + + + + + + diff --git a/addons/curved_lines_2d/tests/cubic_bezier_with_transforms.svg.import b/addons/curved_lines_2d/tests/cubic_bezier_with_transforms.svg.import new file mode 100644 index 0000000..cf7252f --- /dev/null +++ b/addons/curved_lines_2d/tests/cubic_bezier_with_transforms.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dfve05j0id2b3" +path="res://.godot/imported/cubic_bezier_with_transforms.svg-2d7120d2b52be28faa4e76c836293197.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/cubic_bezier_with_transforms.svg" +dest_files=["res://.godot/imported/cubic_bezier_with_transforms.svg-2d7120d2b52be28faa4e76c836293197.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/duke_garland_concept_art.svg b/addons/curved_lines_2d/tests/duke_garland_concept_art.svg new file mode 100644 index 0000000..ecf557d --- /dev/null +++ b/addons/curved_lines_2d/tests/duke_garland_concept_art.svg @@ -0,0 +1,1715 @@ + + + + diff --git a/addons/curved_lines_2d/tests/duke_garland_concept_art.svg.import b/addons/curved_lines_2d/tests/duke_garland_concept_art.svg.import new file mode 100644 index 0000000..6a09a89 --- /dev/null +++ b/addons/curved_lines_2d/tests/duke_garland_concept_art.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b4q22fxmtipdq" +path="res://.godot/imported/duke_garland_concept_art.svg-86da725562fc5966968e0c9a94373080.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/duke_garland_concept_art.svg" +dest_files=["res://.godot/imported/duke_garland_concept_art.svg-86da725562fc5966968e0c9a94373080.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/ellipse.svg b/addons/curved_lines_2d/tests/ellipse.svg new file mode 100644 index 0000000..9b03216 --- /dev/null +++ b/addons/curved_lines_2d/tests/ellipse.svg @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/ellipse.svg.import b/addons/curved_lines_2d/tests/ellipse.svg.import new file mode 100644 index 0000000..d682620 --- /dev/null +++ b/addons/curved_lines_2d/tests/ellipse.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://p22anhyhh38y" +path="res://.godot/imported/ellipse.svg-c138e7b5ccc7e9812ca86bb208f05e78.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/ellipse.svg" +dest_files=["res://.godot/imported/ellipse.svg-c138e7b5ccc7e9812ca86bb208f05e78.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/fan_art.svg b/addons/curved_lines_2d/tests/fan_art.svg new file mode 100644 index 0000000..9fa30ea --- /dev/null +++ b/addons/curved_lines_2d/tests/fan_art.svg @@ -0,0 +1,173 @@ + + + + diff --git a/addons/curved_lines_2d/tests/fan_art.svg.import b/addons/curved_lines_2d/tests/fan_art.svg.import new file mode 100644 index 0000000..b33c422 --- /dev/null +++ b/addons/curved_lines_2d/tests/fan_art.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://k2m545ebji2c" +path="res://.godot/imported/fan_art.svg-6373455ca525f6cc5dd58b922b4d124e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/fan_art.svg" +dest_files=["res://.godot/imported/fan_art.svg-6373455ca525f6cc5dd58b922b4d124e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/gradients_with_transforms.svg b/addons/curved_lines_2d/tests/gradients_with_transforms.svg new file mode 100644 index 0000000..cad3399 --- /dev/null +++ b/addons/curved_lines_2d/tests/gradients_with_transforms.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/gradients_with_transforms.svg.import b/addons/curved_lines_2d/tests/gradients_with_transforms.svg.import new file mode 100644 index 0000000..f278ba8 --- /dev/null +++ b/addons/curved_lines_2d/tests/gradients_with_transforms.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b0vnnkhd3we5p" +path="res://.godot/imported/gradients_with_transforms.svg-a74dbb5b64d5d45b39264100a7454d7a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/gradients_with_transforms.svg" +dest_files=["res://.godot/imported/gradients_with_transforms.svg-a74dbb5b64d5d45b39264100a7454d7a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/inherited_styles.svg b/addons/curved_lines_2d/tests/inherited_styles.svg new file mode 100644 index 0000000..8455c4e --- /dev/null +++ b/addons/curved_lines_2d/tests/inherited_styles.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/inherited_styles.svg.import b/addons/curved_lines_2d/tests/inherited_styles.svg.import new file mode 100644 index 0000000..6815b68 --- /dev/null +++ b/addons/curved_lines_2d/tests/inherited_styles.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ggvh52jeo5ak" +path="res://.godot/imported/inherited_styles.svg-cf83429bfa0c917dccf5647a81774e3f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/inherited_styles.svg" +dest_files=["res://.godot/imported/inherited_styles.svg-cf83429bfa0c917dccf5647a81774e3f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/polyline.svg b/addons/curved_lines_2d/tests/polyline.svg new file mode 100644 index 0000000..6154134 --- /dev/null +++ b/addons/curved_lines_2d/tests/polyline.svg @@ -0,0 +1,23 @@ + + + Example polyline01 - increasingly larger bars + + + + + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/polyline.svg.import b/addons/curved_lines_2d/tests/polyline.svg.import new file mode 100644 index 0000000..ebf4c8f --- /dev/null +++ b/addons/curved_lines_2d/tests/polyline.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dx0jgw7q1n7ga" +path="res://.godot/imported/polyline.svg-36ca12f515ab9f59084db47a078f00bf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/polyline.svg" +dest_files=["res://.godot/imported/polyline.svg-36ca12f515ab9f59084db47a078f00bf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/quadratic_beziers.svg b/addons/curved_lines_2d/tests/quadratic_beziers.svg new file mode 100644 index 0000000..862404b --- /dev/null +++ b/addons/curved_lines_2d/tests/quadratic_beziers.svg @@ -0,0 +1,34 @@ + + + Example quad01 - quadratic Bézier commands in path data + Picture showing a "Q" a "T" command, + along with annotations showing the control points + and end points + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/curved_lines_2d/tests/quadratic_beziers.svg.import b/addons/curved_lines_2d/tests/quadratic_beziers.svg.import new file mode 100644 index 0000000..e60fefb --- /dev/null +++ b/addons/curved_lines_2d/tests/quadratic_beziers.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://couq7q86y8hub" +path="res://.godot/imported/quadratic_beziers.svg-f27542d30c5777812d5638b97160f567.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/quadratic_beziers.svg" +dest_files=["res://.godot/imported/quadratic_beziers.svg-f27542d30c5777812d5638b97160f567.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/rat_concept_art.svg b/addons/curved_lines_2d/tests/rat_concept_art.svg new file mode 100644 index 0000000..9b60dc1 --- /dev/null +++ b/addons/curved_lines_2d/tests/rat_concept_art.svg @@ -0,0 +1,352 @@ + + + + diff --git a/addons/curved_lines_2d/tests/rat_concept_art.svg.import b/addons/curved_lines_2d/tests/rat_concept_art.svg.import new file mode 100644 index 0000000..776bff7 --- /dev/null +++ b/addons/curved_lines_2d/tests/rat_concept_art.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://7xujlrtyddy8" +path="res://.godot/imported/rat_concept_art.svg-db47a77fe3befb30c4238037c97ee30d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/rat_concept_art.svg" +dest_files=["res://.godot/imported/rat_concept_art.svg-db47a77fe3befb30c4238037c97ee30d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/rounded_rect.svg b/addons/curved_lines_2d/tests/rounded_rect.svg new file mode 100644 index 0000000..24f4b68 --- /dev/null +++ b/addons/curved_lines_2d/tests/rounded_rect.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/rounded_rect.svg.import b/addons/curved_lines_2d/tests/rounded_rect.svg.import new file mode 100644 index 0000000..7fd2d45 --- /dev/null +++ b/addons/curved_lines_2d/tests/rounded_rect.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c3hvj5a0n3dlq" +path="res://.godot/imported/rounded_rect.svg-c1640986f11c0abda7dbff3122b82140.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/rounded_rect.svg" +dest_files=["res://.godot/imported/rounded_rect.svg-c1640986f11c0abda7dbff3122b82140.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/simple_circle.svg b/addons/curved_lines_2d/tests/simple_circle.svg new file mode 100644 index 0000000..45a5ad5 --- /dev/null +++ b/addons/curved_lines_2d/tests/simple_circle.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/simple_circle.svg.import b/addons/curved_lines_2d/tests/simple_circle.svg.import new file mode 100644 index 0000000..04761f5 --- /dev/null +++ b/addons/curved_lines_2d/tests/simple_circle.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bixmptevqidib" +path="res://.godot/imported/simple_circle.svg-67f7b4b5ff46e14584bdf1e67b90a8fc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/simple_circle.svg" +dest_files=["res://.godot/imported/simple_circle.svg-67f7b4b5ff46e14584bdf1e67b90a8fc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/simple_circle_gradients.svg b/addons/curved_lines_2d/tests/simple_circle_gradients.svg new file mode 100644 index 0000000..39ede7a --- /dev/null +++ b/addons/curved_lines_2d/tests/simple_circle_gradients.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/simple_circle_gradients.svg.import b/addons/curved_lines_2d/tests/simple_circle_gradients.svg.import new file mode 100644 index 0000000..1161bbf --- /dev/null +++ b/addons/curved_lines_2d/tests/simple_circle_gradients.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1t5pcvkm1wp8" +path="res://.godot/imported/simple_circle_gradients.svg-5c83b0adee7cabf0b5c8045478f8ac36.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/simple_circle_gradients.svg" +dest_files=["res://.godot/imported/simple_circle_gradients.svg-5c83b0adee7cabf0b5c8045478f8ac36.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/snail_concept.svg b/addons/curved_lines_2d/tests/snail_concept.svg new file mode 100644 index 0000000..c440d80 --- /dev/null +++ b/addons/curved_lines_2d/tests/snail_concept.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/tests/snail_concept.svg.import b/addons/curved_lines_2d/tests/snail_concept.svg.import new file mode 100644 index 0000000..b99fb50 --- /dev/null +++ b/addons/curved_lines_2d/tests/snail_concept.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b30xa0q3e1cwc" +path="res://.godot/imported/snail_concept.svg-4fd47850492ffa5b1cd35bdf73a0aa52.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/snail_concept.svg" +dest_files=["res://.godot/imported/snail_concept.svg-4fd47850492ffa5b1cd35bdf73a0aa52.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/tests/werkman_numbers_font.svg b/addons/curved_lines_2d/tests/werkman_numbers_font.svg new file mode 100644 index 0000000..f00a4c9 --- /dev/null +++ b/addons/curved_lines_2d/tests/werkman_numbers_font.svg @@ -0,0 +1,622 @@ + + + +image/svg+xml diff --git a/addons/curved_lines_2d/tests/werkman_numbers_font.svg.import b/addons/curved_lines_2d/tests/werkman_numbers_font.svg.import new file mode 100644 index 0000000..7a30d1b --- /dev/null +++ b/addons/curved_lines_2d/tests/werkman_numbers_font.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rkxljxaqfenn" +path="res://.godot/imported/werkman_numbers_font.svg-86923eaeb2ad1731b58bec0085650842.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/tests/werkman_numbers_font.svg" +dest_files=["res://.godot/imported/werkman_numbers_font.svg-86923eaeb2ad1731b58bec0085650842.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/uniform_transform_edit_buttons.gd b/addons/curved_lines_2d/uniform_transform_edit_buttons.gd new file mode 100644 index 0000000..5ccb474 --- /dev/null +++ b/addons/curved_lines_2d/uniform_transform_edit_buttons.gd @@ -0,0 +1,53 @@ +@tool +extends Control + +signal mode_changed(mode : CurvedLines2D.UniformTransformMode) +signal flip_horizontal() +signal flip_vertical() + + +func enable() -> void: + show() + %DefaultEdit.button_pressed = true + + +func _on_default_edit_toggled(toggled_on: bool) -> void: + if toggled_on: + mode_changed.emit(CurvedLines2D.UniformTransformMode.NONE) + + +func _on_uniform_translate_toggled(toggled_on: bool) -> void: + if toggled_on: + mode_changed.emit(CurvedLines2D.UniformTransformMode.TRANSLATE) + + +func _on_uniform_rotate_toggled(toggled_on: bool) -> void: + if toggled_on: + mode_changed.emit(CurvedLines2D.UniformTransformMode.ROTATE) + + +func _on_uniform_scale_toggled(toggled_on: bool) -> void: + if toggled_on: + mode_changed.emit(CurvedLines2D.UniformTransformMode.SCALE) + + +func _unhandled_input(event: InputEvent) -> void: + if not visible: + return + if event is InputEventKey and (event as InputEventKey).pressed: + if (event as InputEventKey).is_command_or_control_pressed(): + return + if (event as InputEventKey).keycode == KEY_Z: + %UniformTranslate.button_pressed = true + if (event as InputEventKey).keycode == KEY_X: + %UniformRotate.button_pressed = true + if (event as InputEventKey).keycode == KEY_C: + %UniformScale.button_pressed = true + + +func _on_flip_horizontal_pressed() -> void: + flip_horizontal.emit() + + +func _on_flip_vertical_pressed() -> void: + flip_vertical.emit() diff --git a/addons/curved_lines_2d/uniform_transform_edit_buttons.gd.uid b/addons/curved_lines_2d/uniform_transform_edit_buttons.gd.uid new file mode 100644 index 0000000..d014dc0 --- /dev/null +++ b/addons/curved_lines_2d/uniform_transform_edit_buttons.gd.uid @@ -0,0 +1 @@ +uid://brp0qoekngywr diff --git a/addons/curved_lines_2d/uniform_transform_edit_buttons.tscn b/addons/curved_lines_2d/uniform_transform_edit_buttons.tscn new file mode 100644 index 0000000..11772b5 --- /dev/null +++ b/addons/curved_lines_2d/uniform_transform_edit_buttons.tscn @@ -0,0 +1,89 @@ +[gd_scene load_steps=10 format=3 uid="uid://bm7mr2hj3qfoe"] + +[ext_resource type="Script" uid="uid://brp0qoekngywr" path="res://addons/curved_lines_2d/uniform_transform_edit_buttons.gd" id="1_m5784"] +[ext_resource type="Texture2D" uid="uid://daemvs3ws7fpk" path="res://addons/curved_lines_2d/DefaultMode.svg" id="2_memvu"] +[ext_resource type="Texture2D" uid="uid://chojkn0i6ngam" path="res://addons/curved_lines_2d/UniformTranslate.svg" id="2_o8x6h"] +[ext_resource type="Texture2D" uid="uid://d1uok4qb3xets" path="res://addons/curved_lines_2d/UniformRotate.svg" id="3_lkilg"] +[ext_resource type="Texture2D" uid="uid://do5uut1a4xvqf" path="res://addons/curved_lines_2d/UniformScale.svg" id="5_n2wtw"] +[ext_resource type="Texture2D" uid="uid://dvrgy7r2fvcxk" path="res://addons/curved_lines_2d/FlipHorizontal.svg" id="6_ocv7d"] +[ext_resource type="Texture2D" uid="uid://ly2rtvkn6ush" path="res://addons/curved_lines_2d/FlipVertical.svg" id="7_30kgp"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_o8x6h"] +bg_color = Color(0.219608, 0.270588, 0.368627, 1) +border_width_bottom = 2 +border_color = Color(0.411765, 0.611765, 0.909804, 1) + +[sub_resource type="ButtonGroup" id="ButtonGroup_qu4vk"] + +[node name="UniformTransformEditButtons" type="HBoxContainer"] +offset_right = 144.0 +offset_bottom = 646.0 +script = ExtResource("1_m5784") + +[node name="PanelContainer" type="PanelContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +theme_override_styles/panel = SubResource("StyleBoxFlat_o8x6h") + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer"] +layout_mode = 2 + +[node name="DefaultEdit" type="Button" parent="PanelContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Edit the points normally (Q)" +toggle_mode = true +button_group = SubResource("ButtonGroup_qu4vk") +icon = ExtResource("2_memvu") +flat = true + +[node name="UniformTranslate" type="Button" parent="PanelContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Move all the points without moving the node (Z)" +toggle_mode = true +button_group = SubResource("ButtonGroup_qu4vk") +icon = ExtResource("2_o8x6h") +flat = true + +[node name="UniformRotate" type="Button" parent="PanelContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Rotate all the points without rotating the node (X)" +toggle_mode = true +button_group = SubResource("ButtonGroup_qu4vk") +icon = ExtResource("3_lkilg") +flat = true + +[node name="UniformScale" type="Button" parent="PanelContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Resize all the points without resizing the node (C)" +toggle_mode = true +button_group = SubResource("ButtonGroup_qu4vk") +icon = ExtResource("5_n2wtw") +flat = true + +[node name="VSeparator" type="VSeparator" parent="."] +layout_mode = 2 + +[node name="FlipHorizontal" type="Button" parent="."] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Flip Shape Horizontally" +icon = ExtResource("6_ocv7d") +flat = true + +[node name="FlipVertical" type="Button" parent="."] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Flip Shape Vertically" +icon = ExtResource("7_30kgp") +flat = true + +[connection signal="toggled" from="PanelContainer/HBoxContainer/DefaultEdit" to="." method="_on_default_edit_toggled"] +[connection signal="toggled" from="PanelContainer/HBoxContainer/UniformTranslate" to="." method="_on_uniform_translate_toggled"] +[connection signal="toggled" from="PanelContainer/HBoxContainer/UniformRotate" to="." method="_on_uniform_rotate_toggled"] +[connection signal="toggled" from="PanelContainer/HBoxContainer/UniformScale" to="." method="_on_uniform_scale_toggled"] +[connection signal="pressed" from="FlipHorizontal" to="." method="_on_flip_horizontal_pressed"] +[connection signal="pressed" from="FlipVertical" to="." method="_on_flip_vertical_pressed"] diff --git a/addons/curved_lines_2d/video_explainer_tab.tscn b/addons/curved_lines_2d/video_explainer_tab.tscn new file mode 100644 index 0000000..5926d45 --- /dev/null +++ b/addons/curved_lines_2d/video_explainer_tab.tscn @@ -0,0 +1,184 @@ +[gd_scene load_steps=19 format=3 uid="uid://hr7df18ngxmj"] + +[ext_resource type="PackedScene" uid="uid://bhpmwhbdlsp1g" path="res://addons/curved_lines_2d/external_video_button.tscn" id="1_xhvii"] +[ext_resource type="Texture2D" uid="uid://be2xpq0unu641" path="res://addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png" id="2_7bvyv"] +[ext_resource type="Texture2D" uid="uid://dl2umd602n020" path="res://addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png" id="2_p1tlt"] +[ext_resource type="Texture2D" uid="uid://cybtin0ayniuw" path="res://addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp" id="3_68r4x"] +[ext_resource type="Texture2D" uid="uid://ca207yddnm1qr" path="res://addons/curved_lines_2d/video_thumbnails/my_little_pony.png" id="3_mc1gr"] +[ext_resource type="Texture2D" uid="uid://c8up2an21ixt4" path="res://addons/curved_lines_2d/video_thumbnails/msaa.png" id="3_vmvt3"] +[ext_resource type="Texture2D" uid="uid://b3plsn7lvo8au" path="res://addons/curved_lines_2d/video_thumbnails/animating_curves.png" id="3_xvhpr"] +[ext_resource type="Texture2D" uid="uid://bvwovr0nk7psu" path="res://addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png" id="4_oh1j2"] +[ext_resource type="Texture2D" uid="uid://cab1fy78sc831" path="res://addons/curved_lines_2d/video_thumbnails/gluing.png" id="6_5flco"] +[ext_resource type="Texture2D" uid="uid://bfuq8en4jvopi" path="res://addons/curved_lines_2d/video_thumbnails/roadmap-splash.png" id="8_shotc"] +[ext_resource type="Texture2D" uid="uid://bpdkxmo43c2eo" path="res://addons/curved_lines_2d/video_thumbnails/merging_vertices.png" id="8_xvhpr"] +[ext_resource type="Texture2D" uid="uid://5s2evk1r7bqp" path="res://addons/curved_lines_2d/video_thumbnails/part-1-splash.png" id="9_cq1f0"] +[ext_resource type="Texture2D" uid="uid://1enoovrlhmsa" path="res://addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png" id="10_cq1f0"] +[ext_resource type="Texture2D" uid="uid://halxp0f2djrh" path="res://addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png" id="10_h2vt0"] +[ext_resource type="Texture2D" uid="uid://cxsrvw2a54ruj" path="res://addons/curved_lines_2d/video_thumbnails/part-4.png" id="12_db0v2"] +[ext_resource type="Texture2D" uid="uid://b2ng5fl3msmw1" path="res://addons/curved_lines_2d/video_thumbnails/part-5.png" id="13_bmv75"] +[ext_resource type="Texture2D" uid="uid://bp4v8equ22ba8" path="res://addons/curved_lines_2d/video_thumbnails/part-6.png" id="14_7txnu"] +[ext_resource type="Texture2D" uid="uid://bvubevn3e1ax2" path="res://addons/curved_lines_2d/video_thumbnails/part-7.png" id="15_dx0lu"] + +[node name="VideoExplainerTab" type="ScrollContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_constants/separation = 20 + +[node name="ExternalVideoButton5" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/z8Y1e-TehoE +Right click to copy this link" +img = ExtResource("2_p1tlt") +uri = "https://youtu.be/z8Y1e-TehoE" +text = "A-Z Explainer Deep Dive" + +[node name="ExternalVideoButton10" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/I2yh2y9mGRA +Right click to copy this link" +img = ExtResource("3_mc1gr") +uri = "https://youtu.be/I2yh2y9mGRA" +text = "How to draw a My Little Pony" + +[node name="ExternalVideoButton6" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/5PIVoQcm8QE +Right click to copy this link" +img = ExtResource("4_oh1j2") +uri = "https://youtu.be/5PIVoQcm8QE" +text = "Importing SVG Files" + +[node name="ExternalVideoButton4" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/pP0CYEvU2uQ +Right click to copy this link" +img = ExtResource("3_68r4x") +uri = "https://youtu.be/pP0CYEvU2uQ" +text = "Building a Pinball Case" + +[node name="ExternalVideoButton8" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/p_QI5lKM44A +Right click to copy this link" +img = ExtResource("3_xvhpr") +uri = "https://youtu.be/p_QI5lKM44A" +text = "Animating Curves" + +[node name="ExternalVideoButton3" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/dUSJZ7WAIto +Right click to copy this link" +img = ExtResource("8_xvhpr") +uri = "https://youtu.be/dUSJZ7WAIto" +text = "Merging Vertices" + +[node name="ExternalVideoButton2" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/rT5FTg60GiY +Right click to copy this link" +uri = "https://youtu.be/rT5FTg60GiY" +text = "Animating SVG Clip-Paths" + +[node name="ExternalVideoButton9" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/X85A-XVUIHU +Right click to copy this link" +img = ExtResource("3_vmvt3") +uri = "https://youtu.be/X85A-XVUIHU" +text = "Add Anti Aliasing to your Webgame" + +[node name="ExternalVideoButton" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/RrusSXAiCK8 +Right click to copy this link" +img = ExtResource("2_7bvyv") +uri = "https://youtu.be/RrusSXAiCK8" +text = "Bake Spritesheets and Sprite Frames" + +[node name="ExternalVideoButton7" parent="VBoxContainer/HBoxContainer" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://youtu.be/OBNPTFZA2Q0 +Right click to copy this link" +img = ExtResource("6_5flco") +uri = "https://youtu.be/OBNPTFZA2Q0" +text = "Gluing a Node2D to a Point" + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="ExternalVideoButton5" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/prologue-roadmap.mp4 +Right click to copy this link" +img = ExtResource("8_shotc") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/prologue-roadmap.mp4" +text = "Vlog: Let's make an actual game" + +[node name="ExternalVideoButton6" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-one.mp4 +Right click to copy this link" +img = ExtResource("9_cq1f0") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-one.mp4" +text = "Part I: The Responsive Viewport" + +[node name="ExternalVideoButton7" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-two.mp4 +Right click to copy this link" +img = ExtResource("10_h2vt0") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-two.mp4" +text = "PART II: L-BLOCK!!!" + +[node name="ExternalVideoButton8" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-three.mp4 +Right click to copy this link" +img = ExtResource("10_cq1f0") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-three.mp4" +text = "PART III: Dry Blocks" + +[node name="ExternalVideoButton9" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-four.mp4 +Right click to copy this link" +img = ExtResource("12_db0v2") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-four.mp4" +text = "PART IV: The TetrisBlock class explained" + +[node name="ExternalVideoButton10" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-five.mp4 +Right click to copy this link" +img = ExtResource("13_bmv75") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-five.mp4" +text = "PART V: Stacking Tetris Blocks" + +[node name="ExternalVideoButton11" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-six.mp4 +Right click to copy this link" +img = ExtResource("14_7txnu") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-six.mp4" +text = "PART VI: Controlling the Tetris Blocks" + +[node name="ExternalVideoButton12" parent="VBoxContainer/HBoxContainer2" instance=ExtResource("1_xhvii")] +layout_mode = 2 +tooltip_text = "This link will open a webpage in your browser: https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-seven.mp4 +Right click to copy this link" +img = ExtResource("15_dx0lu") +uri = "https://codeberg.org/renevanderark/tatra-vlog/raw/branch/master/final-videos/part-seven.mp4" +text = "PART VII: Clearing Rows of Blocks" diff --git a/addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png b/addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png new file mode 100644 index 0000000..32eebfd Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png.import b/addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png.import new file mode 100644 index 0000000..d194274 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://halxp0f2djrh" +path="res://.godot/imported/PART II_ L-Block.excalidraw.png-394fc670b1b3e623b4d4798a4155efe0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/PART II_ L-Block.excalidraw.png" +dest_files=["res://.godot/imported/PART II_ L-Block.excalidraw.png-394fc670b1b3e623b4d4798a4155efe0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png b/addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png new file mode 100644 index 0000000..efca466 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png.import b/addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png.import new file mode 100644 index 0000000..48b9d70 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://1enoovrlhmsa" +path="res://.godot/imported/Part3-dry-blocks.excalidraw.png-10cabba4704302c7a644c052287608c4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/Part3-dry-blocks.excalidraw.png" +dest_files=["res://.godot/imported/Part3-dry-blocks.excalidraw.png-10cabba4704302c7a644c052287608c4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png b/addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png new file mode 100644 index 0000000..0a68758 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png.import b/addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png.import new file mode 100644 index 0000000..edd4762 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dl2umd602n020" +path="res://.godot/imported/a_z_deep_dive.png-e53c0a41bd1b5ef4701c8d586ee3e332.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/a_z_deep_dive.png" +dest_files=["res://.godot/imported/a_z_deep_dive.png-e53c0a41bd1b5ef4701c8d586ee3e332.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/a_z_explainer.png b/addons/curved_lines_2d/video_thumbnails/a_z_explainer.png new file mode 100644 index 0000000..dac918a Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/a_z_explainer.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/a_z_explainer.png.import b/addons/curved_lines_2d/video_thumbnails/a_z_explainer.png.import new file mode 100644 index 0000000..d38869f --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/a_z_explainer.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://blj26cry4ov1b" +path="res://.godot/imported/a_z_explainer.png-13739717d4ca2162d533c62d29a7fbd1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/a_z_explainer.png" +dest_files=["res://.godot/imported/a_z_explainer.png-13739717d4ca2162d533c62d29a7fbd1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png b/addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png new file mode 100644 index 0000000..4c4eeff Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png.import b/addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png.import new file mode 100644 index 0000000..81a65bc --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dsn2lxwf0mvoq" +path="res://.godot/imported/animating_clip_paths.png-671469b2a054743ea847e65b801efc33.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/animating_clip_paths.png" +dest_files=["res://.godot/imported/animating_clip_paths.png-671469b2a054743ea847e65b801efc33.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/animating_curves.png b/addons/curved_lines_2d/video_thumbnails/animating_curves.png new file mode 100644 index 0000000..10f8d24 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/animating_curves.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/animating_curves.png.import b/addons/curved_lines_2d/video_thumbnails/animating_curves.png.import new file mode 100644 index 0000000..d3e858c --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/animating_curves.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3plsn7lvo8au" +path="res://.godot/imported/animating_curves.png-9103b0a07faf80922d971c1b4881cbae.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/animating_curves.png" +dest_files=["res://.godot/imported/animating_curves.png-9103b0a07faf80922d971c1b4881cbae.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png b/addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png new file mode 100644 index 0000000..28d876d Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png.import b/addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png.import new file mode 100644 index 0000000..a7d0635 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://be2xpq0unu641" +path="res://.godot/imported/animations_to_sprite_frames.png-419bb11c25432bdadc87e7e165bad13f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/animations_to_sprite_frames.png" +dest_files=["res://.godot/imported/animations_to_sprite_frames.png-419bb11c25432bdadc87e7e165bad13f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg b/addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg new file mode 100644 index 0000000..fa42081 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg @@ -0,0 +1,171 @@ + + + Codeberg logo + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Codeberg logo + + + Robert Martinez + + + + + Codeberg and the Codeberg Logo are trademarks of Codeberg e.V. + + + 2020-04-09 + + + Codeberg e.V. + + + codeberg.org + + + + + + + + + + + + + + diff --git a/addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg.import b/addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg.import new file mode 100644 index 0000000..ad55b28 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dacelkfuv24fv" +path="res://.godot/imported/codeberg_icon.svg-6597e0bef44b44c94bc0cad3ab3adf7f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/codeberg_icon.svg" +dest_files=["res://.godot/imported/codeberg_icon.svg-6597e0bef44b44c94bc0cad3ab3adf7f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/curved_lines_2d/video_thumbnails/gluing.png b/addons/curved_lines_2d/video_thumbnails/gluing.png new file mode 100644 index 0000000..9c6b3d8 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/gluing.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/gluing.png.import b/addons/curved_lines_2d/video_thumbnails/gluing.png.import new file mode 100644 index 0000000..f3c8543 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/gluing.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cab1fy78sc831" +path="res://.godot/imported/gluing.png-12984fa7fc2f40ab1e1710c67df20b60.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/gluing.png" +dest_files=["res://.godot/imported/gluing.png-12984fa7fc2f40ab1e1710c67df20b60.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png b/addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png new file mode 100644 index 0000000..12e61af Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png.import b/addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png.import new file mode 100644 index 0000000..7554bf4 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvwovr0nk7psu" +path="res://.godot/imported/importing-svg-files-splash.png-108facb1a40dd971e6bae4eff717043c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/importing-svg-files-splash.png" +dest_files=["res://.godot/imported/importing-svg-files-splash.png-108facb1a40dd971e6bae4eff717043c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/merging_vertices.png b/addons/curved_lines_2d/video_thumbnails/merging_vertices.png new file mode 100644 index 0000000..a5ad1f4 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/merging_vertices.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/merging_vertices.png.import b/addons/curved_lines_2d/video_thumbnails/merging_vertices.png.import new file mode 100644 index 0000000..0a01361 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/merging_vertices.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bpdkxmo43c2eo" +path="res://.godot/imported/merging_vertices.png-50d5edfc62f33de8d25f9887a7c2971e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/merging_vertices.png" +dest_files=["res://.godot/imported/merging_vertices.png-50d5edfc62f33de8d25f9887a7c2971e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/msaa.png b/addons/curved_lines_2d/video_thumbnails/msaa.png new file mode 100644 index 0000000..1fa2601 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/msaa.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/msaa.png.import b/addons/curved_lines_2d/video_thumbnails/msaa.png.import new file mode 100644 index 0000000..6de945e --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/msaa.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c8up2an21ixt4" +path="res://.godot/imported/msaa.png-6d6f65359a86851b6b6a1f49a95a67af.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/msaa.png" +dest_files=["res://.godot/imported/msaa.png-6d6f65359a86851b6b6a1f49a95a67af.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/my_little_pony.png b/addons/curved_lines_2d/video_thumbnails/my_little_pony.png new file mode 100644 index 0000000..65f4c8b Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/my_little_pony.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/my_little_pony.png.import b/addons/curved_lines_2d/video_thumbnails/my_little_pony.png.import new file mode 100644 index 0000000..9acd1f4 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/my_little_pony.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ca207yddnm1qr" +path="res://.godot/imported/my_little_pony.png-d1e748ca5a37a86ce9221be652dfbaee.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/my_little_pony.png" +dest_files=["res://.godot/imported/my_little_pony.png-d1e748ca5a37a86ce9221be652dfbaee.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/part-1-splash.png b/addons/curved_lines_2d/video_thumbnails/part-1-splash.png new file mode 100644 index 0000000..b2f8744 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/part-1-splash.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/part-1-splash.png.import b/addons/curved_lines_2d/video_thumbnails/part-1-splash.png.import new file mode 100644 index 0000000..9cfc423 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/part-1-splash.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://5s2evk1r7bqp" +path="res://.godot/imported/part-1-splash.png-26ed63fd94d848a5f6c3ca129d53a90c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/part-1-splash.png" +dest_files=["res://.godot/imported/part-1-splash.png-26ed63fd94d848a5f6c3ca129d53a90c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/part-4.png b/addons/curved_lines_2d/video_thumbnails/part-4.png new file mode 100644 index 0000000..7aaf881 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/part-4.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/part-4.png.import b/addons/curved_lines_2d/video_thumbnails/part-4.png.import new file mode 100644 index 0000000..efb92e2 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/part-4.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cxsrvw2a54ruj" +path="res://.godot/imported/part-4.png-edfc07d87c56c2ce6f0bd48a0432edbc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/part-4.png" +dest_files=["res://.godot/imported/part-4.png-edfc07d87c56c2ce6f0bd48a0432edbc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/part-5.png b/addons/curved_lines_2d/video_thumbnails/part-5.png new file mode 100644 index 0000000..40e9cfa Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/part-5.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/part-5.png.import b/addons/curved_lines_2d/video_thumbnails/part-5.png.import new file mode 100644 index 0000000..f36db5d --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/part-5.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b2ng5fl3msmw1" +path="res://.godot/imported/part-5.png-3bf86533a0d2be3ce1e3d35f878abba8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/part-5.png" +dest_files=["res://.godot/imported/part-5.png-3bf86533a0d2be3ce1e3d35f878abba8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/part-6.png b/addons/curved_lines_2d/video_thumbnails/part-6.png new file mode 100644 index 0000000..3b5e348 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/part-6.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/part-6.png.import b/addons/curved_lines_2d/video_thumbnails/part-6.png.import new file mode 100644 index 0000000..ad9df15 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/part-6.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bp4v8equ22ba8" +path="res://.godot/imported/part-6.png-3380e6c5297f9f7af870ce1883017149.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/part-6.png" +dest_files=["res://.godot/imported/part-6.png-3380e6c5297f9f7af870ce1883017149.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/part-7.png b/addons/curved_lines_2d/video_thumbnails/part-7.png new file mode 100644 index 0000000..5e1364b Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/part-7.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/part-7.png.import b/addons/curved_lines_2d/video_thumbnails/part-7.png.import new file mode 100644 index 0000000..274ca94 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/part-7.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvubevn3e1ax2" +path="res://.godot/imported/part-7.png-ee2cbbb0938afb880cd5b8e2d1110fee.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/part-7.png" +dest_files=["res://.godot/imported/part-7.png-ee2cbbb0938afb880cd5b8e2d1110fee.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp b/addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp new file mode 100644 index 0000000..31ed61a Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp differ diff --git a/addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp.import b/addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp.import new file mode 100644 index 0000000..cbc48d7 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cybtin0ayniuw" +path="res://.godot/imported/pinball_release_notes.webp-ab1b79a215ddd1566c44ec95d25d2ce0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/pinball_release_notes.webp" +dest_files=["res://.godot/imported/pinball_release_notes.webp-ab1b79a215ddd1566c44ec95d25d2ce0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/roadmap-splash.png b/addons/curved_lines_2d/video_thumbnails/roadmap-splash.png new file mode 100644 index 0000000..b1ad1d3 Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/roadmap-splash.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/roadmap-splash.png.import b/addons/curved_lines_2d/video_thumbnails/roadmap-splash.png.import new file mode 100644 index 0000000..d2f3579 --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/roadmap-splash.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bfuq8en4jvopi" +path="res://.godot/imported/roadmap-splash.png-71cb1f9f95a4c8cd5d1fee1dddf464a6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/roadmap-splash.png" +dest_files=["res://.godot/imported/roadmap-splash.png-71cb1f9f95a4c8cd5d1fee1dddf464a6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/video_thumbnails/tatra.png b/addons/curved_lines_2d/video_thumbnails/tatra.png new file mode 100644 index 0000000..d0aa96c Binary files /dev/null and b/addons/curved_lines_2d/video_thumbnails/tatra.png differ diff --git a/addons/curved_lines_2d/video_thumbnails/tatra.png.import b/addons/curved_lines_2d/video_thumbnails/tatra.png.import new file mode 100644 index 0000000..153ebce --- /dev/null +++ b/addons/curved_lines_2d/video_thumbnails/tatra.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bp5h8cgmsys0a" +path="res://.godot/imported/tatra.png-6114f0d7458aa3b699f28a209e41522e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/curved_lines_2d/video_thumbnails/tatra.png" +dest_files=["res://.godot/imported/tatra.png-6114f0d7458aa3b699f28a209e41522e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/curved_lines_2d/warn_label_settings.tres b/addons/curved_lines_2d/warn_label_settings.tres new file mode 100644 index 0000000..80393ad --- /dev/null +++ b/addons/curved_lines_2d/warn_label_settings.tres @@ -0,0 +1,4 @@ +[gd_resource type="LabelSettings" format=3 uid="uid://4fpqfrlapgeq"] + +[resource] +font_color = Color(1, 1, 0, 1) diff --git a/addons/strategy_cam/icon_camera_grid.svg b/addons/strategy_cam/icon_camera_grid.svg new file mode 100644 index 0000000..1c7238c --- /dev/null +++ b/addons/strategy_cam/icon_camera_grid.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + diff --git a/addons/strategy_cam/icon_camera_grid.svg.import b/addons/strategy_cam/icon_camera_grid.svg.import new file mode 100644 index 0000000..a699ecf --- /dev/null +++ b/addons/strategy_cam/icon_camera_grid.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dv3cw6mamb6rl" +path="res://.godot/imported/icon_camera_grid.svg-466e9cc8bcf9b1a9a5463aaf2cf74537.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/strategy_cam/icon_camera_grid.svg" +dest_files=["res://.godot/imported/icon_camera_grid.svg-466e9cc8bcf9b1a9a5463aaf2cf74537.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/strategy_cam/plugin.cfg b/addons/strategy_cam/plugin.cfg new file mode 100644 index 0000000..85be16b --- /dev/null +++ b/addons/strategy_cam/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="StrategyCamera" +description="A suite of strategy game camera controls. Includes togglable mouse and keyboard controls. See the README.md on the godot-strategy-camera repository to find which inputs must be mapped in the project for the camera to function." +author="Thomas737" +version="1.0" +script="strategy_camera_autoload.gd" diff --git a/addons/strategy_cam/strategy_camera.gd b/addons/strategy_cam/strategy_camera.gd new file mode 100644 index 0000000..de97206 --- /dev/null +++ b/addons/strategy_cam/strategy_camera.gd @@ -0,0 +1,104 @@ +extends Camera2D + +# See WARNING's below for detail on custom control binding. Apart from scroll zooming, every key and mouse +# press must be bound manually by the developer. + +@export var allow_mouse_controls: bool = true +@export var allow_keyboard_controls: bool = true + +@export_group("Keyboard Controls") +## Camera zoom speed when controlled with keys +@export var key_zoom_speed: float = 2.0 +## Translation speed when controlled by keys +@export var translation_speed: float = 100.0 + +@export_group("Camera Zoom Variables") +## Relative zoom in every scroll wheel tick. +@export var zoom_step: float = 0.2 +## Speed at which the camera reaches the next target zoom. Really funky things can happen +## if x and y are set to different values... +@export var zoom_speed: Vector2 = Vector2(10, 10) + +@export_group("Directional Limits") +## Top-left limit of the camera position/movement (applied to the top-left of the camera). +## If this and limit_BR set to Vector2.ZERO, no limits will be applied +@export var limit_TL: Vector2 = Vector2.ZERO +## Bottom-right limit of the camera position/movement (applied to the bottom-right of the camera). +## If this and limit_TL set to Vector2.ZERO, no limits will be applied +@export var limit_BR: Vector2 = Vector2.ZERO + +var camera_TL: Vector2 = Vector2(-576, -324) +var camera_BR: Vector2 = Vector2(576, 324) +var target_zoom: Vector2 = Vector2.ONE + +func _ready() -> void: + target_zoom = zoom + _on_resolution_change() + get_viewport().size_changed.connect(_on_resolution_change) + +func _on_resolution_change() -> void: + camera_TL = -get_viewport_rect().size / 2 + camera_BR = get_viewport_rect().size / 2 + +func _unhandled_input(event: InputEvent) -> void: + if not allow_mouse_controls: + return + + # Zooming by scrolling with the middle mouse button + if event is InputEventMouse: + if event.is_pressed() and not event.is_echo(): + if event.button_index == MOUSE_BUTTON_WHEEL_UP: + zoom_camera(zoom_step) + elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + zoom_camera(-zoom_step) + target_zoom = target_zoom.clamp(Vector2.ONE*0.5, Vector2.INF) + + # Camera translation by clicking and dragging + if event is InputEventMouseMotion: + # WARNING: The dragging control must be defined WITHIN THIS PROJECT + if Input.is_action_pressed("cam_drag"): + position -= event.relative / zoom + +func _process(delta: float) -> void: + if target_zoom.length()-0.001 <= zoom.length() and zoom.length() <= target_zoom.length()+0.001: + zoom = target_zoom + else: + increment_zoom((target_zoom-zoom) * zoom_speed * delta) + + var screen_centre: Vector2 = get_screen_center_position() + var actual_TL: Vector2 = screen_centre + camera_TL / target_zoom + var actual_BR: Vector2 = screen_centre + camera_BR / target_zoom + + # WARNING: The keyboard controls must be defined WITHIN THIS PROJECT + if allow_keyboard_controls: + position.x += Input.get_axis("cam_left", "cam_right") * translation_speed * delta + position.y += Input.get_axis("cam_up", "cam_down") * translation_speed * delta + var camera_zoom_direction: float = Input.get_axis("cam_zoom_out", "cam_zoom_in") + + if camera_zoom_direction: + zoom_camera(camera_zoom_direction * key_zoom_speed * delta) + zoom = target_zoom + + if limit_BR == Vector2.ZERO and limit_TL == Vector2.ZERO: + return + + # Camera limit application + if actual_TL.x < limit_TL.x: + position.x += limit_TL.x - actual_TL.x + if actual_TL.y < limit_TL.y: + position.y += limit_TL.y - actual_TL.y + + if actual_BR.x > limit_BR.x: + position.x -= actual_BR.x - limit_BR.x + if actual_BR.y > limit_BR.y: + position.y -= actual_BR.y - limit_BR.y + +func zoom_camera(zoom_amount: float) -> void: + target_zoom *= pow(10.0, zoom_amount) + +func increment_zoom(zoom_direction: Vector2) -> void: + var previous_mouse_position: Vector2 = get_local_mouse_position() + zoom += zoom_direction + + var diff: Vector2 = previous_mouse_position - get_local_mouse_position() + offset += diff diff --git a/addons/strategy_cam/strategy_camera.gd.uid b/addons/strategy_cam/strategy_camera.gd.uid new file mode 100644 index 0000000..b583a25 --- /dev/null +++ b/addons/strategy_cam/strategy_camera.gd.uid @@ -0,0 +1 @@ +uid://rirna2vebukw diff --git a/addons/strategy_cam/strategy_camera_autoload.gd b/addons/strategy_cam/strategy_camera_autoload.gd new file mode 100644 index 0000000..17b78f8 --- /dev/null +++ b/addons/strategy_cam/strategy_camera_autoload.gd @@ -0,0 +1,10 @@ +@tool +extends EditorPlugin + + +func _enter_tree() -> void: + add_custom_type("StrategyCamera", "Camera2D", preload("strategy_camera.gd"), preload("icon_camera_grid.svg")) + + +func _exit_tree() -> void: + remove_custom_type("StrategyCamera") diff --git a/addons/strategy_cam/strategy_camera_autoload.gd.uid b/addons/strategy_cam/strategy_camera_autoload.gd.uid new file mode 100644 index 0000000..4025782 --- /dev/null +++ b/addons/strategy_cam/strategy_camera_autoload.gd.uid @@ -0,0 +1 @@ +uid://0wl0wfyt5w78 diff --git a/assets/icon.svg b/assets/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/assets/icon.svg @@ -0,0 +1 @@ + diff --git a/assets/icon.svg.import b/assets/icon.svg.import new file mode 100644 index 0000000..86caaf3 --- /dev/null +++ b/assets/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://du7ejwu1yo0j1" +path="res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/icon.svg" +dest_files=["res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/assets/pip.png b/assets/pip.png new file mode 100644 index 0000000..6044a78 Binary files /dev/null and b/assets/pip.png differ diff --git a/assets/pip.png.import b/assets/pip.png.import new file mode 100644 index 0000000..c84dde2 --- /dev/null +++ b/assets/pip.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dkpk1ubnmbl68" +path="res://.godot/imported/pip.png-f36d3b6833d0ab89da130f01fd84ed47.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/pip.png" +dest_files=["res://.godot/imported/pip.png-f36d3b6833d0ab89da130f01fd84ed47.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/base.tscn b/base.tscn new file mode 100644 index 0000000..74d4324 --- /dev/null +++ b/base.tscn @@ -0,0 +1,83 @@ +[gd_scene format=3 uid="uid://dxfhhf4qu42bb"] + +[ext_resource type="Script" uid="uid://demgvopfvjmql" path="res://scripts/Base.cs" id="1_21bcp"] +[ext_resource type="Texture2D" uid="uid://du7ejwu1yo0j1" path="res://assets/icon.svg" id="1_rpg24"] +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="3_21bcp"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="4_tpea4"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="5_42dj3"] +[ext_resource type="PackedScene" uid="uid://dn6jqa3wj40ir" path="res://scripts/components/health_component.tscn" id="6_tpea4"] + +[sub_resource type="Curve2D" id="Curve2D_56f15"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 56.282383, 101.90546, 0, 56.282383, 0, -56.282383, 0, 0, 101.90546, 0, 56.282383, 0, -56.282383, -101.90546, 0, -56.282383, 0, 56.282383, 0, 0, -101.90546, 0, -56.282383, 0, 0, 101.90546, 0) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_cho24"] +resource_local_to_scene = true +script = ExtResource("5_42dj3") + +[sub_resource type="LabelSettings" id="LabelSettings_rpg24"] +font_size = 33 +outline_size = 8 +outline_color = Color(0, 0, 0, 1) + +[node name="Base" type="Area2D" unique_id=1354578205] +script = ExtResource("1_21bcp") + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="." unique_id=1632145743] +polygon = PackedVector2Array(59.1, -64, -59, -64, -63.8, -59, -64, 61, -60.3, 64, 59.6, 64, 63.9, 59, 64, -61.1) + +[node name="Selection" type="Node2D" parent="." unique_id=544477539 node_paths=PackedStringArray("line")] +script = ExtResource("3_21bcp") +stroke_color = Color(0.36841604, 0.683675, 0.26152232, 1) +stroke_width = 4.0 +line = NodePath("Stroke") +curve = SubResource("Curve2D_56f15") +update_curve_at_runtime = true +arc_list = SubResource("Resource_cho24") +shape_type = 2 +size = Vector2(203.81091, 203.81091) +rx = 101.90546 +ry = 101.90546 +metadata/_select_hint_ = true + +[node name="Stroke" type="Line2D" parent="Selection" unique_id=1625752545] +points = PackedVector2Array(101.90546, 0, 101.37935, 10.4194975, 99.83516, 20.537949, 97.32412, 30.304142, 93.89744, 39.66686, 89.60633, 48.574883, 84.50201, 56.976994, 78.635704, 64.821976, 72.058624, 72.058624, 64.821976, 78.63571, 56.97699, 84.502014, 48.574883, 89.60633, 39.666855, 93.89744, 30.304142, 97.32412, 20.537949, 99.83516, 10.419497, 101.37935, 0, 101.90546, -10.4194975, 101.37935, -20.537949, 99.83516, -30.304142, 97.32412, -39.66686, 93.89744, -48.574883, 89.60633, -56.976994, 84.50201, -64.821976, 78.635704, -72.058624, 72.058624, -78.63571, 64.821976, -84.502014, 56.97699, -89.60633, 48.574883, -93.89744, 39.666855, -97.32412, 30.304142, -99.83516, 20.537949, -101.37935, 10.419497, -101.90546, 0, -101.37935, -10.4194975, -99.83516, -20.537949, -97.32412, -30.304142, -93.89744, -39.66686, -89.60633, -48.574883, -84.50201, -56.976994, -78.635704, -64.821976, -72.058624, -72.058624, -64.821976, -78.63571, -56.97699, -84.502014, -48.574883, -89.60633, -39.666855, -93.89744, -30.304142, -97.32412, -20.537949, -99.83516, -10.419497, -101.37935, 0, -101.90546, 10.4194975, -101.37935, 20.537949, -99.83516, 30.304142, -97.32412, 39.66686, -93.89744, 48.574883, -89.60633, 56.976994, -84.50201, 64.821976, -78.635704, 72.058624, -72.058624, 78.63571, -64.821976, 84.502014, -56.97699, 89.60633, -48.574883, 93.89744, -39.666855, 97.32412, -30.304142, 99.83516, -20.537949, 101.37935, -10.419497) +closed = true +width = 4.0 +default_color = Color(0.36841604, 0.683675, 0.26152232, 1) +sharp_limit = 90.0 +antialiased = true +metadata/_edit_lock_ = true + +[node name="Gfx" type="Sprite2D" parent="." unique_id=1646140640] +texture = ExtResource("1_rpg24") + +[node name="Label" type="Label" parent="." unique_id=1802037971] +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -38.0 +offset_top = 65.885 +offset_right = 38.0 +offset_bottom = 111.88508 +grow_horizontal = 2 +text = "Base" +label_settings = SubResource("LabelSettings_rpg24") + +[node name="ProgressBar" type="ProgressBar" parent="." unique_id=266338603] +offset_left = -70.0 +offset_top = -97.0 +offset_right = 70.0 +offset_bottom = -70.0 +max_value = 10.0 +show_percentage = false + +[node name="HealthComponent" parent="." unique_id=1360050278 instance=ExtResource("6_tpea4")] +offset_left = -99.0 +offset_right = -72.0 + +[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"] +[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"] diff --git a/main.tscn b/main.tscn new file mode 100644 index 0000000..0bc75cb --- /dev/null +++ b/main.tscn @@ -0,0 +1,69 @@ +[gd_scene format=3 uid="uid://bf7croj2rk4q6"] + +[ext_resource type="Script" uid="uid://rirna2vebukw" path="res://addons/strategy_cam/strategy_camera.gd" id="2_0xm2m"] +[ext_resource type="PackedScene" uid="uid://dxfhhf4qu42bb" path="res://base.tscn" id="2_h2yge"] +[ext_resource type="Script" uid="uid://de3jpss66xjfh" path="res://addons/curved_lines_2d/scalable_vector_shape_2d.gd" id="3_lquwl"] +[ext_resource type="Script" uid="uid://dlbv4pit17dnu" path="res://addons/curved_lines_2d/scalable_arc.gd" id="4_7mycd"] +[ext_resource type="Script" uid="uid://dl1t88tthmwts" path="res://addons/curved_lines_2d/scalable_arc_list.gd" id="5_272bh"] +[ext_resource type="PackedScene" uid="uid://4b8osd3h3xbm" path="res://pip.tscn" id="6_7mycd"] + +[sub_resource type="Curve2D" id="Curve2D_5vw27"] +resource_local_to_scene = true +_data = { +"points": PackedVector2Array(0, 0, 0, 0, -13.812602, -13.812602, 0, 0, 0, 0, 13.812602, -13.812602, 0, 0, 0, 0, 13.812602, 13.812602, 0, 0, 0, 0, -13.812602, 13.812602, 0, 0, 0, 0, -13.812602, -13.812602) +} +point_count = 5 + +[sub_resource type="Resource" id="Resource_kek77"] +resource_local_to_scene = true +script = ExtResource("5_272bh") + +[node name="Main" type="Node2D" unique_id=866253780] + +[node name="Stuff" type="Node" parent="." unique_id=1050239390] + +[node name="Rectangle" type="Node2D" parent="Stuff" unique_id=742624159 node_paths=PackedStringArray("polygon", "line")] +visible = false +script = ExtResource("3_lquwl") +polygon = NodePath("Polygon2D") +line = NodePath("Stroke") +curve = SubResource("Curve2D_5vw27") +update_curve_at_runtime = true +arc_list = SubResource("Resource_kek77") +shape_type = 1 +size = Vector2(27.625204, 27.625204) + +[node name="Stroke" type="Line2D" parent="Stuff/Rectangle" unique_id=290597343] +points = PackedVector2Array(-13.812602, -13.812602, 13.812602, -13.812602, 13.812602, 13.812602, -13.812602, 13.812602) +closed = true +sharp_limit = 90.0 +metadata/_edit_lock_ = true + +[node name="Polygon2D" type="Polygon2D" parent="Stuff/Rectangle" unique_id=228038856] +color = Color(0.48828125, 0.48828125, 0.48828125, 1) +polygon = PackedVector2Array(-13.812602, -13.812602, 13.812602, -13.812602, 13.812602, 13.812602, -13.812602, 13.812602) +metadata/_edit_lock_ = true + +[node name="StrategyCamera" type="Camera2D" parent="." unique_id=706618209] +limit_enabled = false +script = ExtResource("2_0xm2m") +translation_speed = 300.0 +metadata/_custom_type_script = "uid://rirna2vebukw" + +[node name="PlayerBase" parent="." unique_id=1646140640 instance=ExtResource("2_h2yge")] +position = Vector2(-680, -353) +Faction = 1 + +[node name="NeutralBase" parent="." unique_id=1354578205 instance=ExtResource("2_h2yge")] +position = Vector2(86, -199) + +[node name="NeutralBase2" parent="." unique_id=98685585 instance=ExtResource("2_h2yge")] +position = Vector2(-80, 226) + +[node name="EnemyBase" parent="." unique_id=2059599822 groups=["enemyBase"] instance=ExtResource("2_h2yge")] +position = Vector2(707, 439) +Faction = 2 + +[node name="Pip" parent="." unique_id=1889156888 node_paths=PackedStringArray("Target") instance=ExtResource("6_7mycd")] +position = Vector2(546, 310) +Target = NodePath("../EnemyBase") diff --git a/pip.tscn b/pip.tscn new file mode 100644 index 0000000..483bdbd --- /dev/null +++ b/pip.tscn @@ -0,0 +1,18 @@ +[gd_scene format=3 uid="uid://4b8osd3h3xbm"] + +[ext_resource type="Script" uid="uid://cdbkkb2cpwkn1" path="res://scripts/Pip.cs" id="1_2foya"] +[ext_resource type="Texture2D" uid="uid://dkpk1ubnmbl68" path="res://assets/pip.png" id="2_46jm3"] + +[node name="Pip" type="Area2D" unique_id=1889156888 node_paths=PackedStringArray("Target")] +script = ExtResource("1_2foya") +Faction = 1 +Target = NodePath("") + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="." unique_id=528123989] +polygon = PackedVector2Array(-18.5, -18.5, -18.5, 18.5, 18.5, 18.5, 18.5, -18.5) + +[node name="Gfx" type="Sprite2D" parent="." unique_id=1494214084] +modulate = Color(0.5376854, 0.9999998, 0.6650417, 1) +texture = ExtResource("2_46jm3") + +[connection signal="area_entered" from="." to="." method="_on_area_entered"] diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..7f88f39 --- /dev/null +++ b/project.godot @@ -0,0 +1,85 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[addons] + +curved_lines_2d/use_line_2d_for_stroke=true +curved_lines_2d/add_fill_enabled=false + +[application] + +config/name="Node War" +run/main_scene="uid://bf7croj2rk4q6" +config/features=PackedStringArray("4.6", "C#", "Forward Plus") +config/icon="res://assets/icon.svg" + +[dotnet] + +project/assembly_name="Node War" + +[editor_plugins] + +enabled=PackedStringArray("res://addons/curved_lines_2d/plugin.cfg", "res://addons/strategy_cam/plugin.cfg") + +[file_customization] + +folder_colors={ +"res://scripts/": "yellow" +} + +[global_group] + +enemyBase="" + +[input] + +cam_left={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) +] +} +cam_right={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) +] +} +cam_up={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) +] +} +cam_down={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) +] +} +cam_zoom_in={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} +cam_zoom_out={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} +cam_drag={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} + +[physics] + +3d/physics_engine="Jolt Physics" + +[rendering] + +rendering_device/driver.windows="d3d12" diff --git a/scripts/Base.cs b/scripts/Base.cs new file mode 100644 index 0000000..de3c424 --- /dev/null +++ b/scripts/Base.cs @@ -0,0 +1,103 @@ +using System; +using Godot; +using NodeWar; +using NodeWar.Scripts; + +public partial class Base : Area2D +{ + private ProgressBar _progressBar; + private ProgressBar _healthBar; + private Node2D _selection; + private Node2D _gfx; + + [Export] + public bool Selected = false; + + [Export] + public Faction Faction = Faction.Neutral; + + [Export] + public float Health { get; set; } = 50; + + [Export] + public float MaxHealth { get; set; } = 50; + + private float _buildSpeed = 28; + private float _buildProgress = 0; + private float _maxBuildProgress = 100; + private bool _mouseInside = false; + + private PackedScene _pipScene = GD.Load("res://pip.tscn"); + + public override void _Ready() + { + MouseEntered += OnMouseEntered; + MouseExited += OnMouseExited; + + _healthBar = GetNode("HealthBar"); + _progressBar = GetNode("ProgressBar"); + _selection = GetNode("Selection"); + _gfx = GetNode("Gfx"); + + _selection.Visible = false; + _progressBar.MaxValue = _maxBuildProgress; + _healthBar.MaxValue = MaxHealth; + _healthBar.Value = Health; + + UpdateColor(); + } + + public override void _Process(double delta) + { + if (Faction == Faction.Neutral) + return; + + _buildProgress += _buildSpeed * delta.ToFloat(); + if (_buildProgress >= _maxBuildProgress) + { + _buildProgress = 0; + var pip = _pipScene.Instantiate(); + + GetParent().AddChild(pip); + pip.GlobalPosition = GlobalPosition; + pip.Target = GetTree().GetFirstNodeInGroup("enemyBase") as Base; + } + + UpdateProgressBars(); + } + + public override void _UnhandledInput(InputEvent @event) + { + if (@event is InputEventMouseButton { Pressed: true, ButtonIndex: MouseButton.Left }) + { + _selection.Visible = _mouseInside; + } + } + + private void UpdateColor() + { + _gfx.Modulate = Faction switch + { + Faction.Neutral => Colors.Gray, + Faction.Player => Colors.ForestGreen, + Faction.Computer => Colors.Red, + _ => throw new ArgumentOutOfRangeException(), + }; + } + + private void UpdateProgressBars() + { + _progressBar.Value = _buildProgress; + _healthBar.Value = Health; + } + + private void OnMouseExited() + { + _mouseInside = false; + } + + private void OnMouseEntered() + { + _mouseInside = true; + } +} diff --git a/scripts/Base.cs.uid b/scripts/Base.cs.uid new file mode 100644 index 0000000..d987706 --- /dev/null +++ b/scripts/Base.cs.uid @@ -0,0 +1 @@ +uid://demgvopfvjmql diff --git a/scripts/Extensions.cs b/scripts/Extensions.cs new file mode 100644 index 0000000..f10fcf4 --- /dev/null +++ b/scripts/Extensions.cs @@ -0,0 +1,9 @@ +namespace NodeWar; + +public static class Extensions +{ + public static float ToFloat(this double value) + { + return (float)value; + } +} diff --git a/scripts/Extensions.cs.uid b/scripts/Extensions.cs.uid new file mode 100644 index 0000000..eff30a9 --- /dev/null +++ b/scripts/Extensions.cs.uid @@ -0,0 +1 @@ +uid://dmg4an0s8hjg7 diff --git a/scripts/Faction.cs b/scripts/Faction.cs new file mode 100644 index 0000000..72431bd --- /dev/null +++ b/scripts/Faction.cs @@ -0,0 +1,8 @@ +namespace NodeWar; + +public enum Faction +{ + Neutral, + Player, + Computer +} \ No newline at end of file diff --git a/scripts/Faction.cs.uid b/scripts/Faction.cs.uid new file mode 100644 index 0000000..3865479 --- /dev/null +++ b/scripts/Faction.cs.uid @@ -0,0 +1 @@ +uid://o85xjbm0ecxg diff --git a/scripts/Pip.cs b/scripts/Pip.cs new file mode 100644 index 0000000..4078a65 --- /dev/null +++ b/scripts/Pip.cs @@ -0,0 +1,38 @@ +using Godot; + +namespace NodeWar.Scripts; + +public partial class Pip : Area2D +{ + [Export] + public Faction Faction; + + [Export] + public Base Target; + + [Export] + public float Speed { get; set; } = 100; + + public override void _Ready() + { + AreaEntered += OnAreaEntered; + } + + public override void _Process(double delta) + { + if (Target == null) + return; + + var direction = Target.Position - GlobalPosition; + Position += direction.Normalized() * Speed * delta.ToFloat(); + } + + private void OnAreaEntered(Node2D body) + { + if (body is Base { Faction: Faction.Computer } enteredBase) + { + enteredBase.Health -= 1; + QueueFree(); + } + } +} diff --git a/scripts/Pip.cs.uid b/scripts/Pip.cs.uid new file mode 100644 index 0000000..d8b33c6 --- /dev/null +++ b/scripts/Pip.cs.uid @@ -0,0 +1 @@ +uid://cdbkkb2cpwkn1